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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * GDI region objects. Shamelessly ripped out from the X11 distribution
22 * Thanks for the nice licence.
24 * Copyright 1993, 1994, 1995 Alexandre Julliard
25 * Modifications and additions: Copyright 1998 Huw Davies
28 * This library is free software; you can redistribute it and/or
29 * modify it under the terms of the GNU Lesser General Public
30 * License as published by the Free Software Foundation; either
31 * version 2.1 of the License, or (at your option) any later version.
33 * This library is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 * Lesser General Public License for more details.
38 * You should have received a copy of the GNU Lesser General Public
39 * License along with this library; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
43 /************************************************************************
45 Copyright (c) 1987, 1988 X Consortium
47 Permission is hereby granted, free of charge, to any person obtaining a copy
48 of this software and associated documentation files (the "Software"), to deal
49 in the Software without restriction, including without limitation the rights
50 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51 copies of the Software, and to permit persons to whom the Software is
52 furnished to do so, subject to the following conditions:
54 The above copyright notice and this permission notice shall be included in
55 all copies or substantial portions of the Software.
57 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
61 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
62 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64 Except as contained in this notice, the name of the X Consortium shall not be
65 used in advertising or otherwise to promote the sale, use or other dealings
66 in this Software without prior written authorization from the X Consortium.
69 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
73 Permission to use, copy, modify, and distribute this software and its
74 documentation for any purpose and without fee is hereby granted,
75 provided that the above copyright notice appear in all copies and that
76 both that copyright notice and this permission notice appear in
77 supporting documentation, and that the name of Digital not be
78 used in advertising or publicity pertaining to distribution of the
79 software without specific, written prior permission.
81 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
82 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
83 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
84 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
85 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
86 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
89 ************************************************************************/
91 * The functions in this file implement the Region abstraction, similar to one
92 * used in the X11 sample server. A Region is simply an area, as the name
93 * implies, and is implemented as a "y-x-banded" array of rectangles. To
94 * explain: Each Region is made up of a certain number of rectangles sorted
95 * by y coordinate first, and then by x coordinate.
97 * Furthermore, the rectangles are banded such that every rectangle with a
98 * given upper-left y coordinate (y1) will have the same lower-right y
99 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
100 * will span the entire vertical distance of the band. This means that some
101 * areas that could be merged into a taller rectangle will be represented as
102 * several shorter rectangles to account for shorter rectangles to its left
103 * or right but within its "vertical scope".
105 * An added constraint on the rectangles is that they must cover as much
106 * horizontal area as possible. E.g. no two rectangles in a band are allowed
109 * Whenever possible, bands will be merged together to cover a greater vertical
110 * distance (and thus reduce the number of rectangles). Two bands can be merged
111 * only if the bottom of one touches the top of the other and they have
112 * rectangles in the same places (of the same width, of course). This maintains
113 * the y-x-banding that's so nice to have...
117 #include <suppress.h>
122 PROSRGNDATA prgnDefault
= NULL
;
123 HRGN hrgnDefault
= NULL
;
125 // Internal Functions
128 #define COPY_RECTS(dest, src, nRects) \
130 PRECTL xDest = (dest); \
131 PRECTL xSrc = (src); \
132 UINT xRects = (nRects); \
133 while(xRects-- > 0) { \
134 *(xDest++) = *(xSrc++); \
138 #define COPY_RECTS(dest, src, nRects) RtlCopyMemory(dest, src, (nRects) * sizeof(RECTL))
141 #define EMPTY_REGION(pReg) { \
142 (pReg)->rdh.nCount = 0; \
143 (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
144 (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
145 (pReg)->rdh.iType = RDH_RECTANGLES; \
148 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
150 #define INRECT(r, x, y) \
151 ( ( ((r).right > x)) && \
152 ( ((r).left <= x)) && \
153 ( ((r).bottom > y)) && \
156 /* 1 if two RECTs overlap.
157 * 0 if two RECTs do not overlap.
159 #define EXTENTCHECK(r1, r2) \
160 ((r1)->right > (r2)->left && \
161 (r1)->left < (r2)->right && \
162 (r1)->bottom > (r2)->top && \
163 (r1)->top < (r2)->bottom)
166 * In scan converting polygons, we want to choose those pixels
167 * which are inside the polygon. Thus, we add .5 to the starting
168 * x coordinate for both left and right edges. Now we choose the
169 * first pixel which is inside the pgon for the left edge and the
170 * first pixel which is outside the pgon for the right edge.
171 * Draw the left pixel, but not the right.
173 * How to add .5 to the starting x coordinate:
174 * If the edge is moving to the right, then subtract dy from the
175 * error term from the general form of the algorithm.
176 * If the edge is moving to the left, then add dy to the error term.
178 * The reason for the difference between edges moving to the left
179 * and edges moving to the right is simple: If an edge is moving
180 * to the right, then we want the algorithm to flip immediately.
181 * If it is moving to the left, then we don't want it to flip until
182 * we traverse an entire pixel.
184 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
185 int dx; /* Local storage */ \
188 * If the edge is horizontal, then it is ignored \
189 * and assumed not to be processed. Otherwise, do this stuff. \
193 dx = (x2) - xStart; \
197 incr1 = -2 * dx + 2 * (dy) * m1; \
198 incr2 = -2 * dx + 2 * (dy) * m; \
199 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
203 incr1 = 2 * dx - 2 * (dy) * m1; \
204 incr2 = 2 * dx - 2 * (dy) * m; \
205 d = -2 * m * (dy) + 2 * dx; \
210 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
233 * This structure contains all of the information needed
234 * to run the bresenham algorithm.
235 * The variables may be hardcoded into the declarations
236 * instead of using this structure to make use of
237 * register declarations.
241 INT minor_axis
; /* Minor axis */
242 INT d
; /* Decision variable */
243 INT m
, m1
; /* Slope and slope+1 */
244 INT incr1
, incr2
; /* Error increments */
248 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
249 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
250 bres.m, bres.m1, bres.incr1, bres.incr2)
252 #define BRESINCRPGONSTRUCT(bres) \
253 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
258 * These are the data structures needed to scan
259 * convert regions. Two different scan conversion
260 * methods are available -- the even-odd method, and
261 * the winding number method.
262 * The even-odd rule states that a point is inside
263 * the polygon if a ray drawn from that point in any
264 * direction will pass through an odd number of
266 * By the winding number rule, a point is decided
267 * to be inside the polygon if a ray drawn from that
268 * point in any direction passes through a different
269 * number of clockwise and counter-clockwise path
272 * These data structures are adapted somewhat from
273 * the algorithm in (Foley/Van Dam) for scan converting
275 * The basic algorithm is to start at the top (smallest y)
276 * of the polygon, stepping down to the bottom of
277 * the polygon by incrementing the y coordinate. We
278 * keep a list of edges which the current scanline crosses,
279 * sorted by x. This list is called the Active Edge Table (AET)
280 * As we change the y-coordinate, we update each entry in
281 * in the active edge table to reflect the edges new xcoord.
282 * This list must be sorted at each scanline in case
283 * two edges intersect.
284 * We also keep a data structure known as the Edge Table (ET),
285 * which keeps track of all the edges which the current
286 * scanline has not yet reached. The ET is basically a
287 * list of ScanLineList structures containing a list of
288 * edges which are entered at a given scanline. There is one
289 * ScanLineList per scanline at which an edge is entered.
290 * When we enter a new edge, we move it from the ET to the AET.
292 * From the AET, we can implement the even-odd rule as in
294 * The winding number rule is a little trickier. We also
295 * keep the EdgeTableEntries in the AET linked by the
296 * nextWETE (winding EdgeTableEntry) link. This allows
297 * the edges to be linked just as before for updating
298 * purposes, but only uses the edges linked by the nextWETE
299 * link as edges representing spans of the polygon to
300 * drawn (as with the even-odd rule).
304 * For the winding number rule
307 #define COUNTERCLOCKWISE -1
309 typedef struct _EdgeTableEntry
311 INT ymax
; /* ycoord at which we exit this edge. */
312 BRESINFO bres
; /* Bresenham info to run the edge */
313 struct _EdgeTableEntry
*next
; /* Next in the list */
314 struct _EdgeTableEntry
*back
; /* For insertion sort */
315 struct _EdgeTableEntry
*nextWETE
; /* For winding num rule */
316 int ClockWise
; /* Flag for winding number rule */
320 typedef struct _ScanLineList
322 INT scanline
; /* The scanline represented */
323 EdgeTableEntry
*edgelist
; /* Header node */
324 struct _ScanLineList
*next
; /* Next in the list */
330 INT ymax
; /* ymax for the polygon */
331 INT ymin
; /* ymin for the polygon */
332 ScanLineList scanlines
; /* Header node */
337 * Here is a struct to help with storage allocation
338 * so we can allocate a big chunk at a time, and then take
339 * pieces from this heap when we need to.
341 #define SLLSPERBLOCK 25
343 typedef struct _ScanLineListBlock
345 ScanLineList SLLs
[SLLSPERBLOCK
];
346 struct _ScanLineListBlock
*next
;
351 * A few macros for the inner loops of the fill code where
352 * performance considerations don't allow a procedure call.
354 * Evaluate the given edge at the given scanline.
355 * If the edge has expired, then we leave it and fix up
356 * the active edge table; otherwise, we increment the
357 * x value to be ready for the next scanline.
358 * The winding number rule is in effect, so we must notify
359 * the caller when the edge has been removed so he
360 * can reorder the Winding Active Edge Table.
362 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
363 if (pAET->ymax == y) { /* Leaving this edge */ \
364 pPrevAET->next = pAET->next; \
365 pAET = pPrevAET->next; \
368 pAET->back = pPrevAET; \
371 BRESINCRPGONSTRUCT(pAET->bres); \
379 * Evaluate the given edge at the given scanline.
380 * If the edge has expired, then we leave it and fix up
381 * the active edge table; otherwise, we increment the
382 * x value to be ready for the next scanline.
383 * The even-odd rule is in effect.
385 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
386 if (pAET->ymax == y) { /* Leaving this edge */ \
387 pPrevAET->next = pAET->next; \
388 pAET = pPrevAET->next; \
390 pAET->back = pPrevAET; \
393 BRESINCRPGONSTRUCT(pAET->bres); \
399 /**************************************************************************
403 *************************************************************************/
405 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
406 #define SMALL_COORDINATE 0x80000000
409 * Check to see if there is enough memory in the present region.
411 static __inline
int xmemcheck(ROSRGNDATA
*reg
, PRECTL
*rect
, PRECTL
*firstrect
)
413 if ( (reg
->rdh
.nCount
+1) * sizeof(RECT
) >= reg
->rdh
.nRgnSize
)
416 DWORD NewSize
= 2 * reg
->rdh
.nRgnSize
;
417 if (NewSize
< (reg
->rdh
.nCount
+ 1) * sizeof(RECT
))
419 NewSize
= (reg
->rdh
.nCount
+ 1) * sizeof(RECT
);
421 temp
= ExAllocatePoolWithTag(PagedPool
, NewSize
, TAG_REGION
);
428 /* Copy the rectangles */
429 COPY_RECTS(temp
, *firstrect
, reg
->rdh
.nCount
);
431 reg
->rdh
.nRgnSize
= NewSize
;
432 if (*firstrect
!= ®
->rdh
.rcBound
)
434 ExFreePoolWithTag(*firstrect
, TAG_REGION
);
437 *rect
= (*firstrect
)+reg
->rdh
.nCount
;
442 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(PRECTL *)&(firstrect))
444 typedef void (FASTCALL
*overlapProcp
)(PROSRGNDATA
, PRECT
, PRECT
, PRECT
, PRECT
, INT
, INT
);
445 typedef void (FASTCALL
*nonOverlapProcp
)(PROSRGNDATA
, PRECT
, PRECT
, INT
, INT
);
447 // Number of points to buffer before sending them off to scanlines() : Must be an even number
448 #define NUMPTSTOBUFFER 200
450 #define RGN_DEFAULT_RECTS 2
452 // Used to allocate buffers for points and link the buffers together
453 typedef struct _POINTBLOCK
455 POINT pts
[NUMPTSTOBUFFER
];
456 struct _POINTBLOCK
*next
;
461 * This function is left there for debugging purposes.
465 IntDumpRegion(HRGN hRgn
)
469 Data
= RGNOBJAPI_Lock(hRgn
, NULL
);
472 DbgPrint("IntDumpRegion called with invalid region!\n");
476 DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
478 Data
->rdh
.rcBound
.left
,
479 Data
->rdh
.rcBound
.top
,
480 Data
->rdh
.rcBound
.right
,
481 Data
->rdh
.rcBound
.bottom
,
484 RGNOBJAPI_Unlock(Data
);
486 #endif /* Not NDEBUG */
491 REGION_Complexity(PREGION prgn
)
496 switch (prgn
->rdh
.nCount
)
498 DPRINT("Region Complexity -> %lu", prgn
->rdh
.nCount
);
504 return COMPLEXREGION
;
515 if (dst
!= src
) // Don't want to copy to itself
517 if (dst
->rdh
.nRgnSize
< src
->rdh
.nCount
* sizeof(RECT
))
521 temp
= ExAllocatePoolWithTag(PagedPool
, src
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
525 if (dst
->Buffer
&& dst
->Buffer
!= &dst
->rdh
.rcBound
)
526 ExFreePoolWithTag(dst
->Buffer
, TAG_REGION
); // Free the old buffer
528 dst
->rdh
.nRgnSize
= src
->rdh
.nCount
* sizeof(RECT
); // Size of region buffer
531 dst
->rdh
.nCount
= src
->rdh
.nCount
; // Number of rectangles present in Buffer
532 dst
->rdh
.rcBound
.left
= src
->rdh
.rcBound
.left
;
533 dst
->rdh
.rcBound
.top
= src
->rdh
.rcBound
.top
;
534 dst
->rdh
.rcBound
.right
= src
->rdh
.rcBound
.right
;
535 dst
->rdh
.rcBound
.bottom
= src
->rdh
.rcBound
.bottom
;
536 dst
->rdh
.iType
= src
->rdh
.iType
;
537 COPY_RECTS(dst
->Buffer
, src
->Buffer
, src
->rdh
.nCount
);
549 RECTL
*pRect
, *pRectEnd
, *pExtents
;
551 if (pReg
->rdh
.nCount
== 0)
553 pReg
->rdh
.rcBound
.left
= 0;
554 pReg
->rdh
.rcBound
.top
= 0;
555 pReg
->rdh
.rcBound
.right
= 0;
556 pReg
->rdh
.rcBound
.bottom
= 0;
557 pReg
->rdh
.iType
= RDH_RECTANGLES
;
561 pExtents
= &pReg
->rdh
.rcBound
;
562 pRect
= pReg
->Buffer
;
563 pRectEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
- 1;
565 /* Since pRect is the first rectangle in the region, it must have the
566 * smallest top and since pRectEnd is the last rectangle in the region,
567 * it must have the largest bottom, because of banding. Initialize left and
568 * right from pRect and pRectEnd, resp., as good things to initialize them
570 pExtents
->left
= pRect
->left
;
571 pExtents
->top
= pRect
->top
;
572 pExtents
->right
= pRectEnd
->right
;
573 pExtents
->bottom
= pRectEnd
->bottom
;
575 while (pRect
<= pRectEnd
)
577 if (pRect
->left
< pExtents
->left
)
578 pExtents
->left
= pRect
->left
;
579 if (pRect
->right
> pExtents
->right
)
580 pExtents
->right
= pRect
->right
;
584 pReg
->rdh
.iType
= RDH_RECTANGLES
;
587 // FIXME: This function needs review and testing
588 /***********************************************************************
589 * REGION_CropAndOffsetRegion
593 REGION_CropAndOffsetRegion(
597 const POINTL
*offset
) // FIXME: we should probably remove offset from here
600 const POINT
*off
= offset
;
604 /* Just copy and offset */
608 if (rgnDst
== rgnSrc
)
610 if (off
->x
|| off
->y
)
611 xrect
= rgnDst
->Buffer
;
613 return REGION_Complexity(rgnDst
);
617 xrect
= ExAllocatePoolWithTag(PagedPool
,
618 rgnSrc
->rdh
.nCount
* sizeof(RECT
),
623 /* Free the old buffer. Will be assigned to xrect below. */
624 if (rgnDst
->Buffer
&& (rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
))
625 ExFreePoolWithTag(rgnDst
->Buffer
, TAG_REGION
);
628 if (rgnDst
!= rgnSrc
)
633 if (off
->x
|| off
->y
)
636 for (i
= 0; i
< rgnDst
->rdh
.nCount
; i
++)
638 xrect
[i
].left
= (rgnSrc
->Buffer
+ i
)->left
+ off
->x
;
639 xrect
[i
].right
= (rgnSrc
->Buffer
+ i
)->right
+ off
->x
;
640 xrect
[i
].top
= (rgnSrc
->Buffer
+ i
)->top
+ off
->y
;
641 xrect
[i
].bottom
= (rgnSrc
->Buffer
+ i
)->bottom
+ off
->y
;
644 rgnDst
->rdh
.rcBound
.left
+= off
->x
;
645 rgnDst
->rdh
.rcBound
.right
+= off
->x
;
646 rgnDst
->rdh
.rcBound
.top
+= off
->y
;
647 rgnDst
->rdh
.rcBound
.bottom
+= off
->y
;
651 COPY_RECTS(xrect
, rgnSrc
->Buffer
, rgnDst
->rdh
.nCount
);
654 rgnDst
->Buffer
= xrect
;
656 else if ((rect
->left
>= rect
->right
) ||
657 (rect
->top
>= rect
->bottom
) ||
658 !EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
))
662 else // Region box and clipping rect appear to intersect
665 ULONG i
, j
, clipa
, clipb
, nRgnSize
;
669 INT bottom
= MINLONG
;
671 /* Skip all rects that are completely above our intersect rect */
672 for (clipa
= 0; clipa
< rgnSrc
->rdh
.nCount
; clipa
++)
674 /* bottom is exclusive, so break when we go above it */
675 if (rgnSrc
->Buffer
[clipa
].bottom
> rect
->top
) break;
678 /* Bail out, if there is nothing left */
679 if (clipa
== rgnSrc
->rdh
.nCount
) goto empty
;
681 /* Find the last rect that is still within the intersect rect (exclusive) */
682 for (clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
684 /* bottom is exclusive, so stop, when we start at that y pos */
685 if (rgnSrc
->Buffer
[clipb
].top
>= rect
->bottom
) break;
688 /* Bail out, if there is nothing left */
689 if (clipb
== clipa
) goto empty
;
691 // clipa - index of the first rect in the first intersecting band
692 // clipb - index of the last rect in the last intersecting band plus 1
694 /* Check if the buffer in the dest region is large enough,
695 otherwise allocate a new one */
696 nRgnSize
= (clipb
- clipa
) * sizeof(RECT
);
697 if ((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nRgnSize
< nRgnSize
))
700 temp
= ExAllocatePoolWithTag(PagedPool
, nRgnSize
, TAG_REGION
);
704 /* Free the old buffer */
705 if (rgnDst
->Buffer
&& (rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
))
706 ExFreePoolWithTag(rgnDst
->Buffer
, TAG_REGION
);
708 rgnDst
->Buffer
= temp
;
709 rgnDst
->rdh
.nCount
= 0;
710 rgnDst
->rdh
.nRgnSize
= nRgnSize
;
711 rgnDst
->rdh
.iType
= RDH_RECTANGLES
;
714 /* Loop all rects within the intersect rect from the y perspective */
715 for (i
= clipa
, j
= 0; i
< clipb
; i
++)
717 // i - src index, j - dst index, j is always <= i for obvious reasons
719 lpr
= &rgnSrc
->Buffer
[i
];
721 /* Make sure the source rect is not retarded */
722 ASSERT(lpr
->bottom
> rect
->top
);
723 ASSERT(lpr
->right
> rect
->left
);
725 /* We already checked above, this should hold true */
726 ASSERT(lpr
->bottom
> rect
->top
);
727 ASSERT(lpr
->top
< rect
->bottom
);
729 /* Check if this rect is really inside the intersect rect */
730 if ((lpr
->left
< rect
->right
) && (lpr
->right
> rect
->left
))
732 rpr
= &rgnDst
->Buffer
[j
];
734 /* Crop the rect with the intersect rect and add offset */
735 rpr
->top
= max(lpr
->top
, rect
->top
) + off
->y
;
736 rpr
->bottom
= min(lpr
->bottom
, rect
->bottom
) + off
->y
;
737 rpr
->left
= max(lpr
->left
, rect
->left
) + off
->x
;
738 rpr
->right
= min(lpr
->right
, rect
->right
) + off
->y
;
740 /* Make sure the resulting rect is not retarded */
741 ASSERT(lpr
->bottom
> rect
->top
);
742 ASSERT(lpr
->right
> rect
->left
);
744 /* Track new bounds */
745 if (rpr
->left
< left
) left
= rpr
->left
;
746 if (rpr
->right
> right
) right
= rpr
->right
;
747 if (rpr
->top
< top
) top
= rpr
->top
;
748 if (rpr
->bottom
> bottom
) bottom
= rpr
->bottom
;
750 /* Next target rect */
755 if (j
== 0) goto empty
;
757 /* Update the bounds rect */
758 rgnDst
->rdh
.rcBound
.left
= left
;
759 rgnDst
->rdh
.rcBound
.right
= right
;
760 rgnDst
->rdh
.rcBound
.top
= top
;
761 rgnDst
->rdh
.rcBound
.bottom
= bottom
;
763 /* Set new rect count */
764 rgnDst
->rdh
.nCount
= j
;
767 return REGION_Complexity(rgnDst
);
772 rgnDst
->Buffer
= &rgnDst
->rdh
.rcBound
;
775 EMPTY_REGION(rgnDst
);
781 * Attempt to merge the rects in the current band with those in the
782 * previous one. Used only by REGION_RegionOp.
785 * The new index for the previous band.
787 * \note Side Effects:
788 * If coalescing takes place:
789 * - rectangles in the previous band will have their bottom fields
791 * - pReg->numRects will be decreased.
798 PROSRGNDATA pReg
, /* Region to coalesce */
799 INT prevStart
, /* Index of start of previous band */
800 INT curStart
) /* Index of start of current band */
802 RECTL
*pPrevRect
; /* Current rect in previous band */
803 RECTL
*pCurRect
; /* Current rect in current band */
804 RECTL
*pRegEnd
; /* End of region */
805 INT curNumRects
; /* Number of rectangles in current band */
806 INT prevNumRects
; /* Number of rectangles in previous band */
807 INT bandtop
; /* Top coordinate for current band */
809 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
810 pPrevRect
= pReg
->Buffer
+ prevStart
;
811 prevNumRects
= curStart
- prevStart
;
813 /* Figure out how many rectangles are in the current band. Have to do
814 * this because multiple bands could have been added in REGION_RegionOp
815 * at the end when one region has been exhausted. */
816 pCurRect
= pReg
->Buffer
+ curStart
;
817 bandtop
= pCurRect
->top
;
818 for (curNumRects
= 0;
819 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
825 if (pCurRect
!= pRegEnd
)
827 /* If more than one band was added, we have to find the start
828 * of the last band added so the next coalescing job can start
829 * at the right place... (given when multiple bands are added,
830 * this may be pointless -- see above). */
832 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
836 curStart
= pRegEnd
- pReg
->Buffer
;
837 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
840 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0))
842 pCurRect
-= curNumRects
;
843 /* The bands may only be coalesced if the bottom of the previous
844 * matches the top scanline of the current. */
845 if (pPrevRect
->bottom
== pCurRect
->top
)
847 /* Make sure the bands have rects in the same places. This
848 * assumes that rects have been added in such a way that they
849 * cover the most area possible. I.e. two rects in a band must
850 * have some horizontal space between them. */
853 if ((pPrevRect
->left
!= pCurRect
->left
) ||
854 (pPrevRect
->right
!= pCurRect
->right
))
856 /* The bands don't line up so they can't be coalesced. */
864 while (prevNumRects
!= 0);
866 pReg
->rdh
.nCount
-= curNumRects
;
867 pCurRect
-= curNumRects
;
868 pPrevRect
-= curNumRects
;
870 /* The bands may be merged, so set the bottom of each rect
871 * in the previous band to that of the corresponding rect in
872 * the current band. */
875 pPrevRect
->bottom
= pCurRect
->bottom
;
880 while (curNumRects
!= 0);
882 /* If only one band was added to the region, we have to backup
883 * curStart to the start of the previous band.
885 * If more than one band was added to the region, copy the
886 * other bands down. The assumption here is that the other bands
887 * came from the same region as the current one and no further
888 * coalescing can be done on them since it's all been done
889 * already... curStart is already in the right place. */
890 if (pCurRect
== pRegEnd
)
892 curStart
= prevStart
;
898 *pPrevRect
++ = *pCurRect
++;
900 while (pCurRect
!= pRegEnd
);
909 * Apply an operation to two regions. Called by REGION_Union,
910 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
916 * The new region is overwritten.
918 *\note The idea behind this function is to view the two regions as sets.
919 * Together they cover a rectangle of area that this function divides
920 * into horizontal bands where points are covered only by one region
921 * or by both. For the first case, the nonOverlapFunc is called with
922 * each the band and the band's upper and lower extents. For the
923 * second, the overlapFunc is called to process the entire band. It
924 * is responsible for clipping the rectangles in the band, though
925 * this function provides the boundaries.
926 * At the end of each band, the new region is coalesced, if possible,
927 * to reduce the number of rectangles in the region.
934 ROSRGNDATA
*newReg
, /* Place to store result */
935 ROSRGNDATA
*reg1
, /* First region in operation */
936 ROSRGNDATA
*reg2
, /* 2nd region in operation */
937 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
938 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
939 nonOverlapProcp nonOverlap2Func
) /* Function to call for non-overlapping bands in region 2 */
941 RECTL
*r1
; /* Pointer into first region */
942 RECTL
*r2
; /* Pointer into 2d region */
943 RECTL
*r1End
; /* End of 1st region */
944 RECTL
*r2End
; /* End of 2d region */
945 INT ybot
; /* Bottom of intersection */
946 INT ytop
; /* Top of intersection */
947 RECTL
*oldRects
; /* Old rects for newReg */
948 ULONG prevBand
; /* Index of start of
949 * Previous band in newReg */
950 ULONG curBand
; /* Index of start of current band in newReg */
951 RECTL
*r1BandEnd
; /* End of current band in r1 */
952 RECTL
*r2BandEnd
; /* End of current band in r2 */
953 ULONG top
; /* Top of non-overlapping band */
954 ULONG bot
; /* Bottom of non-overlapping band */
957 * set r1, r2, r1End and r2End appropriately, preserve the important
958 * parts of the destination region until the end in case it's one of
959 * the two source regions, then mark the "new" region empty, allocating
960 * another array of rectangles for it to use. */
963 r1End
= r1
+ reg1
->rdh
.nCount
;
964 r2End
= r2
+ reg2
->rdh
.nCount
;
967 /* newReg may be one of the src regions so we can't empty it. We keep a
968 * note of its rects pointer (so that we can free them later), preserve its
969 * extents and simply set numRects to zero. */
970 oldRects
= newReg
->Buffer
;
971 newReg
->rdh
.nCount
= 0;
973 /* Allocate a reasonable number of rectangles for the new region. The idea
974 * is to allocate enough so the individual functions don't need to
975 * reallocate and copy the array, which is time consuming, yet we don't
976 * have to worry about using too much memory. I hope to be able to
977 * nuke the Xrealloc() at the end of this function eventually. */
978 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
+ 1, reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
980 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
981 newReg
->rdh
.nRgnSize
,
985 newReg
->rdh
.nRgnSize
= 0;
989 /* Initialize ybot and ytop.
990 * In the upcoming loop, ybot and ytop serve different functions depending
991 * on whether the band being handled is an overlapping or non-overlapping
993 * In the case of a non-overlapping band (only one of the regions
994 * has points in the band), ybot is the bottom of the most recent
995 * intersection and thus clips the top of the rectangles in that band.
996 * ytop is the top of the next intersection between the two regions and
997 * serves to clip the bottom of the rectangles in the current band.
998 * For an overlapping band (where the two regions intersect), ytop clips
999 * the top of the rectangles of both regions and ybot clips the bottoms. */
1000 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
1001 ybot
= reg1
->rdh
.rcBound
.top
;
1003 ybot
= reg2
->rdh
.rcBound
.top
;
1005 /* prevBand serves to mark the start of the previous band so rectangles
1006 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1007 * In the beginning, there is no previous band, so prevBand == curBand
1008 * (curBand is set later on, of course, but the first band will always
1009 * start at index 0). prevBand and curBand must be indices because of
1010 * the possible expansion, and resultant moving, of the new region's
1011 * array of rectangles. */
1016 curBand
= newReg
->rdh
.nCount
;
1018 /* This algorithm proceeds one source-band (as opposed to a
1019 * destination band, which is determined by where the two regions
1020 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1021 * rectangle after the last one in the current band for their
1022 * respective regions. */
1024 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1030 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1035 /* First handle the band that doesn't intersect, if any.
1037 * Note that attention is restricted to one band in the
1038 * non-intersecting region at once, so if a region has n
1039 * bands between the current position and the next place it overlaps
1040 * the other, this entire loop will be passed through n times. */
1041 if (r1
->top
< r2
->top
)
1043 top
= max(r1
->top
,ybot
);
1044 bot
= min(r1
->bottom
,r2
->top
);
1046 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
1048 (*nonOverlap1Func
)(newReg
, r1
, r1BandEnd
, top
, bot
);
1053 else if (r2
->top
< r1
->top
)
1055 top
= max(r2
->top
,ybot
);
1056 bot
= min(r2
->bottom
,r1
->top
);
1058 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
1060 (*nonOverlap2Func
)(newReg
, r2
, r2BandEnd
, top
, bot
);
1070 /* If any rectangles got added to the region, try and coalesce them
1071 * with rectangles from the previous band. Note we could just do
1072 * this test in miCoalesce, but some machines incur a not
1073 * inconsiderable cost for function calls, so... */
1074 if (newReg
->rdh
.nCount
!= curBand
)
1076 prevBand
= REGION_Coalesce(newReg
, prevBand
, curBand
);
1079 /* Now see if we've hit an intersecting band. The two bands only
1080 * intersect if ybot > ytop */
1081 ybot
= min(r1
->bottom
, r2
->bottom
);
1082 curBand
= newReg
->rdh
.nCount
;
1085 (*overlapFunc
)(newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1088 if (newReg
->rdh
.nCount
!= curBand
)
1090 prevBand
= REGION_Coalesce(newReg
, prevBand
, curBand
);
1093 /* If we've finished with a band (bottom == ybot) we skip forward
1094 * in the region to the next band. */
1095 if (r1
->bottom
== ybot
)
1099 if (r2
->bottom
== ybot
)
1104 while ((r1
!= r1End
) && (r2
!= r2End
));
1106 /* Deal with whichever region still has rectangles left. */
1107 curBand
= newReg
->rdh
.nCount
;
1110 if (nonOverlap1Func
!= NULL
)
1115 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1120 (*nonOverlap1Func
)(newReg
,
1127 while (r1
!= r1End
);
1130 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
1135 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1140 (*nonOverlap2Func
)(newReg
,
1147 while (r2
!= r2End
);
1150 if (newReg
->rdh
.nCount
!= curBand
)
1152 (void) REGION_Coalesce(newReg
, prevBand
, curBand
);
1155 /* A bit of cleanup. To keep regions from growing without bound,
1156 * we shrink the array of rectangles to match the new number of
1157 * rectangles in the region. This never goes to 0, however...
1159 * Only do this stuff if the number of rectangles allocated is more than
1160 * twice the number of rectangles in the region (a simple optimization...). */
1161 if ((2 * newReg
->rdh
.nCount
* sizeof(RECT
) < newReg
->rdh
.nRgnSize
) && (newReg
->rdh
.nCount
> 2))
1163 if (REGION_NOT_EMPTY(newReg
))
1165 RECTL
*prev_rects
= newReg
->Buffer
;
1166 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
1167 newReg
->rdh
.nCount
* sizeof(RECT
),
1170 if (!newReg
->Buffer
)
1171 newReg
->Buffer
= prev_rects
;
1174 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
1175 COPY_RECTS(newReg
->Buffer
, prev_rects
, newReg
->rdh
.nCount
);
1176 if (prev_rects
!= &newReg
->rdh
.rcBound
)
1177 ExFreePoolWithTag(prev_rects
, TAG_REGION
);
1182 /* No point in doing the extra work involved in an Xrealloc if
1183 * the region is empty */
1184 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
1185 if (newReg
->Buffer
!= &newReg
->rdh
.rcBound
)
1186 ExFreePoolWithTag(newReg
->Buffer
, TAG_REGION
);
1188 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, sizeof(RECT
), TAG_REGION
);
1189 ASSERT(newReg
->Buffer
);
1193 newReg
->rdh
.iType
= RDH_RECTANGLES
;
1195 if (oldRects
!= &newReg
->rdh
.rcBound
)
1196 ExFreePoolWithTag(oldRects
, TAG_REGION
);
1200 /***********************************************************************
1201 * Region Intersection
1202 ***********************************************************************/
1206 * Handle an overlapping band for REGION_Intersect.
1211 * \note Side Effects:
1212 * Rectangles may be added to the region.
1230 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1232 while ((r1
!= r1End
) && (r2
!= r2End
))
1234 left
= max(r1
->left
, r2
->left
);
1235 right
= min(r1
->right
, r2
->right
);
1237 /* If there's any overlap between the two rectangles, add that
1238 * overlap to the new region.
1239 * There's no need to check for subsumption because the only way
1240 * such a need could arise is if some region has two rectangles
1241 * right next to each other. Since that should never happen... */
1244 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1245 pNextRect
->left
= left
;
1246 pNextRect
->top
= top
;
1247 pNextRect
->right
= right
;
1248 pNextRect
->bottom
= bottom
;
1249 pReg
->rdh
.nCount
+= 1;
1253 /* Need to advance the pointers. Shift the one that extends
1254 * to the right the least, since the other still has a chance to
1255 * overlap with that region's next rectangle, if you see what I mean. */
1256 if (r1
->right
< r2
->right
)
1260 else if (r2
->right
< r1
->right
)
1274 /***********************************************************************
1275 * REGION_IntersectRegion
1280 REGION_IntersectRegion(
1285 /* Check for trivial reject */
1286 if ( (!(reg1
->rdh
.nCount
)) || (!(reg2
->rdh
.nCount
)) ||
1287 (!EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
)) )
1288 newReg
->rdh
.nCount
= 0;
1290 REGION_RegionOp(newReg
,
1297 /* Can't alter newReg's extents before we call miRegionOp because
1298 * it might be one of the source regions and miRegionOp depends
1299 * on the extents of those regions being the same. Besides, this
1300 * way there's no checking against rectangles that will be nuked
1301 * due to coalescing, so we have to examine fewer rectangles. */
1302 REGION_SetExtents(newReg
);
1305 /***********************************************************************
1307 ***********************************************************************/
1310 * Handle a non-overlapping band for the union operation. Just
1311 * Adds the rectangles into the region. Doesn't have to check for
1312 * subsumption or anything.
1317 * \note Side Effects:
1318 * pReg->numRects is incremented and the final rectangles overwritten
1319 * with the rectangles we're passed.
1334 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1338 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1339 pNextRect
->left
= r
->left
;
1340 pNextRect
->top
= top
;
1341 pNextRect
->right
= r
->right
;
1342 pNextRect
->bottom
= bottom
;
1343 pReg
->rdh
.nCount
+= 1;
1352 * Handle an overlapping band for the union operation. Picks the
1353 * left-most rectangle each time and merges it into the region.
1358 * \note Side Effects:
1359 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1377 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1379 #define MERGERECT(r) \
1380 if ((pReg->rdh.nCount != 0) && \
1381 ((pNextRect-1)->top == top) && \
1382 ((pNextRect-1)->bottom == bottom) && \
1383 ((pNextRect-1)->right >= r->left)) \
1385 if ((pNextRect-1)->right < r->right) \
1387 (pNextRect-1)->right = r->right; \
1392 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1393 pNextRect->top = top; \
1394 pNextRect->bottom = bottom; \
1395 pNextRect->left = r->left; \
1396 pNextRect->right = r->right; \
1397 pReg->rdh.nCount += 1; \
1402 while ((r1
!= r1End
) && (r2
!= r2End
))
1404 if (r1
->left
< r2
->left
)
1420 while (r1
!= r1End
);
1431 /***********************************************************************
1432 * REGION_UnionRegion
1434 static void FASTCALL
1440 /* Checks all the simple cases
1441 * Region 1 and 2 are the same or region 1 is empty */
1442 if (reg1
== reg2
|| 0 == reg1
->rdh
.nCount
||
1443 reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
||
1444 reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
)
1448 REGION_CopyRegion(newReg
, reg2
);
1454 /* If nothing to union (region 2 empty) */
1455 if (0 == reg2
->rdh
.nCount
||
1456 reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
||
1457 reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
)
1461 REGION_CopyRegion(newReg
, reg1
);
1466 /* Region 1 completely subsumes region 2 */
1467 if (1 == reg1
->rdh
.nCount
&&
1468 reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
&&
1469 reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
&&
1470 reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
&&
1471 reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
)
1475 REGION_CopyRegion(newReg
, reg1
);
1481 /* Region 2 completely subsumes region 1 */
1482 if (1 == reg2
->rdh
.nCount
&&
1483 reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
&&
1484 reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
&&
1485 reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
&&
1486 reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
)
1490 REGION_CopyRegion(newReg
, reg2
);
1496 REGION_RegionOp (newReg
,
1503 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1504 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1505 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1506 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1509 /***********************************************************************
1510 * Region Subtraction
1511 ***********************************************************************/
1514 * Deal with non-overlapping band for subtraction. Any parts from
1515 * region 2 we discard. Anything from region 1 we add to the region.
1520 * \note Side Effects:
1521 * pReg may be affected.
1527 REGION_SubtractNonO1(
1536 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1540 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1541 pNextRect
->left
= r
->left
;
1542 pNextRect
->top
= top
;
1543 pNextRect
->right
= r
->right
;
1544 pNextRect
->bottom
= bottom
;
1545 pReg
->rdh
.nCount
+= 1;
1555 * Overlapping band subtraction. x1 is the left-most point not yet
1561 * \note Side Effects:
1562 * pReg may have rectangles added to it.
1581 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1583 while ((r1
!= r1End
) && (r2
!= r2End
))
1585 if (r2
->right
<= left
)
1587 /* Subtrahend missed the boat: go to next subtrahend. */
1590 else if (r2
->left
<= left
)
1592 /* Subtrahend preceeds minuend: nuke left edge of minuend. */
1594 if (left
>= r1
->right
)
1596 /* Minuend completely covered: advance to next minuend and
1597 * reset left fence to edge of new minuend. */
1604 /* Subtrahend now used up since it doesn't extend beyond
1609 else if (r2
->left
< r1
->right
)
1611 /* Left part of subtrahend covers part of minuend: add uncovered
1612 * part of minuend to region and skip to next subtrahend. */
1613 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1614 pNextRect
->left
= left
;
1615 pNextRect
->top
= top
;
1616 pNextRect
->right
= r2
->left
;
1617 pNextRect
->bottom
= bottom
;
1618 pReg
->rdh
.nCount
+= 1;
1621 if (left
>= r1
->right
)
1623 /* Minuend used up: advance to new... */
1630 /* Subtrahend used up */
1636 /* Minuend used up: add any remaining piece before advancing. */
1637 if (r1
->right
> left
)
1639 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1640 pNextRect
->left
= left
;
1641 pNextRect
->top
= top
;
1642 pNextRect
->right
= r1
->right
;
1643 pNextRect
->bottom
= bottom
;
1644 pReg
->rdh
.nCount
+= 1;
1653 /* Add remaining minuend rectangles to region. */
1656 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1657 pNextRect
->left
= left
;
1658 pNextRect
->top
= top
;
1659 pNextRect
->right
= r1
->right
;
1660 pNextRect
->bottom
= bottom
;
1661 pReg
->rdh
.nCount
+= 1;
1674 * Subtract regS from regM and leave the result in regD.
1675 * S stands for subtrahend, M for minuend and D for difference.
1680 * \note Side Effects:
1681 * regD is overwritten.
1687 REGION_SubtractRegion(
1692 /* Check for trivial reject */
1693 if ((!(regM
->rdh
.nCount
)) ||
1694 (!(regS
->rdh
.nCount
)) ||
1695 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1697 REGION_CopyRegion(regD
, regM
);
1701 REGION_RegionOp(regD
,
1705 REGION_SubtractNonO1
,
1708 /* Can't alter newReg's extents before we call miRegionOp because
1709 * it might be one of the source regions and miRegionOp depends
1710 * on the extents of those regions being the unaltered. Besides, this
1711 * way there's no checking against rectangles that will be nuked
1712 * due to coalescing, so we have to examine fewer rectangles. */
1713 REGION_SetExtents(regD
);
1716 /***********************************************************************
1728 ROSRGNDATA
*tra
, *trb
;
1730 // FIXME: Don't use a handle
1731 tra
= REGION_AllocRgnWithHandle(sra
->rdh
.nCount
+ 1);
1736 htra
= tra
->BaseObject
.hHmgr
;
1738 // FIXME: Don't use a handle
1739 trb
= REGION_AllocRgnWithHandle(srb
->rdh
.nCount
+ 1);
1742 RGNOBJAPI_Unlock(tra
);
1743 GreDeleteObject(htra
);
1746 htrb
= trb
->BaseObject
.hHmgr
;
1748 REGION_SubtractRegion(tra
, sra
, srb
);
1749 REGION_SubtractRegion(trb
, srb
, sra
);
1750 REGION_UnionRegion(dr
, tra
, trb
);
1751 RGNOBJAPI_Unlock(tra
);
1752 RGNOBJAPI_Unlock(trb
);
1754 GreDeleteObject(htra
);
1755 GreDeleteObject(htrb
);
1761 * Adds a rectangle to a REGION
1765 REGION_UnionRectWithRgn(
1771 region
.Buffer
= ®ion
.rdh
.rcBound
;
1772 region
.rdh
.nCount
= 1;
1773 region
.rdh
.nRgnSize
= sizeof(RECT
);
1774 region
.rdh
.rcBound
= *rect
;
1775 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1780 REGION_SubtractRectFromRgn(
1787 rgnLocal
.Buffer
= &rgnLocal
.rdh
.rcBound
;
1788 rgnLocal
.rdh
.nCount
= 1;
1789 rgnLocal
.rdh
.nRgnSize
= sizeof(RECT
);
1790 rgnLocal
.rdh
.rcBound
= *prcl
;
1791 REGION_SubtractRegion(prgnDest
, prgnSrc
, &rgnLocal
);
1792 return REGION_Complexity(prgnDest
);
1797 REGION_CreateSimpleFrameRgn(
1805 if ((x
!= 0) || (y
!= 0))
1809 if (rgn
->rdh
.rcBound
.bottom
- rgn
->rdh
.rcBound
.top
> y
* 2 &&
1810 rgn
->rdh
.rcBound
.right
- rgn
->rdh
.rcBound
.left
> x
* 2)
1815 prc
->left
= rgn
->rdh
.rcBound
.left
;
1816 prc
->top
= rgn
->rdh
.rcBound
.top
;
1817 prc
->right
= rgn
->rdh
.rcBound
.right
;
1818 prc
->bottom
= prc
->top
+ y
;
1824 /* Left rectangle */
1825 prc
->left
= rgn
->rdh
.rcBound
.left
;
1826 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1827 prc
->right
= prc
->left
+ x
;
1828 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1831 /* Right rectangle */
1832 prc
->left
= rgn
->rdh
.rcBound
.right
- x
;
1833 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1834 prc
->right
= rgn
->rdh
.rcBound
.right
;
1835 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1841 /* Bottom rectangle */
1842 prc
->left
= rgn
->rdh
.rcBound
.left
;
1843 prc
->top
= rgn
->rdh
.rcBound
.bottom
- y
;
1844 prc
->right
= rgn
->rdh
.rcBound
.right
;
1845 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
;
1852 /* The frame results in a complex region. rcBounds remains
1853 the same, though. */
1854 rgn
->rdh
.nCount
= (DWORD
)(prc
- rc
);
1855 ASSERT(rgn
->rdh
.nCount
> 1);
1856 rgn
->rdh
.nRgnSize
= rgn
->rdh
.nCount
* sizeof(RECT
);
1857 rgn
->Buffer
= ExAllocatePoolWithTag(PagedPool
, rgn
->rdh
.nRgnSize
, TAG_REGION
);
1860 rgn
->rdh
.nRgnSize
= 0;
1864 _PRAGMA_WARNING_SUPPRESS(__WARNING_MAYBE_UNINIT_VAR
) // rc is initialized
1865 COPY_RECTS(rgn
->Buffer
, rc
, rgn
->rdh
.nCount
);
1873 REGION_CreateFrameRgn(
1879 PROSRGNDATA srcObj
, destObj
;
1883 if (!(srcObj
= RGNOBJAPI_Lock(hSrc
, NULL
)))
1888 if (!REGION_NOT_EMPTY(srcObj
))
1890 RGNOBJAPI_Unlock(srcObj
);
1894 if (!(destObj
= RGNOBJAPI_Lock(hDest
, NULL
)))
1896 RGNOBJAPI_Unlock(srcObj
);
1900 EMPTY_REGION(destObj
);
1901 if (!REGION_CopyRegion(destObj
, srcObj
))
1903 RGNOBJAPI_Unlock(destObj
);
1904 RGNOBJAPI_Unlock(srcObj
);
1908 if (REGION_Complexity(srcObj
) == SIMPLEREGION
)
1910 if (!REGION_CreateSimpleFrameRgn(destObj
, x
, y
))
1912 EMPTY_REGION(destObj
);
1913 RGNOBJAPI_Unlock(destObj
);
1914 RGNOBJAPI_Unlock(srcObj
);
1920 /* Original region moved to right */
1921 rc
= srcObj
->Buffer
;
1922 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1929 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1931 /* Original region moved to left */
1932 rc
= srcObj
->Buffer
;
1933 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1939 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1941 /* Original region moved down */
1942 rc
= srcObj
->Buffer
;
1943 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1952 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1954 /* Original region moved up */
1955 rc
= srcObj
->Buffer
;
1956 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1959 rc
->bottom
-= 2 * y
;
1962 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1964 /* Restore the original region */
1965 rc
= srcObj
->Buffer
;
1966 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1972 REGION_SubtractRegion(destObj
, srcObj
, destObj
);
1975 RGNOBJAPI_Unlock(destObj
);
1976 RGNOBJAPI_Unlock(srcObj
);
1986 _Inout_ PREGION RgnDest
,
1987 _In_ PREGION RgnSrc
)
1989 RECTL
*pCurRect
, *pEndRect
;
1995 pdcattr
= dc
->pdcattr
;
1997 if (pdcattr
->iMapMode
== MM_TEXT
) // Requires only a translation
1999 if (IntGdiCombineRgn(RgnDest
, RgnSrc
, 0, RGN_COPY
) == ERROR
)
2002 IntGdiOffsetRgn(RgnDest
,
2003 pdcattr
->ptlViewportOrg
.x
- pdcattr
->ptlWindowOrg
.x
,
2004 pdcattr
->ptlViewportOrg
.y
- pdcattr
->ptlWindowOrg
.y
);
2008 EMPTY_REGION(RgnDest
);
2010 pEndRect
= RgnSrc
->Buffer
+ RgnSrc
->rdh
.nCount
;
2011 for (pCurRect
= RgnSrc
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
2013 tmpRect
= *pCurRect
;
2014 tmpRect
.left
= XLPTODP(pdcattr
, tmpRect
.left
);
2015 tmpRect
.top
= YLPTODP(pdcattr
, tmpRect
.top
);
2016 tmpRect
.right
= XLPTODP(pdcattr
, tmpRect
.right
);
2017 tmpRect
.bottom
= YLPTODP(pdcattr
, tmpRect
.bottom
);
2019 if (tmpRect
.left
> tmpRect
.right
)
2021 INT tmp
= tmpRect
.left
;
2022 tmpRect
.left
= tmpRect
.right
;
2023 tmpRect
.right
= tmp
;
2026 if (tmpRect
.top
> tmpRect
.bottom
)
2028 INT tmp
= tmpRect
.top
;
2029 tmpRect
.top
= tmpRect
.bottom
;
2030 tmpRect
.bottom
= tmp
;
2033 REGION_UnionRectWithRgn(RgnDest
, &tmpRect
);
2041 REGION_AllocRgnWithHandle(
2047 pReg
= (PROSRGNDATA
)GDIOBJ_AllocateObject(GDIObjType_RGN_TYPE
,
2049 BASEFLAG_LOOKASIDE
);
2052 DPRINT1("Could not allocate a palette.\n");
2056 if (!GDIOBJ_hInsertObject(&pReg
->BaseObject
, GDI_OBJ_HMGR_POWNED
))
2058 DPRINT1("Could not insert palette into handle table.\n");
2059 GDIOBJ_vFreeObject(&pReg
->BaseObject
);
2063 //hReg = pReg->BaseObject.hHmgr;
2065 if (nReg
== 0 || nReg
== 1)
2067 /* Testing shows that > 95% of all regions have only 1 rect.
2068 Including that here saves us from having to do another allocation */
2069 pReg
->Buffer
= &pReg
->rdh
.rcBound
;
2073 pReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, nReg
* sizeof(RECT
), TAG_REGION
);
2076 DPRINT1("Could not allocate region buffer\n");
2077 GDIOBJ_vDeleteObject(&pReg
->BaseObject
);
2083 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
2084 pReg
->rdh
.nCount
= nReg
;
2085 pReg
->rdh
.nRgnSize
= nReg
* sizeof(RECT
);
2086 pReg
->prgnattr
= &pReg
->rgnattr
;
2093 REGION_bAllocRgnAttr(
2099 ppi
= PsGetCurrentProcessWin32Process();
2102 prgnattr
= GdiPoolAllocate(ppi
->pPoolRgnAttr
);
2105 DPRINT1("Could not allocate RGN attr\n");
2109 /* Set the object attribute in the handle table */
2110 prgn
->prgnattr
= prgnattr
;
2111 GDIOBJ_vSetObjectAttr(&prgn
->BaseObject
, prgnattr
);
2118 // Allocate User Space Region Handle.
2122 REGION_AllocUserRgnWithHandle(
2127 prgn
= REGION_AllocRgnWithHandle(nRgn
);
2133 if (!REGION_bAllocRgnAttr(prgn
))
2146 PRGN_ATTR pRgn_Attr
= NULL
;
2148 if (pRgn
&& pRgn
->prgnattr
!= &pRgn
->rgnattr
)
2150 pRgn_Attr
= GDIOBJ_pvGetObjectAttr(&pRgn
->BaseObject
);
2156 if ( !(pRgn_Attr
->AttrFlags
& ATTR_CACHED
) )
2158 if ( pRgn_Attr
->AttrFlags
& (ATTR_RGN_VALID
|ATTR_RGN_DIRTY
) )
2160 switch (pRgn_Attr
->Flags
)
2163 EMPTY_REGION( pRgn
);
2167 REGION_SetRectRgn( pRgn
,
2168 pRgn_Attr
->Rect
.left
,
2169 pRgn_Attr
->Rect
.top
,
2170 pRgn_Attr
->Rect
.right
,
2171 pRgn_Attr
->Rect
.bottom
);
2174 pRgn_Attr
->AttrFlags
&= ~ATTR_RGN_DIRTY
;
2178 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2192 PRGN_ATTR
*ppRgn_Attr
)
2194 PROSRGNDATA pRgn
= NULL
;
2196 pRgn
= REGION_LockRgn(hRgn
);
2198 REGION_vSyncRegion(pRgn
);
2201 *ppRgn_Attr
= pRgn
->prgnattr
;
2211 PRGN_ATTR pRgn_Attr
;
2213 if (pRgn
&& GreGetObjectOwner(pRgn
->BaseObject
.hHmgr
) == GDI_OBJ_HMGR_POWNED
)
2215 pRgn_Attr
= GDIOBJ_pvGetObjectAttr(&pRgn
->BaseObject
);
2221 if ( pRgn_Attr
->AttrFlags
& ATTR_RGN_VALID
)
2223 pRgn_Attr
->Flags
= REGION_Complexity( pRgn
);
2224 pRgn_Attr
->Rect
.left
= pRgn
->rdh
.rcBound
.left
;
2225 pRgn_Attr
->Rect
.top
= pRgn
->rdh
.rcBound
.top
;
2226 pRgn_Attr
->Rect
.right
= pRgn
->rdh
.rcBound
.right
;
2227 pRgn_Attr
->Rect
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2230 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2237 REGION_UnlockRgn(pRgn
);
2242 These regions do not use attribute sections and when allocated, use gdiobj
2246 // System Region Functions
2250 IntSysCreateRectpRgn(
2258 /* Allocate a region, witout a handle */
2259 prgn
= (PREGION
)GDIOBJ_AllocateObject(GDIObjType_RGN_TYPE
, sizeof(REGION
), BASEFLAG_LOOKASIDE
);
2266 prgn
->Buffer
= &prgn
->rdh
.rcBound
;
2267 prgn
->prgnattr
= &prgn
->rgnattr
;
2268 REGION_SetRectRgn(prgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
2275 REGION_vCleanup(PVOID ObjectBody
)
2277 PROSRGNDATA pRgn
= (PROSRGNDATA
)ObjectBody
;
2278 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
2281 ASSERT(pRgn
->prgnattr
);
2282 if (pRgn
->prgnattr
!= &pRgn
->rgnattr
)
2283 GdiPoolFree(ppi
->pPoolRgnAttr
, pRgn
->prgnattr
);
2285 if (pRgn
->Buffer
&& pRgn
->Buffer
!= &pRgn
->rdh
.rcBound
)
2286 ExFreePoolWithTag(pRgn
->Buffer
, TAG_REGION
);
2291 REGION_Delete(PROSRGNDATA pRgn
)
2293 if ( pRgn
== prgnDefault
) return;
2294 GDIOBJ_vDeleteObject(&pRgn
->BaseObject
);
2299 IntGdiReleaseRaoRgn(PDC pDC
)
2301 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2302 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2303 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2304 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2305 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2306 REGION_Delete(pDC
->prgnRao
);
2307 pDC
->prgnRao
= NULL
;
2312 IntGdiReleaseVisRgn(PDC pDC
)
2314 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2315 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2316 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2317 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2318 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2319 REGION_Delete(pDC
->prgnVis
);
2320 pDC
->prgnVis
= prgnDefault
;
2325 IntUpdateVisRectRgn(PDC pDC
, PROSRGNDATA pRgn
)
2327 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2328 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2332 if (Entry
->Flags
& GDI_ENTRY_VALIDATE_VIS
)
2334 pdcattr
= pDC
->pdcattr
;
2336 pdcattr
->VisRectRegion
.Flags
= REGION_Complexity(pRgn
);
2338 if (pRgn
&& pdcattr
->VisRectRegion
.Flags
!= NULLREGION
)
2340 rcl
.left
= pRgn
->rdh
.rcBound
.left
;
2341 rcl
.top
= pRgn
->rdh
.rcBound
.top
;
2342 rcl
.right
= pRgn
->rdh
.rcBound
.right
;
2343 rcl
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2345 rcl
.left
-= pDC
->erclWindow
.left
;
2346 rcl
.top
-= pDC
->erclWindow
.top
;
2347 rcl
.right
-= pDC
->erclWindow
.left
;
2348 rcl
.bottom
-= pDC
->erclWindow
.top
;
2351 RECTL_vSetEmptyRect(&rcl
);
2353 pdcattr
->VisRectRegion
.Rect
= rcl
;
2355 Entry
->Flags
&= ~GDI_ENTRY_VALIDATE_VIS
;
2361 IntGdiSetRegionOwner(HRGN hRgn
, DWORD OwnerMask
)
2367 prgn
= RGNOBJAPI_Lock(hRgn
, &prgnattr
);
2373 if (prgnattr
!= &prgn
->rgnattr
)
2375 GDIOBJ_vSetObjectAttr(&prgn
->BaseObject
, NULL
);
2376 prgn
->prgnattr
= &prgn
->rgnattr
;
2377 ppi
= PsGetCurrentProcessWin32Process();
2378 GdiPoolFree(ppi
->pPoolRgnAttr
, prgnattr
);
2380 RGNOBJAPI_Unlock(prgn
);
2382 return GreSetObjectOwner(hRgn
, OwnerMask
);
2388 PROSRGNDATA prgnDest
,
2389 PROSRGNDATA prgnSrc1
,
2390 PROSRGNDATA prgnSrc2
,
2396 DPRINT("IntGdiCombineRgn: hDest unavailable\n");
2402 DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
2406 if (iCombineMode
== RGN_COPY
)
2408 if (!REGION_CopyRegion(prgnDest
, prgnSrc1
))
2410 return REGION_Complexity(prgnDest
);
2415 DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", iCombineMode
);
2420 switch (iCombineMode
)
2423 REGION_IntersectRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2426 REGION_UnionRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2429 REGION_XorRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2432 REGION_SubtractRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2436 return REGION_Complexity(prgnDest
);
2449 *pRect
= Rgn
->rdh
.rcBound
;
2450 ret
= REGION_Complexity(Rgn
);
2454 return 0; // If invalid region return zero
2466 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
2471 ret
= REGION_GetRgnBox(Rgn
, pRect
);
2472 RGNOBJAPI_Unlock(Rgn
);
2484 XCLIPOBJ ClipRegion
;
2493 pdcattr
= dc
->pdcattr
;
2495 ASSERT(!(pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
)));
2497 VisRgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
2503 // Transform region into device co-ords
2504 if (!REGION_LPTODP(dc
, VisRgn
, Rgn
) ||
2505 IntGdiOffsetRgn(VisRgn
, dc
->ptlDCOrig
.x
, dc
->ptlDCOrig
.y
) == ERROR
)
2507 REGION_Delete(VisRgn
);
2512 IntGdiCombineRgn(VisRgn
, VisRgn
, dc
->prgnRao
, RGN_AND
);
2514 IntEngInitClipObj(&ClipRegion
);
2515 IntEngUpdateClipRegion(&ClipRegion
, VisRgn
->rdh
.nCount
, VisRgn
->Buffer
, &VisRgn
->rdh
.rcBound
);
2517 BrushOrigin
.x
= pdcattr
->ptlBrushOrigin
.x
;
2518 BrushOrigin
.y
= pdcattr
->ptlBrushOrigin
.y
;
2519 psurf
= dc
->dclevel
.pSurface
;
2520 /* FIXME: Handle psurf == NULL !!!! */
2522 bRet
= IntEngPaint(&psurf
->SurfObj
,
2523 &ClipRegion
.ClipObj
,
2524 &dc
->eboFill
.BrushObject
,
2526 0xFFFF); // FIXME: Don't know what to put here
2528 REGION_Delete(VisRgn
);
2529 IntEngFreeClipResources(&ClipRegion
);
2545 if (prgn
->rdh
.nCount
> 0 && INRECT(prgn
->rdh
.rcBound
, X
, Y
))
2548 for (i
= 0; i
< prgn
->rdh
.nCount
; i
++)
2550 if (INRECT(r
[i
], X
, Y
))
2560 REGION_RectInRegion(
2564 PRECTL pCurRect
, pRectEnd
;
2567 /* Swap the coordinates to make right >= left and bottom >= top */
2568 /* (region building rectangles are normalized the same way) */
2569 if( rect
->top
> rect
->bottom
)
2571 rc
.top
= rect
->bottom
;
2572 rc
.bottom
= rect
->top
;
2577 rc
.bottom
= rect
->bottom
;
2580 if( rect
->right
< rect
->left
)
2582 rc
.right
= rect
->left
;
2583 rc
.left
= rect
->right
;
2587 rc
.right
= rect
->right
;
2588 rc
.left
= rect
->left
;
2591 /* This is (just) a useful optimization */
2592 if ((Rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&Rgn
->rdh
.rcBound
, &rc
))
2594 for (pCurRect
= Rgn
->Buffer
, pRectEnd
= pCurRect
+
2595 Rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
2597 if (pCurRect
->bottom
<= rc
.top
)
2598 continue; /* Not far enough down yet */
2600 if (pCurRect
->top
>= rc
.bottom
)
2601 break; /* Too far down */
2603 if (pCurRect
->right
<= rc
.left
)
2604 continue; /* Not far enough over yet */
2606 if (pCurRect
->left
>= rc
.right
)
2628 if (LeftRect
> RightRect
)
2631 LeftRect
= RightRect
;
2635 if (TopRect
> BottomRect
)
2638 TopRect
= BottomRect
;
2642 if ((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
2644 firstRect
= rgn
->Buffer
;
2646 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
2647 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
2648 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
2649 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
2650 rgn
->rdh
.nCount
= 1;
2651 rgn
->rdh
.iType
= RDH_RECTANGLES
;
2666 if (XOffset
|| YOffset
)
2668 int nbox
= rgn
->rdh
.nCount
;
2669 PRECTL pbox
= rgn
->Buffer
;
2675 pbox
->left
+= XOffset
;
2676 pbox
->right
+= XOffset
;
2677 pbox
->top
+= YOffset
;
2678 pbox
->bottom
+= YOffset
;
2682 if (rgn
->Buffer
!= &rgn
->rdh
.rcBound
)
2684 rgn
->rdh
.rcBound
.left
+= XOffset
;
2685 rgn
->rdh
.rcBound
.right
+= XOffset
;
2686 rgn
->rdh
.rcBound
.top
+= YOffset
;
2687 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
2692 return REGION_Complexity(rgn
);
2695 /***********************************************************************
2696 * REGION_InsertEdgeInET
2698 * Insert the given edge into the edge table.
2699 * First we must find the correct bucket in the
2700 * Edge table, then find the right slot in the
2701 * bucket. Finally, we can insert it.
2707 REGION_InsertEdgeInET(
2709 EdgeTableEntry
*ETE
,
2711 ScanLineListBlock
**SLLBlock
,
2714 EdgeTableEntry
*start
, *prev
;
2715 ScanLineList
*pSLL
, *pPrevSLL
;
2716 ScanLineListBlock
*tmpSLLBlock
;
2718 /* Find the right bucket to put the edge into */
2719 pPrevSLL
= &ET
->scanlines
;
2720 pSLL
= pPrevSLL
->next
;
2721 while (pSLL
&& (pSLL
->scanline
< scanline
))
2727 /* Reassign pSLL (pointer to ScanLineList) if necessary */
2728 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
2730 if (*iSLLBlock
> SLLSPERBLOCK
-1)
2732 tmpSLLBlock
= ExAllocatePoolWithTag(PagedPool
, sizeof(ScanLineListBlock
), TAG_REGION
);
2735 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2736 /* FIXME: Free resources? */
2740 (*SLLBlock
)->next
= tmpSLLBlock
;
2741 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2742 *SLLBlock
= tmpSLLBlock
;
2746 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
2748 pSLL
->next
= pPrevSLL
->next
;
2749 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
2750 pPrevSLL
->next
= pSLL
;
2753 pSLL
->scanline
= scanline
;
2755 /* Now insert the edge in the right bucket */
2756 prev
= (EdgeTableEntry
*)NULL
;
2757 start
= pSLL
->edgelist
;
2758 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2761 start
= start
->next
;
2769 pSLL
->edgelist
= ETE
;
2772 /***********************************************************************
2775 * This routine moves EdgeTableEntries from the
2776 * EdgeTable into the Active Edge Table,
2777 * leaving them sorted by smaller x coordinate.
2784 EdgeTableEntry
*AET
,
2785 EdgeTableEntry
*ETEs
)
2787 EdgeTableEntry
*pPrevAET
;
2788 EdgeTableEntry
*tmp
;
2794 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2805 ETEs
->back
= pPrevAET
;
2806 pPrevAET
->next
= ETEs
;
2813 /***********************************************************************
2814 * REGION_computeWAET
2816 * This routine links the AET by the
2817 * nextWETE (winding EdgeTableEntry) link for
2818 * use by the winding number rule. The final
2819 * Active Edge Table (AET) might look something
2823 * ---------- --------- ---------
2824 * |ymax | |ymax | |ymax |
2825 * | ... | |... | |... |
2826 * |next |->|next |->|next |->...
2827 * |nextWETE| |nextWETE| |nextWETE|
2828 * --------- --------- ^--------
2830 * V-------------------> V---> ...
2837 EdgeTableEntry
*AET
)
2839 register EdgeTableEntry
*pWETE
;
2840 register int inside
= 1;
2841 register int isInside
= 0;
2843 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2853 if ((!inside
&& !isInside
) ||
2854 ( inside
&& isInside
))
2856 pWETE
->nextWETE
= AET
;
2863 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2866 /***********************************************************************
2867 * REGION_InsertionSort
2869 * Just a simple insertion sort using
2870 * pointers and back pointers to sort the Active
2877 REGION_InsertionSort(
2878 EdgeTableEntry
*AET
)
2880 EdgeTableEntry
*pETEchase
;
2881 EdgeTableEntry
*pETEinsert
;
2882 EdgeTableEntry
*pETEchaseBackTMP
;
2883 BOOL changed
= FALSE
;
2890 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2891 pETEchase
= pETEchase
->back
;
2894 if (pETEchase
!= pETEinsert
)
2896 pETEchaseBackTMP
= pETEchase
->back
;
2897 pETEinsert
->back
->next
= AET
;
2899 AET
->back
= pETEinsert
->back
;
2901 pETEinsert
->next
= pETEchase
;
2902 pETEchase
->back
->next
= pETEinsert
;
2903 pETEchase
->back
= pETEinsert
;
2904 pETEinsert
->back
= pETEchaseBackTMP
;
2912 /***********************************************************************
2913 * REGION_FreeStorage
2921 ScanLineListBlock
*pSLLBlock
)
2923 ScanLineListBlock
*tmpSLLBlock
;
2927 tmpSLLBlock
= pSLLBlock
->next
;
2928 ExFreePoolWithTag(pSLLBlock
, TAG_REGION
);
2929 pSLLBlock
= tmpSLLBlock
;
2934 /***********************************************************************
2935 * REGION_PtsToRegion
2937 * Create an array of rectangles from a list of points.
2943 int numFullPtBlocks
,
2945 POINTBLOCK
*FirstPtBlock
,
2950 POINTBLOCK
*CurPtBlock
;
2952 RECTL
*extents
, *temp
;
2955 extents
= ®
->rdh
.rcBound
;
2957 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
2959 /* Make sure, we have at least one rect */
2965 if (!(temp
= ExAllocatePoolWithTag(PagedPool
, numRects
* sizeof(RECT
), TAG_REGION
)))
2969 if (reg
->Buffer
!= NULL
)
2971 COPY_RECTS(temp
, reg
->Buffer
, reg
->rdh
.nCount
);
2972 if (reg
->Buffer
!= ®
->rdh
.rcBound
)
2973 ExFreePoolWithTag(reg
->Buffer
, TAG_REGION
);
2977 reg
->rdh
.nCount
= numRects
;
2978 CurPtBlock
= FirstPtBlock
;
2979 rects
= reg
->Buffer
- 1;
2981 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
2983 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--)
2985 /* The loop uses 2 points per iteration */
2986 i
= NUMPTSTOBUFFER
>> 1;
2987 if (!numFullPtBlocks
)
2988 i
= iCurPtBlock
>> 1;
2990 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2)
2992 if (pts
->x
== pts
[1].x
)
2994 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
2995 pts
[1].x
== rects
->right
&&
2996 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
2997 (i
&& pts
[2].y
> pts
[1].y
))
2999 rects
->bottom
= pts
[1].y
+ 1;
3005 rects
->left
= pts
->x
;
3006 rects
->top
= pts
->y
;
3007 rects
->right
= pts
[1].x
;
3008 rects
->bottom
= pts
[1].y
+ 1;
3009 if (rects
->left
< extents
->left
)
3010 extents
->left
= rects
->left
;
3011 if (rects
->right
> extents
->right
)
3012 extents
->right
= rects
->right
;
3015 CurPtBlock
= CurPtBlock
->next
;
3020 extents
->top
= reg
->Buffer
->top
;
3021 extents
->bottom
= rects
->bottom
;
3028 extents
->bottom
= 0;
3031 reg
->rdh
.nCount
= numRects
;
3036 /***********************************************************************
3037 * REGION_CreateEdgeTable
3039 * This routine creates the edge table for
3040 * scan converting polygons.
3041 * The Edge Table (ET) looks like:
3045 * | ymax | ScanLineLists
3046 * |scanline|-->------------>-------------->...
3047 * -------- |scanline| |scanline|
3048 * |edgelist| |edgelist|
3049 * --------- ---------
3053 * list of ETEs list of ETEs
3055 * where ETE is an EdgeTableEntry data structure,
3056 * and there is one ScanLineList per scanline at
3057 * which an edge is initially entered.
3063 REGION_CreateETandAET(
3068 EdgeTableEntry
*AET
,
3069 EdgeTableEntry
*pETEs
,
3070 ScanLineListBlock
*pSLLBlock
)
3072 const POINT
*top
, *bottom
;
3073 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
3079 /* Initialize the Active Edge Table */
3080 AET
->next
= (EdgeTableEntry
*)NULL
;
3081 AET
->back
= (EdgeTableEntry
*)NULL
;
3082 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
3083 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
3085 /* Initialize the Edge Table. */
3086 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
3087 ET
->ymax
= SMALL_COORDINATE
;
3088 ET
->ymin
= LARGE_COORDINATE
;
3089 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
3092 for (poly
= 0; poly
< nbpolygons
; poly
++)
3094 count
= Count
[poly
];
3101 /* For each vertex in the array of points.
3102 * In this loop we are dealing with two vertices at
3103 * a time -- these make up one edge of the polygon. */
3108 /* Find out which point is above and which is below. */
3109 if (PrevPt
->y
> CurrPt
->y
)
3111 bottom
= PrevPt
, top
= CurrPt
;
3112 pETEs
->ClockWise
= 0;
3116 bottom
= CurrPt
, top
= PrevPt
;
3117 pETEs
->ClockWise
= 1;
3120 /* Don't add horizontal edges to the Edge table. */
3121 if (bottom
->y
!= top
->y
)
3123 /* -1 so we don't get last scanline */
3124 pETEs
->ymax
= bottom
->y
- 1;
3126 /* Initialize integer edge algorithm */
3127 dy
= bottom
->y
- top
->y
;
3128 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
3130 REGION_InsertEdgeInET(ET
,
3136 if (PrevPt
->y
> ET
->ymax
)
3137 ET
->ymax
= PrevPt
->y
;
3138 if (PrevPt
->y
< ET
->ymin
)
3139 ET
->ymin
= PrevPt
->y
;
3150 IntSetPolyPolygonRgn(
3157 EdgeTableEntry
*pAET
; /* Active Edge Table */
3158 INT y
; /* Current scanline */
3159 int iPts
= 0; /* Number of pts in buffer */
3160 EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry */
3161 ScanLineList
*pSLL
; /* Current scanLineList */
3162 POINT
*pts
; /* Output buffer */
3163 EdgeTableEntry
*pPrevAET
; /* Pointer to previous AET */
3164 EdgeTable ET
; /* Header node for ET */
3165 EdgeTableEntry AET
; /* Header node for AET */
3166 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
3167 ScanLineListBlock SLLBlock
; /* Header for scanlinelist */
3168 int fixWAET
= FALSE
;
3169 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
3170 POINTBLOCK
*tmpPtBlock
;
3171 int numFullPtBlocks
= 0;
3174 if (mode
== 0 || mode
> 2) return 0;
3176 /* Special case a rectangle */
3177 if (((nbpolygons
== 1) && ((*Count
== 4) ||
3178 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
3179 (((Pts
[0].y
== Pts
[1].y
) &&
3180 (Pts
[1].x
== Pts
[2].x
) &&
3181 (Pts
[2].y
== Pts
[3].y
) &&
3182 (Pts
[3].x
== Pts
[0].x
)) ||
3183 ((Pts
[0].x
== Pts
[1].x
) &&
3184 (Pts
[1].y
== Pts
[2].y
) &&
3185 (Pts
[2].x
== Pts
[3].x
) &&
3186 (Pts
[3].y
== Pts
[0].y
))))
3188 REGION_SetRectRgn(Rgn
,
3189 min(Pts
[0].x
, Pts
[2].x
),
3190 min(Pts
[0].y
, Pts
[2].y
),
3191 max(Pts
[0].x
, Pts
[2].x
),
3192 max(Pts
[0].y
, Pts
[2].y
));
3196 for (poly
= total
= 0; poly
< nbpolygons
; poly
++)
3197 total
+= Count
[poly
];
3199 if (!(pETEs
= ExAllocatePoolWithTag(PagedPool
, sizeof(EdgeTableEntry
) * total
, TAG_REGION
)) )
3204 pts
= FirstPtBlock
.pts
;
3205 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
3206 pSLL
= ET
.scanlines
.next
;
3207 curPtBlock
= &FirstPtBlock
;
3209 if (mode
!= WINDING
)
3211 /* For each scanline */
3212 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3214 /* Add a new edge to the active edge table when we
3215 * get to the next edge. */
3216 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3218 REGION_loadAET(&AET
, pSLL
->edgelist
);
3224 /* For each active edge */
3227 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3230 /* Send out the buffer */
3231 if (iPts
== NUMPTSTOBUFFER
)
3233 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
, sizeof(POINTBLOCK
), TAG_REGION
);
3236 DPRINT1("Can't alloc tPB\n");
3237 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3241 curPtBlock
->next
= tmpPtBlock
;
3242 curPtBlock
= tmpPtBlock
;
3243 pts
= curPtBlock
->pts
;
3248 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
3251 REGION_InsertionSort(&AET
);
3256 /* For each scanline */
3257 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3259 /* Add a new edge to the active edge table when we
3260 * get to the next edge. */
3261 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3263 REGION_loadAET(&AET
, pSLL
->edgelist
);
3264 REGION_computeWAET(&AET
);
3271 /* For each active edge */
3274 /* Add to the buffer only those edges that
3275 * are in the Winding active edge table. */
3278 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3281 /* Send out the buffer */
3282 if (iPts
== NUMPTSTOBUFFER
)
3284 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
,
3285 sizeof(POINTBLOCK
), TAG_REGION
);
3288 DPRINT1("Can't alloc tPB\n");
3289 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3292 curPtBlock
->next
= tmpPtBlock
;
3293 curPtBlock
= tmpPtBlock
;
3294 pts
= curPtBlock
->pts
;
3299 pWETE
= pWETE
->nextWETE
;
3302 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
3305 /* Recompute the winding active edge table if
3306 * we just resorted or have exited an edge. */
3307 if (REGION_InsertionSort(&AET
) || fixWAET
)
3309 REGION_computeWAET(&AET
);
3315 REGION_FreeStorage(SLLBlock
.next
);
3316 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, Rgn
);
3318 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;)
3320 tmpPtBlock
= curPtBlock
->next
;
3321 ExFreePoolWithTag(curPtBlock
, TAG_REGION
);
3322 curPtBlock
= tmpPtBlock
;
3325 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3338 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3343 Ret
= REGION_RectInRegion(Rgn
, rc
);
3344 RGNOBJAPI_Unlock(Rgn
);
3350 // NtGdi Exported Functions
3364 if (iMode
< RGN_AND
|| iMode
> RGN_COPY
)
3369 if (!hrgnDst
|| !hrgnSrc1
|| (iMode
!= RGN_COPY
&& !hrgnSrc2
))
3371 DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
3372 hrgnDst
, hrgnSrc1
, hrgnSrc2
, iMode
);
3376 /* Lock all regions */
3378 ahrgn
[1] = hrgnSrc1
;
3379 ahrgn
[2] = iMode
!= RGN_COPY
? hrgnSrc2
: NULL
;
3380 if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ
*)ahrgn
, (PVOID
*)aprgn
, GDIObjType_RGN_TYPE
))
3382 DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
3383 hrgnDst
, hrgnSrc1
, hrgnSrc2
, iMode
);
3387 /* HACK: Sync usermode attributes */
3388 REGION_vSyncRegion(aprgn
[0]);
3389 REGION_vSyncRegion(aprgn
[1]);
3390 if (aprgn
[2]) REGION_vSyncRegion(aprgn
[2]);
3392 /* Call the internal function */
3393 iResult
= IntGdiCombineRgn(aprgn
[0], aprgn
[1], aprgn
[2], iMode
);
3395 /* Cleanup and return */
3396 REGION_UnlockRgn(aprgn
[0]);
3397 REGION_UnlockRgn(aprgn
[1]);
3398 if (aprgn
[2]) REGION_UnlockRgn(aprgn
[2]);
3404 NtGdiCreateEllipticRgn(
3410 return NtGdiCreateRoundRectRgn(Left
,
3428 /* Allocate region data structure with space for 1 RECTL */
3429 if (!(pRgn
= REGION_AllocUserRgnWithHandle(1)))
3431 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3434 hRgn
= pRgn
->BaseObject
.hHmgr
;
3436 REGION_SetRectRgn(pRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3437 RGNOBJAPI_Unlock(pRgn
);
3439 DPRINT("Returning %p.\n", hRgn
);
3446 NtGdiCreateRoundRectRgn(
3456 int asq
, bsq
, d
, xd
, yd
;
3459 /* Make the dimensions sensible */
3474 ellipse_width
= abs(ellipse_width
);
3475 ellipse_height
= abs(ellipse_height
);
3477 /* Check parameters */
3478 if (ellipse_width
> right
-left
)
3479 ellipse_width
= right
-left
;
3480 if (ellipse_height
> bottom
-top
)
3481 ellipse_height
= bottom
-top
;
3483 /* Check if we can do a normal rectangle instead */
3484 if ((ellipse_width
< 2) || (ellipse_height
< 2))
3485 return NtGdiCreateRectRgn(left
, top
, right
, bottom
);
3488 d
= (ellipse_height
< 128) ? ((3 * ellipse_height
) >> 2) : 64;
3489 if (!(obj
= REGION_AllocUserRgnWithHandle(d
)))
3491 hrgn
= obj
->BaseObject
.hHmgr
;
3493 /* Ellipse algorithm, based on an article by K. Porter
3494 in DDJ Graphics Programming Column, 8/89 */
3495 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
3496 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
3497 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
3499 yd
= asq
* ellipse_height
; /* 2a^2b */
3501 rect
.left
= left
+ ellipse_width
/ 2;
3502 rect
.right
= right
- ellipse_width
/ 2;
3504 /* Loop to draw first half of quadrant */
3507 /* If nearest pixel is toward the center */
3510 /* Move toward center */
3512 rect
.bottom
= rect
.top
+ 1;
3513 REGION_UnionRectWithRgn(obj
, &rect
);
3514 rect
.top
= --bottom
;
3515 rect
.bottom
= rect
.top
+ 1;
3516 REGION_UnionRectWithRgn(obj
, &rect
);
3521 /* Next horiz point */
3528 /* Loop to draw second half of quadrant */
3529 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
3532 /* next vertical point */
3534 rect
.bottom
= rect
.top
+ 1;
3535 REGION_UnionRectWithRgn(obj
, &rect
);
3536 rect
.top
= --bottom
;
3537 rect
.bottom
= rect
.top
+ 1;
3538 REGION_UnionRectWithRgn(obj
, &rect
);
3540 /* If nearest pixel is outside ellipse */
3543 /* Move away from center */
3554 /* Add the inside rectangle */
3558 rect
.bottom
= bottom
;
3559 REGION_UnionRectWithRgn(obj
, &rect
);
3562 RGNOBJAPI_Unlock(obj
);
3572 PROSRGNDATA rgn1
, rgn2
;
3573 PRECTL tRect1
, tRect2
;
3577 if (!(rgn1
= RGNOBJAPI_Lock(hSrcRgn1
, NULL
)))
3580 if (!(rgn2
= RGNOBJAPI_Lock(hSrcRgn2
, NULL
)))
3582 RGNOBJAPI_Unlock(rgn1
);
3586 if (rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
)
3589 if (rgn1
->rdh
.nCount
== 0)
3595 if (rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
||
3596 rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
||
3597 rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
||
3598 rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
)
3601 tRect1
= rgn1
->Buffer
;
3602 tRect2
= rgn2
->Buffer
;
3604 if (!tRect1
|| !tRect2
)
3607 for (i
=0; i
< rgn1
->rdh
.nCount
; i
++)
3609 if (tRect1
[i
].left
!= tRect2
[i
].left
||
3610 tRect1
[i
].right
!= tRect2
[i
].right
||
3611 tRect1
[i
].top
!= tRect2
[i
].top
||
3612 tRect1
[i
].bottom
!= tRect2
[i
].bottom
)
3619 RGNOBJAPI_Unlock(rgn1
);
3620 RGNOBJAPI_Unlock(rgn2
);
3626 NtGdiExtCreateRegion(
3627 OPTIONAL LPXFORM Xform
,
3638 NTSTATUS Status
= STATUS_SUCCESS
;
3642 DPRINT("NtGdiExtCreateRegion\n");
3645 ProbeForRead(RgnData
, Count
, 1);
3646 nCount
= RgnData
->rdh
.nCount
;
3647 iType
= RgnData
->rdh
.iType
;
3648 dwSize
= RgnData
->rdh
.dwSize
;
3649 rects
= (RECT
*)RgnData
->Buffer
;
3651 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3653 Status
= _SEH2_GetExceptionCode();
3657 if (!NT_SUCCESS(Status
))
3659 SetLastNtError(Status
);
3663 /* Check parameters, but don't set last error here */
3664 if (Count
< sizeof(RGNDATAHEADER
) + nCount
* sizeof(RECT
) ||
3665 iType
!= RDH_RECTANGLES
||
3666 dwSize
!= sizeof(RGNDATAHEADER
))
3671 Region
= REGION_AllocUserRgnWithHandle(nCount
);
3675 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3678 hRgn
= Region
->BaseObject
.hHmgr
;
3682 /* Insert the rectangles one by one */
3683 for(i
=0; i
<nCount
; i
++)
3685 REGION_UnionRectWithRgn(Region
, &rects
[i
]);
3691 /* Init the XFORMOBJ from the Xform struct */
3692 Status
= STATUS_INVALID_PARAMETER
;
3693 XFORMOBJ_vInit(&xo
, &matrix
);
3694 ret
= XFORMOBJ_iSetXform(&xo
, (XFORML
*)Xform
);
3696 /* Check for error */
3697 if (ret
!= DDI_ERROR
)
3699 /* Apply the coordinate transformation on the rects */
3700 if (XFORMOBJ_bApplyXform(&xo
,
3702 Region
->rdh
.nCount
* 2,
3706 Status
= STATUS_SUCCESS
;
3711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3713 Status
= _SEH2_GetExceptionCode();
3716 if (!NT_SUCCESS(Status
))
3718 EngSetLastError(ERROR_INVALID_PARAMETER
);
3719 RGNOBJAPI_Unlock(Region
);
3720 GreDeleteObject(hRgn
);
3724 RGNOBJAPI_Unlock(Region
);
3740 if (NULL
== (rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3745 if (NULL
== (oldhBrush
= NtGdiSelectBrush(hDC
, hBrush
)))
3747 RGNOBJAPI_Unlock(rgn
);
3751 for (r
= rgn
->Buffer
; r
< rgn
->Buffer
+ rgn
->rdh
.nCount
; r
++)
3753 NtGdiPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
3756 RGNOBJAPI_Unlock(rgn
);
3757 NtGdiSelectBrush(hDC
, oldhBrush
);
3774 if (!(FrameRgn
= NtGdiCreateRectRgn(0, 0, 0, 0)))
3779 if (!REGION_CreateFrameRgn(FrameRgn
, hRgn
, Width
, Height
))
3781 GreDeleteObject(FrameRgn
);
3785 Ret
= NtGdiFillRgn(hDC
, FrameRgn
, hBrush
);
3787 GreDeleteObject(FrameRgn
);
3801 NTSTATUS Status
= STATUS_SUCCESS
;
3803 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3808 ret
= REGION_GetRgnBox(Rgn
, &SafeRect
);
3809 RGNOBJAPI_Unlock(Rgn
);
3817 ProbeForWrite(pRect
, sizeof(RECT
), 1);
3820 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3822 Status
= _SEH2_GetExceptionCode();
3825 if (!NT_SUCCESS(Status
))
3839 PROSRGNDATA RgnData
;
3843 if (!(RgnData
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3845 EngSetLastError(ERROR_INVALID_HANDLE
);
3849 rc
= RgnData
->Buffer
;
3850 for (i
= 0; i
< RgnData
->rdh
.nCount
; i
++)
3853 if (!NtGdiPatBlt(hDC
, rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, DSTINVERT
))
3855 RGNOBJAPI_Unlock(RgnData
);
3861 RGNOBJAPI_Unlock(RgnData
);
3872 PROSRGNDATA rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3875 DPRINT("NtGdiOffsetRgn: hRgn %p Xoffs %d Yoffs %d rgn %p\n", hRgn
, XOffset
, YOffset
, rgn
);
3879 DPRINT("NtGdiOffsetRgn: hRgn error\n");
3883 ret
= IntGdiOffsetRgn(rgn
, XOffset
, YOffset
);
3885 RGNOBJAPI_Unlock(rgn
);
3899 if (!(prgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3902 ret
= REGION_PtInRegion(prgn
, X
, Y
);
3904 RGNOBJAPI_Unlock(prgn
);
3915 NTSTATUS Status
= STATUS_SUCCESS
;
3919 ProbeForRead(unsaferc
, sizeof(RECT
), 1);
3922 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3924 Status
= _SEH2_GetExceptionCode();
3928 if (!NT_SUCCESS(Status
))
3930 SetLastNtError(Status
);
3931 DPRINT1("NtGdiRectInRegion: Bogus rc\n");
3935 return IntRectInRegion(hRgn
, &rc
);
3949 if (!(rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3951 return 0; // Per documentation
3954 REGION_SetRectRgn(rgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3956 RGNOBJAPI_Unlock(rgn
);
3962 NtGdiUnionRectWithRgn(
3964 const RECTL
*UnsafeRect
)
3966 RECTL SafeRect
= { 0 };
3968 NTSTATUS Status
= STATUS_SUCCESS
;
3970 if (!(Rgn
= RGNOBJAPI_Lock(hDest
, NULL
)))
3972 EngSetLastError(ERROR_INVALID_HANDLE
);
3978 ProbeForRead(UnsafeRect
, sizeof(RECT
), 1);
3979 SafeRect
= *UnsafeRect
;
3981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3983 Status
= _SEH2_GetExceptionCode();
3987 if (! NT_SUCCESS(Status
))
3989 RGNOBJAPI_Unlock(Rgn
);
3990 SetLastNtError(Status
);
3994 REGION_UnionRectWithRgn(Rgn
, &SafeRect
);
3995 RGNOBJAPI_Unlock(Rgn
);
4000 * MSDN: GetRegionData, Return Values:
4002 * "If the function succeeds and dwCount specifies an adequate number of bytes,
4003 * the return value is always dwCount. If dwCount is too small or the function
4004 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
4005 * required number of bytes.
4007 * If the function fails, the return value is zero."
4009 _Success_(return!=0)
4014 _In_ ULONG cjBuffer
,
4015 _Out_opt_bytecap_(cjBuffer
) LPRGNDATA lpRgnData
)
4017 ULONG cjRects
, cjSize
;
4020 /* Lock the region */
4021 prgn
= RGNOBJAPI_Lock(hrgn
, NULL
);
4024 EngSetLastError(ERROR_INVALID_HANDLE
);
4028 /* Calculate the region sizes */
4029 cjRects
= prgn
->rdh
.nCount
* sizeof(RECT
);
4030 cjSize
= cjRects
+ sizeof(RGNDATAHEADER
);
4032 /* Check if region data is requested */
4035 /* Check if the buffer is large enough */
4036 if (cjBuffer
>= cjSize
)
4038 /* Probe the buffer and copy the data */
4041 ProbeForWrite(lpRgnData
, cjSize
, sizeof(ULONG
));
4042 RtlCopyMemory(lpRgnData
, &prgn
->rdh
, sizeof(RGNDATAHEADER
));
4043 RtlCopyMemory(lpRgnData
->Buffer
, prgn
->Buffer
, cjRects
);
4044 lpRgnData
->rdh
.iType
= RDH_RECTANGLES
;
4046 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4048 EngSetLastError(ERROR_INVALID_PARAMETER
);
4055 /* Buffer is too small */
4056 EngSetLastError(ERROR_INVALID_PARAMETER
);
4061 /* Unlock the region and return the size */
4062 RGNOBJAPI_Unlock(prgn
);