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 PREGION 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 SCANLINE_LIST structures containing a list of
288 * edges which are entered at a given scanline. There is one
289 * SCANLINE_LIST 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 EDGE_TABLEEntries in the AET linked by the
296 * nextWETE (winding EDGE_TABLE_ENTRY) 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 _EDGE_TABLE_ENTRY
311 INT ymax
; /* ycoord at which we exit this edge. */
312 BRESINFO bres
; /* Bresenham info to run the edge */
313 struct _EDGE_TABLE_ENTRY
*next
; /* Next in the list */
314 struct _EDGE_TABLE_ENTRY
*back
; /* For insertion sort */
315 struct _EDGE_TABLE_ENTRY
*nextWETE
; /* For winding num rule */
316 INT ClockWise
; /* Flag for winding number rule */
320 typedef struct _SCANLINE_LIST
322 INT scanline
; /* The scanline represented */
323 EDGE_TABLE_ENTRY
*edgelist
; /* Header node */
324 struct _SCANLINE_LIST
*next
; /* Next in the list */
330 INT ymax
; /* ymax for the polygon */
331 INT ymin
; /* ymin for the polygon */
332 SCANLINE_LIST 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 _SCANLINE_LISTBLOCK
345 SCANLINE_LIST SLLs
[SLLSPERBLOCK
];
346 struct _SCANLINE_LISTBLOCK
*next
;
347 } SCANLINE_LISTBLOCK
;
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(PREGION reg
, PRECTL
*rect
, PRECTL
*firstrect
)
413 if ((reg
->rdh
.nCount
+1) * sizeof(RECT
) >= reg
->rdh
.nRgnSize
)
416 DWORD NewSize
= 2 * reg
->rdh
.nRgnSize
;
418 if (NewSize
< (reg
->rdh
.nCount
+ 1) * sizeof(RECT
))
420 NewSize
= (reg
->rdh
.nCount
+ 1) * sizeof(RECT
);
423 temp
= ExAllocatePoolWithTag(PagedPool
, NewSize
, TAG_REGION
);
429 /* Copy the rectangles */
430 COPY_RECTS(temp
, *firstrect
, reg
->rdh
.nCount
);
432 reg
->rdh
.nRgnSize
= NewSize
;
433 if (*firstrect
!= ®
->rdh
.rcBound
)
435 ExFreePoolWithTag(*firstrect
, TAG_REGION
);
439 *rect
= (*firstrect
) + reg
->rdh
.nCount
;
444 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(PRECTL *)&(firstrect))
446 typedef VOID (FASTCALL
*overlapProcp
)(PREGION
, PRECT
, PRECT
, PRECT
, PRECT
, INT
, INT
);
447 typedef VOID (FASTCALL
*nonOverlapProcp
)(PREGION
, PRECT
, PRECT
, INT
, INT
);
449 // Number of points to buffer before sending them off to scanlines() : Must be an even number
450 #define NUMPTSTOBUFFER 200
452 #define RGN_DEFAULT_RECTS 2
454 // Used to allocate buffers for points and link the buffers together
455 typedef struct _POINTBLOCK
457 POINT pts
[NUMPTSTOBUFFER
];
458 struct _POINTBLOCK
*next
;
463 * This function is left there for debugging purposes.
467 IntDumpRegion(HRGN hRgn
)
471 Data
= RGNOBJAPI_Lock(hRgn
, NULL
);
474 DbgPrint("IntDumpRegion called with invalid region!\n");
478 DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
480 Data
->rdh
.rcBound
.left
,
481 Data
->rdh
.rcBound
.top
,
482 Data
->rdh
.rcBound
.right
,
483 Data
->rdh
.rcBound
.bottom
,
486 RGNOBJAPI_Unlock(Data
);
488 #endif /* Not NDEBUG */
493 REGION_Complexity(PREGION prgn
)
498 DPRINT("Region Complexity -> %lu", prgn
->rdh
.nCount
);
499 switch (prgn
->rdh
.nCount
)
506 return COMPLEXREGION
;
517 /* Only copy if source and dest are equal */
520 /* Check if we need to increase our buffer */
521 if (dst
->rdh
.nRgnSize
< src
->rdh
.nCount
* sizeof(RECT
))
525 /* Allocate a new buffer */
526 temp
= ExAllocatePoolWithTag(PagedPool
,
527 src
->rdh
.nCount
* sizeof(RECT
),
532 /* Free the old buffer */
533 if ((dst
->Buffer
!= NULL
) && (dst
->Buffer
!= &dst
->rdh
.rcBound
))
534 ExFreePoolWithTag(dst
->Buffer
, TAG_REGION
);
536 /* Set the new buffer and the size */
538 dst
->rdh
.nRgnSize
= src
->rdh
.nCount
* sizeof(RECT
);
541 dst
->rdh
.nCount
= src
->rdh
.nCount
;
542 dst
->rdh
.rcBound
.left
= src
->rdh
.rcBound
.left
;
543 dst
->rdh
.rcBound
.top
= src
->rdh
.rcBound
.top
;
544 dst
->rdh
.rcBound
.right
= src
->rdh
.rcBound
.right
;
545 dst
->rdh
.rcBound
.bottom
= src
->rdh
.rcBound
.bottom
;
546 dst
->rdh
.iType
= src
->rdh
.iType
;
547 COPY_RECTS(dst
->Buffer
, src
->Buffer
, src
->rdh
.nCount
);
559 RECTL
*pRect
, *pRectEnd
, *pExtents
;
561 /* Quick check for NULLREGION */
562 if (pReg
->rdh
.nCount
== 0)
564 pReg
->rdh
.rcBound
.left
= 0;
565 pReg
->rdh
.rcBound
.top
= 0;
566 pReg
->rdh
.rcBound
.right
= 0;
567 pReg
->rdh
.rcBound
.bottom
= 0;
568 pReg
->rdh
.iType
= RDH_RECTANGLES
;
572 pExtents
= &pReg
->rdh
.rcBound
;
573 pRect
= pReg
->Buffer
;
574 pRectEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
- 1;
576 /* Since pRect is the first rectangle in the region, it must have the
577 * smallest top and since pRectEnd is the last rectangle in the region,
578 * it must have the largest bottom, because of banding. Initialize left and
579 * right from pRect and pRectEnd, resp., as good things to initialize them
581 pExtents
->left
= pRect
->left
;
582 pExtents
->top
= pRect
->top
;
583 pExtents
->right
= pRectEnd
->right
;
584 pExtents
->bottom
= pRectEnd
->bottom
;
586 while (pRect
<= pRectEnd
)
588 if (pRect
->left
< pExtents
->left
)
589 pExtents
->left
= pRect
->left
;
590 if (pRect
->right
> pExtents
->right
)
591 pExtents
->right
= pRect
->right
;
595 pReg
->rdh
.iType
= RDH_RECTANGLES
;
598 // FIXME: This function needs review and testing
599 /***********************************************************************
600 * REGION_CropAndOffsetRegion
610 ULONG i
, j
, clipa
, clipb
, nRgnSize
;
614 INT bottom
= MINLONG
;
616 if ((rect
->left
>= rect
->right
) ||
617 (rect
->top
>= rect
->bottom
) ||
618 (EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
) == 0))
623 /* Skip all rects that are completely above our intersect rect */
624 for (clipa
= 0; clipa
< rgnSrc
->rdh
.nCount
; clipa
++)
626 /* bottom is exclusive, so break when we go above it */
627 if (rgnSrc
->Buffer
[clipa
].bottom
> rect
->top
) break;
630 /* Bail out, if there is nothing left */
631 if (clipa
== rgnSrc
->rdh
.nCount
) goto empty
;
633 /* Find the last rect that is still within the intersect rect (exclusive) */
634 for (clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
636 /* bottom is exclusive, so stop, when we start at that y pos */
637 if (rgnSrc
->Buffer
[clipb
].top
>= rect
->bottom
) break;
640 /* Bail out, if there is nothing left */
641 if (clipb
== clipa
) goto empty
;
643 // clipa - index of the first rect in the first intersecting band
644 // clipb - index of the last rect in the last intersecting band plus 1
646 /* Check if the buffer in the dest region is large enough,
647 otherwise allocate a new one */
648 nRgnSize
= (clipb
- clipa
) * sizeof(RECT
);
649 if ((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nRgnSize
< nRgnSize
))
652 temp
= ExAllocatePoolWithTag(PagedPool
, nRgnSize
, TAG_REGION
);
656 /* Free the old buffer */
657 if (rgnDst
->Buffer
&& (rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
))
658 ExFreePoolWithTag(rgnDst
->Buffer
, TAG_REGION
);
660 rgnDst
->Buffer
= temp
;
661 rgnDst
->rdh
.nCount
= 0;
662 rgnDst
->rdh
.nRgnSize
= nRgnSize
;
663 rgnDst
->rdh
.iType
= RDH_RECTANGLES
;
666 /* Loop all rects within the intersect rect from the y perspective */
667 for (i
= clipa
, j
= 0; i
< clipb
; i
++)
669 /* i - src index, j - dst index, j is always <= i for obvious reasons */
671 lpr
= &rgnSrc
->Buffer
[i
];
673 /* Make sure the source rect is not retarded */
674 ASSERT(lpr
->bottom
> rect
->top
);
675 ASSERT(lpr
->right
> rect
->left
);
677 /* We already checked above, this should hold true */
678 ASSERT(lpr
->bottom
> rect
->top
);
679 ASSERT(lpr
->top
< rect
->bottom
);
681 /* Check if this rect is really inside the intersect rect */
682 if ((lpr
->left
< rect
->right
) && (lpr
->right
> rect
->left
))
684 rpr
= &rgnDst
->Buffer
[j
];
686 /* Crop the rect with the intersect rect and add offset */
687 rpr
->top
= max(lpr
->top
, rect
->top
);
688 rpr
->bottom
= min(lpr
->bottom
, rect
->bottom
);
689 rpr
->left
= max(lpr
->left
, rect
->left
);
690 rpr
->right
= min(lpr
->right
, rect
->right
);
692 /* Make sure the resulting rect is not retarded */
693 ASSERT(lpr
->bottom
> rect
->top
);
694 ASSERT(lpr
->right
> rect
->left
);
696 /* Track new bounds */
697 if (rpr
->left
< left
) left
= rpr
->left
;
698 if (rpr
->right
> right
) right
= rpr
->right
;
699 if (rpr
->top
< top
) top
= rpr
->top
;
700 if (rpr
->bottom
> bottom
) bottom
= rpr
->bottom
;
702 /* Next target rect */
707 if (j
== 0) goto empty
;
709 /* Update the bounds rect */
710 rgnDst
->rdh
.rcBound
.left
= left
;
711 rgnDst
->rdh
.rcBound
.right
= right
;
712 rgnDst
->rdh
.rcBound
.top
= top
;
713 rgnDst
->rdh
.rcBound
.bottom
= bottom
;
715 /* Set new rect count */
716 rgnDst
->rdh
.nCount
= j
;
718 return REGION_Complexity(rgnDst
);
721 if (rgnDst
->Buffer
== NULL
)
723 rgnDst
->Buffer
= &rgnDst
->rdh
.rcBound
;
726 EMPTY_REGION(rgnDst
);
732 * Attempt to merge the rects in the current band with those in the
733 * previous one. Used only by REGION_RegionOp.
736 * The new index for the previous band.
738 * \note Side Effects:
739 * If coalescing takes place:
740 * - rectangles in the previous band will have their bottom fields
742 * - pReg->numRects will be decreased.
749 PREGION pReg
, /* Region to coalesce */
750 INT prevStart
, /* Index of start of previous band */
751 INT curStart
) /* Index of start of current band */
753 RECTL
*pPrevRect
; /* Current rect in previous band */
754 RECTL
*pCurRect
; /* Current rect in current band */
755 RECTL
*pRegEnd
; /* End of region */
756 INT curNumRects
; /* Number of rectangles in current band */
757 INT prevNumRects
; /* Number of rectangles in previous band */
758 INT bandtop
; /* Top coordinate for current band */
760 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
761 pPrevRect
= pReg
->Buffer
+ prevStart
;
762 prevNumRects
= curStart
- prevStart
;
764 /* Figure out how many rectangles are in the current band. Have to do
765 * this because multiple bands could have been added in REGION_RegionOp
766 * at the end when one region has been exhausted. */
767 pCurRect
= pReg
->Buffer
+ curStart
;
768 bandtop
= pCurRect
->top
;
769 for (curNumRects
= 0;
770 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
776 if (pCurRect
!= pRegEnd
)
778 /* If more than one band was added, we have to find the start
779 * of the last band added so the next coalescing job can start
780 * at the right place... (given when multiple bands are added,
781 * this may be pointless -- see above). */
783 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
788 curStart
= pRegEnd
- pReg
->Buffer
;
789 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
792 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0))
794 pCurRect
-= curNumRects
;
796 /* The bands may only be coalesced if the bottom of the previous
797 * matches the top scanline of the current. */
798 if (pPrevRect
->bottom
== pCurRect
->top
)
800 /* Make sure the bands have rects in the same places. This
801 * assumes that rects have been added in such a way that they
802 * cover the most area possible. I.e. two rects in a band must
803 * have some horizontal space between them. */
806 if ((pPrevRect
->left
!= pCurRect
->left
) ||
807 (pPrevRect
->right
!= pCurRect
->right
))
809 /* The bands don't line up so they can't be coalesced. */
817 while (prevNumRects
!= 0);
819 pReg
->rdh
.nCount
-= curNumRects
;
820 pCurRect
-= curNumRects
;
821 pPrevRect
-= curNumRects
;
823 /* The bands may be merged, so set the bottom of each rect
824 * in the previous band to that of the corresponding rect in
825 * the current band. */
828 pPrevRect
->bottom
= pCurRect
->bottom
;
833 while (curNumRects
!= 0);
835 /* If only one band was added to the region, we have to backup
836 * curStart to the start of the previous band.
838 * If more than one band was added to the region, copy the
839 * other bands down. The assumption here is that the other bands
840 * came from the same region as the current one and no further
841 * coalescing can be done on them since it's all been done
842 * already... curStart is already in the right place. */
843 if (pCurRect
== pRegEnd
)
845 curStart
= prevStart
;
851 *pPrevRect
++ = *pCurRect
++;
853 while (pCurRect
!= pRegEnd
);
862 * Apply an operation to two regions. Called by REGION_Union,
863 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
869 * The new region is overwritten.
871 *\note The idea behind this function is to view the two regions as sets.
872 * Together they cover a rectangle of area that this function divides
873 * into horizontal bands where points are covered only by one region
874 * or by both. For the first case, the nonOverlapFunc is called with
875 * each the band and the band's upper and lower extents. For the
876 * second, the overlapFunc is called to process the entire band. It
877 * is responsible for clipping the rectangles in the band, though
878 * this function provides the boundaries.
879 * At the end of each band, the new region is coalesced, if possible,
880 * to reduce the number of rectangles in the region.
887 PREGION newReg
, /* Place to store result */
888 PREGION reg1
, /* First region in operation */
889 PREGION reg2
, /* 2nd region in operation */
890 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
891 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
892 nonOverlapProcp nonOverlap2Func
) /* Function to call for non-overlapping bands in region 2 */
894 RECTL
*r1
; /* Pointer into first region */
895 RECTL
*r2
; /* Pointer into 2d region */
896 RECTL
*r1End
; /* End of 1st region */
897 RECTL
*r2End
; /* End of 2d region */
898 INT ybot
; /* Bottom of intersection */
899 INT ytop
; /* Top of intersection */
900 RECTL
*oldRects
; /* Old rects for newReg */
901 ULONG prevBand
; /* Index of start of
902 * Previous band in newReg */
903 ULONG curBand
; /* Index of start of current band in newReg */
904 RECTL
*r1BandEnd
; /* End of current band in r1 */
905 RECTL
*r2BandEnd
; /* End of current band in r2 */
906 ULONG top
; /* Top of non-overlapping band */
907 ULONG bot
; /* Bottom of non-overlapping band */
910 * set r1, r2, r1End and r2End appropriately, preserve the important
911 * parts of the destination region until the end in case it's one of
912 * the two source regions, then mark the "new" region empty, allocating
913 * another array of rectangles for it to use. */
916 r1End
= r1
+ reg1
->rdh
.nCount
;
917 r2End
= r2
+ reg2
->rdh
.nCount
;
919 /* newReg may be one of the src regions so we can't empty it. We keep a
920 * note of its rects pointer (so that we can free them later), preserve its
921 * extents and simply set numRects to zero. */
922 oldRects
= newReg
->Buffer
;
923 newReg
->rdh
.nCount
= 0;
925 /* Allocate a reasonable number of rectangles for the new region. The idea
926 * is to allocate enough so the individual functions don't need to
927 * reallocate and copy the array, which is time consuming, yet we don't
928 * have to worry about using too much memory. I hope to be able to
929 * nuke the Xrealloc() at the end of this function eventually. */
930 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
+ 1, reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
932 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
933 newReg
->rdh
.nRgnSize
,
935 if (newReg
->Buffer
== NULL
)
937 newReg
->rdh
.nRgnSize
= 0;
941 /* Initialize ybot and ytop.
942 * In the upcoming loop, ybot and ytop serve different functions depending
943 * on whether the band being handled is an overlapping or non-overlapping
945 * In the case of a non-overlapping band (only one of the regions
946 * has points in the band), ybot is the bottom of the most recent
947 * intersection and thus clips the top of the rectangles in that band.
948 * ytop is the top of the next intersection between the two regions and
949 * serves to clip the bottom of the rectangles in the current band.
950 * For an overlapping band (where the two regions intersect), ytop clips
951 * the top of the rectangles of both regions and ybot clips the bottoms. */
952 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
953 ybot
= reg1
->rdh
.rcBound
.top
;
955 ybot
= reg2
->rdh
.rcBound
.top
;
957 /* prevBand serves to mark the start of the previous band so rectangles
958 * can be coalesced into larger rectangles. qv. miCoalesce, above.
959 * In the beginning, there is no previous band, so prevBand == curBand
960 * (curBand is set later on, of course, but the first band will always
961 * start at index 0). prevBand and curBand must be indices because of
962 * the possible expansion, and resultant moving, of the new region's
963 * array of rectangles. */
967 curBand
= newReg
->rdh
.nCount
;
969 /* This algorithm proceeds one source-band (as opposed to a
970 * destination band, which is determined by where the two regions
971 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
972 * rectangle after the last one in the current band for their
973 * respective regions. */
975 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
981 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
986 /* First handle the band that doesn't intersect, if any.
988 * Note that attention is restricted to one band in the
989 * non-intersecting region at once, so if a region has n
990 * bands between the current position and the next place it overlaps
991 * the other, this entire loop will be passed through n times. */
992 if (r1
->top
< r2
->top
)
994 top
= max(r1
->top
,ybot
);
995 bot
= min(r1
->bottom
,r2
->top
);
997 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
999 (*nonOverlap1Func
)(newReg
, r1
, r1BandEnd
, top
, bot
);
1004 else if (r2
->top
< r1
->top
)
1006 top
= max(r2
->top
,ybot
);
1007 bot
= min(r2
->bottom
,r1
->top
);
1009 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
1011 (*nonOverlap2Func
)(newReg
, r2
, r2BandEnd
, top
, bot
);
1021 /* If any rectangles got added to the region, try and coalesce them
1022 * with rectangles from the previous band. Note we could just do
1023 * this test in miCoalesce, but some machines incur a not
1024 * inconsiderable cost for function calls, so... */
1025 if (newReg
->rdh
.nCount
!= curBand
)
1027 prevBand
= REGION_Coalesce(newReg
, prevBand
, curBand
);
1030 /* Now see if we've hit an intersecting band. The two bands only
1031 * intersect if ybot > ytop */
1032 ybot
= min(r1
->bottom
, r2
->bottom
);
1033 curBand
= newReg
->rdh
.nCount
;
1036 (*overlapFunc
)(newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1039 if (newReg
->rdh
.nCount
!= curBand
)
1041 prevBand
= REGION_Coalesce(newReg
, prevBand
, curBand
);
1044 /* If we've finished with a band (bottom == ybot) we skip forward
1045 * in the region to the next band. */
1046 if (r1
->bottom
== ybot
)
1050 if (r2
->bottom
== ybot
)
1055 while ((r1
!= r1End
) && (r2
!= r2End
));
1057 /* Deal with whichever region still has rectangles left. */
1058 curBand
= newReg
->rdh
.nCount
;
1061 if (nonOverlap1Func
!= NULL
)
1066 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1071 (*nonOverlap1Func
)(newReg
,
1078 while (r1
!= r1End
);
1081 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
1086 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1091 (*nonOverlap2Func
)(newReg
,
1098 while (r2
!= r2End
);
1101 if (newReg
->rdh
.nCount
!= curBand
)
1103 (VOID
)REGION_Coalesce(newReg
, prevBand
, curBand
);
1106 /* A bit of cleanup. To keep regions from growing without bound,
1107 * we shrink the array of rectangles to match the new number of
1108 * rectangles in the region. This never goes to 0, however...
1110 * Only do this stuff if the number of rectangles allocated is more than
1111 * twice the number of rectangles in the region (a simple optimization...). */
1112 if ((newReg
->rdh
.nRgnSize
> (2 * newReg
->rdh
.nCount
* sizeof(RECT
))) &&
1113 (newReg
->rdh
.nCount
> 2))
1115 if (REGION_NOT_EMPTY(newReg
))
1117 RECTL
*prev_rects
= newReg
->Buffer
;
1118 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
1119 newReg
->rdh
.nCount
* sizeof(RECT
),
1122 if (newReg
->Buffer
== NULL
)
1124 newReg
->Buffer
= prev_rects
;
1128 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
1129 COPY_RECTS(newReg
->Buffer
, prev_rects
, newReg
->rdh
.nCount
);
1130 if (prev_rects
!= &newReg
->rdh
.rcBound
)
1131 ExFreePoolWithTag(prev_rects
, TAG_REGION
);
1136 /* No point in doing the extra work involved in an Xrealloc if
1137 * the region is empty */
1138 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
1139 if (newReg
->Buffer
!= &newReg
->rdh
.rcBound
)
1140 ExFreePoolWithTag(newReg
->Buffer
, TAG_REGION
);
1142 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
1145 ASSERT(newReg
->Buffer
);
1149 newReg
->rdh
.iType
= RDH_RECTANGLES
;
1151 if (oldRects
!= &newReg
->rdh
.rcBound
)
1152 ExFreePoolWithTag(oldRects
, TAG_REGION
);
1156 /***********************************************************************
1157 * Region Intersection
1158 ***********************************************************************/
1162 * Handle an overlapping band for REGION_Intersect.
1167 * \note Side Effects:
1168 * Rectangles may be added to the region.
1186 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1188 while ((r1
!= r1End
) && (r2
!= r2End
))
1190 left
= max(r1
->left
, r2
->left
);
1191 right
= min(r1
->right
, r2
->right
);
1193 /* If there's any overlap between the two rectangles, add that
1194 * overlap to the new region.
1195 * There's no need to check for subsumption because the only way
1196 * such a need could arise is if some region has two rectangles
1197 * right next to each other. Since that should never happen... */
1200 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1201 pNextRect
->left
= left
;
1202 pNextRect
->top
= top
;
1203 pNextRect
->right
= right
;
1204 pNextRect
->bottom
= bottom
;
1205 pReg
->rdh
.nCount
+= 1;
1209 /* Need to advance the pointers. Shift the one that extends
1210 * to the right the least, since the other still has a chance to
1211 * overlap with that region's next rectangle, if you see what I mean. */
1212 if (r1
->right
< r2
->right
)
1216 else if (r2
->right
< r1
->right
)
1230 /***********************************************************************
1231 * REGION_IntersectRegion
1236 REGION_IntersectRegion(
1241 /* Check for trivial reject */
1242 if ((reg1
->rdh
.nCount
== 0) ||
1243 (reg2
->rdh
.nCount
== 0) ||
1244 (EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
) == 0))
1246 newReg
->rdh
.nCount
= 0;
1250 REGION_RegionOp(newReg
,
1258 /* Can't alter newReg's extents before we call miRegionOp because
1259 * it might be one of the source regions and miRegionOp depends
1260 * on the extents of those regions being the same. Besides, this
1261 * way there's no checking against rectangles that will be nuked
1262 * due to coalescing, so we have to examine fewer rectangles. */
1263 REGION_SetExtents(newReg
);
1266 /***********************************************************************
1268 ***********************************************************************/
1271 * Handle a non-overlapping band for the union operation. Just
1272 * Adds the rectangles into the region. Doesn't have to check for
1273 * subsumption or anything.
1278 * \note Side Effects:
1279 * pReg->numRects is incremented and the final rectangles overwritten
1280 * with the rectangles we're passed.
1295 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1299 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1300 pNextRect
->left
= r
->left
;
1301 pNextRect
->top
= top
;
1302 pNextRect
->right
= r
->right
;
1303 pNextRect
->bottom
= bottom
;
1304 pReg
->rdh
.nCount
+= 1;
1313 * Handle an overlapping band for the union operation. Picks the
1314 * left-most rectangle each time and merges it into the region.
1319 * \note Side Effects:
1320 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1338 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1340 #define MERGERECT(r) \
1341 if ((pReg->rdh.nCount != 0) && \
1342 ((pNextRect-1)->top == top) && \
1343 ((pNextRect-1)->bottom == bottom) && \
1344 ((pNextRect-1)->right >= r->left)) \
1346 if ((pNextRect-1)->right < r->right) \
1348 (pNextRect-1)->right = r->right; \
1353 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1354 pNextRect->top = top; \
1355 pNextRect->bottom = bottom; \
1356 pNextRect->left = r->left; \
1357 pNextRect->right = r->right; \
1358 pReg->rdh.nCount += 1; \
1363 while ((r1
!= r1End
) && (r2
!= r2End
))
1365 if (r1
->left
< r2
->left
)
1381 while (r1
!= r1End
);
1394 /***********************************************************************
1395 * REGION_UnionRegion
1405 /* Checks all the simple cases
1406 * Region 1 and 2 are the same or region 1 is empty */
1407 if ((reg1
== reg2
) || (reg1
->rdh
.nCount
== 0) ||
1408 (reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
) ||
1409 (reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
))
1413 REGION_CopyRegion(newReg
, reg2
);
1419 /* If nothing to union (region 2 empty) */
1420 if ((reg2
->rdh
.nCount
== 0) ||
1421 (reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
) ||
1422 (reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
))
1426 REGION_CopyRegion(newReg
, reg1
);
1432 /* Region 1 completely subsumes region 2 */
1433 if ((reg1
->rdh
.nCount
== 1) &&
1434 (reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
) &&
1435 (reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
) &&
1436 (reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
) &&
1437 (reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
))
1441 REGION_CopyRegion(newReg
, reg1
);
1447 /* Region 2 completely subsumes region 1 */
1448 if ((reg2
->rdh
.nCount
== 1) &&
1449 (reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
) &&
1450 (reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
) &&
1451 (reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
) &&
1452 (reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
))
1456 REGION_CopyRegion(newReg
, reg2
);
1462 REGION_RegionOp(newReg
,
1469 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1470 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1471 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1472 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1475 /***********************************************************************
1476 * Region Subtraction
1477 ***********************************************************************/
1480 * Deal with non-overlapping band for subtraction. Any parts from
1481 * region 2 we discard. Anything from region 1 we add to the region.
1486 * \note Side Effects:
1487 * pReg may be affected.
1493 REGION_SubtractNonO1(
1502 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1506 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1507 pNextRect
->left
= r
->left
;
1508 pNextRect
->top
= top
;
1509 pNextRect
->right
= r
->right
;
1510 pNextRect
->bottom
= bottom
;
1511 pReg
->rdh
.nCount
+= 1;
1521 * Overlapping band subtraction. x1 is the left-most point not yet
1527 * \note Side Effects:
1528 * pReg may have rectangles added to it.
1547 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1549 while ((r1
!= r1End
) && (r2
!= r2End
))
1551 if (r2
->right
<= left
)
1553 /* Subtrahend missed the boat: go to next subtrahend. */
1556 else if (r2
->left
<= left
)
1558 /* Subtrahend preceeds minuend: nuke left edge of minuend. */
1560 if (left
>= r1
->right
)
1562 /* Minuend completely covered: advance to next minuend and
1563 * reset left fence to edge of new minuend. */
1570 /* Subtrahend now used up since it doesn't extend beyond
1575 else if (r2
->left
< r1
->right
)
1577 /* Left part of subtrahend covers part of minuend: add uncovered
1578 * part of minuend to region and skip to next subtrahend. */
1579 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1580 pNextRect
->left
= left
;
1581 pNextRect
->top
= top
;
1582 pNextRect
->right
= r2
->left
;
1583 pNextRect
->bottom
= bottom
;
1584 pReg
->rdh
.nCount
+= 1;
1587 if (left
>= r1
->right
)
1589 /* Minuend used up: advance to new... */
1596 /* Subtrahend used up */
1602 /* Minuend used up: add any remaining piece before advancing. */
1603 if (r1
->right
> left
)
1605 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1606 pNextRect
->left
= left
;
1607 pNextRect
->top
= top
;
1608 pNextRect
->right
= r1
->right
;
1609 pNextRect
->bottom
= bottom
;
1610 pReg
->rdh
.nCount
+= 1;
1620 /* Add remaining minuend rectangles to region. */
1623 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1624 pNextRect
->left
= left
;
1625 pNextRect
->top
= top
;
1626 pNextRect
->right
= r1
->right
;
1627 pNextRect
->bottom
= bottom
;
1628 pReg
->rdh
.nCount
+= 1;
1641 * Subtract regS from regM and leave the result in regD.
1642 * S stands for subtrahend, M for minuend and D for difference.
1647 * \note Side Effects:
1648 * regD is overwritten.
1654 REGION_SubtractRegion(
1659 /* Check for trivial reject */
1660 if ((regM
->rdh
.nCount
== 0) ||
1661 (regS
->rdh
.nCount
== 0) ||
1662 (EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
) == 0))
1664 REGION_CopyRegion(regD
, regM
);
1668 REGION_RegionOp(regD
,
1672 REGION_SubtractNonO1
,
1675 /* Can't alter newReg's extents before we call miRegionOp because
1676 * it might be one of the source regions and miRegionOp depends
1677 * on the extents of those regions being the unaltered. Besides, this
1678 * way there's no checking against rectangles that will be nuked
1679 * due to coalescing, so we have to examine fewer rectangles. */
1680 REGION_SetExtents(regD
);
1683 /***********************************************************************
1697 // FIXME: Don't use a handle
1698 tra
= REGION_AllocRgnWithHandle(sra
->rdh
.nCount
+ 1);
1703 htra
= tra
->BaseObject
.hHmgr
;
1705 // FIXME: Don't use a handle
1706 trb
= REGION_AllocRgnWithHandle(srb
->rdh
.nCount
+ 1);
1709 RGNOBJAPI_Unlock(tra
);
1710 GreDeleteObject(htra
);
1713 htrb
= trb
->BaseObject
.hHmgr
;
1715 REGION_SubtractRegion(tra
, sra
, srb
);
1716 REGION_SubtractRegion(trb
, srb
, sra
);
1717 REGION_UnionRegion(dr
, tra
, trb
);
1718 RGNOBJAPI_Unlock(tra
);
1719 RGNOBJAPI_Unlock(trb
);
1721 GreDeleteObject(htra
);
1722 GreDeleteObject(htrb
);
1728 * Adds a rectangle to a REGION
1732 REGION_UnionRectWithRgn(
1738 region
.Buffer
= ®ion
.rdh
.rcBound
;
1739 region
.rdh
.nCount
= 1;
1740 region
.rdh
.nRgnSize
= sizeof(RECT
);
1741 region
.rdh
.rcBound
= *rect
;
1742 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1747 REGION_SubtractRectFromRgn(
1754 rgnLocal
.Buffer
= &rgnLocal
.rdh
.rcBound
;
1755 rgnLocal
.rdh
.nCount
= 1;
1756 rgnLocal
.rdh
.nRgnSize
= sizeof(RECT
);
1757 rgnLocal
.rdh
.rcBound
= *prcl
;
1758 REGION_SubtractRegion(prgnDest
, prgnSrc
, &rgnLocal
);
1759 return REGION_Complexity(prgnDest
);
1764 REGION_CreateSimpleFrameRgn(
1772 if ((x
!= 0) || (y
!= 0))
1776 if ((rgn
->rdh
.rcBound
.bottom
- rgn
->rdh
.rcBound
.top
> y
* 2) &&
1777 (rgn
->rdh
.rcBound
.right
- rgn
->rdh
.rcBound
.left
> x
* 2))
1782 prc
->left
= rgn
->rdh
.rcBound
.left
;
1783 prc
->top
= rgn
->rdh
.rcBound
.top
;
1784 prc
->right
= rgn
->rdh
.rcBound
.right
;
1785 prc
->bottom
= prc
->top
+ y
;
1791 /* Left rectangle */
1792 prc
->left
= rgn
->rdh
.rcBound
.left
;
1793 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1794 prc
->right
= prc
->left
+ x
;
1795 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1798 /* Right rectangle */
1799 prc
->left
= rgn
->rdh
.rcBound
.right
- x
;
1800 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1801 prc
->right
= rgn
->rdh
.rcBound
.right
;
1802 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1808 /* Bottom rectangle */
1809 prc
->left
= rgn
->rdh
.rcBound
.left
;
1810 prc
->top
= rgn
->rdh
.rcBound
.bottom
- y
;
1811 prc
->right
= rgn
->rdh
.rcBound
.right
;
1812 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
;
1819 /* The frame results in a complex region. rcBounds remains
1820 the same, though. */
1821 rgn
->rdh
.nCount
= (DWORD
)(prc
- rc
);
1822 ASSERT(rgn
->rdh
.nCount
> 1);
1823 rgn
->rdh
.nRgnSize
= rgn
->rdh
.nCount
* sizeof(RECT
);
1824 rgn
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
1827 if (rgn
->Buffer
== NULL
)
1829 rgn
->rdh
.nRgnSize
= 0;
1833 _PRAGMA_WARNING_SUPPRESS(__WARNING_MAYBE_UNINIT_VAR
) // rc is initialized
1834 COPY_RECTS(rgn
->Buffer
, rc
, rgn
->rdh
.nCount
);
1843 REGION_CreateFrameRgn(
1849 PREGION srcObj
, destObj
;
1853 srcObj
= RGNOBJAPI_Lock(hSrc
, NULL
);
1859 if (!REGION_NOT_EMPTY(srcObj
))
1861 RGNOBJAPI_Unlock(srcObj
);
1865 destObj
= RGNOBJAPI_Lock(hDest
, NULL
);
1866 if (destObj
== NULL
)
1868 RGNOBJAPI_Unlock(srcObj
);
1872 EMPTY_REGION(destObj
);
1873 if (!REGION_CopyRegion(destObj
, srcObj
))
1875 RGNOBJAPI_Unlock(destObj
);
1876 RGNOBJAPI_Unlock(srcObj
);
1880 if (REGION_Complexity(srcObj
) == SIMPLEREGION
)
1882 if (!REGION_CreateSimpleFrameRgn(destObj
, x
, y
))
1884 EMPTY_REGION(destObj
);
1885 RGNOBJAPI_Unlock(destObj
);
1886 RGNOBJAPI_Unlock(srcObj
);
1892 /* Original region moved to right */
1893 rc
= srcObj
->Buffer
;
1894 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1901 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1903 /* Original region moved to left */
1904 rc
= srcObj
->Buffer
;
1905 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1912 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1914 /* Original region moved down */
1915 rc
= srcObj
->Buffer
;
1916 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1925 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1927 /* Original region moved up */
1928 rc
= srcObj
->Buffer
;
1929 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1932 rc
->bottom
-= 2 * y
;
1936 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1938 /* Restore the original region */
1939 rc
= srcObj
->Buffer
;
1940 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1947 REGION_SubtractRegion(destObj
, srcObj
, destObj
);
1950 RGNOBJAPI_Unlock(destObj
);
1951 RGNOBJAPI_Unlock(srcObj
);
1961 _Inout_ PREGION RgnDest
,
1962 _In_ PREGION RgnSrc
)
1964 RECTL
*pCurRect
, *pEndRect
;
1970 pdcattr
= dc
->pdcattr
;
1972 if (pdcattr
->iMapMode
== MM_TEXT
) // Requires only a translation
1974 if (IntGdiCombineRgn(RgnDest
, RgnSrc
, 0, RGN_COPY
) == ERROR
)
1977 IntGdiOffsetRgn(RgnDest
,
1978 pdcattr
->ptlViewportOrg
.x
- pdcattr
->ptlWindowOrg
.x
,
1979 pdcattr
->ptlViewportOrg
.y
- pdcattr
->ptlWindowOrg
.y
);
1983 EMPTY_REGION(RgnDest
);
1985 pEndRect
= RgnSrc
->Buffer
+ RgnSrc
->rdh
.nCount
;
1986 for (pCurRect
= RgnSrc
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
1988 tmpRect
= *pCurRect
;
1989 tmpRect
.left
= XLPTODP(pdcattr
, tmpRect
.left
);
1990 tmpRect
.top
= YLPTODP(pdcattr
, tmpRect
.top
);
1991 tmpRect
.right
= XLPTODP(pdcattr
, tmpRect
.right
);
1992 tmpRect
.bottom
= YLPTODP(pdcattr
, tmpRect
.bottom
);
1994 if (tmpRect
.left
> tmpRect
.right
)
1996 INT tmp
= tmpRect
.left
;
1997 tmpRect
.left
= tmpRect
.right
;
1998 tmpRect
.right
= tmp
;
2001 if (tmpRect
.top
> tmpRect
.bottom
)
2003 INT tmp
= tmpRect
.top
;
2004 tmpRect
.top
= tmpRect
.bottom
;
2005 tmpRect
.bottom
= tmp
;
2008 REGION_UnionRectWithRgn(RgnDest
, &tmpRect
);
2016 REGION_AllocRgnWithHandle(
2022 pReg
= (PREGION
)GDIOBJ_AllocateObject(GDIObjType_RGN_TYPE
,
2024 BASEFLAG_LOOKASIDE
);
2027 DPRINT1("Could not allocate a palette.\n");
2031 if (!GDIOBJ_hInsertObject(&pReg
->BaseObject
, GDI_OBJ_HMGR_POWNED
))
2033 DPRINT1("Could not insert palette into handle table.\n");
2034 GDIOBJ_vFreeObject(&pReg
->BaseObject
);
2038 //hReg = pReg->BaseObject.hHmgr;
2040 if ((nReg
== 0) || (nReg
== 1))
2042 /* Testing shows that > 95% of all regions have only 1 rect.
2043 Including that here saves us from having to do another allocation */
2044 pReg
->Buffer
= &pReg
->rdh
.rcBound
;
2048 pReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
,
2049 nReg
* sizeof(RECT
),
2051 if (pReg
->Buffer
== NULL
)
2053 DPRINT1("Could not allocate region buffer\n");
2054 GDIOBJ_vDeleteObject(&pReg
->BaseObject
);
2060 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
2061 pReg
->rdh
.nCount
= nReg
;
2062 pReg
->rdh
.nRgnSize
= nReg
* sizeof(RECT
);
2063 pReg
->prgnattr
= &pReg
->rgnattr
;
2070 REGION_bAllocRgnAttr(
2076 ppi
= PsGetCurrentProcessWin32Process();
2079 prgnattr
= GdiPoolAllocate(ppi
->pPoolRgnAttr
);
2080 if (prgnattr
== NULL
)
2082 DPRINT1("Could not allocate RGN attr\n");
2086 /* Set the object attribute in the handle table */
2087 prgn
->prgnattr
= prgnattr
;
2088 GDIOBJ_vSetObjectAttr(&prgn
->BaseObject
, prgnattr
);
2095 // Allocate User Space Region Handle.
2099 REGION_AllocUserRgnWithHandle(
2104 prgn
= REGION_AllocRgnWithHandle(nRgn
);
2110 if (!REGION_bAllocRgnAttr(prgn
))
2123 PRGN_ATTR pRgn_Attr
= NULL
;
2125 if (pRgn
&& pRgn
->prgnattr
!= &pRgn
->rgnattr
)
2127 pRgn_Attr
= GDIOBJ_pvGetObjectAttr(&pRgn
->BaseObject
);
2133 if ( !(pRgn_Attr
->AttrFlags
& ATTR_CACHED
) )
2135 if ( pRgn_Attr
->AttrFlags
& (ATTR_RGN_VALID
|ATTR_RGN_DIRTY
) )
2137 switch (pRgn_Attr
->iComplexity
)
2140 EMPTY_REGION( pRgn
);
2144 REGION_SetRectRgn( pRgn
,
2145 pRgn_Attr
->Rect
.left
,
2146 pRgn_Attr
->Rect
.top
,
2147 pRgn_Attr
->Rect
.right
,
2148 pRgn_Attr
->Rect
.bottom
);
2151 pRgn_Attr
->AttrFlags
&= ~ATTR_RGN_DIRTY
;
2155 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2169 PRGN_ATTR
*ppRgn_Attr
)
2173 pRgn
= REGION_LockRgn(hRgn
);
2177 REGION_vSyncRegion(pRgn
);
2180 *ppRgn_Attr
= pRgn
->prgnattr
;
2190 PRGN_ATTR pRgn_Attr
;
2192 if (pRgn
&& GreGetObjectOwner(pRgn
->BaseObject
.hHmgr
) == GDI_OBJ_HMGR_POWNED
)
2194 pRgn_Attr
= GDIOBJ_pvGetObjectAttr(&pRgn
->BaseObject
);
2200 if ( pRgn_Attr
->AttrFlags
& ATTR_RGN_VALID
)
2202 pRgn_Attr
->iComplexity
= REGION_Complexity( pRgn
);
2203 pRgn_Attr
->Rect
.left
= pRgn
->rdh
.rcBound
.left
;
2204 pRgn_Attr
->Rect
.top
= pRgn
->rdh
.rcBound
.top
;
2205 pRgn_Attr
->Rect
.right
= pRgn
->rdh
.rcBound
.right
;
2206 pRgn_Attr
->Rect
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2216 REGION_UnlockRgn(pRgn
);
2221 These regions do not use attribute sections and when allocated, use gdiobj
2225 // System Region Functions
2229 IntSysCreateRectpRgn(
2237 /* Allocate a region, witout a handle */
2238 prgn
= (PREGION
)GDIOBJ_AllocateObject(GDIObjType_RGN_TYPE
, sizeof(REGION
), BASEFLAG_LOOKASIDE
);
2245 prgn
->Buffer
= &prgn
->rdh
.rcBound
;
2246 prgn
->prgnattr
= &prgn
->rgnattr
;
2247 REGION_SetRectRgn(prgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
2254 REGION_vCleanup(PVOID ObjectBody
)
2256 PREGION pRgn
= (PREGION
)ObjectBody
;
2257 PPROCESSINFO ppi
= PsGetCurrentProcessWin32Process();
2260 ASSERT(pRgn
->prgnattr
);
2261 if (pRgn
->prgnattr
!= &pRgn
->rgnattr
)
2262 GdiPoolFree(ppi
->pPoolRgnAttr
, pRgn
->prgnattr
);
2264 if (pRgn
->Buffer
&& pRgn
->Buffer
!= &pRgn
->rdh
.rcBound
)
2265 ExFreePoolWithTag(pRgn
->Buffer
, TAG_REGION
);
2270 REGION_Delete(PREGION pRgn
)
2272 if (pRgn
== prgnDefault
)
2275 GDIOBJ_vDeleteObject(&pRgn
->BaseObject
);
2280 IntGdiReleaseRaoRgn(PDC pDC
)
2282 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2283 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2284 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2285 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2286 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2287 REGION_Delete(pDC
->prgnRao
);
2288 pDC
->prgnRao
= NULL
;
2293 IntGdiReleaseVisRgn(PDC pDC
)
2295 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2296 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2297 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2298 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2299 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2300 REGION_Delete(pDC
->prgnVis
);
2301 pDC
->prgnVis
= prgnDefault
;
2306 IntUpdateVisRectRgn(PDC pDC
, PREGION pRgn
)
2308 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2309 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2313 if (Entry
->Flags
& GDI_ENTRY_VALIDATE_VIS
)
2315 pdcattr
= pDC
->pdcattr
;
2317 pdcattr
->VisRectRegion
.iComplexity
= REGION_Complexity(pRgn
);
2319 if (pRgn
&& pdcattr
->VisRectRegion
.iComplexity
!= NULLREGION
)
2321 rcl
.left
= pRgn
->rdh
.rcBound
.left
;
2322 rcl
.top
= pRgn
->rdh
.rcBound
.top
;
2323 rcl
.right
= pRgn
->rdh
.rcBound
.right
;
2324 rcl
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2326 rcl
.left
-= pDC
->erclWindow
.left
;
2327 rcl
.top
-= pDC
->erclWindow
.top
;
2328 rcl
.right
-= pDC
->erclWindow
.left
;
2329 rcl
.bottom
-= pDC
->erclWindow
.top
;
2333 RECTL_vSetEmptyRect(&rcl
);
2336 pdcattr
->VisRectRegion
.Rect
= rcl
;
2338 Entry
->Flags
&= ~GDI_ENTRY_VALIDATE_VIS
;
2344 IntGdiSetRegionOwner(HRGN hRgn
, DWORD OwnerMask
)
2350 prgn
= RGNOBJAPI_Lock(hRgn
, &prgnattr
);
2356 if (prgnattr
!= &prgn
->rgnattr
)
2358 GDIOBJ_vSetObjectAttr(&prgn
->BaseObject
, NULL
);
2359 prgn
->prgnattr
= &prgn
->rgnattr
;
2360 ppi
= PsGetCurrentProcessWin32Process();
2361 GdiPoolFree(ppi
->pPoolRgnAttr
, prgnattr
);
2364 RGNOBJAPI_Unlock(prgn
);
2366 return GreSetObjectOwner(hRgn
, OwnerMask
);
2378 if (prgnDest
== NULL
)
2380 DPRINT("IntGdiCombineRgn: hDest unavailable\n");
2384 if (prgnSrc1
== NULL
)
2386 DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
2390 if (iCombineMode
== RGN_COPY
)
2392 if (!REGION_CopyRegion(prgnDest
, prgnSrc1
))
2395 return REGION_Complexity(prgnDest
);
2398 if (prgnSrc2
== NULL
)
2400 DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", iCombineMode
);
2405 switch (iCombineMode
)
2408 REGION_IntersectRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2411 REGION_UnionRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2414 REGION_XorRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2417 REGION_SubtractRegion(prgnDest
, prgnSrc1
, prgnSrc2
);
2421 return REGION_Complexity(prgnDest
);
2434 *pRect
= Rgn
->rdh
.rcBound
;
2435 ret
= REGION_Complexity(Rgn
);
2439 return 0; // If invalid region return zero
2451 Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
2457 ret
= REGION_GetRgnBox(Rgn
, pRect
);
2458 RGNOBJAPI_Unlock(Rgn
);
2470 XCLIPOBJ ClipRegion
;
2476 if ((dc
== NULL
) || (Rgn
== NULL
))
2479 pdcattr
= dc
->pdcattr
;
2481 ASSERT(!(pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
)));
2483 VisRgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
2489 // Transform region into device co-ords
2490 if (!REGION_LPTODP(dc
, VisRgn
, Rgn
) ||
2491 IntGdiOffsetRgn(VisRgn
, dc
->ptlDCOrig
.x
, dc
->ptlDCOrig
.y
) == ERROR
)
2493 REGION_Delete(VisRgn
);
2498 IntGdiCombineRgn(VisRgn
, VisRgn
, dc
->prgnRao
, RGN_AND
);
2500 IntEngInitClipObj(&ClipRegion
);
2501 IntEngUpdateClipRegion(&ClipRegion
,
2504 &VisRgn
->rdh
.rcBound
);
2506 BrushOrigin
.x
= pdcattr
->ptlBrushOrigin
.x
;
2507 BrushOrigin
.y
= pdcattr
->ptlBrushOrigin
.y
;
2508 psurf
= dc
->dclevel
.pSurface
;
2509 /* FIXME: Handle psurf == NULL !!!! */
2511 bRet
= IntEngPaint(&psurf
->SurfObj
,
2512 &ClipRegion
.ClipObj
,
2513 &dc
->eboFill
.BrushObject
,
2515 0xFFFF); // FIXME: Don't know what to put here
2517 REGION_Delete(VisRgn
);
2518 IntEngFreeClipResources(&ClipRegion
);
2534 if (prgn
->rdh
.nCount
> 0 && INRECT(prgn
->rdh
.rcBound
, X
, Y
))
2537 for (i
= 0; i
< prgn
->rdh
.nCount
; i
++)
2539 if (INRECT(r
[i
], X
, Y
))
2549 REGION_RectInRegion(
2553 PRECTL pCurRect
, pRectEnd
;
2556 /* Swap the coordinates to make right >= left and bottom >= top */
2557 /* (region building rectangles are normalized the same way) */
2558 if (rect
->top
> rect
->bottom
)
2560 rc
.top
= rect
->bottom
;
2561 rc
.bottom
= rect
->top
;
2566 rc
.bottom
= rect
->bottom
;
2569 if (rect
->right
< rect
->left
)
2571 rc
.right
= rect
->left
;
2572 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
)
2618 if (LeftRect
> RightRect
)
2621 LeftRect
= RightRect
;
2625 if (TopRect
> BottomRect
)
2628 TopRect
= BottomRect
;
2632 if ((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
2634 firstRect
= rgn
->Buffer
;
2636 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
2637 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
2638 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
2639 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
2640 rgn
->rdh
.nCount
= 1;
2641 rgn
->rdh
.iType
= RDH_RECTANGLES
;
2656 if (XOffset
|| YOffset
)
2658 int nbox
= rgn
->rdh
.nCount
;
2659 PRECTL pbox
= rgn
->Buffer
;
2665 pbox
->left
+= XOffset
;
2666 pbox
->right
+= XOffset
;
2667 pbox
->top
+= YOffset
;
2668 pbox
->bottom
+= YOffset
;
2672 if (rgn
->Buffer
!= &rgn
->rdh
.rcBound
)
2674 rgn
->rdh
.rcBound
.left
+= XOffset
;
2675 rgn
->rdh
.rcBound
.right
+= XOffset
;
2676 rgn
->rdh
.rcBound
.top
+= YOffset
;
2677 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
2682 return REGION_Complexity(rgn
);
2685 /***********************************************************************
2686 * REGION_InsertEdgeInET
2688 * Insert the given edge into the edge table.
2689 * First we must find the correct bucket in the
2690 * Edge table, then find the right slot in the
2691 * bucket. Finally, we can insert it.
2697 REGION_InsertEdgeInET(
2699 EDGE_TABLE_ENTRY
*ETE
,
2701 SCANLINE_LISTBLOCK
**SLLBlock
,
2704 EDGE_TABLE_ENTRY
*start
, *prev
;
2705 SCANLINE_LIST
*pSLL
, *pPrevSLL
;
2706 SCANLINE_LISTBLOCK
*tmpSLLBlock
;
2708 /* Find the right bucket to put the edge into */
2709 pPrevSLL
= &ET
->scanlines
;
2710 pSLL
= pPrevSLL
->next
;
2711 while (pSLL
&& (pSLL
->scanline
< scanline
))
2717 /* Reassign pSLL (pointer to SCANLINE_LIST) if necessary */
2718 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
2720 if (*iSLLBlock
> SLLSPERBLOCK
-1)
2722 tmpSLLBlock
= ExAllocatePoolWithTag(PagedPool
,
2723 sizeof(SCANLINE_LISTBLOCK
),
2725 if (tmpSLLBlock
== NULL
)
2727 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2728 /* FIXME: Free resources? */
2732 (*SLLBlock
)->next
= tmpSLLBlock
;
2733 tmpSLLBlock
->next
= (SCANLINE_LISTBLOCK
*)NULL
;
2734 *SLLBlock
= tmpSLLBlock
;
2738 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
2740 pSLL
->next
= pPrevSLL
->next
;
2741 pSLL
->edgelist
= (EDGE_TABLE_ENTRY
*)NULL
;
2742 pPrevSLL
->next
= pSLL
;
2745 pSLL
->scanline
= scanline
;
2747 /* Now insert the edge in the right bucket */
2748 prev
= (EDGE_TABLE_ENTRY
*)NULL
;
2749 start
= pSLL
->edgelist
;
2750 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2753 start
= start
->next
;
2761 pSLL
->edgelist
= ETE
;
2764 /***********************************************************************
2767 * This routine moves EDGE_TABLEEntries from the
2768 * EDGE_TABLE into the Active Edge Table,
2769 * leaving them sorted by smaller x coordinate.
2776 EDGE_TABLE_ENTRY
*AET
,
2777 EDGE_TABLE_ENTRY
*ETEs
)
2779 EDGE_TABLE_ENTRY
*pPrevAET
;
2780 EDGE_TABLE_ENTRY
*tmp
;
2786 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2797 ETEs
->back
= pPrevAET
;
2798 pPrevAET
->next
= ETEs
;
2805 /***********************************************************************
2806 * REGION_computeWAET
2808 * This routine links the AET by the
2809 * nextWETE (winding EDGE_TABLE_ENTRY) link for
2810 * use by the winding number rule. The final
2811 * Active Edge Table (AET) might look something
2815 * ---------- --------- ---------
2816 * |ymax | |ymax | |ymax |
2817 * | ... | |... | |... |
2818 * |next |->|next |->|next |->...
2819 * |nextWETE| |nextWETE| |nextWETE|
2820 * --------- --------- ^--------
2822 * V-------------------> V---> ...
2829 EDGE_TABLE_ENTRY
*AET
)
2831 register EDGE_TABLE_ENTRY
*pWETE
;
2832 register INT inside
= 1;
2833 register INT isInside
= 0;
2835 AET
->nextWETE
= (EDGE_TABLE_ENTRY
*)NULL
;
2845 if ((!inside
&& !isInside
) ||
2846 ( inside
&& isInside
))
2848 pWETE
->nextWETE
= AET
;
2855 pWETE
->nextWETE
= (EDGE_TABLE_ENTRY
*)NULL
;
2858 /***********************************************************************
2859 * REGION_InsertionSort
2861 * Just a simple insertion sort using
2862 * pointers and back pointers to sort the Active
2869 REGION_InsertionSort(
2870 EDGE_TABLE_ENTRY
*AET
)
2872 EDGE_TABLE_ENTRY
*pETEchase
;
2873 EDGE_TABLE_ENTRY
*pETEinsert
;
2874 EDGE_TABLE_ENTRY
*pETEchaseBackTMP
;
2875 BOOL changed
= FALSE
;
2882 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2883 pETEchase
= pETEchase
->back
;
2886 if (pETEchase
!= pETEinsert
)
2888 pETEchaseBackTMP
= pETEchase
->back
;
2889 pETEinsert
->back
->next
= AET
;
2891 AET
->back
= pETEinsert
->back
;
2893 pETEinsert
->next
= pETEchase
;
2894 pETEchase
->back
->next
= pETEinsert
;
2895 pETEchase
->back
= pETEinsert
;
2896 pETEinsert
->back
= pETEchaseBackTMP
;
2904 /***********************************************************************
2905 * REGION_FreeStorage
2913 SCANLINE_LISTBLOCK
*pSLLBlock
)
2915 SCANLINE_LISTBLOCK
*tmpSLLBlock
;
2919 tmpSLLBlock
= pSLLBlock
->next
;
2920 ExFreePoolWithTag(pSLLBlock
, TAG_REGION
);
2921 pSLLBlock
= tmpSLLBlock
;
2926 /***********************************************************************
2927 * REGION_PtsToRegion
2929 * Create an array of rectangles from a list of points.
2935 INT numFullPtBlocks
,
2937 POINTBLOCK
*FirstPtBlock
,
2942 POINTBLOCK
*CurPtBlock
;
2944 RECTL
*extents
, *temp
;
2947 extents
= ®
->rdh
.rcBound
;
2949 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
2951 /* Make sure, we have at least one rect */
2957 temp
= ExAllocatePoolWithTag(PagedPool
, numRects
* sizeof(RECT
), TAG_REGION
);
2963 if (reg
->Buffer
!= NULL
)
2965 COPY_RECTS(temp
, reg
->Buffer
, reg
->rdh
.nCount
);
2966 if (reg
->Buffer
!= ®
->rdh
.rcBound
)
2967 ExFreePoolWithTag(reg
->Buffer
, TAG_REGION
);
2971 reg
->rdh
.nCount
= numRects
;
2972 CurPtBlock
= FirstPtBlock
;
2973 rects
= reg
->Buffer
- 1;
2975 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
2977 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--)
2979 /* The loop uses 2 points per iteration */
2980 i
= NUMPTSTOBUFFER
>> 1;
2981 if (numFullPtBlocks
== 0)
2982 i
= iCurPtBlock
>> 1;
2984 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2)
2986 if (pts
->x
== pts
[1].x
)
2989 if ((numRects
&& pts
->x
== rects
->left
) &&
2990 (pts
->y
== rects
->bottom
) &&
2991 (pts
[1].x
== rects
->right
) &&
2992 ((numRects
== 1) || (rects
[-1].top
!= rects
->top
)) &&
2993 (i
&& pts
[2].y
> pts
[1].y
))
2995 rects
->bottom
= pts
[1].y
+ 1;
3001 rects
->left
= pts
->x
;
3002 rects
->top
= pts
->y
;
3003 rects
->right
= pts
[1].x
;
3004 rects
->bottom
= pts
[1].y
+ 1;
3006 if (rects
->left
< extents
->left
)
3007 extents
->left
= rects
->left
;
3008 if (rects
->right
> extents
->right
)
3009 extents
->right
= rects
->right
;
3012 CurPtBlock
= CurPtBlock
->next
;
3017 extents
->top
= reg
->Buffer
->top
;
3018 extents
->bottom
= rects
->bottom
;
3025 extents
->bottom
= 0;
3028 reg
->rdh
.nCount
= numRects
;
3033 /***********************************************************************
3034 * REGION_CreateEDGE_TABLE
3036 * This routine creates the edge table for
3037 * scan converting polygons.
3038 * The Edge Table (ET) looks like:
3042 * | ymax | SCANLINE_LISTs
3043 * |scanline|-->------------>-------------->...
3044 * -------- |scanline| |scanline|
3045 * |edgelist| |edgelist|
3046 * --------- ---------
3050 * list of ETEs list of ETEs
3052 * where ETE is an EDGE_TABLE_ENTRY data structure,
3053 * and there is one SCANLINE_LIST per scanline at
3054 * which an edge is initially entered.
3060 REGION_CreateETandAET(
3065 EDGE_TABLE_ENTRY
*AET
,
3066 EDGE_TABLE_ENTRY
*pETEs
,
3067 SCANLINE_LISTBLOCK
*pSLLBlock
)
3069 const POINT
*top
, *bottom
;
3070 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
3075 /* Initialize the Active Edge Table */
3076 AET
->next
= (EDGE_TABLE_ENTRY
*)NULL
;
3077 AET
->back
= (EDGE_TABLE_ENTRY
*)NULL
;
3078 AET
->nextWETE
= (EDGE_TABLE_ENTRY
*)NULL
;
3079 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
3081 /* Initialize the Edge Table. */
3082 ET
->scanlines
.next
= (SCANLINE_LIST
*)NULL
;
3083 ET
->ymax
= SMALL_COORDINATE
;
3084 ET
->ymin
= LARGE_COORDINATE
;
3085 pSLLBlock
->next
= (SCANLINE_LISTBLOCK
*)NULL
;
3088 for (poly
= 0; poly
< nbpolygons
; poly
++)
3090 count
= Count
[poly
];
3097 /* For each vertex in the array of points.
3098 * In this loop we are dealing with two vertices at
3099 * a time -- these make up one edge of the polygon. */
3104 /* Find out which point is above and which is below. */
3105 if (PrevPt
->y
> CurrPt
->y
)
3107 bottom
= PrevPt
, top
= CurrPt
;
3108 pETEs
->ClockWise
= 0;
3112 bottom
= CurrPt
, top
= PrevPt
;
3113 pETEs
->ClockWise
= 1;
3116 /* Don't add horizontal edges to the Edge table. */
3117 if (bottom
->y
!= top
->y
)
3119 /* -1 so we don't get last scanline */
3120 pETEs
->ymax
= bottom
->y
- 1;
3122 /* Initialize integer edge algorithm */
3123 dy
= bottom
->y
- top
->y
;
3124 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
3126 REGION_InsertEdgeInET(ET
,
3132 if (PrevPt
->y
> ET
->ymax
)
3133 ET
->ymax
= PrevPt
->y
;
3134 if (PrevPt
->y
< ET
->ymin
)
3135 ET
->ymin
= PrevPt
->y
;
3146 IntSetPolyPolygonRgn(
3153 EDGE_TABLE_ENTRY
*pAET
; /* Active Edge Table */
3154 INT y
; /* Current scanline */
3155 INT iPts
= 0; /* Number of pts in buffer */
3156 EDGE_TABLE_ENTRY
*pWETE
; /* Winding Edge Table Entry */
3157 SCANLINE_LIST
*pSLL
; /* Current SCANLINE_LIST */
3158 POINT
*pts
; /* Output buffer */
3159 EDGE_TABLE_ENTRY
*pPrevAET
; /* Pointer to previous AET */
3160 EDGE_TABLE ET
; /* Header node for ET */
3161 EDGE_TABLE_ENTRY AET
; /* Header node for AET */
3162 EDGE_TABLE_ENTRY
*pETEs
; /* EDGE_TABLEEntries pool */
3163 SCANLINE_LISTBLOCK SLLBlock
; /* Header for SCANLINE_LIST */
3164 INT fixWAET
= FALSE
;
3165 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
3166 POINTBLOCK
*tmpPtBlock
;
3167 INT numFullPtBlocks
= 0;
3170 if (mode
== 0 || mode
> 2) return 0;
3172 /* Special case a rectangle */
3173 if (((nbpolygons
== 1) && ((*Count
== 4) ||
3174 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
3175 (((Pts
[0].y
== Pts
[1].y
) &&
3176 (Pts
[1].x
== Pts
[2].x
) &&
3177 (Pts
[2].y
== Pts
[3].y
) &&
3178 (Pts
[3].x
== Pts
[0].x
)) ||
3179 ((Pts
[0].x
== Pts
[1].x
) &&
3180 (Pts
[1].y
== Pts
[2].y
) &&
3181 (Pts
[2].x
== Pts
[3].x
) &&
3182 (Pts
[3].y
== Pts
[0].y
))))
3184 REGION_SetRectRgn(Rgn
,
3185 min(Pts
[0].x
, Pts
[2].x
),
3186 min(Pts
[0].y
, Pts
[2].y
),
3187 max(Pts
[0].x
, Pts
[2].x
),
3188 max(Pts
[0].y
, Pts
[2].y
));
3192 for (poly
= total
= 0; poly
< nbpolygons
; poly
++)
3193 total
+= Count
[poly
];
3195 pETEs
= ExAllocatePoolWithTag(PagedPool
,
3196 sizeof(EDGE_TABLE_ENTRY
) * total
,
3203 pts
= FirstPtBlock
.pts
;
3204 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
3205 pSLL
= ET
.scanlines
.next
;
3206 curPtBlock
= &FirstPtBlock
;
3208 if (mode
!= WINDING
)
3210 /* For each scanline */
3211 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3213 /* Add a new edge to the active edge table when we
3214 * get to the next edge. */
3215 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3217 REGION_loadAET(&AET
, pSLL
->edgelist
);
3223 /* For each active edge */
3226 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3229 /* Send out the buffer */
3230 if (iPts
== NUMPTSTOBUFFER
)
3232 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
,
3235 if (tmpPtBlock
== NULL
)
3237 DPRINT1("Can't alloc tPB\n");
3238 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3242 curPtBlock
->next
= tmpPtBlock
;
3243 curPtBlock
= tmpPtBlock
;
3244 pts
= curPtBlock
->pts
;
3249 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
3252 REGION_InsertionSort(&AET
);
3257 /* For each scanline */
3258 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3260 /* Add a new edge to the active edge table when we
3261 * get to the next edge. */
3262 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3264 REGION_loadAET(&AET
, pSLL
->edgelist
);
3265 REGION_computeWAET(&AET
);
3273 /* For each active edge */
3276 /* Add to the buffer only those edges that
3277 * are in the Winding active edge table. */
3280 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3283 /* Send out the buffer */
3284 if (iPts
== NUMPTSTOBUFFER
)
3286 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
,
3289 if (tmpPtBlock
== NULL
)
3291 DPRINT1("Can't alloc tPB\n");
3292 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3295 curPtBlock
->next
= tmpPtBlock
;
3296 curPtBlock
= tmpPtBlock
;
3297 pts
= curPtBlock
->pts
;
3302 pWETE
= pWETE
->nextWETE
;
3305 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
3308 /* Recompute the winding active edge table if
3309 * we just resorted or have exited an edge. */
3310 if (REGION_InsertionSort(&AET
) || fixWAET
)
3312 REGION_computeWAET(&AET
);
3318 REGION_FreeStorage(SLLBlock
.next
);
3319 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, Rgn
);
3321 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;)
3323 tmpPtBlock
= curPtBlock
->next
;
3324 ExFreePoolWithTag(curPtBlock
, TAG_REGION
);
3325 curPtBlock
= tmpPtBlock
;
3328 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3341 Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3347 Ret
= REGION_RectInRegion(Rgn
, rc
);
3348 RGNOBJAPI_Unlock(Rgn
);
3354 // NtGdi Exported Functions
3368 /* Validate the combine mode */
3369 if ((iMode
< RGN_AND
) || (iMode
> RGN_COPY
))
3374 /* Validate that we have the required regions */
3375 if ((hrgnDst
== NULL
) ||
3376 (hrgnSrc1
== NULL
) ||
3377 ((iMode
!= RGN_COPY
) && (hrgnSrc2
== NULL
)))
3379 DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
3380 hrgnDst
, hrgnSrc1
, hrgnSrc2
, iMode
);
3384 /* Lock all regions */
3386 ahrgn
[1] = hrgnSrc1
;
3387 ahrgn
[2] = iMode
!= RGN_COPY
? hrgnSrc2
: NULL
;
3388 if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ
*)ahrgn
, (PVOID
*)aprgn
, GDIObjType_RGN_TYPE
))
3390 DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
3391 hrgnDst
, hrgnSrc1
, hrgnSrc2
, iMode
);
3395 /* HACK: Sync usermode attributes */
3396 REGION_vSyncRegion(aprgn
[0]);
3397 REGION_vSyncRegion(aprgn
[1]);
3398 if (aprgn
[2]) REGION_vSyncRegion(aprgn
[2]);
3400 /* Call the internal function */
3401 iResult
= IntGdiCombineRgn(aprgn
[0], aprgn
[1], aprgn
[2], iMode
);
3403 /// FIXME: need to sync user attr back
3405 /* Cleanup and return */
3406 REGION_UnlockRgn(aprgn
[0]);
3407 REGION_UnlockRgn(aprgn
[1]);
3409 REGION_UnlockRgn(aprgn
[2]);
3416 NtGdiCreateEllipticRgn(
3422 return NtGdiCreateRoundRectRgn(Left
,
3440 /* Allocate region data structure with space for 1 RECTL */
3441 pRgn
= REGION_AllocUserRgnWithHandle(1);
3444 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3448 hRgn
= pRgn
->BaseObject
.hHmgr
;
3450 REGION_SetRectRgn(pRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3451 RGNOBJAPI_Unlock(pRgn
);
3453 DPRINT("Returning %p.\n", hRgn
);
3460 NtGdiCreateRoundRectRgn(
3470 INT asq
, bsq
, d
, xd
, yd
;
3473 /* Make the dimensions sensible */
3488 ellipse_width
= abs(ellipse_width
);
3489 ellipse_height
= abs(ellipse_height
);
3491 /* Check parameters */
3492 if (ellipse_width
> right
-left
)
3493 ellipse_width
= right
-left
;
3494 if (ellipse_height
> bottom
-top
)
3495 ellipse_height
= bottom
-top
;
3497 /* Check if we can do a normal rectangle instead */
3498 if ((ellipse_width
< 2) || (ellipse_height
< 2))
3499 return NtGdiCreateRectRgn(left
, top
, right
, bottom
);
3502 d
= (ellipse_height
< 128) ? ((3 * ellipse_height
) >> 2) : 64;
3503 obj
= REGION_AllocUserRgnWithHandle(d
);
3507 hrgn
= obj
->BaseObject
.hHmgr
;
3509 /* Ellipse algorithm, based on an article by K. Porter
3510 in DDJ Graphics Programming Column, 8/89 */
3511 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
3512 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
3513 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
3515 yd
= asq
* ellipse_height
; /* 2a^2b */
3517 rect
.left
= left
+ ellipse_width
/ 2;
3518 rect
.right
= right
- ellipse_width
/ 2;
3520 /* Loop to draw first half of quadrant */
3523 /* If nearest pixel is toward the center */
3526 /* Move toward center */
3528 rect
.bottom
= rect
.top
+ 1;
3529 REGION_UnionRectWithRgn(obj
, &rect
);
3530 rect
.top
= --bottom
;
3531 rect
.bottom
= rect
.top
+ 1;
3532 REGION_UnionRectWithRgn(obj
, &rect
);
3537 /* Next horiz point */
3544 /* Loop to draw second half of quadrant */
3545 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
3548 /* next vertical point */
3550 rect
.bottom
= rect
.top
+ 1;
3551 REGION_UnionRectWithRgn(obj
, &rect
);
3552 rect
.top
= --bottom
;
3553 rect
.bottom
= rect
.top
+ 1;
3554 REGION_UnionRectWithRgn(obj
, &rect
);
3556 /* If nearest pixel is outside ellipse */
3559 /* Move away from center */
3570 /* Add the inside rectangle */
3574 rect
.bottom
= bottom
;
3575 REGION_UnionRectWithRgn(obj
, &rect
);
3578 RGNOBJAPI_Unlock(obj
);
3589 PRECTL tRect1
, tRect2
;
3593 rgn1
= RGNOBJAPI_Lock(hSrcRgn1
, NULL
);
3597 rgn2
= RGNOBJAPI_Lock(hSrcRgn2
, NULL
);
3600 RGNOBJAPI_Unlock(rgn1
);
3604 if (rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
)
3607 if (rgn1
->rdh
.nCount
== 0)
3613 if ((rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
) ||
3614 (rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
) ||
3615 (rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
) ||
3616 (rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
))
3619 tRect1
= rgn1
->Buffer
;
3620 tRect2
= rgn2
->Buffer
;
3622 if ((tRect1
== NULL
) || (tRect2
== NULL
))
3625 for (i
=0; i
< rgn1
->rdh
.nCount
; i
++)
3627 if ((tRect1
[i
].left
!= tRect2
[i
].left
) ||
3628 (tRect1
[i
].right
!= tRect2
[i
].right
) ||
3629 (tRect1
[i
].top
!= tRect2
[i
].top
) ||
3630 (tRect1
[i
].bottom
!= tRect2
[i
].bottom
))
3637 RGNOBJAPI_Unlock(rgn1
);
3638 RGNOBJAPI_Unlock(rgn2
);
3644 NtGdiExtCreateRegion(
3645 OPTIONAL LPXFORM Xform
,
3656 NTSTATUS Status
= STATUS_SUCCESS
;
3660 DPRINT("NtGdiExtCreateRegion\n");
3663 ProbeForRead(RgnData
, Count
, 1);
3664 nCount
= RgnData
->rdh
.nCount
;
3665 iType
= RgnData
->rdh
.iType
;
3666 dwSize
= RgnData
->rdh
.dwSize
;
3667 rects
= (RECT
*)RgnData
->Buffer
;
3669 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3671 Status
= _SEH2_GetExceptionCode();
3675 if (!NT_SUCCESS(Status
))
3677 SetLastNtError(Status
);
3681 /* Check parameters, but don't set last error here */
3682 if ((Count
< sizeof(RGNDATAHEADER
) + nCount
* sizeof(RECT
)) ||
3683 (iType
!= RDH_RECTANGLES
) ||
3684 (dwSize
!= sizeof(RGNDATAHEADER
)))
3689 Region
= REGION_AllocUserRgnWithHandle(nCount
);
3693 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3696 hRgn
= Region
->BaseObject
.hHmgr
;
3700 /* Insert the rectangles one by one */
3701 for(i
=0; i
<nCount
; i
++)
3703 REGION_UnionRectWithRgn(Region
, &rects
[i
]);
3710 /* Init the XFORMOBJ from the Xform struct */
3711 Status
= STATUS_INVALID_PARAMETER
;
3712 XFORMOBJ_vInit(&xo
, &matrix
);
3713 ret
= XFORMOBJ_iSetXform(&xo
, (XFORML
*)Xform
);
3715 /* Check for error */
3716 if (ret
!= DDI_ERROR
)
3718 /* Apply the coordinate transformation on the rects */
3719 if (XFORMOBJ_bApplyXform(&xo
,
3721 Region
->rdh
.nCount
* 2,
3725 Status
= STATUS_SUCCESS
;
3730 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3732 Status
= _SEH2_GetExceptionCode();
3735 if (!NT_SUCCESS(Status
))
3737 EngSetLastError(ERROR_INVALID_PARAMETER
);
3738 RGNOBJAPI_Unlock(Region
);
3739 GreDeleteObject(hRgn
);
3743 RGNOBJAPI_Unlock(Region
);
3759 rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3765 oldhBrush
= NtGdiSelectBrush(hDC
, hBrush
);
3766 if (oldhBrush
== NULL
)
3768 RGNOBJAPI_Unlock(rgn
);
3772 for (r
= rgn
->Buffer
; r
< rgn
->Buffer
+ rgn
->rdh
.nCount
; r
++)
3774 NtGdiPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
3777 RGNOBJAPI_Unlock(rgn
);
3778 NtGdiSelectBrush(hDC
, oldhBrush
);
3795 FrameRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
3796 if (FrameRgn
== NULL
)
3801 if (!REGION_CreateFrameRgn(FrameRgn
, hRgn
, Width
, Height
))
3803 GreDeleteObject(FrameRgn
);
3807 Ret
= NtGdiFillRgn(hDC
, FrameRgn
, hBrush
);
3809 GreDeleteObject(FrameRgn
);
3823 NTSTATUS Status
= STATUS_SUCCESS
;
3825 Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3831 ret
= REGION_GetRgnBox(Rgn
, &SafeRect
);
3832 RGNOBJAPI_Unlock(Rgn
);
3840 ProbeForWrite(pRect
, sizeof(RECT
), 1);
3843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3845 Status
= _SEH2_GetExceptionCode();
3848 if (!NT_SUCCESS(Status
))
3866 RgnData
= RGNOBJAPI_Lock(hRgn
, NULL
);
3867 if (RgnData
== NULL
)
3869 EngSetLastError(ERROR_INVALID_HANDLE
);
3873 rc
= RgnData
->Buffer
;
3874 for (i
= 0; i
< RgnData
->rdh
.nCount
; i
++)
3877 if (!NtGdiPatBlt(hDC
, rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, DSTINVERT
))
3879 RGNOBJAPI_Unlock(RgnData
);
3885 RGNOBJAPI_Unlock(RgnData
);
3899 DPRINT("NtGdiOffsetRgn: hRgn %p Xoffs %d Yoffs %d rgn %p\n", hRgn
, XOffset
, YOffset
, rgn
);
3901 rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3904 DPRINT("NtGdiOffsetRgn: hRgn error\n");
3908 ret
= IntGdiOffsetRgn(rgn
, XOffset
, YOffset
);
3910 RGNOBJAPI_Unlock(rgn
);
3924 prgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3928 ret
= REGION_PtInRegion(prgn
, X
, Y
);
3930 RGNOBJAPI_Unlock(prgn
);
3941 NTSTATUS Status
= STATUS_SUCCESS
;
3945 ProbeForRead(unsaferc
, sizeof(RECT
), 1);
3948 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3950 Status
= _SEH2_GetExceptionCode();
3954 if (!NT_SUCCESS(Status
))
3956 SetLastNtError(Status
);
3957 DPRINT1("NtGdiRectInRegion: Bogus rc\n");
3961 return IntRectInRegion(hRgn
, &rc
);
3975 rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3978 return 0; // Per documentation
3981 REGION_SetRectRgn(rgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3983 RGNOBJAPI_Unlock(rgn
);
3989 NtGdiUnionRectWithRgn(
3991 const RECTL
*UnsafeRect
)
3993 RECTL SafeRect
= { 0 };
3995 NTSTATUS Status
= STATUS_SUCCESS
;
3997 Rgn
= RGNOBJAPI_Lock(hDest
, NULL
);
4000 EngSetLastError(ERROR_INVALID_HANDLE
);
4006 ProbeForRead(UnsafeRect
, sizeof(RECT
), 1);
4007 SafeRect
= *UnsafeRect
;
4009 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4011 Status
= _SEH2_GetExceptionCode();
4015 if (!NT_SUCCESS(Status
))
4017 RGNOBJAPI_Unlock(Rgn
);
4018 SetLastNtError(Status
);
4022 REGION_UnionRectWithRgn(Rgn
, &SafeRect
);
4023 RGNOBJAPI_Unlock(Rgn
);
4028 * MSDN: GetRegionData, Return Values:
4030 * "If the function succeeds and dwCount specifies an adequate number of bytes,
4031 * the return value is always dwCount. If dwCount is too small or the function
4032 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
4033 * required number of bytes.
4035 * If the function fails, the return value is zero."
4037 _Success_(return!=0)
4042 _In_ ULONG cjBuffer
,
4043 _Out_opt_bytecap_(cjBuffer
) LPRGNDATA lpRgnData
)
4045 ULONG cjRects
, cjSize
;
4048 /* Lock the region */
4049 prgn
= RGNOBJAPI_Lock(hrgn
, NULL
);
4052 EngSetLastError(ERROR_INVALID_HANDLE
);
4056 /* Calculate the region sizes */
4057 cjRects
= prgn
->rdh
.nCount
* sizeof(RECT
);
4058 cjSize
= cjRects
+ sizeof(RGNDATAHEADER
);
4060 /* Check if region data is requested */
4063 /* Check if the buffer is large enough */
4064 if (cjBuffer
>= cjSize
)
4066 /* Probe the buffer and copy the data */
4069 ProbeForWrite(lpRgnData
, cjSize
, sizeof(ULONG
));
4070 RtlCopyMemory(lpRgnData
, &prgn
->rdh
, sizeof(RGNDATAHEADER
));
4071 RtlCopyMemory(lpRgnData
->Buffer
, prgn
->Buffer
, cjRects
);
4072 lpRgnData
->rdh
.iType
= RDH_RECTANGLES
;
4074 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4076 EngSetLastError(ERROR_INVALID_PARAMETER
);
4083 /* Buffer is too small */
4084 EngSetLastError(ERROR_INVALID_PARAMETER
);
4089 /* Unlock the region and return the size */
4090 RGNOBJAPI_Unlock(prgn
);