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...
121 PROSRGNDATA prgnDefault
= NULL
;
122 HRGN hrgnDefault
= NULL
;
124 // Internal Functions
127 #define COPY_RECTS(dest, src, nRects) \
129 PRECTL xDest = (dest); \
130 PRECTL xSrc = (src); \
131 UINT xRects = (nRects); \
132 while(xRects-- > 0) { \
133 *(xDest++) = *(xSrc++); \
137 #define COPY_RECTS(dest, src, nRects) RtlCopyMemory(dest, src, (nRects) * sizeof(RECTL))
140 #define EMPTY_REGION(pReg) { \
141 (pReg)->rdh.nCount = 0; \
142 (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
143 (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
144 (pReg)->rdh.iType = RDH_RECTANGLES; \
147 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
149 #define INRECT(r, x, y) \
150 ( ( ((r).right > x)) && \
151 ( ((r).left <= x)) && \
152 ( ((r).bottom > y)) && \
155 /* 1 if two RECTs overlap.
156 * 0 if two RECTs do not overlap.
158 #define EXTENTCHECK(r1, r2) \
159 ((r1)->right > (r2)->left && \
160 (r1)->left < (r2)->right && \
161 (r1)->bottom > (r2)->top && \
162 (r1)->top < (r2)->bottom)
165 * In scan converting polygons, we want to choose those pixels
166 * which are inside the polygon. Thus, we add .5 to the starting
167 * x coordinate for both left and right edges. Now we choose the
168 * first pixel which is inside the pgon for the left edge and the
169 * first pixel which is outside the pgon for the right edge.
170 * Draw the left pixel, but not the right.
172 * How to add .5 to the starting x coordinate:
173 * If the edge is moving to the right, then subtract dy from the
174 * error term from the general form of the algorithm.
175 * If the edge is moving to the left, then add dy to the error term.
177 * The reason for the difference between edges moving to the left
178 * and edges moving to the right is simple: If an edge is moving
179 * to the right, then we want the algorithm to flip immediately.
180 * If it is moving to the left, then we don't want it to flip until
181 * we traverse an entire pixel.
183 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
184 int dx; /* local storage */ \
187 * if the edge is horizontal, then it is ignored \
188 * and assumed not to be processed. Otherwise, do this stuff. \
192 dx = (x2) - xStart; \
196 incr1 = -2 * dx + 2 * (dy) * m1; \
197 incr2 = -2 * dx + 2 * (dy) * m; \
198 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
202 incr1 = 2 * dx - 2 * (dy) * m1; \
203 incr2 = 2 * dx - 2 * (dy) * m; \
204 d = -2 * m * (dy) + 2 * dx; \
209 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
232 * This structure contains all of the information needed
233 * to run the bresenham algorithm.
234 * The variables may be hardcoded into the declarations
235 * instead of using this structure to make use of
236 * register declarations.
240 INT minor_axis
; /* minor axis */
241 INT d
; /* decision variable */
242 INT m
, m1
; /* slope and slope+1 */
243 INT incr1
, incr2
; /* error increments */
247 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
248 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
249 bres.m, bres.m1, bres.incr1, bres.incr2)
251 #define BRESINCRPGONSTRUCT(bres) \
252 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
257 * These are the data structures needed to scan
258 * convert regions. Two different scan conversion
259 * methods are available -- the even-odd method, and
260 * the winding number method.
261 * The even-odd rule states that a point is inside
262 * the polygon if a ray drawn from that point in any
263 * direction will pass through an odd number of
265 * By the winding number rule, a point is decided
266 * to be inside the polygon if a ray drawn from that
267 * point in any direction passes through a different
268 * number of clockwise and counter-clockwise path
271 * These data structures are adapted somewhat from
272 * the algorithm in (Foley/Van Dam) for scan converting
274 * The basic algorithm is to start at the top (smallest y)
275 * of the polygon, stepping down to the bottom of
276 * the polygon by incrementing the y coordinate. We
277 * keep a list of edges which the current scanline crosses,
278 * sorted by x. This list is called the Active Edge Table (AET)
279 * As we change the y-coordinate, we update each entry in
280 * in the active edge table to reflect the edges new xcoord.
281 * This list must be sorted at each scanline in case
282 * two edges intersect.
283 * We also keep a data structure known as the Edge Table (ET),
284 * which keeps track of all the edges which the current
285 * scanline has not yet reached. The ET is basically a
286 * list of ScanLineList structures containing a list of
287 * edges which are entered at a given scanline. There is one
288 * ScanLineList per scanline at which an edge is entered.
289 * When we enter a new edge, we move it from the ET to the AET.
291 * From the AET, we can implement the even-odd rule as in
293 * The winding number rule is a little trickier. We also
294 * keep the EdgeTableEntries in the AET linked by the
295 * nextWETE (winding EdgeTableEntry) link. This allows
296 * the edges to be linked just as before for updating
297 * purposes, but only uses the edges linked by the nextWETE
298 * link as edges representing spans of the polygon to
299 * drawn (as with the even-odd rule).
303 * for the winding number rule
306 #define COUNTERCLOCKWISE -1
308 typedef struct _EdgeTableEntry
310 INT ymax
; /* ycoord at which we exit this edge. */
311 BRESINFO bres
; /* Bresenham info to run the edge */
312 struct _EdgeTableEntry
*next
; /* next in the list */
313 struct _EdgeTableEntry
*back
; /* for insertion sort */
314 struct _EdgeTableEntry
*nextWETE
; /* for winding num rule */
315 int ClockWise
; /* flag for winding number rule */
319 typedef struct _ScanLineList
321 INT scanline
; /* the scanline represented */
322 EdgeTableEntry
*edgelist
; /* header node */
323 struct _ScanLineList
*next
; /* next in the list */
329 INT ymax
; /* ymax for the polygon */
330 INT ymin
; /* ymin for the polygon */
331 ScanLineList scanlines
; /* header node */
336 * Here is a struct to help with storage allocation
337 * so we can allocate a big chunk at a time, and then take
338 * pieces from this heap when we need to.
340 #define SLLSPERBLOCK 25
342 typedef struct _ScanLineListBlock
344 ScanLineList SLLs
[SLLSPERBLOCK
];
345 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( PROSRGNDATA obj
)
494 if (!obj
) return NULLREGION
;
495 switch(obj
->rdh
.nCount
)
497 DPRINT("Region Complexity -> %d",obj
->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 seems to be wrong
581 /***********************************************************************
582 * REGION_CropAndOffsetRegion
585 REGION_CropAndOffsetRegion(
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
;
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
;
653 INT left
= rgnSrc
->rdh
.rcBound
.right
+ off
->x
;
654 INT right
= rgnSrc
->rdh
.rcBound
.left
+ off
->x
;
656 for (clipa
= 0; (rgnSrc
->Buffer
+ clipa
)->bottom
<= rect
->top
; clipa
++)
657 //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
658 ; // skip bands above the clipping rectangle
660 for (clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
661 if ((rgnSrc
->Buffer
+ clipb
)->top
>= rect
->bottom
)
662 break; // and below it
664 // clipa - index of the first rect in the first intersecting band
665 // clipb - index of the last rect in the last intersecting band
667 if ((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nCount
< (i
= (clipb
- clipa
))))
670 temp
= ExAllocatePoolWithTag(PagedPool
, i
* sizeof(RECT
), TAG_REGION
);
674 if (rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
675 ExFreePoolWithTag(rgnDst
->Buffer
, TAG_REGION
); //free the old buffer
676 rgnDst
->Buffer
= temp
;
677 rgnDst
->rdh
.nCount
= i
;
678 rgnDst
->rdh
.nRgnSize
= i
* sizeof(RECT
);
681 for (i
= clipa
, j
= 0; i
< clipb
; i
++)
683 // i - src index, j - dst index, j is always <= i for obvious reasons
685 lpr
= rgnSrc
->Buffer
+ i
;
687 if (lpr
->left
< rect
->right
&& lpr
->right
> rect
->left
)
689 rpr
= rgnDst
->Buffer
+ j
;
691 rpr
->top
= lpr
->top
+ off
->y
;
692 rpr
->bottom
= lpr
->bottom
+ off
->y
;
693 rpr
->left
= ((lpr
->left
> rect
->left
) ? lpr
->left
: rect
->left
) + off
->x
;
694 rpr
->right
= ((lpr
->right
< rect
->right
) ? lpr
->right
: rect
->right
) + off
->x
;
696 if (rpr
->left
< left
) left
= rpr
->left
;
697 if (rpr
->right
> right
) right
= rpr
->right
;
703 if (j
== 0) goto empty
;
705 rgnDst
->rdh
.rcBound
.left
= left
;
706 rgnDst
->rdh
.rcBound
.right
= right
;
708 left
= rect
->top
+ off
->y
;
709 right
= rect
->bottom
+ off
->y
;
711 rgnDst
->rdh
.nCount
= j
--;
712 for (i
= 0; i
<= j
; i
++) // fixup top band
713 if ((rgnDst
->Buffer
+ i
)->top
< left
)
714 (rgnDst
->Buffer
+ i
)->top
= left
;
718 for (i
= j
; i
> 0; i
--) // fixup bottom band
719 if ((rgnDst
->Buffer
+ i
)->bottom
> right
)
720 (rgnDst
->Buffer
+ i
)->bottom
= right
;
724 rgnDst
->rdh
.rcBound
.top
= (rgnDst
->Buffer
)->top
;
725 rgnDst
->rdh
.rcBound
.bottom
= (rgnDst
->Buffer
+ j
)->bottom
;
727 rgnDst
->rdh
.iType
= RDH_RECTANGLES
;
735 rgnDst
->Buffer
= ExAllocatePoolWithTag(PagedPool
, RGN_DEFAULT_RECTS
* sizeof(RECT
), TAG_REGION
);
738 rgnDst
->rdh
.nCount
= RGN_DEFAULT_RECTS
;
739 rgnDst
->rdh
.nRgnSize
= RGN_DEFAULT_RECTS
* sizeof(RECT
);
744 EMPTY_REGION(rgnDst
);
750 * Attempt to merge the rects in the current band with those in the
751 * previous one. Used only by REGION_RegionOp.
754 * The new index for the previous band.
756 * \note Side Effects:
757 * If coalescing takes place:
758 * - rectangles in the previous band will have their bottom fields
760 * - pReg->numRects will be decreased.
765 PROSRGNDATA pReg
, /* Region to coalesce */
766 INT prevStart
, /* Index of start of previous band */
767 INT curStart
/* Index of start of current band */
770 RECTL
*pPrevRect
; /* Current rect in previous band */
771 RECTL
*pCurRect
; /* Current rect in current band */
772 RECTL
*pRegEnd
; /* End of region */
773 INT curNumRects
; /* Number of rectangles in current band */
774 INT prevNumRects
; /* Number of rectangles in previous band */
775 INT bandtop
; /* top coordinate for current band */
777 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
778 pPrevRect
= pReg
->Buffer
+ prevStart
;
779 prevNumRects
= curStart
- prevStart
;
782 * Figure out how many rectangles are in the current band. Have to do
783 * this because multiple bands could have been added in REGION_RegionOp
784 * at the end when one region has been exhausted.
786 pCurRect
= pReg
->Buffer
+ curStart
;
787 bandtop
= pCurRect
->top
;
788 for (curNumRects
= 0;
789 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
795 if (pCurRect
!= pRegEnd
)
798 * If more than one band was added, we have to find the start
799 * of the last band added so the next coalescing job can start
800 * at the right place... (given when multiple bands are added,
801 * this may be pointless -- see above).
804 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
808 curStart
= pRegEnd
- pReg
->Buffer
;
809 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
812 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0))
814 pCurRect
-= curNumRects
;
816 * The bands may only be coalesced if the bottom of the previous
817 * matches the top scanline of the current.
819 if (pPrevRect
->bottom
== pCurRect
->top
)
822 * Make sure the bands have rects in the same places. This
823 * assumes that rects have been added in such a way that they
824 * cover the most area possible. I.e. two rects in a band must
825 * have some horizontal space between them.
829 if ((pPrevRect
->left
!= pCurRect
->left
) ||
830 (pPrevRect
->right
!= pCurRect
->right
))
833 * The bands don't line up so they can't be coalesced.
841 while (prevNumRects
!= 0);
843 pReg
->rdh
.nCount
-= curNumRects
;
844 pCurRect
-= curNumRects
;
845 pPrevRect
-= curNumRects
;
848 * The bands may be merged, so set the bottom of each rect
849 * in the previous band to that of the corresponding rect in
854 pPrevRect
->bottom
= pCurRect
->bottom
;
859 while (curNumRects
!= 0);
862 * If only one band was added to the region, we have to backup
863 * curStart to the start of the previous band.
865 * If more than one band was added to the region, copy the
866 * other bands down. The assumption here is that the other bands
867 * came from the same region as the current one and no further
868 * coalescing can be done on them since it's all been done
869 * already... curStart is already in the right place.
871 if (pCurRect
== pRegEnd
)
873 curStart
= prevStart
;
879 *pPrevRect
++ = *pCurRect
++;
881 while (pCurRect
!= pRegEnd
);
889 * Apply an operation to two regions. Called by REGION_Union,
890 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
896 * The new region is overwritten.
898 *\note The idea behind this function is to view the two regions as sets.
899 * Together they cover a rectangle of area that this function divides
900 * into horizontal bands where points are covered only by one region
901 * or by both. For the first case, the nonOverlapFunc is called with
902 * each the band and the band's upper and lower extents. For the
903 * second, the overlapFunc is called to process the entire band. It
904 * is responsible for clipping the rectangles in the band, though
905 * this function provides the boundaries.
906 * At the end of each band, the new region is coalesced, if possible,
907 * to reduce the number of rectangles in the region.
912 ROSRGNDATA
*newReg
, /* Place to store result */
913 ROSRGNDATA
*reg1
, /* First region in operation */
914 ROSRGNDATA
*reg2
, /* 2nd region in operation */
915 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
916 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
917 nonOverlapProcp nonOverlap2Func
/* Function to call for non-overlapping bands in region 2 */
920 RECTL
*r1
; /* Pointer into first region */
921 RECTL
*r2
; /* Pointer into 2d region */
922 RECTL
*r1End
; /* End of 1st region */
923 RECTL
*r2End
; /* End of 2d region */
924 INT ybot
; /* Bottom of intersection */
925 INT ytop
; /* Top of intersection */
926 RECTL
*oldRects
; /* Old rects for newReg */
927 ULONG prevBand
; /* Index of start of
928 * previous band in newReg */
929 ULONG curBand
; /* Index of start of current band in newReg */
930 RECTL
*r1BandEnd
; /* End of current band in r1 */
931 RECTL
*r2BandEnd
; /* End of current band in r2 */
932 ULONG top
; /* Top of non-overlapping band */
933 ULONG bot
; /* Bottom of non-overlapping band */
937 * set r1, r2, r1End and r2End appropriately, preserve the important
938 * parts of the destination region until the end in case it's one of
939 * the two source regions, then mark the "new" region empty, allocating
940 * another array of rectangles for it to use.
944 r1End
= r1
+ reg1
->rdh
.nCount
;
945 r2End
= r2
+ reg2
->rdh
.nCount
;
949 * newReg may be one of the src regions so we can't empty it. We keep a
950 * note of its rects pointer (so that we can free them later), preserve its
951 * extents and simply set numRects to zero.
954 oldRects
= newReg
->Buffer
;
955 newReg
->rdh
.nCount
= 0;
958 * Allocate a reasonable number of rectangles for the new region. The idea
959 * is to allocate enough so the individual functions don't need to
960 * reallocate and copy the array, which is time consuming, yet we don't
961 * have to worry about using too much memory. I hope to be able to
962 * nuke the Xrealloc() at the end of this function eventually.
964 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
,reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
966 if (! (newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, newReg
->rdh
.nRgnSize
, TAG_REGION
)))
968 newReg
->rdh
.nRgnSize
= 0;
973 * Initialize ybot and ytop.
974 * In the upcoming loop, ybot and ytop serve different functions depending
975 * on whether the band being handled is an overlapping or non-overlapping
977 * In the case of a non-overlapping band (only one of the regions
978 * has points in the band), ybot is the bottom of the most recent
979 * intersection and thus clips the top of the rectangles in that band.
980 * ytop is the top of the next intersection between the two regions and
981 * serves to clip the bottom of the rectangles in the current band.
982 * For an overlapping band (where the two regions intersect), ytop clips
983 * the top of the rectangles of both regions and ybot clips the bottoms.
985 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
986 ybot
= reg1
->rdh
.rcBound
.top
;
988 ybot
= reg2
->rdh
.rcBound
.top
;
991 * prevBand serves to mark the start of the previous band so rectangles
992 * can be coalesced into larger rectangles. qv. miCoalesce, above.
993 * In the beginning, there is no previous band, so prevBand == curBand
994 * (curBand is set later on, of course, but the first band will always
995 * start at index 0). prevBand and curBand must be indices because of
996 * the possible expansion, and resultant moving, of the new region's
997 * array of rectangles.
1003 curBand
= newReg
->rdh
.nCount
;
1006 * This algorithm proceeds one source-band (as opposed to a
1007 * destination band, which is determined by where the two regions
1008 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1009 * rectangle after the last one in the current band for their
1010 * respective regions.
1013 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1019 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1025 * First handle the band that doesn't intersect, if any.
1027 * Note that attention is restricted to one band in the
1028 * non-intersecting region at once, so if a region has n
1029 * bands between the current position and the next place it overlaps
1030 * the other, this entire loop will be passed through n times.
1032 if (r1
->top
< r2
->top
)
1034 top
= max(r1
->top
,ybot
);
1035 bot
= min(r1
->bottom
,r2
->top
);
1037 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
1039 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
1044 else if (r2
->top
< r1
->top
)
1046 top
= max(r2
->top
,ybot
);
1047 bot
= min(r2
->bottom
,r1
->top
);
1049 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
1051 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
1062 * If any rectangles got added to the region, try and coalesce them
1063 * with rectangles from the previous band. Note we could just do
1064 * this test in miCoalesce, but some machines incur a not
1065 * inconsiderable cost for function calls, so...
1067 if (newReg
->rdh
.nCount
!= curBand
)
1069 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1073 * Now see if we've hit an intersecting band. The two bands only
1074 * intersect if ybot > ytop
1076 ybot
= min(r1
->bottom
, r2
->bottom
);
1077 curBand
= newReg
->rdh
.nCount
;
1080 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1083 if (newReg
->rdh
.nCount
!= curBand
)
1085 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1089 * If we've finished with a band (bottom == ybot) we skip forward
1090 * in the region to the next band.
1092 if (r1
->bottom
== ybot
)
1096 if (r2
->bottom
== ybot
)
1101 while ((r1
!= r1End
) && (r2
!= r2End
));
1104 * Deal with whichever region still has rectangles left.
1106 curBand
= newReg
->rdh
.nCount
;
1109 if (nonOverlap1Func
!= NULL
)
1114 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1118 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
1119 max(r1
->top
,ybot
), r1
->bottom
);
1122 while (r1
!= r1End
);
1125 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
1130 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1134 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
1135 max(r2
->top
,ybot
), r2
->bottom
);
1138 while (r2
!= r2End
);
1141 if (newReg
->rdh
.nCount
!= curBand
)
1143 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
1147 * A bit of cleanup. To keep regions from growing without bound,
1148 * we shrink the array of rectangles to match the new number of
1149 * rectangles in the region. This never goes to 0, however...
1151 * Only do this stuff if the number of rectangles allocated is more than
1152 * twice the number of rectangles in the region (a simple optimization...).
1154 if ((2 * newReg
->rdh
.nCount
*sizeof(RECT
) < newReg
->rdh
.nRgnSize
&& (newReg
->rdh
.nCount
> 2)))
1156 if (REGION_NOT_EMPTY(newReg
))
1158 RECTL
*prev_rects
= newReg
->Buffer
;
1159 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, newReg
->rdh
.nCount
*sizeof(RECT
), TAG_REGION
);
1161 if (! newReg
->Buffer
)
1162 newReg
->Buffer
= prev_rects
;
1165 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
1166 COPY_RECTS(newReg
->Buffer
, prev_rects
, newReg
->rdh
.nCount
);
1167 if (prev_rects
!= &newReg
->rdh
.rcBound
)
1168 ExFreePoolWithTag(prev_rects
, TAG_REGION
);
1174 * No point in doing the extra work involved in an Xrealloc if
1175 * the region is empty
1177 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
1178 if (newReg
->Buffer
!= &newReg
->rdh
.rcBound
)
1179 ExFreePoolWithTag(newReg
->Buffer
, TAG_REGION
);
1180 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, sizeof(RECT
), TAG_REGION
);
1181 ASSERT(newReg
->Buffer
);
1184 newReg
->rdh
.iType
= RDH_RECTANGLES
;
1186 if (oldRects
!= &newReg
->rdh
.rcBound
)
1187 ExFreePoolWithTag(oldRects
, TAG_REGION
);
1191 /***********************************************************************
1192 * Region Intersection
1193 ***********************************************************************/
1197 * Handle an overlapping band for REGION_Intersect.
1202 * \note Side Effects:
1203 * Rectangles may be added to the region.
1206 static void FASTCALL
1220 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1222 while ((r1
!= r1End
) && (r2
!= r2End
))
1224 left
= max(r1
->left
, r2
->left
);
1225 right
= min(r1
->right
, r2
->right
);
1228 * If there's any overlap between the two rectangles, add that
1229 * overlap to the new region.
1230 * There's no need to check for subsumption because the only way
1231 * such a need could arise is if some region has two rectangles
1232 * right next to each other. Since that should never happen...
1236 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1237 pNextRect
->left
= left
;
1238 pNextRect
->top
= top
;
1239 pNextRect
->right
= right
;
1240 pNextRect
->bottom
= bottom
;
1241 pReg
->rdh
.nCount
+= 1;
1246 * Need to advance the pointers. Shift the one that extends
1247 * to the right the least, since the other still has a chance to
1248 * overlap with that region's next rectangle, if you see what I mean.
1250 if (r1
->right
< r2
->right
)
1254 else if (r2
->right
< r1
->right
)
1267 /***********************************************************************
1268 * REGION_IntersectRegion
1270 static void FASTCALL
1271 REGION_IntersectRegion(
1277 /* check for trivial reject */
1278 if ( (!(reg1
->rdh
.nCount
)) || (!(reg2
->rdh
.nCount
)) ||
1279 (!EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
)) )
1280 newReg
->rdh
.nCount
= 0;
1282 REGION_RegionOp (newReg
, reg1
, reg2
,
1283 REGION_IntersectO
, NULL
, NULL
);
1286 * Can't alter newReg's extents before we call miRegionOp because
1287 * it might be one of the source regions and miRegionOp depends
1288 * on the extents of those regions being the same. Besides, this
1289 * way there's no checking against rectangles that will be nuked
1290 * due to coalescing, so we have to examine fewer rectangles.
1293 REGION_SetExtents(newReg
);
1296 /***********************************************************************
1298 ***********************************************************************/
1301 * Handle a non-overlapping band for the union operation. Just
1302 * Adds the rectangles into the region. Doesn't have to check for
1303 * subsumption or anything.
1308 * \note Side Effects:
1309 * pReg->numRects is incremented and the final rectangles overwritten
1310 * with the rectangles we're passed.
1313 static void FASTCALL
1324 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1328 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1329 pNextRect
->left
= r
->left
;
1330 pNextRect
->top
= top
;
1331 pNextRect
->right
= r
->right
;
1332 pNextRect
->bottom
= bottom
;
1333 pReg
->rdh
.nCount
+= 1;
1341 * Handle an overlapping band for the union operation. Picks the
1342 * left-most rectangle each time and merges it into the region.
1347 * \note Side Effects:
1348 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1352 static void FASTCALL
1365 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1367 #define MERGERECT(r) \
1368 if ((pReg->rdh.nCount != 0) && \
1369 ((pNextRect-1)->top == top) && \
1370 ((pNextRect-1)->bottom == bottom) && \
1371 ((pNextRect-1)->right >= r->left)) \
1373 if ((pNextRect-1)->right < r->right) \
1375 (pNextRect-1)->right = r->right; \
1380 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1381 pNextRect->top = top; \
1382 pNextRect->bottom = bottom; \
1383 pNextRect->left = r->left; \
1384 pNextRect->right = r->right; \
1385 pReg->rdh.nCount += 1; \
1390 while ((r1
!= r1End
) && (r2
!= r2End
))
1392 if (r1
->left
< r2
->left
)
1408 while (r1
!= r1End
);
1410 else while (r2
!= r2End
)
1417 /***********************************************************************
1418 * REGION_UnionRegion
1420 static void FASTCALL
1427 /* checks all the simple cases */
1430 * Region 1 and 2 are the same or region 1 is empty
1432 if (reg1
== reg2
|| 0 == reg1
->rdh
.nCount
||
1433 reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
||
1434 reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
)
1438 REGION_CopyRegion(newReg
, reg2
);
1444 * if nothing to union (region 2 empty)
1446 if (0 == reg2
->rdh
.nCount
||
1447 reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
||
1448 reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
)
1452 REGION_CopyRegion(newReg
, reg1
);
1458 * Region 1 completely subsumes region 2
1460 if (1 == reg1
->rdh
.nCount
&&
1461 reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
&&
1462 reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
&&
1463 reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
&&
1464 reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
)
1468 REGION_CopyRegion(newReg
, reg1
);
1474 * Region 2 completely subsumes region 1
1476 if (1 == reg2
->rdh
.nCount
&&
1477 reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
&&
1478 reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
&&
1479 reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
&&
1480 reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
)
1484 REGION_CopyRegion(newReg
, reg2
);
1489 REGION_RegionOp (newReg
, reg1
, reg2
, REGION_UnionO
,
1490 REGION_UnionNonO
, REGION_UnionNonO
);
1491 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1492 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1493 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1494 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1497 /***********************************************************************
1498 * Region Subtraction
1499 ***********************************************************************/
1502 * Deal with non-overlapping band for subtraction. Any parts from
1503 * region 2 we discard. Anything from region 1 we add to the region.
1508 * \note Side Effects:
1509 * pReg may be affected.
1512 static void FASTCALL
1513 REGION_SubtractNonO1(
1523 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1527 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1528 pNextRect
->left
= r
->left
;
1529 pNextRect
->top
= top
;
1530 pNextRect
->right
= r
->right
;
1531 pNextRect
->bottom
= bottom
;
1532 pReg
->rdh
.nCount
+= 1;
1541 * Overlapping band subtraction. x1 is the left-most point not yet
1547 * \note Side Effects:
1548 * pReg may have rectangles added to it.
1551 static void FASTCALL
1566 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1568 while ((r1
!= r1End
) && (r2
!= r2End
))
1570 if (r2
->right
<= left
)
1573 * Subtrahend missed the boat: go to next subtrahend.
1577 else if (r2
->left
<= left
)
1580 * Subtrahend preceeds minuend: nuke left edge of minuend.
1583 if (left
>= r1
->right
)
1586 * Minuend completely covered: advance to next minuend and
1587 * reset left fence to edge of new minuend.
1596 * Subtrahend now used up since it doesn't extend beyond
1602 else if (r2
->left
< r1
->right
)
1605 * Left part of subtrahend covers part of minuend: add uncovered
1606 * part of minuend to region and skip to next subtrahend.
1608 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1609 pNextRect
->left
= left
;
1610 pNextRect
->top
= top
;
1611 pNextRect
->right
= r2
->left
;
1612 pNextRect
->bottom
= bottom
;
1613 pReg
->rdh
.nCount
+= 1;
1616 if (left
>= r1
->right
)
1619 * Minuend used up: advance to new...
1628 * Subtrahend used up
1636 * Minuend used up: add any remaining piece before advancing.
1638 if (r1
->right
> left
)
1640 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1641 pNextRect
->left
= left
;
1642 pNextRect
->top
= top
;
1643 pNextRect
->right
= r1
->right
;
1644 pNextRect
->bottom
= bottom
;
1645 pReg
->rdh
.nCount
+= 1;
1655 * Add remaining minuend rectangles to region.
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;
1676 * Subtract regS from regM and leave the result in regD.
1677 * S stands for subtrahend, M for minuend and D for difference.
1682 * \note Side Effects:
1683 * regD is overwritten.
1686 static void FASTCALL
1687 REGION_SubtractRegion(
1693 /* check for trivial reject */
1694 if ( (!(regM
->rdh
.nCount
)) || (!(regS
->rdh
.nCount
)) ||
1695 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1697 REGION_CopyRegion(regD
, regM
);
1701 REGION_RegionOp (regD
, regM
, regS
, REGION_SubtractO
,
1702 REGION_SubtractNonO1
, NULL
);
1705 * Can't alter newReg's extents before we call miRegionOp because
1706 * it might be one of the source regions and miRegionOp depends
1707 * on the extents of those regions being the unaltered. Besides, this
1708 * way there's no checking against rectangles that will be nuked
1709 * due to coalescing, so we have to examine fewer rectangles.
1711 REGION_SetExtents (regD
);
1714 /***********************************************************************
1717 static void FASTCALL
1725 ROSRGNDATA
*tra
, *trb
;
1727 // FIXME: don't use a handle
1728 tra
= REGION_AllocRgnWithHandle(sra
->rdh
.nCount
+ 1);
1733 htra
= tra
->BaseObject
.hHmgr
;
1735 // FIXME: don't use a handle
1736 trb
= REGION_AllocRgnWithHandle(srb
->rdh
.nCount
+ 1);
1739 RGNOBJAPI_Unlock(tra
);
1740 GreDeleteObject(htra
);
1743 htrb
= trb
->BaseObject
.hHmgr
;
1745 REGION_SubtractRegion(tra
, sra
, srb
);
1746 REGION_SubtractRegion(trb
, srb
, sra
);
1747 REGION_UnionRegion(dr
, tra
, trb
);
1748 RGNOBJAPI_Unlock(tra
);
1749 RGNOBJAPI_Unlock(trb
);
1751 GreDeleteObject(htra
);
1752 GreDeleteObject(htrb
);
1758 * Adds a rectangle to a REGION
1761 REGION_UnionRectWithRgn(
1768 region
.Buffer
= ®ion
.rdh
.rcBound
;
1769 region
.rdh
.nCount
= 1;
1770 region
.rdh
.nRgnSize
= sizeof(RECT
);
1771 region
.rdh
.rcBound
= *rect
;
1772 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1776 REGION_CreateSimpleFrameRgn(
1785 if (x
!= 0 || y
!= 0)
1789 if (rgn
->rdh
.rcBound
.bottom
- rgn
->rdh
.rcBound
.top
> y
* 2 &&
1790 rgn
->rdh
.rcBound
.right
- rgn
->rdh
.rcBound
.left
> x
* 2)
1795 prc
->left
= rgn
->rdh
.rcBound
.left
;
1796 prc
->top
= rgn
->rdh
.rcBound
.top
;
1797 prc
->right
= rgn
->rdh
.rcBound
.right
;
1798 prc
->bottom
= prc
->top
+ y
;
1804 /* left rectangle */
1805 prc
->left
= rgn
->rdh
.rcBound
.left
;
1806 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1807 prc
->right
= prc
->left
+ x
;
1808 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1811 /* right rectangle */
1812 prc
->left
= rgn
->rdh
.rcBound
.right
- x
;
1813 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1814 prc
->right
= rgn
->rdh
.rcBound
.right
;
1815 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1821 /* bottom rectangle */
1822 prc
->left
= rgn
->rdh
.rcBound
.left
;
1823 prc
->top
= rgn
->rdh
.rcBound
.bottom
- y
;
1824 prc
->right
= rgn
->rdh
.rcBound
.right
;
1825 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
;
1832 /* The frame results in a complex region. rcBounds remains
1833 the same, though. */
1834 rgn
->rdh
.nCount
= (DWORD
)(prc
- rc
);
1835 ASSERT(rgn
->rdh
.nCount
> 1);
1836 rgn
->rdh
.nRgnSize
= rgn
->rdh
.nCount
* sizeof(RECT
);
1837 rgn
->Buffer
= ExAllocatePoolWithTag(PagedPool
, rgn
->rdh
.nRgnSize
, TAG_REGION
);
1840 rgn
->rdh
.nRgnSize
= 0;
1844 COPY_RECTS(rgn
->Buffer
, rc
, rgn
->rdh
.nCount
);
1852 REGION_CreateFrameRgn(
1859 PROSRGNDATA srcObj
, destObj
;
1863 if (!(srcObj
= RGNOBJAPI_Lock(hSrc
, NULL
)))
1867 if (!REGION_NOT_EMPTY(srcObj
))
1869 RGNOBJAPI_Unlock(srcObj
);
1872 if (!(destObj
= RGNOBJAPI_Lock(hDest
, NULL
)))
1874 RGNOBJAPI_Unlock(srcObj
);
1878 EMPTY_REGION(destObj
);
1879 if (!REGION_CopyRegion(destObj
, srcObj
))
1881 RGNOBJAPI_Unlock(destObj
);
1882 RGNOBJAPI_Unlock(srcObj
);
1886 if (REGION_Complexity(srcObj
) == SIMPLEREGION
)
1888 if (!REGION_CreateSimpleFrameRgn(destObj
, x
, y
))
1890 EMPTY_REGION(destObj
);
1891 RGNOBJAPI_Unlock(destObj
);
1892 RGNOBJAPI_Unlock(srcObj
);
1898 /* Original region moved to right */
1899 rc
= srcObj
->Buffer
;
1900 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1906 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1908 /* Original region moved to left */
1909 rc
= srcObj
->Buffer
;
1910 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1916 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1918 /* Original region moved down */
1919 rc
= srcObj
->Buffer
;
1920 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1928 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1930 /* Original region moved up */
1931 rc
= srcObj
->Buffer
;
1932 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1935 rc
->bottom
-= 2 * y
;
1938 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1940 /* Restore the original region */
1941 rc
= srcObj
->Buffer
;
1942 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1948 REGION_SubtractRegion(destObj
, srcObj
, destObj
);
1951 RGNOBJAPI_Unlock(destObj
);
1952 RGNOBJAPI_Unlock(srcObj
);
1963 RECTL
*pCurRect
, *pEndRect
;
1964 PROSRGNDATA srcObj
= NULL
;
1965 PROSRGNDATA destObj
= NULL
;
1973 pdcattr
= dc
->pdcattr
;
1975 if (pdcattr
->iMapMode
== MM_TEXT
) // Requires only a translation
1977 if (NtGdiCombineRgn(hDest
, hSrc
, 0, RGN_COPY
) == ERROR
)
1980 NtGdiOffsetRgn(hDest
, pdcattr
->ptlViewportOrg
.x
- pdcattr
->ptlWindowOrg
.x
,
1981 pdcattr
->ptlViewportOrg
.y
- pdcattr
->ptlWindowOrg
.y
);
1986 if ( !(srcObj
= RGNOBJAPI_Lock(hSrc
, NULL
)) )
1988 if ( !(destObj
= RGNOBJAPI_Lock(hDest
, NULL
)) )
1990 RGNOBJAPI_Unlock(srcObj
);
1993 EMPTY_REGION(destObj
);
1995 pEndRect
= srcObj
->Buffer
+ srcObj
->rdh
.nCount
;
1996 for (pCurRect
= srcObj
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
1998 tmpRect
= *pCurRect
;
1999 tmpRect
.left
= XLPTODP(pdcattr
, tmpRect
.left
);
2000 tmpRect
.top
= YLPTODP(pdcattr
, tmpRect
.top
);
2001 tmpRect
.right
= XLPTODP(pdcattr
, tmpRect
.right
);
2002 tmpRect
.bottom
= YLPTODP(pdcattr
, tmpRect
.bottom
);
2004 if (tmpRect
.left
> tmpRect
.right
)
2006 INT tmp
= tmpRect
.left
;
2007 tmpRect
.left
= tmpRect
.right
;
2008 tmpRect
.right
= tmp
;
2010 if (tmpRect
.top
> tmpRect
.bottom
)
2012 INT tmp
= tmpRect
.top
;
2013 tmpRect
.top
= tmpRect
.bottom
;
2014 tmpRect
.bottom
= tmp
;
2017 REGION_UnionRectWithRgn(destObj
, &tmpRect
);
2021 RGNOBJAPI_Unlock(srcObj
);
2022 RGNOBJAPI_Unlock(destObj
);
2030 REGION_AllocRgnWithHandle(INT nReg
)
2035 pReg
= (PROSRGNDATA
)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_REGION
);
2041 hReg
= pReg
->BaseObject
.hHmgr
;
2043 if (nReg
== 0 || nReg
== 1)
2045 /* Testing shows that > 95% of all regions have only 1 rect.
2046 Including that here saves us from having to do another allocation */
2047 pReg
->Buffer
= &pReg
->rdh
.rcBound
;
2051 pReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, nReg
* sizeof(RECT
), TAG_REGION
);
2054 RGNOBJAPI_Unlock(pReg
);
2055 GDIOBJ_FreeObjByHandle(hReg
, GDI_OBJECT_TYPE_REGION
);
2061 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
2062 pReg
->rdh
.nCount
= nReg
;
2063 pReg
->rdh
.nRgnSize
= nReg
* sizeof(RECT
);
2069 // Allocate User Space Region Handle.
2073 REGION_AllocUserRgnWithHandle(INT nRgn
)
2077 PGDI_TABLE_ENTRY Entry
;
2079 pRgn
= REGION_AllocRgnWithHandle(nRgn
);
2082 Index
= GDI_HANDLE_GET_INDEX(pRgn
->BaseObject
.hHmgr
);
2083 Entry
= &GdiHandleTable
->Entries
[Index
];
2084 Entry
->UserData
= AllocateObjectAttr();
2091 RGNOBJAPI_Lock(HRGN hRgn
, PRGN_ATTR
*ppRgn_Attr
)
2094 PGDI_TABLE_ENTRY Entry
;
2096 PRGN_ATTR pRgn_Attr
;
2099 pRgn
= REGION_LockRgn(hRgn
);
2103 Index
= GDI_HANDLE_GET_INDEX(hRgn
);
2104 Entry
= &GdiHandleTable
->Entries
[Index
];
2105 pRgn_Attr
= Entry
->UserData
;
2106 pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
2108 if ( pid
== NtCurrentTeb()->ClientId
.UniqueProcess
&&
2113 if ( !(pRgn_Attr
->AttrFlags
& ATTR_CACHED
) &&
2114 pRgn_Attr
->AttrFlags
& (ATTR_RGN_VALID
|ATTR_RGN_DIRTY
) )
2116 switch (pRgn_Attr
->Flags
)
2119 EMPTY_REGION( pRgn
);
2123 REGION_SetRectRgn( pRgn
,
2124 pRgn_Attr
->Rect
.left
,
2125 pRgn_Attr
->Rect
.top
,
2126 pRgn_Attr
->Rect
.right
,
2127 pRgn_Attr
->Rect
.bottom
);
2130 pRgn_Attr
->AttrFlags
&= ~ATTR_RGN_DIRTY
;
2133 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2139 *ppRgn_Attr
= pRgn_Attr
;
2152 RGNOBJAPI_Unlock(PROSRGNDATA pRgn
)
2155 PGDI_TABLE_ENTRY Entry
;
2156 PRGN_ATTR pRgn_Attr
;
2161 Index
= GDI_HANDLE_GET_INDEX(pRgn
->BaseObject
.hHmgr
);
2162 Entry
= &GdiHandleTable
->Entries
[Index
];
2163 pRgn_Attr
= Entry
->UserData
;
2164 pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
2166 if ( pid
== NtCurrentTeb()->ClientId
.UniqueProcess
&&
2171 if ( pRgn_Attr
->AttrFlags
& ATTR_RGN_VALID
)
2173 pRgn_Attr
->Flags
= REGION_Complexity( pRgn
);
2174 pRgn_Attr
->Rect
.left
= pRgn
->rdh
.rcBound
.left
;
2175 pRgn_Attr
->Rect
.top
= pRgn
->rdh
.rcBound
.top
;
2176 pRgn_Attr
->Rect
.right
= pRgn
->rdh
.rcBound
.right
;
2177 pRgn_Attr
->Rect
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2180 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2186 REGION_UnlockRgn(pRgn
);
2191 These regions do not use attribute sections and when allocated, use gdiobj
2195 // System Region Functions
2199 IntSysCreateRectpRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
2203 pRgn
= (PROSRGNDATA
)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_REGION
);
2208 pRgn
->Buffer
= &pRgn
->rdh
.rcBound
;
2209 REGION_SetRectRgn(pRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
2210 REGION_UnlockRgn(pRgn
);
2216 IntSysCreateRectRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
2218 PROSRGNDATA pRgn
= IntSysCreateRectpRgn(LeftRect
,TopRect
,RightRect
,BottomRect
);
2219 return (pRgn
? pRgn
->BaseObject
.hHmgr
: NULL
);
2223 REGION_Cleanup(PVOID ObjectBody
)
2225 PROSRGNDATA pRgn
= (PROSRGNDATA
)ObjectBody
;
2226 if (pRgn
->Buffer
&& pRgn
->Buffer
!= &pRgn
->rdh
.rcBound
)
2227 ExFreePoolWithTag(pRgn
->Buffer
, TAG_REGION
);
2231 // use REGION_FreeRgnByHandle(hRgn); for systems regions.
2233 REGION_Delete(PROSRGNDATA pRgn
)
2235 if ( pRgn
== prgnDefault
) return;
2236 REGION_FreeRgn(pRgn
);
2240 IntGdiReleaseRaoRgn(PDC pDC
)
2242 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2243 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2244 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2245 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2246 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2250 IntGdiReleaseVisRgn(PDC pDC
)
2252 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2253 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2254 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2255 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2256 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2257 REGION_Delete(pDC
->prgnVis
);
2258 pDC
->prgnVis
= prgnDefault
;
2262 IntUpdateVisRectRgn(PDC pDC
, PROSRGNDATA pRgn
)
2264 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2265 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2269 if (Entry
->Flags
& GDI_ENTRY_VALIDATE_VIS
)
2271 pdcattr
= pDC
->pdcattr
;
2273 pdcattr
->VisRectRegion
.Flags
= REGION_Complexity(pRgn
);
2275 if (pRgn
&& pdcattr
->VisRectRegion
.Flags
!= NULLREGION
)
2277 rcl
.left
= pRgn
->rdh
.rcBound
.left
;
2278 rcl
.top
= pRgn
->rdh
.rcBound
.top
;
2279 rcl
.right
= pRgn
->rdh
.rcBound
.right
;
2280 rcl
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2282 rcl
.left
-= pDC
->erclWindow
.left
;
2283 rcl
.top
-= pDC
->erclWindow
.top
;
2284 rcl
.right
-= pDC
->erclWindow
.left
;
2285 rcl
.bottom
-= pDC
->erclWindow
.top
;
2288 RECTL_vSetEmptyRect(&rcl
);
2290 pdcattr
->VisRectRegion
.Rect
= rcl
;
2292 Entry
->Flags
&= ~GDI_ENTRY_VALIDATE_VIS
;
2298 IntGdiCombineRgn(PROSRGNDATA destRgn
,
2299 PROSRGNDATA src1Rgn
,
2300 PROSRGNDATA src2Rgn
,
2309 if (CombineMode
== RGN_COPY
)
2311 if ( !REGION_CopyRegion(destRgn
, src1Rgn
) )
2313 result
= REGION_Complexity(destRgn
);
2319 switch (CombineMode
)
2322 REGION_IntersectRegion(destRgn
, src1Rgn
, src2Rgn
);
2325 REGION_UnionRegion(destRgn
, src1Rgn
, src2Rgn
);
2328 REGION_XorRegion(destRgn
, src1Rgn
, src2Rgn
);
2331 REGION_SubtractRegion(destRgn
, src1Rgn
, src2Rgn
);
2334 result
= REGION_Complexity(destRgn
);
2336 else if (src2Rgn
== NULL
)
2338 DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode
);
2339 EngSetLastError(ERROR_INVALID_HANDLE
);
2345 DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
2346 EngSetLastError(ERROR_INVALID_HANDLE
);
2351 DPRINT("IntGdiCombineRgn: hDest unavailable\n");
2352 EngSetLastError(ERROR_INVALID_HANDLE
);
2367 *pRect
= Rgn
->rdh
.rcBound
;
2368 ret
= REGION_Complexity(Rgn
);
2372 return 0; //if invalid region return zero
2384 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
2389 ret
= REGION_GetRgnBox(Rgn
, pRect
);
2390 RGNOBJAPI_Unlock(Rgn
);
2404 CLIPOBJ
* ClipRegion
;
2410 if (!dc
) return FALSE
;
2411 pdcattr
= dc
->pdcattr
;
2413 ASSERT(!(pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
)));
2415 if (!(tmpVisRgn
= IntSysCreateRectRgn(0, 0, 0, 0))) return FALSE
;
2417 // Transform region into device co-ords
2418 if (!REGION_LPTODP(dc
, tmpVisRgn
, hRgn
) ||
2419 NtGdiOffsetRgn(tmpVisRgn
, dc
->ptlDCOrig
.x
, dc
->ptlDCOrig
.y
) == ERROR
)
2421 REGION_FreeRgnByHandle(tmpVisRgn
);
2425 NtGdiCombineRgn(tmpVisRgn
, tmpVisRgn
, dc
->rosdc
.hGCClipRgn
, RGN_AND
);
2427 visrgn
= RGNOBJAPI_Lock(tmpVisRgn
, NULL
);
2430 REGION_FreeRgnByHandle(tmpVisRgn
);
2434 ClipRegion
= IntEngCreateClipRegion(visrgn
->rdh
.nCount
,
2436 &visrgn
->rdh
.rcBound
);
2439 BrushOrigin
.x
= pdcattr
->ptlBrushOrigin
.x
;
2440 BrushOrigin
.y
= pdcattr
->ptlBrushOrigin
.y
;
2441 psurf
= dc
->dclevel
.pSurface
;
2442 /* FIXME - Handle psurf == NULL !!!! */
2444 bRet
= IntEngPaint(&psurf
->SurfObj
,
2446 &dc
->eboFill
.BrushObject
,
2448 0xFFFF);//FIXME:don't know what to put here
2450 RGNOBJAPI_Unlock(visrgn
);
2451 REGION_FreeRgnByHandle(tmpVisRgn
);
2459 REGION_RectInRegion(
2464 PRECTL pCurRect
, pRectEnd
;
2467 /* swap the coordinates to make right >= left and bottom >= top */
2468 /* (region building rectangles are normalized the same way) */
2469 if( rect
->top
> rect
->bottom
) {
2470 rc
.top
= rect
->bottom
;
2471 rc
.bottom
= rect
->top
;
2474 rc
.bottom
= rect
->bottom
;
2476 if( rect
->right
< rect
->left
) {
2477 rc
.right
= rect
->left
;
2478 rc
.left
= rect
->right
;
2480 rc
.right
= rect
->right
;
2481 rc
.left
= rect
->left
;
2484 /* this is (just) a useful optimization */
2485 if ((Rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&Rgn
->rdh
.rcBound
, &rc
))
2487 for (pCurRect
= Rgn
->Buffer
, pRectEnd
= pCurRect
+
2488 Rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
2490 if (pCurRect
->bottom
<= rc
.top
)
2491 continue; /* not far enough down yet */
2493 if (pCurRect
->top
>= rc
.bottom
)
2494 break; /* too far down */
2496 if (pCurRect
->right
<= rc
.left
)
2497 continue; /* not far enough over yet */
2499 if (pCurRect
->left
>= rc
.right
) {
2521 if (LeftRect
> RightRect
)
2524 LeftRect
= RightRect
;
2527 if (TopRect
> BottomRect
)
2530 TopRect
= BottomRect
;
2534 if ((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
2536 firstRect
= rgn
->Buffer
;
2538 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
2539 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
2540 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
2541 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
2542 rgn
->rdh
.nCount
= 1;
2543 rgn
->rdh
.iType
= RDH_RECTANGLES
;
2558 if (XOffset
|| YOffset
)
2560 int nbox
= rgn
->rdh
.nCount
;
2561 PRECTL pbox
= rgn
->Buffer
;
2567 pbox
->left
+= XOffset
;
2568 pbox
->right
+= XOffset
;
2569 pbox
->top
+= YOffset
;
2570 pbox
->bottom
+= YOffset
;
2573 if (rgn
->Buffer
!= &rgn
->rdh
.rcBound
)
2575 rgn
->rdh
.rcBound
.left
+= XOffset
;
2576 rgn
->rdh
.rcBound
.right
+= XOffset
;
2577 rgn
->rdh
.rcBound
.top
+= YOffset
;
2578 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
2582 return REGION_Complexity(rgn
);
2585 /***********************************************************************
2586 * REGION_InsertEdgeInET
2588 * Insert the given edge into the edge table.
2589 * First we must find the correct bucket in the
2590 * Edge table, then find the right slot in the
2591 * bucket. Finally, we can insert it.
2594 static void FASTCALL
2595 REGION_InsertEdgeInET(
2597 EdgeTableEntry
*ETE
,
2599 ScanLineListBlock
**SLLBlock
,
2603 EdgeTableEntry
*start
, *prev
;
2604 ScanLineList
*pSLL
, *pPrevSLL
;
2605 ScanLineListBlock
*tmpSLLBlock
;
2608 * find the right bucket to put the edge into
2610 pPrevSLL
= &ET
->scanlines
;
2611 pSLL
= pPrevSLL
->next
;
2612 while (pSLL
&& (pSLL
->scanline
< scanline
))
2619 * reassign pSLL (pointer to ScanLineList) if necessary
2621 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
2623 if (*iSLLBlock
> SLLSPERBLOCK
-1)
2625 tmpSLLBlock
= ExAllocatePoolWithTag(PagedPool
, sizeof(ScanLineListBlock
), TAG_REGION
);
2628 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2629 /* FIXME - free resources? */
2632 (*SLLBlock
)->next
= tmpSLLBlock
;
2633 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2634 *SLLBlock
= tmpSLLBlock
;
2637 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
2639 pSLL
->next
= pPrevSLL
->next
;
2640 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
2641 pPrevSLL
->next
= pSLL
;
2643 pSLL
->scanline
= scanline
;
2646 * now insert the edge in the right bucket
2648 prev
= (EdgeTableEntry
*)NULL
;
2649 start
= pSLL
->edgelist
;
2650 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2653 start
= start
->next
;
2660 pSLL
->edgelist
= ETE
;
2663 /***********************************************************************
2666 * This routine moves EdgeTableEntries from the
2667 * EdgeTable into the Active Edge Table,
2668 * leaving them sorted by smaller x coordinate.
2671 static void FASTCALL
2673 EdgeTableEntry
*AET
,
2674 EdgeTableEntry
*ETEs
2677 EdgeTableEntry
*pPrevAET
;
2678 EdgeTableEntry
*tmp
;
2684 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2693 ETEs
->back
= pPrevAET
;
2694 pPrevAET
->next
= ETEs
;
2701 /***********************************************************************
2702 * REGION_computeWAET
2704 * This routine links the AET by the
2705 * nextWETE (winding EdgeTableEntry) link for
2706 * use by the winding number rule. The final
2707 * Active Edge Table (AET) might look something
2711 * ---------- --------- ---------
2712 * |ymax | |ymax | |ymax |
2713 * | ... | |... | |... |
2714 * |next |->|next |->|next |->...
2715 * |nextWETE| |nextWETE| |nextWETE|
2716 * --------- --------- ^--------
2718 * V-------------------> V---> ...
2721 static void FASTCALL
2722 REGION_computeWAET(EdgeTableEntry
*AET
)
2724 register EdgeTableEntry
*pWETE
;
2725 register int inside
= 1;
2726 register int isInside
= 0;
2728 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2738 if ( (!inside
&& !isInside
) ||
2739 ( inside
&& isInside
) )
2741 pWETE
->nextWETE
= AET
;
2747 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2750 /***********************************************************************
2751 * REGION_InsertionSort
2753 * Just a simple insertion sort using
2754 * pointers and back pointers to sort the Active
2758 static BOOL FASTCALL
2759 REGION_InsertionSort(EdgeTableEntry
*AET
)
2761 EdgeTableEntry
*pETEchase
;
2762 EdgeTableEntry
*pETEinsert
;
2763 EdgeTableEntry
*pETEchaseBackTMP
;
2764 BOOL changed
= FALSE
;
2771 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2772 pETEchase
= pETEchase
->back
;
2775 if (pETEchase
!= pETEinsert
)
2777 pETEchaseBackTMP
= pETEchase
->back
;
2778 pETEinsert
->back
->next
= AET
;
2780 AET
->back
= pETEinsert
->back
;
2781 pETEinsert
->next
= pETEchase
;
2782 pETEchase
->back
->next
= pETEinsert
;
2783 pETEchase
->back
= pETEinsert
;
2784 pETEinsert
->back
= pETEchaseBackTMP
;
2791 /***********************************************************************
2792 * REGION_FreeStorage
2796 static void FASTCALL
2797 REGION_FreeStorage(ScanLineListBlock
*pSLLBlock
)
2799 ScanLineListBlock
*tmpSLLBlock
;
2803 tmpSLLBlock
= pSLLBlock
->next
;
2804 ExFreePool(pSLLBlock
);
2805 pSLLBlock
= tmpSLLBlock
;
2810 /***********************************************************************
2811 * REGION_PtsToRegion
2813 * Create an array of rectangles from a list of points.
2817 int numFullPtBlocks
,
2819 POINTBLOCK
*FirstPtBlock
,
2824 POINTBLOCK
*CurPtBlock
;
2826 RECTL
*extents
, *temp
;
2829 extents
= ®
->rdh
.rcBound
;
2831 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
2833 if (!(temp
= ExAllocatePoolWithTag(PagedPool
, numRects
* sizeof(RECT
), TAG_REGION
)))
2837 if (reg
->Buffer
!= NULL
)
2839 COPY_RECTS(temp
, reg
->Buffer
, reg
->rdh
.nCount
);
2840 if (reg
->Buffer
!= ®
->rdh
.rcBound
)
2841 ExFreePoolWithTag(reg
->Buffer
, TAG_REGION
);
2845 reg
->rdh
.nCount
= numRects
;
2846 CurPtBlock
= FirstPtBlock
;
2847 rects
= reg
->Buffer
- 1;
2849 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
2851 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--)
2853 /* the loop uses 2 points per iteration */
2854 i
= NUMPTSTOBUFFER
>> 1;
2855 if (!numFullPtBlocks
)
2856 i
= iCurPtBlock
>> 1;
2857 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2)
2859 if (pts
->x
== pts
[1].x
)
2861 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
2862 pts
[1].x
== rects
->right
&&
2863 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
2864 (i
&& pts
[2].y
> pts
[1].y
))
2866 rects
->bottom
= pts
[1].y
+ 1;
2871 rects
->left
= pts
->x
;
2872 rects
->top
= pts
->y
;
2873 rects
->right
= pts
[1].x
;
2874 rects
->bottom
= pts
[1].y
+ 1;
2875 if (rects
->left
< extents
->left
)
2876 extents
->left
= rects
->left
;
2877 if (rects
->right
> extents
->right
)
2878 extents
->right
= rects
->right
;
2880 CurPtBlock
= CurPtBlock
->next
;
2885 extents
->top
= reg
->Buffer
->top
;
2886 extents
->bottom
= rects
->bottom
;
2893 extents
->bottom
= 0;
2895 reg
->rdh
.nCount
= numRects
;
2900 /***********************************************************************
2901 * REGION_CreateEdgeTable
2903 * This routine creates the edge table for
2904 * scan converting polygons.
2905 * The Edge Table (ET) looks like:
2909 * | ymax | ScanLineLists
2910 * |scanline|-->------------>-------------->...
2911 * -------- |scanline| |scanline|
2912 * |edgelist| |edgelist|
2913 * --------- ---------
2917 * list of ETEs list of ETEs
2919 * where ETE is an EdgeTableEntry data structure,
2920 * and there is one ScanLineList per scanline at
2921 * which an edge is initially entered.
2924 static void FASTCALL
2925 REGION_CreateETandAET(
2930 EdgeTableEntry
*AET
,
2931 EdgeTableEntry
*pETEs
,
2932 ScanLineListBlock
*pSLLBlock
2935 const POINT
*top
, *bottom
;
2936 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
2943 * initialize the Active Edge Table
2945 AET
->next
= (EdgeTableEntry
*)NULL
;
2946 AET
->back
= (EdgeTableEntry
*)NULL
;
2947 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2948 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
2951 * initialize the Edge Table.
2953 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
2954 ET
->ymax
= SMALL_COORDINATE
;
2955 ET
->ymin
= LARGE_COORDINATE
;
2956 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2959 for (poly
= 0; poly
< nbpolygons
; poly
++)
2961 count
= Count
[poly
];
2969 * for each vertex in the array of points.
2970 * In this loop we are dealing with two vertices at
2971 * a time -- these make up one edge of the polygon.
2978 * find out which point is above and which is below.
2980 if (PrevPt
->y
> CurrPt
->y
)
2982 bottom
= PrevPt
, top
= CurrPt
;
2983 pETEs
->ClockWise
= 0;
2987 bottom
= CurrPt
, top
= PrevPt
;
2988 pETEs
->ClockWise
= 1;
2992 * don't add horizontal edges to the Edge table.
2994 if (bottom
->y
!= top
->y
)
2996 pETEs
->ymax
= bottom
->y
-1;
2997 /* -1 so we don't get last scanline */
3000 * initialize integer edge algorithm
3002 dy
= bottom
->y
- top
->y
;
3003 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
3005 REGION_InsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
,
3008 if (PrevPt
->y
> ET
->ymax
)
3009 ET
->ymax
= PrevPt
->y
;
3010 if (PrevPt
->y
< ET
->ymin
)
3011 ET
->ymin
= PrevPt
->y
;
3021 IntCreatePolyPolygonRgn(
3030 EdgeTableEntry
*pAET
; /* Active Edge Table */
3031 INT y
; /* current scanline */
3032 int iPts
= 0; /* number of pts in buffer */
3033 EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry*/
3034 ScanLineList
*pSLL
; /* current scanLineList */
3035 POINT
*pts
; /* output buffer */
3036 EdgeTableEntry
*pPrevAET
; /* ptr to previous AET */
3037 EdgeTable ET
; /* header node for ET */
3038 EdgeTableEntry AET
; /* header node for AET */
3039 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
3040 ScanLineListBlock SLLBlock
; /* header for scanlinelist */
3041 int fixWAET
= FALSE
;
3042 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
3043 POINTBLOCK
*tmpPtBlock
;
3044 int numFullPtBlocks
= 0;
3047 if (mode
== 0 || mode
> 2) return 0;
3049 if (!(region
= REGION_AllocUserRgnWithHandle(nbpolygons
)))
3051 hrgn
= region
->BaseObject
.hHmgr
;
3053 /* special case a rectangle */
3055 if (((nbpolygons
== 1) && ((*Count
== 4) ||
3056 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
3057 (((Pts
[0].y
== Pts
[1].y
) &&
3058 (Pts
[1].x
== Pts
[2].x
) &&
3059 (Pts
[2].y
== Pts
[3].y
) &&
3060 (Pts
[3].x
== Pts
[0].x
)) ||
3061 ((Pts
[0].x
== Pts
[1].x
) &&
3062 (Pts
[1].y
== Pts
[2].y
) &&
3063 (Pts
[2].x
== Pts
[3].x
) &&
3064 (Pts
[3].y
== Pts
[0].y
))))
3066 RGNOBJAPI_Unlock(region
);
3067 NtGdiSetRectRgn(hrgn
, min(Pts
[0].x
, Pts
[2].x
), min(Pts
[0].y
, Pts
[2].y
),
3068 max(Pts
[0].x
, Pts
[2].x
), max(Pts
[0].y
, Pts
[2].y
));
3072 for (poly
= total
= 0; poly
< nbpolygons
; poly
++)
3073 total
+= Count
[poly
];
3074 if (! (pETEs
= ExAllocatePoolWithTag(PagedPool
, sizeof(EdgeTableEntry
) * total
, TAG_REGION
)) )
3076 GreDeleteObject(hrgn
);
3079 pts
= FirstPtBlock
.pts
;
3080 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
3081 pSLL
= ET
.scanlines
.next
;
3082 curPtBlock
= &FirstPtBlock
;
3084 if (mode
!= WINDING
)
3089 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3092 * Add a new edge to the active edge table when we
3093 * get to the next edge.
3095 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3097 REGION_loadAET(&AET
, pSLL
->edgelist
);
3104 * for each active edge
3108 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3112 * send out the buffer
3114 if (iPts
== NUMPTSTOBUFFER
)
3116 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
, sizeof(POINTBLOCK
), TAG_REGION
);
3119 DPRINT1("Can't alloc tPB\n");
3120 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3123 curPtBlock
->next
= tmpPtBlock
;
3124 curPtBlock
= tmpPtBlock
;
3125 pts
= curPtBlock
->pts
;
3129 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
3131 REGION_InsertionSort(&AET
);
3139 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3142 * Add a new edge to the active edge table when we
3143 * get to the next edge.
3145 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3147 REGION_loadAET(&AET
, pSLL
->edgelist
);
3148 REGION_computeWAET(&AET
);
3156 * for each active edge
3161 * add to the buffer only those edges that
3162 * are in the Winding active edge table.
3166 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3170 * send out the buffer
3172 if (iPts
== NUMPTSTOBUFFER
)
3174 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
,
3175 sizeof(POINTBLOCK
), TAG_REGION
);
3178 DPRINT1("Can't alloc tPB\n");
3179 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3180 GreDeleteObject(hrgn
);
3183 curPtBlock
->next
= tmpPtBlock
;
3184 curPtBlock
= tmpPtBlock
;
3185 pts
= curPtBlock
->pts
;
3189 pWETE
= pWETE
->nextWETE
;
3191 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
3195 * recompute the winding active edge table if
3196 * we just resorted or have exited an edge.
3198 if (REGION_InsertionSort(&AET
) || fixWAET
)
3200 REGION_computeWAET(&AET
);
3205 REGION_FreeStorage(SLLBlock
.next
);
3206 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, region
);
3208 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;)
3210 tmpPtBlock
= curPtBlock
->next
;
3211 ExFreePoolWithTag(curPtBlock
, TAG_REGION
);
3212 curPtBlock
= tmpPtBlock
;
3214 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3215 RGNOBJAPI_Unlock(region
);
3220 // NtGdi Exported Functions
3224 NtGdiCombineRgn(HRGN hDest
,
3230 PROSRGNDATA destRgn
, src1Rgn
, src2Rgn
= NULL
;
3232 if ( CombineMode
> RGN_COPY
&& CombineMode
< RGN_AND
)
3234 EngSetLastError(ERROR_INVALID_PARAMETER
);
3238 destRgn
= RGNOBJAPI_Lock(hDest
, NULL
);
3241 EngSetLastError(ERROR_INVALID_HANDLE
);
3245 src1Rgn
= RGNOBJAPI_Lock(hSrc1
, NULL
);
3248 RGNOBJAPI_Unlock(destRgn
);
3249 EngSetLastError(ERROR_INVALID_HANDLE
);
3254 src2Rgn
= RGNOBJAPI_Lock(hSrc2
, NULL
);
3256 result
= IntGdiCombineRgn( destRgn
, src1Rgn
, src2Rgn
, CombineMode
);
3259 RGNOBJAPI_Unlock(src2Rgn
);
3260 RGNOBJAPI_Unlock(src1Rgn
);
3261 RGNOBJAPI_Unlock(destRgn
);
3268 NtGdiCreateEllipticRgn(
3275 return NtGdiCreateRoundRectRgn(Left
, Top
, Right
, Bottom
,
3276 Right
- Left
, Bottom
- Top
);
3280 NtGdiCreateRectRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
3285 /* Allocate region data structure with space for 1 RECTL */
3286 if (!(pRgn
= REGION_AllocUserRgnWithHandle(1)))
3288 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3291 hRgn
= pRgn
->BaseObject
.hHmgr
;
3293 REGION_SetRectRgn(pRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3294 RGNOBJAPI_Unlock(pRgn
);
3301 NtGdiCreateRoundRectRgn(
3312 int asq
, bsq
, d
, xd
, yd
;
3315 /* Make the dimensions sensible */
3330 ellipse_width
= abs(ellipse_width
);
3331 ellipse_height
= abs(ellipse_height
);
3333 /* Check parameters */
3335 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
3336 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
3338 /* Check if we can do a normal rectangle instead */
3340 if ((ellipse_width
< 2) || (ellipse_height
< 2))
3341 return NtGdiCreateRectRgn(left
, top
, right
, bottom
);
3345 d
= (ellipse_height
< 128) ? ((3 * ellipse_height
) >> 2) : 64;
3346 if (!(obj
= REGION_AllocUserRgnWithHandle(d
))) return 0;
3347 hrgn
= obj
->BaseObject
.hHmgr
;
3349 /* Ellipse algorithm, based on an article by K. Porter */
3350 /* in DDJ Graphics Programming Column, 8/89 */
3352 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
3353 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
3354 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
3356 yd
= asq
* ellipse_height
; /* 2a^2b */
3358 rect
.left
= left
+ ellipse_width
/ 2;
3359 rect
.right
= right
- ellipse_width
/ 2;
3361 /* Loop to draw first half of quadrant */
3365 if (d
> 0) /* if nearest pixel is toward the center */
3367 /* move toward center */
3369 rect
.bottom
= rect
.top
+ 1;
3370 REGION_UnionRectWithRgn(obj
, &rect
);
3371 rect
.top
= --bottom
;
3372 rect
.bottom
= rect
.top
+ 1;
3373 REGION_UnionRectWithRgn(obj
, &rect
);
3377 rect
.left
--; /* next horiz point */
3382 /* Loop to draw second half of quadrant */
3384 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
3387 /* next vertical point */
3389 rect
.bottom
= rect
.top
+ 1;
3390 REGION_UnionRectWithRgn(obj
, &rect
);
3391 rect
.top
= --bottom
;
3392 rect
.bottom
= rect
.top
+ 1;
3393 REGION_UnionRectWithRgn(obj
, &rect
);
3394 if (d
< 0) /* if nearest pixel is outside ellipse */
3396 rect
.left
--; /* move away from center */
3404 /* Add the inside rectangle */
3409 rect
.bottom
= bottom
;
3410 REGION_UnionRectWithRgn(obj
, &rect
);
3413 RGNOBJAPI_Unlock(obj
);
3424 PROSRGNDATA rgn1
, rgn2
;
3425 PRECTL tRect1
, tRect2
;
3429 if ( !(rgn1
= RGNOBJAPI_Lock(hSrcRgn1
, NULL
)) )
3432 if ( !(rgn2
= RGNOBJAPI_Lock(hSrcRgn2
, NULL
)) )
3434 RGNOBJAPI_Unlock(rgn1
);
3438 if ( rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
) goto exit
;
3440 if ( rgn1
->rdh
.nCount
== 0 )
3446 if ( rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
||
3447 rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
||
3448 rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
||
3449 rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
)
3452 tRect1
= rgn1
->Buffer
;
3453 tRect2
= rgn2
->Buffer
;
3455 if (!tRect1
|| !tRect2
)
3458 for (i
=0; i
< rgn1
->rdh
.nCount
; i
++)
3460 if ( tRect1
[i
].left
!= tRect2
[i
].left
||
3461 tRect1
[i
].right
!= tRect2
[i
].right
||
3462 tRect1
[i
].top
!= tRect2
[i
].top
||
3463 tRect1
[i
].bottom
!= tRect2
[i
].bottom
)
3469 RGNOBJAPI_Unlock(rgn1
);
3470 RGNOBJAPI_Unlock(rgn2
);
3476 NtGdiExtCreateRegion(
3477 OPTIONAL LPXFORM Xform
,
3487 NTSTATUS Status
= STATUS_SUCCESS
;
3491 DPRINT("NtGdiExtCreateRegion\n");
3494 ProbeForRead(RgnData
, Count
, 1);
3495 nCount
= RgnData
->rdh
.nCount
;
3496 iType
= RgnData
->rdh
.iType
;
3497 dwSize
= RgnData
->rdh
.dwSize
;
3499 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3501 Status
= _SEH2_GetExceptionCode();
3504 if (!NT_SUCCESS(Status
))
3506 SetLastNtError(Status
);
3510 /* Check parameters, but don't set last error here */
3511 if (Count
< sizeof(RGNDATAHEADER
) + nCount
* sizeof(RECT
) ||
3512 iType
!= RDH_RECTANGLES
||
3513 dwSize
!= sizeof(RGNDATAHEADER
))
3518 Region
= REGION_AllocUserRgnWithHandle(nCount
);
3522 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3525 hRgn
= Region
->BaseObject
.hHmgr
;
3533 /* Init the XFORMOBJ from the Xform struct */
3534 Status
= STATUS_INVALID_PARAMETER
;
3535 XFORMOBJ_vInit(&xo
, &matrix
);
3536 ret
= XFORMOBJ_iSetXform(&xo
, (XFORML
*)Xform
);
3538 /* Check for error, also no scale and shear allowed */
3539 if (ret
!= DDI_ERROR
&& ret
!= GX_GENERAL
)
3541 /* Apply the coordinate transformation on the rects */
3542 if (XFORMOBJ_bApplyXform(&xo
,
3548 Status
= STATUS_SUCCESS
;
3554 /* Copy rect coordinates */
3555 RtlCopyMemory(Region
->Buffer
,
3557 nCount
* sizeof(RECT
));
3560 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3562 Status
= _SEH2_GetExceptionCode();
3565 if (!NT_SUCCESS(Status
))
3567 EngSetLastError(ERROR_INVALID_PARAMETER
);
3568 RGNOBJAPI_Unlock(Region
);
3569 GreDeleteObject(hRgn
);
3573 RGNOBJAPI_Unlock(Region
);
3590 if (NULL
== (rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3595 if (NULL
== (oldhBrush
= NtGdiSelectBrush(hDC
, hBrush
)))
3597 RGNOBJAPI_Unlock(rgn
);
3601 for (r
= rgn
->Buffer
; r
< rgn
->Buffer
+ rgn
->rdh
.nCount
; r
++)
3603 NtGdiPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
3606 RGNOBJAPI_Unlock(rgn
);
3607 NtGdiSelectBrush(hDC
, oldhBrush
);
3625 if (!(FrameRgn
= IntSysCreateRectRgn(0, 0, 0, 0)))
3629 if (!REGION_CreateFrameRgn(FrameRgn
, hRgn
, Width
, Height
))
3631 REGION_FreeRgnByHandle(FrameRgn
);
3635 Ret
= NtGdiFillRgn(hDC
, FrameRgn
, hBrush
);
3637 REGION_FreeRgnByHandle(FrameRgn
);
3651 NTSTATUS Status
= STATUS_SUCCESS
;
3653 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3658 ret
= REGION_GetRgnBox(Rgn
, &SafeRect
);
3659 RGNOBJAPI_Unlock(Rgn
);
3667 ProbeForWrite(pRect
, sizeof(RECT
), 1);
3670 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3672 Status
= _SEH2_GetExceptionCode();
3675 if (!NT_SUCCESS(Status
))
3690 PROSRGNDATA RgnData
;
3694 if (!(RgnData
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3696 EngSetLastError(ERROR_INVALID_HANDLE
);
3700 rc
= RgnData
->Buffer
;
3701 for (i
= 0; i
< RgnData
->rdh
.nCount
; i
++)
3704 if (!NtGdiPatBlt(hDC
, rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, DSTINVERT
))
3706 RGNOBJAPI_Unlock(RgnData
);
3712 RGNOBJAPI_Unlock(RgnData
);
3724 PROSRGNDATA rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3727 DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn
, XOffset
, YOffset
, rgn
);
3731 DPRINT("NtGdiOffsetRgn: hRgn error\n");
3735 ret
= IntGdiOffsetRgn(rgn
, XOffset
, YOffset
);
3737 RGNOBJAPI_Unlock(rgn
);
3753 if (!(rgn
= RGNOBJAPI_Lock(hRgn
, NULL
) ) )
3756 if (rgn
->rdh
.nCount
> 0 && INRECT(rgn
->rdh
.rcBound
, X
, Y
))
3759 for (i
= 0; i
< rgn
->rdh
.nCount
; i
++)
3761 if (INRECT(*r
, X
, Y
))
3763 RGNOBJAPI_Unlock(rgn
);
3769 RGNOBJAPI_Unlock(rgn
);
3783 NTSTATUS Status
= STATUS_SUCCESS
;
3785 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3792 ProbeForRead(unsaferc
, sizeof(RECT
), 1);
3795 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3797 Status
= _SEH2_GetExceptionCode();
3801 if (!NT_SUCCESS(Status
))
3803 RGNOBJAPI_Unlock(Rgn
);
3804 SetLastNtError(Status
);
3805 DPRINT1("NtGdiRectInRegion: bogus rc\n");
3809 Ret
= REGION_RectInRegion(Rgn
, &rc
);
3810 RGNOBJAPI_Unlock(Rgn
);
3826 if ( !(rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)) )
3828 return 0; //per documentation
3831 REGION_SetRectRgn(rgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3833 RGNOBJAPI_Unlock(rgn
);
3838 NtGdiUnionRectWithRgn(
3840 const RECTL
*UnsafeRect
3843 RECTL SafeRect
= {0};
3845 NTSTATUS Status
= STATUS_SUCCESS
;
3847 if (!(Rgn
= RGNOBJAPI_Lock(hDest
, NULL
)))
3849 EngSetLastError(ERROR_INVALID_HANDLE
);
3855 ProbeForRead(UnsafeRect
, sizeof(RECT
), 1);
3856 SafeRect
= *UnsafeRect
;
3858 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3860 Status
= _SEH2_GetExceptionCode();
3864 if (! NT_SUCCESS(Status
))
3866 RGNOBJAPI_Unlock(Rgn
);
3867 SetLastNtError(Status
);
3871 REGION_UnionRectWithRgn(Rgn
, &SafeRect
);
3872 RGNOBJAPI_Unlock(Rgn
);
3877 * MSDN: GetRegionData, Return Values:
3879 * "If the function succeeds and dwCount specifies an adequate number of bytes,
3880 * the return value is always dwCount. If dwCount is too small or the function
3881 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
3882 * required number of bytes.
3884 * If the function fails, the return value is zero."
3894 PROSRGNDATA obj
= RGNOBJAPI_Lock(hrgn
, NULL
);
3895 NTSTATUS Status
= STATUS_SUCCESS
;
3900 size
= obj
->rdh
.nCount
* sizeof(RECT
);
3901 if (count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
3903 RGNOBJAPI_Unlock(obj
);
3904 if (rgndata
) /* buffer is too small, signal it by return 0 */
3906 else /* user requested buffer size with rgndata NULL */
3907 return size
+ sizeof(RGNDATAHEADER
);
3912 ProbeForWrite(rgndata
, count
, 1);
3913 RtlCopyMemory(rgndata
, &obj
->rdh
, sizeof(RGNDATAHEADER
));
3914 RtlCopyMemory(rgndata
->Buffer
, obj
->Buffer
, size
);
3916 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3918 Status
= _SEH2_GetExceptionCode();
3922 if (!NT_SUCCESS(Status
))
3924 SetLastNtError(Status
);
3925 RGNOBJAPI_Unlock(obj
);
3929 RGNOBJAPI_Unlock(obj
);
3930 return size
+ sizeof(RGNDATAHEADER
);