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
454 typedef struct _POINTBLOCK
456 POINT pts
[NUMPTSTOBUFFER
];
457 struct _POINTBLOCK
*next
;
462 * This function is left there for debugging purposes.
466 IntDumpRegion(HRGN hRgn
)
470 Data
= RGNOBJAPI_Lock(hRgn
, NULL
);
473 DbgPrint("IntDumpRegion called with invalid region!\n");
477 DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
479 Data
->rdh
.rcBound
.left
,
480 Data
->rdh
.rcBound
.top
,
481 Data
->rdh
.rcBound
.right
,
482 Data
->rdh
.rcBound
.bottom
,
485 RGNOBJAPI_Unlock(Data
);
487 #endif /* Not NDEBUG */
492 REGION_Complexity(PREGION prgn
)
494 if (!prgn
) return NULLREGION
;
495 switch(prgn
->rdh
.nCount
)
497 DPRINT("Region Complexity -> %lu", prgn
->rdh
.nCount
);
498 case 0: return NULLREGION
;
499 case 1: return SIMPLEREGION
;
500 default: return COMPLEXREGION
;
512 if (dst
!= src
) // Don't want to copy to itself
514 if (dst
->rdh
.nRgnSize
< src
->rdh
.nCount
* sizeof(RECT
))
518 temp
= ExAllocatePoolWithTag(PagedPool
, src
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
522 if (dst
->Buffer
&& dst
->Buffer
!= &dst
->rdh
.rcBound
)
523 ExFreePoolWithTag(dst
->Buffer
, TAG_REGION
); // Free the old buffer
525 dst
->rdh
.nRgnSize
= src
->rdh
.nCount
* sizeof(RECT
); // Size of region buffer
527 dst
->rdh
.nCount
= src
->rdh
.nCount
; // Number of rectangles present in Buffer
528 dst
->rdh
.rcBound
.left
= src
->rdh
.rcBound
.left
;
529 dst
->rdh
.rcBound
.top
= src
->rdh
.rcBound
.top
;
530 dst
->rdh
.rcBound
.right
= src
->rdh
.rcBound
.right
;
531 dst
->rdh
.rcBound
.bottom
= src
->rdh
.rcBound
.bottom
;
532 dst
->rdh
.iType
= src
->rdh
.iType
;
533 COPY_RECTS(dst
->Buffer
, src
->Buffer
, src
->rdh
.nCount
);
539 REGION_SetExtents(ROSRGNDATA
*pReg
)
541 RECTL
*pRect
, *pRectEnd
, *pExtents
;
543 if (pReg
->rdh
.nCount
== 0)
545 pReg
->rdh
.rcBound
.left
= 0;
546 pReg
->rdh
.rcBound
.top
= 0;
547 pReg
->rdh
.rcBound
.right
= 0;
548 pReg
->rdh
.rcBound
.bottom
= 0;
549 pReg
->rdh
.iType
= RDH_RECTANGLES
;
553 pExtents
= &pReg
->rdh
.rcBound
;
554 pRect
= pReg
->Buffer
;
555 pRectEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
- 1;
558 * Since pRect is the first rectangle in the region, it must have the
559 * smallest top and since pRectEnd is the last rectangle in the region,
560 * it must have the largest bottom, because of banding. Initialize left and
561 * right from pRect and pRectEnd, resp., as good things to initialize them
564 pExtents
->left
= pRect
->left
;
565 pExtents
->top
= pRect
->top
;
566 pExtents
->right
= pRectEnd
->right
;
567 pExtents
->bottom
= pRectEnd
->bottom
;
569 while (pRect
<= pRectEnd
)
571 if (pRect
->left
< pExtents
->left
)
572 pExtents
->left
= pRect
->left
;
573 if (pRect
->right
> pExtents
->right
)
574 pExtents
->right
= pRect
->right
;
577 pReg
->rdh
.iType
= RDH_RECTANGLES
;
580 // FIXME: This function needs review and testing
581 /***********************************************************************
582 * REGION_CropAndOffsetRegion
586 REGION_CropAndOffsetRegion(
590 const POINTL
*offset
) // FIXME: we should probably remove offset from here
593 const POINT
*off
= offset
;
597 if (!rect
) // Just copy and offset
600 if (rgnDst
== rgnSrc
)
602 if (off
->x
|| off
->y
)
603 xrect
= rgnDst
->Buffer
;
605 return REGION_Complexity(rgnDst
);
609 xrect
= ExAllocatePoolWithTag(PagedPool
, rgnSrc
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
612 if (rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
613 ExFreePoolWithTag(rgnDst
->Buffer
, TAG_REGION
); // Free the old buffer. Will be assigned to xrect below.
616 if (rgnDst
!= rgnSrc
)
621 if (off
->x
|| off
->y
)
624 for (i
= 0; i
< rgnDst
->rdh
.nCount
; i
++)
626 xrect
[i
].left
= (rgnSrc
->Buffer
+ i
)->left
+ off
->x
;
627 xrect
[i
].right
= (rgnSrc
->Buffer
+ i
)->right
+ off
->x
;
628 xrect
[i
].top
= (rgnSrc
->Buffer
+ i
)->top
+ off
->y
;
629 xrect
[i
].bottom
= (rgnSrc
->Buffer
+ i
)->bottom
+ off
->y
;
631 rgnDst
->rdh
.rcBound
.left
+= off
->x
;
632 rgnDst
->rdh
.rcBound
.right
+= off
->x
;
633 rgnDst
->rdh
.rcBound
.top
+= off
->y
;
634 rgnDst
->rdh
.rcBound
.bottom
+= off
->y
;
638 COPY_RECTS(xrect
, rgnSrc
->Buffer
, rgnDst
->rdh
.nCount
);
641 rgnDst
->Buffer
= xrect
;
643 else if ((rect
->left
>= rect
->right
) ||
644 (rect
->top
>= rect
->bottom
) ||
645 !EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
))
649 else // Region box and clipping rect appear to intersect
652 ULONG i
, j
, clipa
, clipb
, nRgnSize
;
656 INT bottom
= MINLONG
;
658 /* Skip all rects that are completely above our intersect rect */
659 for (clipa
= 0; clipa
< rgnSrc
->rdh
.nCount
; clipa
++)
661 /* bottom is exclusive, so break when we go above it */
662 if (rgnSrc
->Buffer
[clipa
].bottom
> rect
->top
) break;
665 /* Bail out, if there is nothing left */
666 if (clipa
== rgnSrc
->rdh
.nCount
) goto empty
;
668 /* Find the last rect that is still within the intersect rect (exclusive) */
669 for (clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
671 /* bottom is exclusive, so stop, when we start at that y pos */
672 if (rgnSrc
->Buffer
[clipb
].top
>= rect
->bottom
) break;
675 /* Bail out, if there is nothing left */
676 if (clipb
== clipa
) goto empty
;
678 // clipa - index of the first rect in the first intersecting band
679 // clipb - index of the last rect in the last intersecting band plus 1
681 /* Check if the buffer in the dest region is large enough,
682 otherwise allocate a new one */
683 nRgnSize
= (clipb
- clipa
) * sizeof(RECT
);
684 if ((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nRgnSize
< nRgnSize
))
687 temp
= ExAllocatePoolWithTag(PagedPool
, nRgnSize
, TAG_REGION
);
691 /* Free the old buffer */
692 if (rgnDst
->Buffer
&& (rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
))
693 ExFreePoolWithTag(rgnDst
->Buffer
, TAG_REGION
);
695 rgnDst
->Buffer
= temp
;
696 rgnDst
->rdh
.nCount
= 0;
697 rgnDst
->rdh
.nRgnSize
= nRgnSize
;
698 rgnDst
->rdh
.iType
= RDH_RECTANGLES
;
701 /* Loop all rects within the intersect rect from the y perspective */
702 for (i
= clipa
, j
= 0; i
< clipb
; i
++)
704 // i - src index, j - dst index, j is always <= i for obvious reasons
706 lpr
= &rgnSrc
->Buffer
[i
];
708 /* Make sure the source rect is not retarded */
709 ASSERT(lpr
->bottom
> rect
->top
);
710 ASSERT(lpr
->right
> rect
->left
);
712 /* We already checked above, this should hold true */
713 ASSERT(lpr
->bottom
> rect
->top
);
714 ASSERT(lpr
->top
< rect
->bottom
);
716 /* Check if this rect is really inside the intersect rect */
717 if ((lpr
->left
< rect
->right
) && (lpr
->right
> rect
->left
))
719 rpr
= &rgnDst
->Buffer
[j
];
721 /* Crop the rect with the intersect rect and add offset */
722 rpr
->top
= max(lpr
->top
, rect
->top
) + off
->y
;
723 rpr
->bottom
= min(lpr
->bottom
, rect
->bottom
) + off
->y
;
724 rpr
->left
= max(lpr
->left
, rect
->left
) + off
->x
;
725 rpr
->right
= min(lpr
->right
, rect
->right
) + off
->y
;
727 /* Make sure the resulting rect is not retarded */
728 ASSERT(lpr
->bottom
> rect
->top
);
729 ASSERT(lpr
->right
> rect
->left
);
731 /* Track new bounds */
732 if (rpr
->left
< left
) left
= rpr
->left
;
733 if (rpr
->right
> right
) right
= rpr
->right
;
734 if (rpr
->top
< top
) top
= rpr
->top
;
735 if (rpr
->bottom
> bottom
) bottom
= rpr
->bottom
;
737 /* Next target rect */
742 if (j
== 0) goto empty
;
744 /* Update the bounds rect */
745 rgnDst
->rdh
.rcBound
.left
= left
;
746 rgnDst
->rdh
.rcBound
.right
= right
;
747 rgnDst
->rdh
.rcBound
.top
= top
;
748 rgnDst
->rdh
.rcBound
.bottom
= bottom
;
750 /* Set new rect count */
751 rgnDst
->rdh
.nCount
= j
;
754 return REGION_Complexity(rgnDst
);
759 rgnDst
->Buffer
= &rgnDst
->rdh
.rcBound
;
762 EMPTY_REGION(rgnDst
);
768 * Attempt to merge the rects in the current band with those in the
769 * previous one. Used only by REGION_RegionOp.
772 * The new index for the previous band.
774 * \note Side Effects:
775 * If coalescing takes place:
776 * - rectangles in the previous band will have their bottom fields
778 * - pReg->numRects will be decreased.
783 PROSRGNDATA pReg
, /* Region to coalesce */
784 INT prevStart
, /* Index of start of previous band */
785 INT curStart
/* Index of start of current band */
788 RECTL
*pPrevRect
; /* Current rect in previous band */
789 RECTL
*pCurRect
; /* Current rect in current band */
790 RECTL
*pRegEnd
; /* End of region */
791 INT curNumRects
; /* Number of rectangles in current band */
792 INT prevNumRects
; /* Number of rectangles in previous band */
793 INT bandtop
; /* Top coordinate for current band */
795 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
796 pPrevRect
= pReg
->Buffer
+ prevStart
;
797 prevNumRects
= curStart
- prevStart
;
800 * Figure out how many rectangles are in the current band. Have to do
801 * this because multiple bands could have been added in REGION_RegionOp
802 * at the end when one region has been exhausted.
804 pCurRect
= pReg
->Buffer
+ curStart
;
805 bandtop
= pCurRect
->top
;
806 for (curNumRects
= 0;
807 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
813 if (pCurRect
!= pRegEnd
)
816 * If more than one band was added, we have to find the start
817 * of the last band added so the next coalescing job can start
818 * at the right place... (given when multiple bands are added,
819 * this may be pointless -- see above).
822 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
826 curStart
= pRegEnd
- pReg
->Buffer
;
827 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
830 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0))
832 pCurRect
-= curNumRects
;
834 * The bands may only be coalesced if the bottom of the previous
835 * matches the top scanline of the current.
837 if (pPrevRect
->bottom
== pCurRect
->top
)
840 * Make sure the bands have rects in the same places. This
841 * assumes that rects have been added in such a way that they
842 * cover the most area possible. I.e. two rects in a band must
843 * have some horizontal space between them.
847 if ((pPrevRect
->left
!= pCurRect
->left
) ||
848 (pPrevRect
->right
!= pCurRect
->right
))
851 * The bands don't line up so they can't be coalesced.
859 while (prevNumRects
!= 0);
861 pReg
->rdh
.nCount
-= curNumRects
;
862 pCurRect
-= curNumRects
;
863 pPrevRect
-= curNumRects
;
866 * The bands may be merged, so set the bottom of each rect
867 * in the previous band to that of the corresponding rect in
872 pPrevRect
->bottom
= pCurRect
->bottom
;
877 while (curNumRects
!= 0);
880 * If only one band was added to the region, we have to backup
881 * curStart to the start of the previous band.
883 * If more than one band was added to the region, copy the
884 * other bands down. The assumption here is that the other bands
885 * came from the same region as the current one and no further
886 * coalescing can be done on them since it's all been done
887 * already... curStart is already in the right place.
889 if (pCurRect
== pRegEnd
)
891 curStart
= prevStart
;
897 *pPrevRect
++ = *pCurRect
++;
899 while (pCurRect
!= pRegEnd
);
907 * Apply an operation to two regions. Called by REGION_Union,
908 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
914 * The new region is overwritten.
916 *\note The idea behind this function is to view the two regions as sets.
917 * Together they cover a rectangle of area that this function divides
918 * into horizontal bands where points are covered only by one region
919 * or by both. For the first case, the nonOverlapFunc is called with
920 * each the band and the band's upper and lower extents. For the
921 * second, the overlapFunc is called to process the entire band. It
922 * is responsible for clipping the rectangles in the band, though
923 * this function provides the boundaries.
924 * At the end of each band, the new region is coalesced, if possible,
925 * to reduce the number of rectangles in the region.
930 ROSRGNDATA
*newReg
, /* Place to store result */
931 ROSRGNDATA
*reg1
, /* First region in operation */
932 ROSRGNDATA
*reg2
, /* 2nd region in operation */
933 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
934 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
935 nonOverlapProcp nonOverlap2Func
/* Function to call for non-overlapping bands in region 2 */
938 RECTL
*r1
; /* Pointer into first region */
939 RECTL
*r2
; /* Pointer into 2d region */
940 RECTL
*r1End
; /* End of 1st region */
941 RECTL
*r2End
; /* End of 2d region */
942 INT ybot
; /* Bottom of intersection */
943 INT ytop
; /* Top of intersection */
944 RECTL
*oldRects
; /* Old rects for newReg */
945 ULONG prevBand
; /* Index of start of
946 * Previous band in newReg */
947 ULONG curBand
; /* Index of start of current band in newReg */
948 RECTL
*r1BandEnd
; /* End of current band in r1 */
949 RECTL
*r2BandEnd
; /* End of current band in r2 */
950 ULONG top
; /* Top of non-overlapping band */
951 ULONG bot
; /* Bottom of non-overlapping band */
955 * set r1, r2, r1End and r2End appropriately, preserve the important
956 * parts of the destination region until the end in case it's one of
957 * the two source regions, then mark the "new" region empty, allocating
958 * another array of rectangles for it to use.
962 r1End
= r1
+ reg1
->rdh
.nCount
;
963 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.
972 oldRects
= newReg
->Buffer
;
973 newReg
->rdh
.nCount
= 0;
976 * Allocate a reasonable number of rectangles for the new region. The idea
977 * is to allocate enough so the individual functions don't need to
978 * reallocate and copy the array, which is time consuming, yet we don't
979 * have to worry about using too much memory. I hope to be able to
980 * nuke the Xrealloc() at the end of this function eventually.
982 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
+ 1,reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
984 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, newReg
->rdh
.nRgnSize
, TAG_REGION
);
987 newReg
->rdh
.nRgnSize
= 0;
992 * Initialize ybot and ytop.
993 * In the upcoming loop, ybot and ytop serve different functions depending
994 * on whether the band being handled is an overlapping or non-overlapping
996 * In the case of a non-overlapping band (only one of the regions
997 * has points in the band), ybot is the bottom of the most recent
998 * intersection and thus clips the top of the rectangles in that band.
999 * ytop is the top of the next intersection between the two regions and
1000 * serves to clip the bottom of the rectangles in the current band.
1001 * For an overlapping band (where the two regions intersect), ytop clips
1002 * the top of the rectangles of both regions and ybot clips the bottoms.
1004 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
1005 ybot
= reg1
->rdh
.rcBound
.top
;
1007 ybot
= reg2
->rdh
.rcBound
.top
;
1010 * prevBand serves to mark the start of the previous band so rectangles
1011 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1012 * In the beginning, there is no previous band, so prevBand == curBand
1013 * (curBand is set later on, of course, but the first band will always
1014 * start at index 0). prevBand and curBand must be indices because of
1015 * the possible expansion, and resultant moving, of the new region's
1016 * array of rectangles.
1022 curBand
= newReg
->rdh
.nCount
;
1025 * This algorithm proceeds one source-band (as opposed to a
1026 * destination band, which is determined by where the two regions
1027 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1028 * rectangle after the last one in the current band for their
1029 * respective regions.
1032 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1038 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1044 * First handle the band that doesn't intersect, if any.
1046 * Note that attention is restricted to one band in the
1047 * non-intersecting region at once, so if a region has n
1048 * bands between the current position and the next place it overlaps
1049 * the other, this entire loop will be passed through n times.
1051 if (r1
->top
< r2
->top
)
1053 top
= max(r1
->top
,ybot
);
1054 bot
= min(r1
->bottom
,r2
->top
);
1056 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
1058 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
1063 else if (r2
->top
< r1
->top
)
1065 top
= max(r2
->top
,ybot
);
1066 bot
= min(r2
->bottom
,r1
->top
);
1068 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
1070 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
1081 * If any rectangles got added to the region, try and coalesce them
1082 * with rectangles from the previous band. Note we could just do
1083 * this test in miCoalesce, but some machines incur a not
1084 * inconsiderable cost for function calls, so...
1086 if (newReg
->rdh
.nCount
!= curBand
)
1088 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1092 * Now see if we've hit an intersecting band. The two bands only
1093 * intersect if ybot > ytop
1095 ybot
= min(r1
->bottom
, r2
->bottom
);
1096 curBand
= newReg
->rdh
.nCount
;
1099 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1102 if (newReg
->rdh
.nCount
!= curBand
)
1104 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1108 * If we've finished with a band (bottom == ybot) we skip forward
1109 * in the region to the next band.
1111 if (r1
->bottom
== ybot
)
1115 if (r2
->bottom
== ybot
)
1120 while ((r1
!= r1End
) && (r2
!= r2End
));
1123 * Deal with whichever region still has rectangles left.
1125 curBand
= newReg
->rdh
.nCount
;
1128 if (nonOverlap1Func
!= NULL
)
1133 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1137 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
1138 max(r1
->top
,ybot
), r1
->bottom
);
1141 while (r1
!= r1End
);
1144 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
1149 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1153 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
1154 max(r2
->top
,ybot
), r2
->bottom
);
1157 while (r2
!= r2End
);
1160 if (newReg
->rdh
.nCount
!= curBand
)
1162 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
1166 * A bit of cleanup. To keep regions from growing without bound,
1167 * we shrink the array of rectangles to match the new number of
1168 * rectangles in the region. This never goes to 0, however...
1170 * Only do this stuff if the number of rectangles allocated is more than
1171 * twice the number of rectangles in the region (a simple optimization...).
1173 if ((2 * newReg
->rdh
.nCount
*sizeof(RECT
) < newReg
->rdh
.nRgnSize
&& (newReg
->rdh
.nCount
> 2)))
1175 if (REGION_NOT_EMPTY(newReg
))
1177 RECTL
*prev_rects
= newReg
->Buffer
;
1178 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, newReg
->rdh
.nCount
*sizeof(RECT
), TAG_REGION
);
1180 if (! newReg
->Buffer
)
1181 newReg
->Buffer
= prev_rects
;
1184 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
1185 COPY_RECTS(newReg
->Buffer
, prev_rects
, newReg
->rdh
.nCount
);
1186 if (prev_rects
!= &newReg
->rdh
.rcBound
)
1187 ExFreePoolWithTag(prev_rects
, TAG_REGION
);
1193 * No point in doing the extra work involved in an Xrealloc if
1194 * the region is empty
1196 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
1197 if (newReg
->Buffer
!= &newReg
->rdh
.rcBound
)
1198 ExFreePoolWithTag(newReg
->Buffer
, TAG_REGION
);
1199 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, sizeof(RECT
), TAG_REGION
);
1200 ASSERT(newReg
->Buffer
);
1203 newReg
->rdh
.iType
= RDH_RECTANGLES
;
1205 if (oldRects
!= &newReg
->rdh
.rcBound
)
1206 ExFreePoolWithTag(oldRects
, TAG_REGION
);
1210 /***********************************************************************
1211 * Region Intersection
1212 ***********************************************************************/
1216 * Handle an overlapping band for REGION_Intersect.
1221 * \note Side Effects:
1222 * Rectangles may be added to the region.
1225 static void FASTCALL
1239 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1241 while ((r1
!= r1End
) && (r2
!= r2End
))
1243 left
= max(r1
->left
, r2
->left
);
1244 right
= min(r1
->right
, r2
->right
);
1247 * If there's any overlap between the two rectangles, add that
1248 * overlap to the new region.
1249 * There's no need to check for subsumption because the only way
1250 * such a need could arise is if some region has two rectangles
1251 * right next to each other. Since that should never happen...
1255 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1256 pNextRect
->left
= left
;
1257 pNextRect
->top
= top
;
1258 pNextRect
->right
= right
;
1259 pNextRect
->bottom
= bottom
;
1260 pReg
->rdh
.nCount
+= 1;
1265 * Need to advance the pointers. Shift the one that extends
1266 * to the right the least, since the other still has a chance to
1267 * overlap with that region's next rectangle, if you see what I mean.
1269 if (r1
->right
< r2
->right
)
1273 else if (r2
->right
< r1
->right
)
1286 /***********************************************************************
1287 * REGION_IntersectRegion
1289 static void FASTCALL
1290 REGION_IntersectRegion(
1296 /* Check for trivial reject */
1297 if ( (!(reg1
->rdh
.nCount
)) || (!(reg2
->rdh
.nCount
)) ||
1298 (!EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
)) )
1299 newReg
->rdh
.nCount
= 0;
1301 REGION_RegionOp (newReg
, reg1
, reg2
,
1302 REGION_IntersectO
, NULL
, NULL
);
1305 * Can't alter newReg's extents before we call miRegionOp because
1306 * it might be one of the source regions and miRegionOp depends
1307 * on the extents of those regions being the same. Besides, this
1308 * way there's no checking against rectangles that will be nuked
1309 * due to coalescing, so we have to examine fewer rectangles.
1312 REGION_SetExtents(newReg
);
1315 /***********************************************************************
1317 ***********************************************************************/
1320 * Handle a non-overlapping band for the union operation. Just
1321 * Adds the rectangles into the region. Doesn't have to check for
1322 * subsumption or anything.
1327 * \note Side Effects:
1328 * pReg->numRects is incremented and the final rectangles overwritten
1329 * with the rectangles we're passed.
1332 static void FASTCALL
1343 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1347 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1348 pNextRect
->left
= r
->left
;
1349 pNextRect
->top
= top
;
1350 pNextRect
->right
= r
->right
;
1351 pNextRect
->bottom
= bottom
;
1352 pReg
->rdh
.nCount
+= 1;
1360 * Handle an overlapping band for the union operation. Picks the
1361 * left-most rectangle each time and merges it into the region.
1366 * \note Side Effects:
1367 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1371 static void FASTCALL
1384 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1386 #define MERGERECT(r) \
1387 if ((pReg->rdh.nCount != 0) && \
1388 ((pNextRect-1)->top == top) && \
1389 ((pNextRect-1)->bottom == bottom) && \
1390 ((pNextRect-1)->right >= r->left)) \
1392 if ((pNextRect-1)->right < r->right) \
1394 (pNextRect-1)->right = r->right; \
1399 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1400 pNextRect->top = top; \
1401 pNextRect->bottom = bottom; \
1402 pNextRect->left = r->left; \
1403 pNextRect->right = r->right; \
1404 pReg->rdh.nCount += 1; \
1409 while ((r1
!= r1End
) && (r2
!= r2End
))
1411 if (r1
->left
< r2
->left
)
1427 while (r1
!= r1End
);
1429 else while (r2
!= r2End
)
1436 /***********************************************************************
1437 * REGION_UnionRegion
1439 static void FASTCALL
1446 /* Checks all the simple cases */
1449 * Region 1 and 2 are the same or region 1 is empty
1451 if (reg1
== reg2
|| 0 == reg1
->rdh
.nCount
||
1452 reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
||
1453 reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
)
1457 REGION_CopyRegion(newReg
, reg2
);
1463 * If nothing to union (region 2 empty)
1465 if (0 == reg2
->rdh
.nCount
||
1466 reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
||
1467 reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
)
1471 REGION_CopyRegion(newReg
, reg1
);
1477 * Region 1 completely subsumes region 2
1479 if (1 == reg1
->rdh
.nCount
&&
1480 reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
&&
1481 reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
&&
1482 reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
&&
1483 reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
)
1487 REGION_CopyRegion(newReg
, reg1
);
1493 * Region 2 completely subsumes region 1
1495 if (1 == reg2
->rdh
.nCount
&&
1496 reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
&&
1497 reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
&&
1498 reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
&&
1499 reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
)
1503 REGION_CopyRegion(newReg
, reg2
);
1508 REGION_RegionOp (newReg
, reg1
, reg2
, REGION_UnionO
,
1509 REGION_UnionNonO
, REGION_UnionNonO
);
1510 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1511 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1512 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1513 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1516 /***********************************************************************
1517 * Region Subtraction
1518 ***********************************************************************/
1521 * Deal with non-overlapping band for subtraction. Any parts from
1522 * region 2 we discard. Anything from region 1 we add to the region.
1527 * \note Side Effects:
1528 * pReg may be affected.
1531 static void FASTCALL
1532 REGION_SubtractNonO1(
1542 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1546 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1547 pNextRect
->left
= r
->left
;
1548 pNextRect
->top
= top
;
1549 pNextRect
->right
= r
->right
;
1550 pNextRect
->bottom
= bottom
;
1551 pReg
->rdh
.nCount
+= 1;
1560 * Overlapping band subtraction. x1 is the left-most point not yet
1566 * \note Side Effects:
1567 * pReg may have rectangles added to it.
1570 static void FASTCALL
1585 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1587 while ((r1
!= r1End
) && (r2
!= r2End
))
1589 if (r2
->right
<= left
)
1592 * Subtrahend missed the boat: go to next subtrahend.
1596 else if (r2
->left
<= left
)
1599 * Subtrahend preceeds minuend: nuke left edge of minuend.
1602 if (left
>= r1
->right
)
1605 * Minuend completely covered: advance to next minuend and
1606 * reset left fence to edge of new minuend.
1615 * Subtrahend now used up since it doesn't extend beyond
1621 else if (r2
->left
< r1
->right
)
1624 * Left part of subtrahend covers part of minuend: add uncovered
1625 * part of minuend to region and skip to next subtrahend.
1627 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1628 pNextRect
->left
= left
;
1629 pNextRect
->top
= top
;
1630 pNextRect
->right
= r2
->left
;
1631 pNextRect
->bottom
= bottom
;
1632 pReg
->rdh
.nCount
+= 1;
1635 if (left
>= r1
->right
)
1638 * Minuend used up: advance to new...
1647 * Subtrahend used up
1655 * Minuend used up: add any remaining piece before advancing.
1657 if (r1
->right
> left
)
1659 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1660 pNextRect
->left
= left
;
1661 pNextRect
->top
= top
;
1662 pNextRect
->right
= r1
->right
;
1663 pNextRect
->bottom
= bottom
;
1664 pReg
->rdh
.nCount
+= 1;
1674 * Add remaining minuend rectangles to region.
1678 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1679 pNextRect
->left
= left
;
1680 pNextRect
->top
= top
;
1681 pNextRect
->right
= r1
->right
;
1682 pNextRect
->bottom
= bottom
;
1683 pReg
->rdh
.nCount
+= 1;
1695 * Subtract regS from regM and leave the result in regD.
1696 * S stands for subtrahend, M for minuend and D for difference.
1701 * \note Side Effects:
1702 * regD is overwritten.
1705 static void FASTCALL
1706 REGION_SubtractRegion(
1712 /* Check for trivial reject */
1713 if ( (!(regM
->rdh
.nCount
)) || (!(regS
->rdh
.nCount
)) ||
1714 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1716 REGION_CopyRegion(regD
, regM
);
1720 REGION_RegionOp (regD
, regM
, regS
, REGION_SubtractO
,
1721 REGION_SubtractNonO1
, NULL
);
1724 * Can't alter newReg's extents before we call miRegionOp because
1725 * it might be one of the source regions and miRegionOp depends
1726 * on the extents of those regions being the unaltered. Besides, this
1727 * way there's no checking against rectangles that will be nuked
1728 * due to coalescing, so we have to examine fewer rectangles.
1730 REGION_SetExtents (regD
);
1733 /***********************************************************************
1736 static void FASTCALL
1744 ROSRGNDATA
*tra
, *trb
;
1746 // FIXME: Don't use a handle
1747 tra
= REGION_AllocRgnWithHandle(sra
->rdh
.nCount
+ 1);
1752 htra
= tra
->BaseObject
.hHmgr
;
1754 // FIXME: Don't use a handle
1755 trb
= REGION_AllocRgnWithHandle(srb
->rdh
.nCount
+ 1);
1758 RGNOBJAPI_Unlock(tra
);
1759 GreDeleteObject(htra
);
1762 htrb
= trb
->BaseObject
.hHmgr
;
1764 REGION_SubtractRegion(tra
, sra
, srb
);
1765 REGION_SubtractRegion(trb
, srb
, sra
);
1766 REGION_UnionRegion(dr
, tra
, trb
);
1767 RGNOBJAPI_Unlock(tra
);
1768 RGNOBJAPI_Unlock(trb
);
1770 GreDeleteObject(htra
);
1771 GreDeleteObject(htrb
);
1777 * Adds a rectangle to a REGION
1780 REGION_UnionRectWithRgn(
1787 region
.Buffer
= ®ion
.rdh
.rcBound
;
1788 region
.rdh
.nCount
= 1;
1789 region
.rdh
.nRgnSize
= sizeof(RECT
);
1790 region
.rdh
.rcBound
= *rect
;
1791 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1796 REGION_SubtractRectFromRgn(
1803 rgnLocal
.Buffer
= &rgnLocal
.rdh
.rcBound
;
1804 rgnLocal
.rdh
.nCount
= 1;
1805 rgnLocal
.rdh
.nRgnSize
= sizeof(RECT
);
1806 rgnLocal
.rdh
.rcBound
= *prcl
;
1807 REGION_SubtractRegion(prgnDest
, prgnSrc
, &rgnLocal
);
1808 return REGION_Complexity(prgnDest
);
1812 REGION_CreateSimpleFrameRgn(
1821 if ((x
!= 0) || (y
!= 0))
1825 if (rgn
->rdh
.rcBound
.bottom
- rgn
->rdh
.rcBound
.top
> y
* 2 &&
1826 rgn
->rdh
.rcBound
.right
- rgn
->rdh
.rcBound
.left
> x
* 2)
1831 prc
->left
= rgn
->rdh
.rcBound
.left
;
1832 prc
->top
= rgn
->rdh
.rcBound
.top
;
1833 prc
->right
= rgn
->rdh
.rcBound
.right
;
1834 prc
->bottom
= prc
->top
+ y
;
1840 /* Left rectangle */
1841 prc
->left
= rgn
->rdh
.rcBound
.left
;
1842 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1843 prc
->right
= prc
->left
+ x
;
1844 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1847 /* Right rectangle */
1848 prc
->left
= rgn
->rdh
.rcBound
.right
- x
;
1849 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1850 prc
->right
= rgn
->rdh
.rcBound
.right
;
1851 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1857 /* Bottom rectangle */
1858 prc
->left
= rgn
->rdh
.rcBound
.left
;
1859 prc
->top
= rgn
->rdh
.rcBound
.bottom
- y
;
1860 prc
->right
= rgn
->rdh
.rcBound
.right
;
1861 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
;
1868 /* The frame results in a complex region. rcBounds remains
1869 the same, though. */
1870 rgn
->rdh
.nCount
= (DWORD
)(prc
- rc
);
1871 ASSERT(rgn
->rdh
.nCount
> 1);
1872 rgn
->rdh
.nRgnSize
= rgn
->rdh
.nCount
* sizeof(RECT
);
1873 rgn
->Buffer
= ExAllocatePoolWithTag(PagedPool
, rgn
->rdh
.nRgnSize
, TAG_REGION
);
1876 rgn
->rdh
.nRgnSize
= 0;
1880 _PRAGMA_WARNING_SUPPRESS(__WARNING_MAYBE_UNINIT_VAR
) // rc is initialized
1881 COPY_RECTS(rgn
->Buffer
, rc
, rgn
->rdh
.nCount
);
1889 REGION_CreateFrameRgn(
1896 PROSRGNDATA srcObj
, destObj
;
1900 if (!(srcObj
= RGNOBJAPI_Lock(hSrc
, NULL
)))
1904 if (!REGION_NOT_EMPTY(srcObj
))
1906 RGNOBJAPI_Unlock(srcObj
);
1909 if (!(destObj
= RGNOBJAPI_Lock(hDest
, NULL
)))
1911 RGNOBJAPI_Unlock(srcObj
);
1915 EMPTY_REGION(destObj
);
1916 if (!REGION_CopyRegion(destObj
, srcObj
))
1918 RGNOBJAPI_Unlock(destObj
);
1919 RGNOBJAPI_Unlock(srcObj
);
1923 if (REGION_Complexity(srcObj
) == SIMPLEREGION
)
1925 if (!REGION_CreateSimpleFrameRgn(destObj
, x
, y
))
1927 EMPTY_REGION(destObj
);
1928 RGNOBJAPI_Unlock(destObj
);
1929 RGNOBJAPI_Unlock(srcObj
);
1935 /* Original region moved to right */
1936 rc
= srcObj
->Buffer
;
1937 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1943 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1945 /* Original region moved to left */
1946 rc
= srcObj
->Buffer
;
1947 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1953 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1955 /* Original region moved down */
1956 rc
= srcObj
->Buffer
;
1957 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1965 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1967 /* Original region moved up */
1968 rc
= srcObj
->Buffer
;
1969 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1972 rc
->bottom
-= 2 * y
;
1975 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1977 /* Restore the original region */
1978 rc
= srcObj
->Buffer
;
1979 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1985 REGION_SubtractRegion(destObj
, srcObj
, destObj
);
1988 RGNOBJAPI_Unlock(destObj
);
1989 RGNOBJAPI_Unlock(srcObj
);
1998 _Inout_ PREGION RgnDest
,
1999 _In_ PREGION RgnSrc
)
2001 RECTL
*pCurRect
, *pEndRect
;
2007 pdcattr
= dc
->pdcattr
;
2009 if (pdcattr
->iMapMode
== MM_TEXT
) // Requires only a translation
2011 if (IntGdiCombineRgn(RgnDest
, RgnSrc
, 0, RGN_COPY
) == ERROR
)
2014 IntGdiOffsetRgn(RgnDest
, pdcattr
->ptlViewportOrg
.x
- pdcattr
->ptlWindowOrg
.x
,
2015 pdcattr
->ptlViewportOrg
.y
- pdcattr
->ptlWindowOrg
.y
);
2019 EMPTY_REGION(RgnDest
);
2021 pEndRect
= RgnSrc
->Buffer
+ RgnSrc
->rdh
.nCount
;
2022 for (pCurRect
= RgnSrc
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
2024 tmpRect
= *pCurRect
;
2025 tmpRect
.left
= XLPTODP(pdcattr
, tmpRect
.left
);
2026 tmpRect
.top
= YLPTODP(pdcattr
, tmpRect
.top
);
2027 tmpRect
.right
= XLPTODP(pdcattr
, tmpRect
.right
);
2028 tmpRect
.bottom
= YLPTODP(pdcattr
, tmpRect
.bottom
);
2030 if (tmpRect
.left
> tmpRect
.right
)
2032 INT tmp
= tmpRect
.left
;
2033 tmpRect
.left
= tmpRect
.right
;
2034 tmpRect
.right
= tmp
;
2036 if (tmpRect
.top
> tmpRect
.bottom
)
2038 INT tmp
= tmpRect
.top
;
2039 tmpRect
.top
= tmpRect
.bottom
;
2040 tmpRect
.bottom
= tmp
;
2043 REGION_UnionRectWithRgn(RgnDest
, &tmpRect
);
2051 REGION_AllocRgnWithHandle(INT nReg
)
2056 pReg
= (PROSRGNDATA
)GDIOBJ_AllocateObject(GDIObjType_RGN_TYPE
,
2058 BASEFLAG_LOOKASIDE
);
2061 DPRINT1("Could not allocate a palette.\n");
2065 if (!GDIOBJ_hInsertObject(&pReg
->BaseObject
, GDI_OBJ_HMGR_POWNED
))
2067 DPRINT1("Could not insert palette into handle table.\n");
2068 GDIOBJ_vFreeObject(&pReg
->BaseObject
);
2072 //hReg = pReg->BaseObject.hHmgr;
2074 if (nReg
== 0 || nReg
== 1)
2076 /* Testing shows that > 95% of all regions have only 1 rect.
2077 Including that here saves us from having to do another allocation */
2078 pReg
->Buffer
= &pReg
->rdh
.rcBound
;
2082 pReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, nReg
* sizeof(RECT
), TAG_REGION
);
2085 DPRINT1("Could not allocate region buffer\n");
2086 GDIOBJ_vDeleteObject(&pReg
->BaseObject
);
2092 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
2093 pReg
->rdh
.nCount
= nReg
;
2094 pReg
->rdh
.nRgnSize
= nReg
* sizeof(RECT
);
2095 pReg
->prgnattr
= &pReg
->rgnattr
;
2102 REGION_bAllocRgnAttr(PREGION prgn
)
2107 ppi
= PsGetCurrentProcessWin32Process();
2110 prgnattr
= GdiPoolAllocate(ppi
->pPoolRgnAttr
);
2113 DPRINT1("Could not allocate RGN attr\n");
2117 /* Set the object attribute in the handle table */
2118 prgn
->prgnattr
= prgnattr
;
2119 GDIOBJ_vSetObjectAttr(&prgn
->BaseObject
, prgnattr
);
2126 // Allocate User Space Region Handle.
2130 REGION_AllocUserRgnWithHandle(INT nRgn
)
2134 prgn
= REGION_AllocRgnWithHandle(nRgn
);
2140 if (!REGION_bAllocRgnAttr(prgn
))
2150 REGION_vSyncRegion(PREGION pRgn
)
2152 PRGN_ATTR pRgn_Attr
= NULL
;
2154 if (pRgn
&& pRgn
->prgnattr
!= &pRgn
->rgnattr
)
2156 pRgn_Attr
= GDIOBJ_pvGetObjectAttr(&pRgn
->BaseObject
);
2162 if ( !(pRgn_Attr
->AttrFlags
& ATTR_CACHED
) )
2164 if ( pRgn_Attr
->AttrFlags
& (ATTR_RGN_VALID
|ATTR_RGN_DIRTY
) )
2166 switch (pRgn_Attr
->Flags
)
2169 EMPTY_REGION( pRgn
);
2173 REGION_SetRectRgn( pRgn
,
2174 pRgn_Attr
->Rect
.left
,
2175 pRgn_Attr
->Rect
.top
,
2176 pRgn_Attr
->Rect
.right
,
2177 pRgn_Attr
->Rect
.bottom
);
2180 pRgn_Attr
->AttrFlags
&= ~ATTR_RGN_DIRTY
;
2184 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2196 RGNOBJAPI_Lock(HRGN hRgn
, PRGN_ATTR
*ppRgn_Attr
)
2198 PROSRGNDATA pRgn
= NULL
;
2200 pRgn
= REGION_LockRgn(hRgn
);
2202 REGION_vSyncRegion(pRgn
);
2205 *ppRgn_Attr
= pRgn
->prgnattr
;
2212 RGNOBJAPI_Unlock(PROSRGNDATA pRgn
)
2214 PRGN_ATTR pRgn_Attr
;
2216 if (pRgn
&& GreGetObjectOwner(pRgn
->BaseObject
.hHmgr
) == GDI_OBJ_HMGR_POWNED
)
2218 pRgn_Attr
= GDIOBJ_pvGetObjectAttr(&pRgn
->BaseObject
);
2224 if ( pRgn_Attr
->AttrFlags
& ATTR_RGN_VALID
)
2226 pRgn_Attr
->Flags
= REGION_Complexity( pRgn
);
2227 pRgn_Attr
->Rect
.left
= pRgn
->rdh
.rcBound
.left
;
2228 pRgn_Attr
->Rect
.top
= pRgn
->rdh
.rcBound
.top
;
2229 pRgn_Attr
->Rect
.right
= pRgn
->rdh
.rcBound
.right
;
2230 pRgn_Attr
->Rect
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2233 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2240 REGION_UnlockRgn(pRgn
);
2245 These regions do not use attribute sections and when allocated, use gdiobj
2249 // System Region Functions
2253 IntSysCreateRectpRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
2257 /* Allocate a region, witout a handle */
2258 prgn
= (PREGION
)GDIOBJ_AllocateObject(GDIObjType_RGN_TYPE
, sizeof(REGION
), BASEFLAG_LOOKASIDE
);
2265 prgn
->Buffer
= &prgn
->rdh
.rcBound
;
2266 prgn
->prgnattr
= &prgn
->rgnattr
;
2267 REGION_SetRectRgn(prgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
2273 REGION_vCleanup(PVOID ObjectBody
)
2275 PROSRGNDATA pRgn
= (PROSRGNDATA
)ObjectBody
;
2276 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
2279 ASSERT(pRgn
->prgnattr
);
2280 if (pRgn
->prgnattr
!= &pRgn
->rgnattr
)
2281 GdiPoolFree(ppi
->pPoolRgnAttr
, pRgn
->prgnattr
);
2283 if (pRgn
->Buffer
&& pRgn
->Buffer
!= &pRgn
->rdh
.rcBound
)
2284 ExFreePoolWithTag(pRgn
->Buffer
, TAG_REGION
);
2288 REGION_Delete(PROSRGNDATA pRgn
)
2290 if ( pRgn
== prgnDefault
) return;
2291 GDIOBJ_vDeleteObject(&pRgn
->BaseObject
);
2295 IntGdiReleaseRaoRgn(PDC pDC
)
2297 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2298 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2299 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2300 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2301 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2302 REGION_Delete(pDC
->prgnRao
);
2303 pDC
->prgnRao
= NULL
;
2307 IntGdiReleaseVisRgn(PDC pDC
)
2309 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2310 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2311 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2312 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2313 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2314 REGION_Delete(pDC
->prgnVis
);
2315 pDC
->prgnVis
= prgnDefault
;
2319 IntUpdateVisRectRgn(PDC pDC
, PROSRGNDATA pRgn
)
2321 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2322 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2326 if (Entry
->Flags
& GDI_ENTRY_VALIDATE_VIS
)
2328 pdcattr
= pDC
->pdcattr
;
2330 pdcattr
->VisRectRegion
.Flags
= REGION_Complexity(pRgn
);
2332 if (pRgn
&& pdcattr
->VisRectRegion
.Flags
!= NULLREGION
)
2334 rcl
.left
= pRgn
->rdh
.rcBound
.left
;
2335 rcl
.top
= pRgn
->rdh
.rcBound
.top
;
2336 rcl
.right
= pRgn
->rdh
.rcBound
.right
;
2337 rcl
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2339 rcl
.left
-= pDC
->erclWindow
.left
;
2340 rcl
.top
-= pDC
->erclWindow
.top
;
2341 rcl
.right
-= pDC
->erclWindow
.left
;
2342 rcl
.bottom
-= pDC
->erclWindow
.top
;
2345 RECTL_vSetEmptyRect(&rcl
);
2347 pdcattr
->VisRectRegion
.Rect
= rcl
;
2349 Entry
->Flags
&= ~GDI_ENTRY_VALIDATE_VIS
;
2355 IntGdiSetRegionOwner(HRGN hRgn
, DWORD OwnerMask
)
2361 prgn
= RGNOBJAPI_Lock(hRgn
, &prgnattr
);
2367 if (prgnattr
!= &prgn
->rgnattr
)
2369 GDIOBJ_vSetObjectAttr(&prgn
->BaseObject
, NULL
);
2370 prgn
->prgnattr
= &prgn
->rgnattr
;
2371 ppi
= PsGetCurrentProcessWin32Process();
2372 GdiPoolFree(ppi
->pPoolRgnAttr
, prgnattr
);
2374 RGNOBJAPI_Unlock(prgn
);
2376 return GreSetObjectOwner(hRgn
, OwnerMask
);
2382 PROSRGNDATA prgnDest
,
2383 PROSRGNDATA prgnSrc1
,
2384 PROSRGNDATA prgnSrc2
,
2390 DPRINT("IntGdiCombineRgn: hDest unavailable\n");
2396 DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
2400 if (iCombineMode
== RGN_COPY
)
2402 if (!REGION_CopyRegion(prgnDest
, prgnSrc1
))
2404 return REGION_Complexity(prgnDest
);
2409 DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", iCombineMode
);
2414 switch (iCombineMode
)
2417 REGION_IntersectRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2420 REGION_UnionRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2423 REGION_XorRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2426 REGION_SubtractRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2430 return REGION_Complexity(prgnDest
);
2443 *pRect
= Rgn
->rdh
.rcBound
;
2444 ret
= REGION_Complexity(Rgn
);
2448 return 0; // If invalid region return zero
2460 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
2465 ret
= REGION_GetRgnBox(Rgn
, pRect
);
2466 RGNOBJAPI_Unlock(Rgn
);
2479 XCLIPOBJ ClipRegion
;
2488 pdcattr
= dc
->pdcattr
;
2490 ASSERT(!(pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
)));
2492 VisRgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
2498 // Transform region into device co-ords
2499 if (!REGION_LPTODP(dc
, VisRgn
, Rgn
) ||
2500 IntGdiOffsetRgn(VisRgn
, dc
->ptlDCOrig
.x
, dc
->ptlDCOrig
.y
) == ERROR
)
2502 REGION_Delete(VisRgn
);
2507 IntGdiCombineRgn(VisRgn
, VisRgn
, dc
->prgnRao
, RGN_AND
);
2509 IntEngInitClipObj(&ClipRegion
);
2510 IntEngUpdateClipRegion(&ClipRegion
, VisRgn
->rdh
.nCount
, VisRgn
->Buffer
, &VisRgn
->rdh
.rcBound
);
2512 BrushOrigin
.x
= pdcattr
->ptlBrushOrigin
.x
;
2513 BrushOrigin
.y
= pdcattr
->ptlBrushOrigin
.y
;
2514 psurf
= dc
->dclevel
.pSurface
;
2515 /* FIXME: Handle psurf == NULL !!!! */
2517 bRet
= IntEngPaint(&psurf
->SurfObj
,
2518 &ClipRegion
.ClipObj
,
2519 &dc
->eboFill
.BrushObject
,
2521 0xFFFF); // FIXME: Don't know what to put here
2523 REGION_Delete(VisRgn
);
2524 IntEngFreeClipResources(&ClipRegion
);
2540 if (prgn
->rdh
.nCount
> 0 && INRECT(prgn
->rdh
.rcBound
, X
, Y
))
2543 for (i
= 0; i
< prgn
->rdh
.nCount
; i
++)
2545 if (INRECT(r
[i
], X
, Y
))
2555 REGION_RectInRegion(
2560 PRECTL pCurRect
, pRectEnd
;
2563 /* Swap the coordinates to make right >= left and bottom >= top */
2564 /* (region building rectangles are normalized the same way) */
2565 if( rect
->top
> rect
->bottom
) {
2566 rc
.top
= rect
->bottom
;
2567 rc
.bottom
= rect
->top
;
2570 rc
.bottom
= rect
->bottom
;
2572 if( rect
->right
< rect
->left
) {
2573 rc
.right
= rect
->left
;
2574 rc
.left
= rect
->right
;
2576 rc
.right
= rect
->right
;
2577 rc
.left
= rect
->left
;
2580 /* This is (just) a useful optimization */
2581 if ((Rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&Rgn
->rdh
.rcBound
, &rc
))
2583 for (pCurRect
= Rgn
->Buffer
, pRectEnd
= pCurRect
+
2584 Rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
2586 if (pCurRect
->bottom
<= rc
.top
)
2587 continue; /* Not far enough down yet */
2589 if (pCurRect
->top
>= rc
.bottom
)
2590 break; /* Too far down */
2592 if (pCurRect
->right
<= rc
.left
)
2593 continue; /* Not far enough over yet */
2595 if (pCurRect
->left
>= rc
.right
) {
2617 if (LeftRect
> RightRect
)
2620 LeftRect
= RightRect
;
2623 if (TopRect
> BottomRect
)
2626 TopRect
= BottomRect
;
2630 if ((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
2632 firstRect
= rgn
->Buffer
;
2634 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
2635 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
2636 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
2637 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
2638 rgn
->rdh
.nCount
= 1;
2639 rgn
->rdh
.iType
= RDH_RECTANGLES
;
2654 if (XOffset
|| YOffset
)
2656 int nbox
= rgn
->rdh
.nCount
;
2657 PRECTL pbox
= rgn
->Buffer
;
2663 pbox
->left
+= XOffset
;
2664 pbox
->right
+= XOffset
;
2665 pbox
->top
+= YOffset
;
2666 pbox
->bottom
+= YOffset
;
2669 if (rgn
->Buffer
!= &rgn
->rdh
.rcBound
)
2671 rgn
->rdh
.rcBound
.left
+= XOffset
;
2672 rgn
->rdh
.rcBound
.right
+= XOffset
;
2673 rgn
->rdh
.rcBound
.top
+= YOffset
;
2674 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
2678 return REGION_Complexity(rgn
);
2681 /***********************************************************************
2682 * REGION_InsertEdgeInET
2684 * Insert the given edge into the edge table.
2685 * First we must find the correct bucket in the
2686 * Edge table, then find the right slot in the
2687 * bucket. Finally, we can insert it.
2690 static void FASTCALL
2691 REGION_InsertEdgeInET(
2693 EdgeTableEntry
*ETE
,
2695 ScanLineListBlock
**SLLBlock
,
2699 EdgeTableEntry
*start
, *prev
;
2700 ScanLineList
*pSLL
, *pPrevSLL
;
2701 ScanLineListBlock
*tmpSLLBlock
;
2704 * Find the right bucket to put the edge into
2706 pPrevSLL
= &ET
->scanlines
;
2707 pSLL
= pPrevSLL
->next
;
2708 while (pSLL
&& (pSLL
->scanline
< scanline
))
2715 * Reassign pSLL (pointer to ScanLineList) if necessary
2717 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
2719 if (*iSLLBlock
> SLLSPERBLOCK
-1)
2721 tmpSLLBlock
= ExAllocatePoolWithTag(PagedPool
, sizeof(ScanLineListBlock
), TAG_REGION
);
2724 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2725 /* FIXME: Free resources? */
2728 (*SLLBlock
)->next
= tmpSLLBlock
;
2729 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2730 *SLLBlock
= tmpSLLBlock
;
2733 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
2735 pSLL
->next
= pPrevSLL
->next
;
2736 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
2737 pPrevSLL
->next
= pSLL
;
2739 pSLL
->scanline
= scanline
;
2742 * Now insert the edge in the right bucket
2744 prev
= (EdgeTableEntry
*)NULL
;
2745 start
= pSLL
->edgelist
;
2746 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2749 start
= start
->next
;
2756 pSLL
->edgelist
= ETE
;
2759 /***********************************************************************
2762 * This routine moves EdgeTableEntries from the
2763 * EdgeTable into the Active Edge Table,
2764 * leaving them sorted by smaller x coordinate.
2767 static void FASTCALL
2769 EdgeTableEntry
*AET
,
2770 EdgeTableEntry
*ETEs
2773 EdgeTableEntry
*pPrevAET
;
2774 EdgeTableEntry
*tmp
;
2780 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2789 ETEs
->back
= pPrevAET
;
2790 pPrevAET
->next
= ETEs
;
2797 /***********************************************************************
2798 * REGION_computeWAET
2800 * This routine links the AET by the
2801 * nextWETE (winding EdgeTableEntry) link for
2802 * use by the winding number rule. The final
2803 * Active Edge Table (AET) might look something
2807 * ---------- --------- ---------
2808 * |ymax | |ymax | |ymax |
2809 * | ... | |... | |... |
2810 * |next |->|next |->|next |->...
2811 * |nextWETE| |nextWETE| |nextWETE|
2812 * --------- --------- ^--------
2814 * V-------------------> V---> ...
2817 static void FASTCALL
2818 REGION_computeWAET(EdgeTableEntry
*AET
)
2820 register EdgeTableEntry
*pWETE
;
2821 register int inside
= 1;
2822 register int isInside
= 0;
2824 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2834 if ( (!inside
&& !isInside
) ||
2835 ( inside
&& isInside
) )
2837 pWETE
->nextWETE
= AET
;
2843 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2846 /***********************************************************************
2847 * REGION_InsertionSort
2849 * Just a simple insertion sort using
2850 * pointers and back pointers to sort the Active
2854 static BOOL FASTCALL
2855 REGION_InsertionSort(EdgeTableEntry
*AET
)
2857 EdgeTableEntry
*pETEchase
;
2858 EdgeTableEntry
*pETEinsert
;
2859 EdgeTableEntry
*pETEchaseBackTMP
;
2860 BOOL changed
= FALSE
;
2867 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2868 pETEchase
= pETEchase
->back
;
2871 if (pETEchase
!= pETEinsert
)
2873 pETEchaseBackTMP
= pETEchase
->back
;
2874 pETEinsert
->back
->next
= AET
;
2876 AET
->back
= pETEinsert
->back
;
2877 pETEinsert
->next
= pETEchase
;
2878 pETEchase
->back
->next
= pETEinsert
;
2879 pETEchase
->back
= pETEinsert
;
2880 pETEinsert
->back
= pETEchaseBackTMP
;
2887 /***********************************************************************
2888 * REGION_FreeStorage
2892 static void FASTCALL
2893 REGION_FreeStorage(ScanLineListBlock
*pSLLBlock
)
2895 ScanLineListBlock
*tmpSLLBlock
;
2899 tmpSLLBlock
= pSLLBlock
->next
;
2900 ExFreePoolWithTag(pSLLBlock
, TAG_REGION
);
2901 pSLLBlock
= tmpSLLBlock
;
2906 /***********************************************************************
2907 * REGION_PtsToRegion
2909 * Create an array of rectangles from a list of points.
2913 int numFullPtBlocks
,
2915 POINTBLOCK
*FirstPtBlock
,
2920 POINTBLOCK
*CurPtBlock
;
2922 RECTL
*extents
, *temp
;
2925 extents
= ®
->rdh
.rcBound
;
2927 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
2929 /* Make sure, we have at least one rect */
2935 if (!(temp
= ExAllocatePoolWithTag(PagedPool
, numRects
* sizeof(RECT
), TAG_REGION
)))
2939 if (reg
->Buffer
!= NULL
)
2941 COPY_RECTS(temp
, reg
->Buffer
, reg
->rdh
.nCount
);
2942 if (reg
->Buffer
!= ®
->rdh
.rcBound
)
2943 ExFreePoolWithTag(reg
->Buffer
, TAG_REGION
);
2947 reg
->rdh
.nCount
= numRects
;
2948 CurPtBlock
= FirstPtBlock
;
2949 rects
= reg
->Buffer
- 1;
2951 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
2953 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--)
2955 /* The loop uses 2 points per iteration */
2956 i
= NUMPTSTOBUFFER
>> 1;
2957 if (!numFullPtBlocks
)
2958 i
= iCurPtBlock
>> 1;
2959 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2)
2961 if (pts
->x
== pts
[1].x
)
2963 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
2964 pts
[1].x
== rects
->right
&&
2965 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
2966 (i
&& pts
[2].y
> pts
[1].y
))
2968 rects
->bottom
= pts
[1].y
+ 1;
2973 rects
->left
= pts
->x
;
2974 rects
->top
= pts
->y
;
2975 rects
->right
= pts
[1].x
;
2976 rects
->bottom
= pts
[1].y
+ 1;
2977 if (rects
->left
< extents
->left
)
2978 extents
->left
= rects
->left
;
2979 if (rects
->right
> extents
->right
)
2980 extents
->right
= rects
->right
;
2982 CurPtBlock
= CurPtBlock
->next
;
2987 extents
->top
= reg
->Buffer
->top
;
2988 extents
->bottom
= rects
->bottom
;
2995 extents
->bottom
= 0;
2997 reg
->rdh
.nCount
= numRects
;
3002 /***********************************************************************
3003 * REGION_CreateEdgeTable
3005 * This routine creates the edge table for
3006 * scan converting polygons.
3007 * The Edge Table (ET) looks like:
3011 * | ymax | ScanLineLists
3012 * |scanline|-->------------>-------------->...
3013 * -------- |scanline| |scanline|
3014 * |edgelist| |edgelist|
3015 * --------- ---------
3019 * list of ETEs list of ETEs
3021 * where ETE is an EdgeTableEntry data structure,
3022 * and there is one ScanLineList per scanline at
3023 * which an edge is initially entered.
3026 static void FASTCALL
3027 REGION_CreateETandAET(
3032 EdgeTableEntry
*AET
,
3033 EdgeTableEntry
*pETEs
,
3034 ScanLineListBlock
*pSLLBlock
3037 const POINT
*top
, *bottom
;
3038 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
3045 * Initialize the Active Edge Table
3047 AET
->next
= (EdgeTableEntry
*)NULL
;
3048 AET
->back
= (EdgeTableEntry
*)NULL
;
3049 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
3050 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
3053 * Initialize the Edge Table.
3055 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
3056 ET
->ymax
= SMALL_COORDINATE
;
3057 ET
->ymin
= LARGE_COORDINATE
;
3058 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
3061 for (poly
= 0; poly
< nbpolygons
; poly
++)
3063 count
= Count
[poly
];
3071 * For each vertex in the array of points.
3072 * In this loop we are dealing with two vertices at
3073 * a time -- these make up one edge of the polygon.
3080 * Find out which point is above and which is below.
3082 if (PrevPt
->y
> CurrPt
->y
)
3084 bottom
= PrevPt
, top
= CurrPt
;
3085 pETEs
->ClockWise
= 0;
3089 bottom
= CurrPt
, top
= PrevPt
;
3090 pETEs
->ClockWise
= 1;
3094 * Don't add horizontal edges to the Edge table.
3096 if (bottom
->y
!= top
->y
)
3098 pETEs
->ymax
= bottom
->y
-1;
3099 /* -1 so we don't get last scanline */
3102 * Initialize integer edge algorithm
3104 dy
= bottom
->y
- top
->y
;
3105 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
3107 REGION_InsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
,
3110 if (PrevPt
->y
> ET
->ymax
)
3111 ET
->ymax
= PrevPt
->y
;
3112 if (PrevPt
->y
< ET
->ymin
)
3113 ET
->ymin
= PrevPt
->y
;
3123 IntSetPolyPolygonRgn(
3131 EdgeTableEntry
*pAET
; /* Active Edge Table */
3132 INT y
; /* Current scanline */
3133 int iPts
= 0; /* Number of pts in buffer */
3134 EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry */
3135 ScanLineList
*pSLL
; /* Current scanLineList */
3136 POINT
*pts
; /* Output buffer */
3137 EdgeTableEntry
*pPrevAET
; /* Pointer to previous AET */
3138 EdgeTable ET
; /* Header node for ET */
3139 EdgeTableEntry AET
; /* Header node for AET */
3140 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
3141 ScanLineListBlock SLLBlock
; /* Header for scanlinelist */
3142 int fixWAET
= FALSE
;
3143 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
3144 POINTBLOCK
*tmpPtBlock
;
3145 int numFullPtBlocks
= 0;
3148 if (mode
== 0 || mode
> 2) return 0;
3150 /* Special case a rectangle */
3152 if (((nbpolygons
== 1) && ((*Count
== 4) ||
3153 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
3154 (((Pts
[0].y
== Pts
[1].y
) &&
3155 (Pts
[1].x
== Pts
[2].x
) &&
3156 (Pts
[2].y
== Pts
[3].y
) &&
3157 (Pts
[3].x
== Pts
[0].x
)) ||
3158 ((Pts
[0].x
== Pts
[1].x
) &&
3159 (Pts
[1].y
== Pts
[2].y
) &&
3160 (Pts
[2].x
== Pts
[3].x
) &&
3161 (Pts
[3].y
== Pts
[0].y
))))
3163 REGION_SetRectRgn(Rgn
,
3164 min(Pts
[0].x
, Pts
[2].x
),
3165 min(Pts
[0].y
, Pts
[2].y
),
3166 max(Pts
[0].x
, Pts
[2].x
),
3167 max(Pts
[0].y
, Pts
[2].y
));
3171 for (poly
= total
= 0; poly
< nbpolygons
; poly
++)
3172 total
+= Count
[poly
];
3173 if (! (pETEs
= ExAllocatePoolWithTag(PagedPool
, sizeof(EdgeTableEntry
) * total
, TAG_REGION
)) )
3177 pts
= FirstPtBlock
.pts
;
3178 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
3179 pSLL
= ET
.scanlines
.next
;
3180 curPtBlock
= &FirstPtBlock
;
3182 if (mode
!= WINDING
)
3187 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3190 * Add a new edge to the active edge table when we
3191 * get to the next edge.
3193 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3195 REGION_loadAET(&AET
, pSLL
->edgelist
);
3202 * For each active edge
3206 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3210 * Send out the buffer
3212 if (iPts
== NUMPTSTOBUFFER
)
3214 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
, sizeof(POINTBLOCK
), TAG_REGION
);
3217 DPRINT1("Can't alloc tPB\n");
3218 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3221 curPtBlock
->next
= tmpPtBlock
;
3222 curPtBlock
= tmpPtBlock
;
3223 pts
= curPtBlock
->pts
;
3227 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
3229 REGION_InsertionSort(&AET
);
3237 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3240 * Add a new edge to the active edge table when we
3241 * get to the next edge.
3243 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3245 REGION_loadAET(&AET
, pSLL
->edgelist
);
3246 REGION_computeWAET(&AET
);
3254 * For each active edge
3259 * Add to the buffer only those edges that
3260 * are in the Winding active edge table.
3264 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3268 * Send out the buffer
3270 if (iPts
== NUMPTSTOBUFFER
)
3272 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
,
3273 sizeof(POINTBLOCK
), TAG_REGION
);
3276 DPRINT1("Can't alloc tPB\n");
3277 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3280 curPtBlock
->next
= tmpPtBlock
;
3281 curPtBlock
= tmpPtBlock
;
3282 pts
= curPtBlock
->pts
;
3286 pWETE
= pWETE
->nextWETE
;
3288 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
3292 * Recompute the winding active edge table if
3293 * we just resorted or have exited an edge.
3295 if (REGION_InsertionSort(&AET
) || fixWAET
)
3297 REGION_computeWAET(&AET
);
3302 REGION_FreeStorage(SLLBlock
.next
);
3303 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, Rgn
);
3305 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;)
3307 tmpPtBlock
= curPtBlock
->next
;
3308 ExFreePoolWithTag(curPtBlock
, TAG_REGION
);
3309 curPtBlock
= tmpPtBlock
;
3311 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3325 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3330 Ret
= REGION_RectInRegion(Rgn
, rc
);
3331 RGNOBJAPI_Unlock(Rgn
);
3337 // NtGdi Exported Functions
3351 if (iMode
< RGN_AND
|| iMode
> RGN_COPY
)
3356 if (!hrgnDst
|| !hrgnSrc1
|| (iMode
!= RGN_COPY
&& !hrgnSrc2
))
3358 DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
3359 hrgnDst
, hrgnSrc1
, hrgnSrc2
, iMode
);
3363 /* Lock all regions */
3365 ahrgn
[1] = hrgnSrc1
;
3366 ahrgn
[2] = iMode
!= RGN_COPY
? hrgnSrc2
: NULL
;
3367 if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ
*)ahrgn
, (PVOID
*)aprgn
, GDIObjType_RGN_TYPE
))
3369 DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
3370 hrgnDst
, hrgnSrc1
, hrgnSrc2
, iMode
);
3374 /* HACK: Sync usermode attributes */
3375 REGION_vSyncRegion(aprgn
[0]);
3376 REGION_vSyncRegion(aprgn
[1]);
3377 if (aprgn
[2]) REGION_vSyncRegion(aprgn
[2]);
3379 /* Call the internal function */
3380 iResult
= IntGdiCombineRgn(aprgn
[0], aprgn
[1], aprgn
[2], iMode
);
3382 /* Cleanup and return */
3383 REGION_UnlockRgn(aprgn
[0]);
3384 REGION_UnlockRgn(aprgn
[1]);
3385 if (aprgn
[2]) REGION_UnlockRgn(aprgn
[2]);
3391 NtGdiCreateEllipticRgn(
3398 return NtGdiCreateRoundRectRgn(Left
, Top
, Right
, Bottom
,
3399 Right
- Left
, Bottom
- Top
);
3403 NtGdiCreateRectRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
3408 /* Allocate region data structure with space for 1 RECTL */
3409 if (!(pRgn
= REGION_AllocUserRgnWithHandle(1)))
3411 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3414 hRgn
= pRgn
->BaseObject
.hHmgr
;
3416 REGION_SetRectRgn(pRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3417 RGNOBJAPI_Unlock(pRgn
);
3419 DPRINT("Returning %p.\n", hRgn
);
3426 NtGdiCreateRoundRectRgn(
3437 int asq
, bsq
, d
, xd
, yd
;
3440 /* Make the dimensions sensible */
3455 ellipse_width
= abs(ellipse_width
);
3456 ellipse_height
= abs(ellipse_height
);
3458 /* Check parameters */
3460 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
3461 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
3463 /* Check if we can do a normal rectangle instead */
3465 if ((ellipse_width
< 2) || (ellipse_height
< 2))
3466 return NtGdiCreateRectRgn(left
, top
, right
, bottom
);
3470 d
= (ellipse_height
< 128) ? ((3 * ellipse_height
) >> 2) : 64;
3471 if (!(obj
= REGION_AllocUserRgnWithHandle(d
))) return 0;
3472 hrgn
= obj
->BaseObject
.hHmgr
;
3474 /* Ellipse algorithm, based on an article by K. Porter */
3475 /* in DDJ Graphics Programming Column, 8/89 */
3477 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
3478 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
3479 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
3481 yd
= asq
* ellipse_height
; /* 2a^2b */
3483 rect
.left
= left
+ ellipse_width
/ 2;
3484 rect
.right
= right
- ellipse_width
/ 2;
3486 /* Loop to draw first half of quadrant */
3490 if (d
> 0) /* If nearest pixel is toward the center */
3492 /* Move toward center */
3494 rect
.bottom
= rect
.top
+ 1;
3495 REGION_UnionRectWithRgn(obj
, &rect
);
3496 rect
.top
= --bottom
;
3497 rect
.bottom
= rect
.top
+ 1;
3498 REGION_UnionRectWithRgn(obj
, &rect
);
3502 rect
.left
--; /* Next horiz point */
3507 /* Loop to draw second half of quadrant */
3509 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
3512 /* next vertical point */
3514 rect
.bottom
= rect
.top
+ 1;
3515 REGION_UnionRectWithRgn(obj
, &rect
);
3516 rect
.top
= --bottom
;
3517 rect
.bottom
= rect
.top
+ 1;
3518 REGION_UnionRectWithRgn(obj
, &rect
);
3519 if (d
< 0) /* If nearest pixel is outside ellipse */
3521 rect
.left
--; /* Move away from center */
3529 /* Add the inside rectangle */
3534 rect
.bottom
= bottom
;
3535 REGION_UnionRectWithRgn(obj
, &rect
);
3538 RGNOBJAPI_Unlock(obj
);
3549 PROSRGNDATA rgn1
, rgn2
;
3550 PRECTL tRect1
, tRect2
;
3554 if ( !(rgn1
= RGNOBJAPI_Lock(hSrcRgn1
, NULL
)) )
3557 if ( !(rgn2
= RGNOBJAPI_Lock(hSrcRgn2
, NULL
)) )
3559 RGNOBJAPI_Unlock(rgn1
);
3563 if ( rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
) goto exit
;
3565 if ( rgn1
->rdh
.nCount
== 0 )
3571 if ( rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
||
3572 rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
||
3573 rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
||
3574 rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
)
3577 tRect1
= rgn1
->Buffer
;
3578 tRect2
= rgn2
->Buffer
;
3580 if (!tRect1
|| !tRect2
)
3583 for (i
=0; i
< rgn1
->rdh
.nCount
; i
++)
3585 if ( tRect1
[i
].left
!= tRect2
[i
].left
||
3586 tRect1
[i
].right
!= tRect2
[i
].right
||
3587 tRect1
[i
].top
!= tRect2
[i
].top
||
3588 tRect1
[i
].bottom
!= tRect2
[i
].bottom
)
3594 RGNOBJAPI_Unlock(rgn1
);
3595 RGNOBJAPI_Unlock(rgn2
);
3601 NtGdiExtCreateRegion(
3602 OPTIONAL LPXFORM Xform
,
3614 NTSTATUS Status
= STATUS_SUCCESS
;
3618 DPRINT("NtGdiExtCreateRegion\n");
3621 ProbeForRead(RgnData
, Count
, 1);
3622 nCount
= RgnData
->rdh
.nCount
;
3623 iType
= RgnData
->rdh
.iType
;
3624 dwSize
= RgnData
->rdh
.dwSize
;
3625 rects
= (RECT
*)RgnData
->Buffer
;
3627 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3629 Status
= _SEH2_GetExceptionCode();
3632 if (!NT_SUCCESS(Status
))
3634 SetLastNtError(Status
);
3638 /* Check parameters, but don't set last error here */
3639 if (Count
< sizeof(RGNDATAHEADER
) + nCount
* sizeof(RECT
) ||
3640 iType
!= RDH_RECTANGLES
||
3641 dwSize
!= sizeof(RGNDATAHEADER
))
3646 Region
= REGION_AllocUserRgnWithHandle(nCount
);
3650 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3653 hRgn
= Region
->BaseObject
.hHmgr
;
3657 /* Insert the rectangles one by one */
3658 for(i
=0; i
<nCount
; i
++)
3660 REGION_UnionRectWithRgn(Region
, &rects
[i
]);
3666 /* Init the XFORMOBJ from the Xform struct */
3667 Status
= STATUS_INVALID_PARAMETER
;
3668 XFORMOBJ_vInit(&xo
, &matrix
);
3669 ret
= XFORMOBJ_iSetXform(&xo
, (XFORML
*)Xform
);
3671 /* Check for error, also no scale and shear allowed */
3672 if (ret
!= DDI_ERROR
&& ret
!= GX_GENERAL
)
3674 /* Apply the coordinate transformation on the rects */
3675 if (XFORMOBJ_bApplyXform(&xo
,
3677 Region
->rdh
.nCount
* 2,
3681 Status
= STATUS_SUCCESS
;
3686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3688 Status
= _SEH2_GetExceptionCode();
3691 if (!NT_SUCCESS(Status
))
3693 EngSetLastError(ERROR_INVALID_PARAMETER
);
3694 RGNOBJAPI_Unlock(Region
);
3695 GreDeleteObject(hRgn
);
3699 RGNOBJAPI_Unlock(Region
);
3716 if (NULL
== (rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3721 if (NULL
== (oldhBrush
= NtGdiSelectBrush(hDC
, hBrush
)))
3723 RGNOBJAPI_Unlock(rgn
);
3727 for (r
= rgn
->Buffer
; r
< rgn
->Buffer
+ rgn
->rdh
.nCount
; r
++)
3729 NtGdiPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
3732 RGNOBJAPI_Unlock(rgn
);
3733 NtGdiSelectBrush(hDC
, oldhBrush
);
3751 if (!(FrameRgn
= NtGdiCreateRectRgn(0, 0, 0, 0)))
3755 if (!REGION_CreateFrameRgn(FrameRgn
, hRgn
, Width
, Height
))
3757 GreDeleteObject(FrameRgn
);
3761 Ret
= NtGdiFillRgn(hDC
, FrameRgn
, hBrush
);
3763 GreDeleteObject(FrameRgn
);
3777 NTSTATUS Status
= STATUS_SUCCESS
;
3779 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3784 ret
= REGION_GetRgnBox(Rgn
, &SafeRect
);
3785 RGNOBJAPI_Unlock(Rgn
);
3793 ProbeForWrite(pRect
, sizeof(RECT
), 1);
3796 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3798 Status
= _SEH2_GetExceptionCode();
3801 if (!NT_SUCCESS(Status
))
3816 PROSRGNDATA RgnData
;
3820 if (!(RgnData
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3822 EngSetLastError(ERROR_INVALID_HANDLE
);
3826 rc
= RgnData
->Buffer
;
3827 for (i
= 0; i
< RgnData
->rdh
.nCount
; i
++)
3830 if (!NtGdiPatBlt(hDC
, rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, DSTINVERT
))
3832 RGNOBJAPI_Unlock(RgnData
);
3838 RGNOBJAPI_Unlock(RgnData
);
3850 PROSRGNDATA rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3853 DPRINT("NtGdiOffsetRgn: hRgn %p Xoffs %d Yoffs %d rgn %p\n", hRgn
, XOffset
, YOffset
, rgn
);
3857 DPRINT("NtGdiOffsetRgn: hRgn error\n");
3861 ret
= IntGdiOffsetRgn(rgn
, XOffset
, YOffset
);
3863 RGNOBJAPI_Unlock(rgn
);
3878 if (!(prgn
= RGNOBJAPI_Lock(hRgn
, NULL
) ) )
3881 ret
= REGION_PtInRegion(prgn
, X
, Y
);
3883 RGNOBJAPI_Unlock(prgn
);
3895 NTSTATUS Status
= STATUS_SUCCESS
;
3899 ProbeForRead(unsaferc
, sizeof(RECT
), 1);
3902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3904 Status
= _SEH2_GetExceptionCode();
3908 if (!NT_SUCCESS(Status
))
3910 SetLastNtError(Status
);
3911 DPRINT1("NtGdiRectInRegion: Bogus rc\n");
3915 return IntRectInRegion(hRgn
, &rc
);
3930 if ( !(rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)) )
3932 return 0; // Per documentation
3935 REGION_SetRectRgn(rgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3937 RGNOBJAPI_Unlock(rgn
);
3942 NtGdiUnionRectWithRgn(
3944 const RECTL
*UnsafeRect
3947 RECTL SafeRect
= { 0 };
3949 NTSTATUS Status
= STATUS_SUCCESS
;
3951 if (!(Rgn
= RGNOBJAPI_Lock(hDest
, NULL
)))
3953 EngSetLastError(ERROR_INVALID_HANDLE
);
3959 ProbeForRead(UnsafeRect
, sizeof(RECT
), 1);
3960 SafeRect
= *UnsafeRect
;
3962 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3964 Status
= _SEH2_GetExceptionCode();
3968 if (! NT_SUCCESS(Status
))
3970 RGNOBJAPI_Unlock(Rgn
);
3971 SetLastNtError(Status
);
3975 REGION_UnionRectWithRgn(Rgn
, &SafeRect
);
3976 RGNOBJAPI_Unlock(Rgn
);
3981 * MSDN: GetRegionData, Return Values:
3983 * "If the function succeeds and dwCount specifies an adequate number of bytes,
3984 * the return value is always dwCount. If dwCount is too small or the function
3985 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
3986 * required number of bytes.
3988 * If the function fails, the return value is zero."
3990 _Success_(return!=0)
3995 _In_ ULONG cjBuffer
,
3996 _Out_opt_bytecap_(cjBuffer
) LPRGNDATA lpRgnData
)
3998 ULONG cjRects
, cjSize
;
4001 /* Lock the region */
4002 prgn
= RGNOBJAPI_Lock(hrgn
, NULL
);
4005 EngSetLastError(ERROR_INVALID_HANDLE
);
4009 /* Calculate the region sizes */
4010 cjRects
= prgn
->rdh
.nCount
* sizeof(RECT
);
4011 cjSize
= cjRects
+ sizeof(RGNDATAHEADER
);
4013 /* Check if region data is requested */
4016 /* Check if the buffer is large enough */
4017 if (cjBuffer
>= cjSize
)
4019 /* Probe the buffer and copy the data */
4022 ProbeForWrite(lpRgnData
, cjSize
, sizeof(ULONG
));
4023 RtlCopyMemory(lpRgnData
, &prgn
->rdh
, sizeof(RGNDATAHEADER
));
4024 RtlCopyMemory(lpRgnData
->Buffer
, prgn
->Buffer
, cjRects
);
4025 lpRgnData
->rdh
.iType
= RDH_RECTANGLES
;
4027 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4029 EngSetLastError(ERROR_INVALID_PARAMETER
);
4036 /* Buffer is too small */
4037 EngSetLastError(ERROR_INVALID_PARAMETER
);
4042 /* Unlock the region and return the size */
4043 RGNOBJAPI_Unlock(prgn
);