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
);
610 if (rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
611 ExFreePoolWithTag(rgnDst
->Buffer
, TAG_REGION
); //free the old buffer. will be assigned to xrect below.
618 if (rgnDst
!= rgnSrc
)
623 if (off
->x
|| off
->y
)
625 for (i
= 0; i
< rgnDst
->rdh
.nCount
; i
++)
627 xrect
[i
].left
= (rgnSrc
->Buffer
+ i
)->left
+ off
->x
;
628 xrect
[i
].right
= (rgnSrc
->Buffer
+ i
)->right
+ off
->x
;
629 xrect
[i
].top
= (rgnSrc
->Buffer
+ i
)->top
+ off
->y
;
630 xrect
[i
].bottom
= (rgnSrc
->Buffer
+ i
)->bottom
+ off
->y
;
632 rgnDst
->rdh
.rcBound
.left
+= off
->x
;
633 rgnDst
->rdh
.rcBound
.right
+= off
->x
;
634 rgnDst
->rdh
.rcBound
.top
+= off
->y
;
635 rgnDst
->rdh
.rcBound
.bottom
+= off
->y
;
639 COPY_RECTS(xrect
, rgnSrc
->Buffer
, rgnDst
->rdh
.nCount
);
642 rgnDst
->Buffer
= xrect
;
647 else if ((rect
->left
>= rect
->right
) ||
648 (rect
->top
>= rect
->bottom
) ||
649 !EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
))
653 else // region box and clipping rect appear to intersect
656 ULONG i
, j
, clipa
, clipb
;
657 INT left
= rgnSrc
->rdh
.rcBound
.right
+ off
->x
;
658 INT right
= rgnSrc
->rdh
.rcBound
.left
+ off
->x
;
660 for (clipa
= 0; (rgnSrc
->Buffer
+ clipa
)->bottom
<= rect
->top
; clipa
++)
661 //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
662 ; // skip bands above the clipping rectangle
664 for (clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
665 if ((rgnSrc
->Buffer
+ clipb
)->top
>= rect
->bottom
)
666 break; // and below it
668 // clipa - index of the first rect in the first intersecting band
669 // clipb - index of the last rect in the last intersecting band
671 if ((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nCount
< (i
= (clipb
- clipa
))))
674 temp
= ExAllocatePoolWithTag(PagedPool
, i
* sizeof(RECT
), TAG_REGION
);
678 if (rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
679 ExFreePoolWithTag(rgnDst
->Buffer
, TAG_REGION
); //free the old buffer
680 rgnDst
->Buffer
= temp
;
681 rgnDst
->rdh
.nCount
= i
;
682 rgnDst
->rdh
.nRgnSize
= i
* sizeof(RECT
);
685 for (i
= clipa
, j
= 0; i
< clipb
; i
++)
687 // i - src index, j - dst index, j is always <= i for obvious reasons
689 lpr
= rgnSrc
->Buffer
+ i
;
691 if (lpr
->left
< rect
->right
&& lpr
->right
> rect
->left
)
693 rpr
= rgnDst
->Buffer
+ j
;
695 rpr
->top
= lpr
->top
+ off
->y
;
696 rpr
->bottom
= lpr
->bottom
+ off
->y
;
697 rpr
->left
= ((lpr
->left
> rect
->left
) ? lpr
->left
: rect
->left
) + off
->x
;
698 rpr
->right
= ((lpr
->right
< rect
->right
) ? lpr
->right
: rect
->right
) + off
->x
;
700 if (rpr
->left
< left
) left
= rpr
->left
;
701 if (rpr
->right
> right
) right
= rpr
->right
;
707 if (j
== 0) goto empty
;
709 rgnDst
->rdh
.rcBound
.left
= left
;
710 rgnDst
->rdh
.rcBound
.right
= right
;
712 left
= rect
->top
+ off
->y
;
713 right
= rect
->bottom
+ off
->y
;
715 rgnDst
->rdh
.nCount
= j
--;
716 for (i
= 0; i
<= j
; i
++) // fixup top band
717 if ((rgnDst
->Buffer
+ i
)->top
< left
)
718 (rgnDst
->Buffer
+ i
)->top
= left
;
722 for (i
= j
; i
> 0; i
--) // fixup bottom band
723 if ((rgnDst
->Buffer
+ i
)->bottom
> right
)
724 (rgnDst
->Buffer
+ i
)->bottom
= right
;
728 rgnDst
->rdh
.rcBound
.top
= (rgnDst
->Buffer
)->top
;
729 rgnDst
->rdh
.rcBound
.bottom
= (rgnDst
->Buffer
+ j
)->bottom
;
731 rgnDst
->rdh
.iType
= RDH_RECTANGLES
;
739 rgnDst
->Buffer
= ExAllocatePoolWithTag(PagedPool
, RGN_DEFAULT_RECTS
* sizeof(RECT
), TAG_REGION
);
742 rgnDst
->rdh
.nCount
= RGN_DEFAULT_RECTS
;
743 rgnDst
->rdh
.nRgnSize
= RGN_DEFAULT_RECTS
* sizeof(RECT
);
748 EMPTY_REGION(rgnDst
);
754 * Attempt to merge the rects in the current band with those in the
755 * previous one. Used only by REGION_RegionOp.
758 * The new index for the previous band.
760 * \note Side Effects:
761 * If coalescing takes place:
762 * - rectangles in the previous band will have their bottom fields
764 * - pReg->numRects will be decreased.
769 PROSRGNDATA pReg
, /* Region to coalesce */
770 INT prevStart
, /* Index of start of previous band */
771 INT curStart
/* Index of start of current band */
774 RECTL
*pPrevRect
; /* Current rect in previous band */
775 RECTL
*pCurRect
; /* Current rect in current band */
776 RECTL
*pRegEnd
; /* End of region */
777 INT curNumRects
; /* Number of rectangles in current band */
778 INT prevNumRects
; /* Number of rectangles in previous band */
779 INT bandtop
; /* top coordinate for current band */
781 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
782 pPrevRect
= pReg
->Buffer
+ prevStart
;
783 prevNumRects
= curStart
- prevStart
;
786 * Figure out how many rectangles are in the current band. Have to do
787 * this because multiple bands could have been added in REGION_RegionOp
788 * at the end when one region has been exhausted.
790 pCurRect
= pReg
->Buffer
+ curStart
;
791 bandtop
= pCurRect
->top
;
792 for (curNumRects
= 0;
793 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
799 if (pCurRect
!= pRegEnd
)
802 * If more than one band was added, we have to find the start
803 * of the last band added so the next coalescing job can start
804 * at the right place... (given when multiple bands are added,
805 * this may be pointless -- see above).
808 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
812 curStart
= pRegEnd
- pReg
->Buffer
;
813 pRegEnd
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
816 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0))
818 pCurRect
-= curNumRects
;
820 * The bands may only be coalesced if the bottom of the previous
821 * matches the top scanline of the current.
823 if (pPrevRect
->bottom
== pCurRect
->top
)
826 * Make sure the bands have rects in the same places. This
827 * assumes that rects have been added in such a way that they
828 * cover the most area possible. I.e. two rects in a band must
829 * have some horizontal space between them.
833 if ((pPrevRect
->left
!= pCurRect
->left
) ||
834 (pPrevRect
->right
!= pCurRect
->right
))
837 * The bands don't line up so they can't be coalesced.
845 while (prevNumRects
!= 0);
847 pReg
->rdh
.nCount
-= curNumRects
;
848 pCurRect
-= curNumRects
;
849 pPrevRect
-= curNumRects
;
852 * The bands may be merged, so set the bottom of each rect
853 * in the previous band to that of the corresponding rect in
858 pPrevRect
->bottom
= pCurRect
->bottom
;
863 while (curNumRects
!= 0);
866 * If only one band was added to the region, we have to backup
867 * curStart to the start of the previous band.
869 * If more than one band was added to the region, copy the
870 * other bands down. The assumption here is that the other bands
871 * came from the same region as the current one and no further
872 * coalescing can be done on them since it's all been done
873 * already... curStart is already in the right place.
875 if (pCurRect
== pRegEnd
)
877 curStart
= prevStart
;
883 *pPrevRect
++ = *pCurRect
++;
885 while (pCurRect
!= pRegEnd
);
893 * Apply an operation to two regions. Called by REGION_Union,
894 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
900 * The new region is overwritten.
902 *\note The idea behind this function is to view the two regions as sets.
903 * Together they cover a rectangle of area that this function divides
904 * into horizontal bands where points are covered only by one region
905 * or by both. For the first case, the nonOverlapFunc is called with
906 * each the band and the band's upper and lower extents. For the
907 * second, the overlapFunc is called to process the entire band. It
908 * is responsible for clipping the rectangles in the band, though
909 * this function provides the boundaries.
910 * At the end of each band, the new region is coalesced, if possible,
911 * to reduce the number of rectangles in the region.
916 ROSRGNDATA
*newReg
, /* Place to store result */
917 ROSRGNDATA
*reg1
, /* First region in operation */
918 ROSRGNDATA
*reg2
, /* 2nd region in operation */
919 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
920 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
921 nonOverlapProcp nonOverlap2Func
/* Function to call for non-overlapping bands in region 2 */
924 RECTL
*r1
; /* Pointer into first region */
925 RECTL
*r2
; /* Pointer into 2d region */
926 RECTL
*r1End
; /* End of 1st region */
927 RECTL
*r2End
; /* End of 2d region */
928 INT ybot
; /* Bottom of intersection */
929 INT ytop
; /* Top of intersection */
930 RECTL
*oldRects
; /* Old rects for newReg */
931 ULONG prevBand
; /* Index of start of
932 * previous band in newReg */
933 ULONG curBand
; /* Index of start of current band in newReg */
934 RECTL
*r1BandEnd
; /* End of current band in r1 */
935 RECTL
*r2BandEnd
; /* End of current band in r2 */
936 ULONG top
; /* Top of non-overlapping band */
937 ULONG bot
; /* Bottom of non-overlapping band */
941 * set r1, r2, r1End and r2End appropriately, preserve the important
942 * parts of the destination region until the end in case it's one of
943 * the two source regions, then mark the "new" region empty, allocating
944 * another array of rectangles for it to use.
948 r1End
= r1
+ reg1
->rdh
.nCount
;
949 r2End
= r2
+ reg2
->rdh
.nCount
;
953 * newReg may be one of the src regions so we can't empty it. We keep a
954 * note of its rects pointer (so that we can free them later), preserve its
955 * extents and simply set numRects to zero.
958 oldRects
= newReg
->Buffer
;
959 newReg
->rdh
.nCount
= 0;
962 * Allocate a reasonable number of rectangles for the new region. The idea
963 * is to allocate enough so the individual functions don't need to
964 * reallocate and copy the array, which is time consuming, yet we don't
965 * have to worry about using too much memory. I hope to be able to
966 * nuke the Xrealloc() at the end of this function eventually.
968 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
,reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
970 if (! (newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, newReg
->rdh
.nRgnSize
, TAG_REGION
)))
972 newReg
->rdh
.nRgnSize
= 0;
977 * Initialize ybot and ytop.
978 * In the upcoming loop, ybot and ytop serve different functions depending
979 * on whether the band being handled is an overlapping or non-overlapping
981 * In the case of a non-overlapping band (only one of the regions
982 * has points in the band), ybot is the bottom of the most recent
983 * intersection and thus clips the top of the rectangles in that band.
984 * ytop is the top of the next intersection between the two regions and
985 * serves to clip the bottom of the rectangles in the current band.
986 * For an overlapping band (where the two regions intersect), ytop clips
987 * the top of the rectangles of both regions and ybot clips the bottoms.
989 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
990 ybot
= reg1
->rdh
.rcBound
.top
;
992 ybot
= reg2
->rdh
.rcBound
.top
;
995 * prevBand serves to mark the start of the previous band so rectangles
996 * can be coalesced into larger rectangles. qv. miCoalesce, above.
997 * In the beginning, there is no previous band, so prevBand == curBand
998 * (curBand is set later on, of course, but the first band will always
999 * start at index 0). prevBand and curBand must be indices because of
1000 * the possible expansion, and resultant moving, of the new region's
1001 * array of rectangles.
1007 curBand
= newReg
->rdh
.nCount
;
1010 * This algorithm proceeds one source-band (as opposed to a
1011 * destination band, which is determined by where the two regions
1012 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1013 * rectangle after the last one in the current band for their
1014 * respective regions.
1017 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1023 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1029 * First handle the band that doesn't intersect, if any.
1031 * Note that attention is restricted to one band in the
1032 * non-intersecting region at once, so if a region has n
1033 * bands between the current position and the next place it overlaps
1034 * the other, this entire loop will be passed through n times.
1036 if (r1
->top
< r2
->top
)
1038 top
= max(r1
->top
,ybot
);
1039 bot
= min(r1
->bottom
,r2
->top
);
1041 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
1043 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
1048 else if (r2
->top
< r1
->top
)
1050 top
= max(r2
->top
,ybot
);
1051 bot
= min(r2
->bottom
,r1
->top
);
1053 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
1055 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
1066 * If any rectangles got added to the region, try and coalesce them
1067 * with rectangles from the previous band. Note we could just do
1068 * this test in miCoalesce, but some machines incur a not
1069 * inconsiderable cost for function calls, so...
1071 if (newReg
->rdh
.nCount
!= curBand
)
1073 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1077 * Now see if we've hit an intersecting band. The two bands only
1078 * intersect if ybot > ytop
1080 ybot
= min(r1
->bottom
, r2
->bottom
);
1081 curBand
= newReg
->rdh
.nCount
;
1084 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1087 if (newReg
->rdh
.nCount
!= curBand
)
1089 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1093 * If we've finished with a band (bottom == ybot) we skip forward
1094 * in the region to the next band.
1096 if (r1
->bottom
== ybot
)
1100 if (r2
->bottom
== ybot
)
1105 while ((r1
!= r1End
) && (r2
!= r2End
));
1108 * Deal with whichever region still has rectangles left.
1110 curBand
= newReg
->rdh
.nCount
;
1113 if (nonOverlap1Func
!= NULL
)
1118 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1122 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
1123 max(r1
->top
,ybot
), r1
->bottom
);
1126 while (r1
!= r1End
);
1129 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
1134 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1138 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
1139 max(r2
->top
,ybot
), r2
->bottom
);
1142 while (r2
!= r2End
);
1145 if (newReg
->rdh
.nCount
!= curBand
)
1147 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
1151 * A bit of cleanup. To keep regions from growing without bound,
1152 * we shrink the array of rectangles to match the new number of
1153 * rectangles in the region. This never goes to 0, however...
1155 * Only do this stuff if the number of rectangles allocated is more than
1156 * twice the number of rectangles in the region (a simple optimization...).
1158 if ((2 * newReg
->rdh
.nCount
*sizeof(RECT
) < newReg
->rdh
.nRgnSize
&& (newReg
->rdh
.nCount
> 2)))
1160 if (REGION_NOT_EMPTY(newReg
))
1162 RECTL
*prev_rects
= newReg
->Buffer
;
1163 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, newReg
->rdh
.nCount
*sizeof(RECT
), TAG_REGION
);
1165 if (! newReg
->Buffer
)
1166 newReg
->Buffer
= prev_rects
;
1169 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
1170 COPY_RECTS(newReg
->Buffer
, prev_rects
, newReg
->rdh
.nCount
);
1171 if (prev_rects
!= &newReg
->rdh
.rcBound
)
1172 ExFreePoolWithTag(prev_rects
, TAG_REGION
);
1178 * No point in doing the extra work involved in an Xrealloc if
1179 * the region is empty
1181 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
1182 if (newReg
->Buffer
!= &newReg
->rdh
.rcBound
)
1183 ExFreePoolWithTag(newReg
->Buffer
, TAG_REGION
);
1184 newReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, sizeof(RECT
), TAG_REGION
);
1185 ASSERT(newReg
->Buffer
);
1188 newReg
->rdh
.iType
= RDH_RECTANGLES
;
1190 if (oldRects
!= &newReg
->rdh
.rcBound
)
1191 ExFreePoolWithTag(oldRects
, TAG_REGION
);
1195 /***********************************************************************
1196 * Region Intersection
1197 ***********************************************************************/
1201 * Handle an overlapping band for REGION_Intersect.
1206 * \note Side Effects:
1207 * Rectangles may be added to the region.
1210 static void FASTCALL
1224 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1226 while ((r1
!= r1End
) && (r2
!= r2End
))
1228 left
= max(r1
->left
, r2
->left
);
1229 right
= min(r1
->right
, r2
->right
);
1232 * If there's any overlap between the two rectangles, add that
1233 * overlap to the new region.
1234 * There's no need to check for subsumption because the only way
1235 * such a need could arise is if some region has two rectangles
1236 * right next to each other. Since that should never happen...
1240 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1241 pNextRect
->left
= left
;
1242 pNextRect
->top
= top
;
1243 pNextRect
->right
= right
;
1244 pNextRect
->bottom
= bottom
;
1245 pReg
->rdh
.nCount
+= 1;
1250 * Need to advance the pointers. Shift the one that extends
1251 * to the right the least, since the other still has a chance to
1252 * overlap with that region's next rectangle, if you see what I mean.
1254 if (r1
->right
< r2
->right
)
1258 else if (r2
->right
< r1
->right
)
1271 /***********************************************************************
1272 * REGION_IntersectRegion
1274 static void FASTCALL
1275 REGION_IntersectRegion(
1281 /* check for trivial reject */
1282 if ( (!(reg1
->rdh
.nCount
)) || (!(reg2
->rdh
.nCount
)) ||
1283 (!EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
)) )
1284 newReg
->rdh
.nCount
= 0;
1286 REGION_RegionOp (newReg
, reg1
, reg2
,
1287 REGION_IntersectO
, NULL
, NULL
);
1290 * Can't alter newReg's extents before we call miRegionOp because
1291 * it might be one of the source regions and miRegionOp depends
1292 * on the extents of those regions being the same. Besides, this
1293 * way there's no checking against rectangles that will be nuked
1294 * due to coalescing, so we have to examine fewer rectangles.
1297 REGION_SetExtents(newReg
);
1300 /***********************************************************************
1302 ***********************************************************************/
1305 * Handle a non-overlapping band for the union operation. Just
1306 * Adds the rectangles into the region. Doesn't have to check for
1307 * subsumption or anything.
1312 * \note Side Effects:
1313 * pReg->numRects is incremented and the final rectangles overwritten
1314 * with the rectangles we're passed.
1317 static void FASTCALL
1328 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1332 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1333 pNextRect
->left
= r
->left
;
1334 pNextRect
->top
= top
;
1335 pNextRect
->right
= r
->right
;
1336 pNextRect
->bottom
= bottom
;
1337 pReg
->rdh
.nCount
+= 1;
1345 * Handle an overlapping band for the union operation. Picks the
1346 * left-most rectangle each time and merges it into the region.
1351 * \note Side Effects:
1352 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1356 static void FASTCALL
1369 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1371 #define MERGERECT(r) \
1372 if ((pReg->rdh.nCount != 0) && \
1373 ((pNextRect-1)->top == top) && \
1374 ((pNextRect-1)->bottom == bottom) && \
1375 ((pNextRect-1)->right >= r->left)) \
1377 if ((pNextRect-1)->right < r->right) \
1379 (pNextRect-1)->right = r->right; \
1384 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1385 pNextRect->top = top; \
1386 pNextRect->bottom = bottom; \
1387 pNextRect->left = r->left; \
1388 pNextRect->right = r->right; \
1389 pReg->rdh.nCount += 1; \
1394 while ((r1
!= r1End
) && (r2
!= r2End
))
1396 if (r1
->left
< r2
->left
)
1412 while (r1
!= r1End
);
1414 else while (r2
!= r2End
)
1421 /***********************************************************************
1422 * REGION_UnionRegion
1424 static void FASTCALL
1431 /* checks all the simple cases */
1434 * Region 1 and 2 are the same or region 1 is empty
1436 if (reg1
== reg2
|| 0 == reg1
->rdh
.nCount
||
1437 reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
||
1438 reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
)
1442 REGION_CopyRegion(newReg
, reg2
);
1448 * if nothing to union (region 2 empty)
1450 if (0 == reg2
->rdh
.nCount
||
1451 reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
||
1452 reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
)
1456 REGION_CopyRegion(newReg
, reg1
);
1462 * Region 1 completely subsumes region 2
1464 if (1 == reg1
->rdh
.nCount
&&
1465 reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
&&
1466 reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
&&
1467 reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
&&
1468 reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
)
1472 REGION_CopyRegion(newReg
, reg1
);
1478 * Region 2 completely subsumes region 1
1480 if (1 == reg2
->rdh
.nCount
&&
1481 reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
&&
1482 reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
&&
1483 reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
&&
1484 reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
)
1488 REGION_CopyRegion(newReg
, reg2
);
1493 REGION_RegionOp (newReg
, reg1
, reg2
, REGION_UnionO
,
1494 REGION_UnionNonO
, REGION_UnionNonO
);
1495 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1496 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1497 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1498 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1501 /***********************************************************************
1502 * Region Subtraction
1503 ***********************************************************************/
1506 * Deal with non-overlapping band for subtraction. Any parts from
1507 * region 2 we discard. Anything from region 1 we add to the region.
1512 * \note Side Effects:
1513 * pReg may be affected.
1516 static void FASTCALL
1517 REGION_SubtractNonO1(
1527 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1531 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1532 pNextRect
->left
= r
->left
;
1533 pNextRect
->top
= top
;
1534 pNextRect
->right
= r
->right
;
1535 pNextRect
->bottom
= bottom
;
1536 pReg
->rdh
.nCount
+= 1;
1545 * Overlapping band subtraction. x1 is the left-most point not yet
1551 * \note Side Effects:
1552 * pReg may have rectangles added to it.
1555 static void FASTCALL
1570 pNextRect
= pReg
->Buffer
+ pReg
->rdh
.nCount
;
1572 while ((r1
!= r1End
) && (r2
!= r2End
))
1574 if (r2
->right
<= left
)
1577 * Subtrahend missed the boat: go to next subtrahend.
1581 else if (r2
->left
<= left
)
1584 * Subtrahend preceeds minuend: nuke left edge of minuend.
1587 if (left
>= r1
->right
)
1590 * Minuend completely covered: advance to next minuend and
1591 * reset left fence to edge of new minuend.
1600 * Subtrahend now used up since it doesn't extend beyond
1606 else if (r2
->left
< r1
->right
)
1609 * Left part of subtrahend covers part of minuend: add uncovered
1610 * part of minuend to region and skip to next subtrahend.
1612 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1613 pNextRect
->left
= left
;
1614 pNextRect
->top
= top
;
1615 pNextRect
->right
= r2
->left
;
1616 pNextRect
->bottom
= bottom
;
1617 pReg
->rdh
.nCount
+= 1;
1620 if (left
>= r1
->right
)
1623 * Minuend used up: advance to new...
1632 * Subtrahend used up
1640 * Minuend used up: add any remaining piece before advancing.
1642 if (r1
->right
> left
)
1644 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1645 pNextRect
->left
= left
;
1646 pNextRect
->top
= top
;
1647 pNextRect
->right
= r1
->right
;
1648 pNextRect
->bottom
= bottom
;
1649 pReg
->rdh
.nCount
+= 1;
1659 * Add remaining minuend rectangles to region.
1663 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1664 pNextRect
->left
= left
;
1665 pNextRect
->top
= top
;
1666 pNextRect
->right
= r1
->right
;
1667 pNextRect
->bottom
= bottom
;
1668 pReg
->rdh
.nCount
+= 1;
1680 * Subtract regS from regM and leave the result in regD.
1681 * S stands for subtrahend, M for minuend and D for difference.
1686 * \note Side Effects:
1687 * regD is overwritten.
1690 static void FASTCALL
1691 REGION_SubtractRegion(
1697 /* check for trivial reject */
1698 if ( (!(regM
->rdh
.nCount
)) || (!(regS
->rdh
.nCount
)) ||
1699 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1701 REGION_CopyRegion(regD
, regM
);
1705 REGION_RegionOp (regD
, regM
, regS
, REGION_SubtractO
,
1706 REGION_SubtractNonO1
, NULL
);
1709 * Can't alter newReg's extents before we call miRegionOp because
1710 * it might be one of the source regions and miRegionOp depends
1711 * on the extents of those regions being the unaltered. Besides, this
1712 * way there's no checking against rectangles that will be nuked
1713 * due to coalescing, so we have to examine fewer rectangles.
1715 REGION_SetExtents (regD
);
1718 /***********************************************************************
1721 static void FASTCALL
1729 ROSRGNDATA
*tra
, *trb
;
1731 // FIXME: don't use a handle
1732 tra
= REGION_AllocRgnWithHandle(sra
->rdh
.nCount
+ 1);
1737 htra
= tra
->BaseObject
.hHmgr
;
1739 // FIXME: don't use a handle
1740 trb
= REGION_AllocRgnWithHandle(srb
->rdh
.nCount
+ 1);
1743 RGNOBJAPI_Unlock(tra
);
1744 GreDeleteObject(htra
);
1747 htrb
= trb
->BaseObject
.hHmgr
;
1749 REGION_SubtractRegion(tra
, sra
, srb
);
1750 REGION_SubtractRegion(trb
, srb
, sra
);
1751 REGION_UnionRegion(dr
, tra
, trb
);
1752 RGNOBJAPI_Unlock(tra
);
1753 RGNOBJAPI_Unlock(trb
);
1755 GreDeleteObject(htra
);
1756 GreDeleteObject(htrb
);
1762 * Adds a rectangle to a REGION
1765 REGION_UnionRectWithRgn(
1772 region
.Buffer
= ®ion
.rdh
.rcBound
;
1773 region
.rdh
.nCount
= 1;
1774 region
.rdh
.nRgnSize
= sizeof(RECT
);
1775 region
.rdh
.rcBound
= *rect
;
1776 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1780 REGION_CreateSimpleFrameRgn(
1789 if (x
!= 0 || y
!= 0)
1793 if (rgn
->rdh
.rcBound
.bottom
- rgn
->rdh
.rcBound
.top
> y
* 2 &&
1794 rgn
->rdh
.rcBound
.right
- rgn
->rdh
.rcBound
.left
> x
* 2)
1799 prc
->left
= rgn
->rdh
.rcBound
.left
;
1800 prc
->top
= rgn
->rdh
.rcBound
.top
;
1801 prc
->right
= rgn
->rdh
.rcBound
.right
;
1802 prc
->bottom
= prc
->top
+ y
;
1808 /* left rectangle */
1809 prc
->left
= rgn
->rdh
.rcBound
.left
;
1810 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1811 prc
->right
= prc
->left
+ x
;
1812 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1815 /* right rectangle */
1816 prc
->left
= rgn
->rdh
.rcBound
.right
- x
;
1817 prc
->top
= rgn
->rdh
.rcBound
.top
+ y
;
1818 prc
->right
= rgn
->rdh
.rcBound
.right
;
1819 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
- y
;
1825 /* bottom rectangle */
1826 prc
->left
= rgn
->rdh
.rcBound
.left
;
1827 prc
->top
= rgn
->rdh
.rcBound
.bottom
- y
;
1828 prc
->right
= rgn
->rdh
.rcBound
.right
;
1829 prc
->bottom
= rgn
->rdh
.rcBound
.bottom
;
1836 /* The frame results in a complex region. rcBounds remains
1837 the same, though. */
1838 rgn
->rdh
.nCount
= (DWORD
)(prc
- rc
);
1839 ASSERT(rgn
->rdh
.nCount
> 1);
1840 rgn
->rdh
.nRgnSize
= rgn
->rdh
.nCount
* sizeof(RECT
);
1841 rgn
->Buffer
= ExAllocatePoolWithTag(PagedPool
, rgn
->rdh
.nRgnSize
, TAG_REGION
);
1844 rgn
->rdh
.nRgnSize
= 0;
1848 COPY_RECTS(rgn
->Buffer
, rc
, rgn
->rdh
.nCount
);
1856 REGION_CreateFrameRgn(
1863 PROSRGNDATA srcObj
, destObj
;
1867 if (!(srcObj
= RGNOBJAPI_Lock(hSrc
, NULL
)))
1871 if (!REGION_NOT_EMPTY(srcObj
))
1873 RGNOBJAPI_Unlock(srcObj
);
1876 if (!(destObj
= RGNOBJAPI_Lock(hDest
, NULL
)))
1878 RGNOBJAPI_Unlock(srcObj
);
1882 EMPTY_REGION(destObj
);
1883 if (!REGION_CopyRegion(destObj
, srcObj
))
1885 RGNOBJAPI_Unlock(destObj
);
1886 RGNOBJAPI_Unlock(srcObj
);
1890 if (REGION_Complexity(srcObj
) == SIMPLEREGION
)
1892 if (!REGION_CreateSimpleFrameRgn(destObj
, x
, y
))
1894 EMPTY_REGION(destObj
);
1895 RGNOBJAPI_Unlock(destObj
);
1896 RGNOBJAPI_Unlock(srcObj
);
1902 /* Original region moved to right */
1903 rc
= srcObj
->Buffer
;
1904 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1910 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1912 /* Original region moved to left */
1913 rc
= srcObj
->Buffer
;
1914 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1920 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1922 /* Original region moved down */
1923 rc
= srcObj
->Buffer
;
1924 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1932 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1934 /* Original region moved up */
1935 rc
= srcObj
->Buffer
;
1936 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1939 rc
->bottom
-= 2 * y
;
1942 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1944 /* Restore the original region */
1945 rc
= srcObj
->Buffer
;
1946 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1952 REGION_SubtractRegion(destObj
, srcObj
, destObj
);
1955 RGNOBJAPI_Unlock(destObj
);
1956 RGNOBJAPI_Unlock(srcObj
);
1967 RECTL
*pCurRect
, *pEndRect
;
1968 PROSRGNDATA srcObj
= NULL
;
1969 PROSRGNDATA destObj
= NULL
;
1977 pdcattr
= dc
->pdcattr
;
1979 if (pdcattr
->iMapMode
== MM_TEXT
) // Requires only a translation
1981 if (NtGdiCombineRgn(hDest
, hSrc
, 0, RGN_COPY
) == ERROR
)
1984 NtGdiOffsetRgn(hDest
, pdcattr
->ptlViewportOrg
.x
- pdcattr
->ptlWindowOrg
.x
,
1985 pdcattr
->ptlViewportOrg
.y
- pdcattr
->ptlWindowOrg
.y
);
1990 if ( !(srcObj
= RGNOBJAPI_Lock(hSrc
, NULL
)) )
1992 if ( !(destObj
= RGNOBJAPI_Lock(hDest
, NULL
)) )
1994 RGNOBJAPI_Unlock(srcObj
);
1997 EMPTY_REGION(destObj
);
1999 pEndRect
= srcObj
->Buffer
+ srcObj
->rdh
.nCount
;
2000 for (pCurRect
= srcObj
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
2002 tmpRect
= *pCurRect
;
2003 tmpRect
.left
= XLPTODP(pdcattr
, tmpRect
.left
);
2004 tmpRect
.top
= YLPTODP(pdcattr
, tmpRect
.top
);
2005 tmpRect
.right
= XLPTODP(pdcattr
, tmpRect
.right
);
2006 tmpRect
.bottom
= YLPTODP(pdcattr
, tmpRect
.bottom
);
2008 if (tmpRect
.left
> tmpRect
.right
)
2010 INT tmp
= tmpRect
.left
;
2011 tmpRect
.left
= tmpRect
.right
;
2012 tmpRect
.right
= tmp
;
2014 if (tmpRect
.top
> tmpRect
.bottom
)
2016 INT tmp
= tmpRect
.top
;
2017 tmpRect
.top
= tmpRect
.bottom
;
2018 tmpRect
.bottom
= tmp
;
2021 REGION_UnionRectWithRgn(destObj
, &tmpRect
);
2025 RGNOBJAPI_Unlock(srcObj
);
2026 RGNOBJAPI_Unlock(destObj
);
2034 REGION_AllocRgnWithHandle(INT nReg
)
2039 PGDI_TABLE_ENTRY Entry
;
2041 pReg
= (PROSRGNDATA
)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_REGION
);
2047 hReg
= pReg
->BaseObject
.hHmgr
;
2049 if (nReg
== 0 || nReg
== 1)
2051 /* Testing shows that > 95% of all regions have only 1 rect.
2052 Including that here saves us from having to do another allocation */
2053 pReg
->Buffer
= &pReg
->rdh
.rcBound
;
2057 pReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, nReg
* sizeof(RECT
), TAG_REGION
);
2060 RGNOBJAPI_Unlock(pReg
);
2061 GDIOBJ_FreeObjByHandle(hReg
, GDI_OBJECT_TYPE_REGION
);
2066 KeEnterCriticalRegion();
2067 Index
= GDI_HANDLE_GET_INDEX(hReg
);
2068 Entry
= &GdiHandleTable
->Entries
[Index
];
2069 Entry
->UserData
= AllocateObjectAttr();
2070 KeLeaveCriticalRegion();
2073 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
2074 pReg
->rdh
.nCount
= nReg
;
2075 pReg
->rdh
.nRgnSize
= nReg
* sizeof(RECT
);
2082 RGNOBJAPI_Lock(HRGN hRgn
, PRGN_ATTR
*ppRgn_Attr
)
2085 PGDI_TABLE_ENTRY Entry
;
2087 PRGN_ATTR pRgn_Attr
;
2090 pRgn
= REGION_LockRgn(hRgn
);
2094 KeEnterCriticalRegion();
2095 Index
= GDI_HANDLE_GET_INDEX(hRgn
);
2096 Entry
= &GdiHandleTable
->Entries
[Index
];
2097 pRgn_Attr
= Entry
->UserData
;
2098 pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
2099 KeLeaveCriticalRegion();
2101 if ( pid
== NtCurrentTeb()->ClientId
.UniqueProcess
&&
2106 if ( !(pRgn_Attr
->AttrFlags
& ATTR_CACHED
) &&
2107 pRgn_Attr
->AttrFlags
& (ATTR_RGN_VALID
|ATTR_RGN_DIRTY
) )
2109 switch (pRgn_Attr
->Flags
)
2112 EMPTY_REGION( pRgn
);
2116 REGION_SetRectRgn( pRgn
,
2117 pRgn_Attr
->Rect
.left
,
2118 pRgn_Attr
->Rect
.top
,
2119 pRgn_Attr
->Rect
.right
,
2120 pRgn_Attr
->Rect
.bottom
);
2123 pRgn_Attr
->AttrFlags
&= ~ATTR_RGN_DIRTY
;
2126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2132 *ppRgn_Attr
= pRgn_Attr
;
2145 RGNOBJAPI_Unlock(PROSRGNDATA pRgn
)
2148 PGDI_TABLE_ENTRY Entry
;
2149 PRGN_ATTR pRgn_Attr
;
2154 KeEnterCriticalRegion();
2155 Index
= GDI_HANDLE_GET_INDEX(pRgn
->BaseObject
.hHmgr
);
2156 Entry
= &GdiHandleTable
->Entries
[Index
];
2157 pRgn_Attr
= Entry
->UserData
;
2158 pid
= (HANDLE
)((ULONG_PTR
)Entry
->ProcessId
& ~0x1);
2159 KeLeaveCriticalRegion();
2161 if ( pid
== NtCurrentTeb()->ClientId
.UniqueProcess
&&
2166 if ( pRgn_Attr
->AttrFlags
& ATTR_RGN_VALID
)
2168 pRgn_Attr
->Flags
= REGION_Complexity( pRgn
);
2169 pRgn_Attr
->Rect
.left
= pRgn
->rdh
.rcBound
.left
;
2170 pRgn_Attr
->Rect
.top
= pRgn
->rdh
.rcBound
.top
;
2171 pRgn_Attr
->Rect
.right
= pRgn
->rdh
.rcBound
.right
;
2172 pRgn_Attr
->Rect
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2181 REGION_UnlockRgn(pRgn
);
2186 These regions do not use attribute sections and when allocated, use gdiobj
2191 REGION_Cleanup(PVOID ObjectBody
)
2193 PROSRGNDATA pRgn
= (PROSRGNDATA
)ObjectBody
;
2194 if (pRgn
->Buffer
&& pRgn
->Buffer
!= &pRgn
->rdh
.rcBound
)
2195 ExFreePool(pRgn
->Buffer
);
2200 REGION_Delete(PROSRGNDATA pRgn
)
2202 if ( pRgn
== prgnDefault
) return;
2203 REGION_FreeRgn(pRgn
);
2207 IntGdiReleaseRaoRgn(PDC pDC
)
2209 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2210 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2211 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2212 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2213 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2217 IntGdiReleaseVisRgn(PDC pDC
)
2219 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2220 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2221 pDC
->fs
|= DC_FLAG_DIRTY_RAO
;
2222 Entry
->Flags
|= GDI_ENTRY_VALIDATE_VIS
;
2223 RECTL_vSetEmptyRect(&pDC
->erclClip
);
2224 REGION_Delete(pDC
->prgnVis
);
2225 pDC
->prgnVis
= prgnDefault
;
2229 IntUpdateVisRectRgn(PDC pDC
, PROSRGNDATA pRgn
)
2231 INT Index
= GDI_HANDLE_GET_INDEX(pDC
->BaseObject
.hHmgr
);
2232 PGDI_TABLE_ENTRY Entry
= &GdiHandleTable
->Entries
[Index
];
2236 if (Entry
->Flags
& GDI_ENTRY_VALIDATE_VIS
)
2238 pdcattr
= pDC
->pdcattr
;
2240 pdcattr
->VisRectRegion
.Flags
= REGION_Complexity(pRgn
);
2242 if (pRgn
&& pdcattr
->VisRectRegion
.Flags
!= NULLREGION
)
2244 rcl
.left
= pRgn
->rdh
.rcBound
.left
;
2245 rcl
.top
= pRgn
->rdh
.rcBound
.top
;
2246 rcl
.right
= pRgn
->rdh
.rcBound
.right
;
2247 rcl
.bottom
= pRgn
->rdh
.rcBound
.bottom
;
2249 rcl
.left
-= pDC
->erclWindow
.left
;
2250 rcl
.top
-= pDC
->erclWindow
.top
;
2251 rcl
.right
-= pDC
->erclWindow
.left
;
2252 rcl
.bottom
-= pDC
->erclWindow
.top
;
2255 RECTL_vSetEmptyRect(&rcl
);
2257 pdcattr
->VisRectRegion
.Rect
= rcl
;
2259 Entry
->Flags
&= ~GDI_ENTRY_VALIDATE_VIS
;
2265 IntGdiCombineRgn(PROSRGNDATA destRgn
,
2266 PROSRGNDATA src1Rgn
,
2267 PROSRGNDATA src2Rgn
,
2276 if (CombineMode
== RGN_COPY
)
2278 if ( !REGION_CopyRegion(destRgn
, src1Rgn
) )
2280 result
= REGION_Complexity(destRgn
);
2286 switch (CombineMode
)
2289 REGION_IntersectRegion(destRgn
, src1Rgn
, src2Rgn
);
2292 REGION_UnionRegion(destRgn
, src1Rgn
, src2Rgn
);
2295 REGION_XorRegion(destRgn
, src1Rgn
, src2Rgn
);
2298 REGION_SubtractRegion(destRgn
, src1Rgn
, src2Rgn
);
2301 result
= REGION_Complexity(destRgn
);
2303 else if (src2Rgn
== NULL
)
2305 DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode
);
2306 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2312 DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
2313 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2318 DPRINT("IntGdiCombineRgn: hDest unavailable\n");
2319 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2326 IntGdiCreateRectRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
2330 if (!(pRgn
= REGION_AllocRgnWithHandle(1))) return NULL
;
2332 REGION_SetRectRgn(pRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
2333 RGNOBJAPI_Unlock(pRgn
);
2334 // Return pointer with Share locks.
2335 pRgn
= GDIOBJ_ShareLockObj(pRgn
->BaseObject
.hHmgr
, GDI_OBJECT_TYPE_REGION
);
2350 *pRect
= Rgn
->rdh
.rcBound
;
2351 ret
= REGION_Complexity(Rgn
);
2355 return 0; //if invalid region return zero
2367 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
2372 ret
= REGION_GetRgnBox(Rgn
, pRect
);
2373 RGNOBJAPI_Unlock(Rgn
);
2387 CLIPOBJ
* ClipRegion
;
2393 if (!dc
) return FALSE
;
2394 pdcattr
= dc
->pdcattr
;
2396 ASSERT(!(pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
)));
2398 if (!(tmpVisRgn
= NtGdiCreateRectRgn(0, 0, 0, 0))) return FALSE
;
2400 // Transform region into device co-ords
2401 if (!REGION_LPTODP(dc
, tmpVisRgn
, hRgn
) ||
2402 NtGdiOffsetRgn(tmpVisRgn
, dc
->ptlDCOrig
.x
, dc
->ptlDCOrig
.y
) == ERROR
)
2404 GreDeleteObject(tmpVisRgn
);
2408 NtGdiCombineRgn(tmpVisRgn
, tmpVisRgn
, dc
->rosdc
.hGCClipRgn
, RGN_AND
);
2410 visrgn
= RGNOBJAPI_Lock(tmpVisRgn
, NULL
);
2413 GreDeleteObject(tmpVisRgn
);
2417 ClipRegion
= IntEngCreateClipRegion(visrgn
->rdh
.nCount
,
2419 &visrgn
->rdh
.rcBound
);
2422 BrushOrigin
.x
= pdcattr
->ptlBrushOrigin
.x
;
2423 BrushOrigin
.y
= pdcattr
->ptlBrushOrigin
.y
;
2424 psurf
= dc
->dclevel
.pSurface
;
2425 /* FIXME - Handle psurf == NULL !!!! */
2427 bRet
= IntEngPaint(&psurf
->SurfObj
,
2429 &dc
->eboFill
.BrushObject
,
2431 0xFFFF);//FIXME:don't know what to put here
2433 RGNOBJAPI_Unlock(visrgn
);
2434 GreDeleteObject(tmpVisRgn
);
2442 REGION_RectInRegion(
2447 PRECTL pCurRect
, pRectEnd
;
2450 /* swap the coordinates to make right >= left and bottom >= top */
2451 /* (region building rectangles are normalized the same way) */
2452 if( rect
->top
> rect
->bottom
) {
2453 rc
.top
= rect
->bottom
;
2454 rc
.bottom
= rect
->top
;
2457 rc
.bottom
= rect
->bottom
;
2459 if( rect
->right
< rect
->left
) {
2460 rc
.right
= rect
->left
;
2461 rc
.left
= rect
->right
;
2463 rc
.right
= rect
->right
;
2464 rc
.left
= rect
->left
;
2467 /* this is (just) a useful optimization */
2468 if ((Rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&Rgn
->rdh
.rcBound
, &rc
))
2470 for (pCurRect
= Rgn
->Buffer
, pRectEnd
= pCurRect
+
2471 Rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
2473 if (pCurRect
->bottom
<= rc
.top
)
2474 continue; /* not far enough down yet */
2476 if (pCurRect
->top
>= rc
.bottom
)
2477 break; /* too far down */
2479 if (pCurRect
->right
<= rc
.left
)
2480 continue; /* not far enough over yet */
2482 if (pCurRect
->left
>= rc
.right
) {
2504 if (LeftRect
> RightRect
)
2507 LeftRect
= RightRect
;
2510 if (TopRect
> BottomRect
)
2513 TopRect
= BottomRect
;
2517 if ((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
2519 firstRect
= rgn
->Buffer
;
2521 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
2522 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
2523 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
2524 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
2525 rgn
->rdh
.nCount
= 1;
2526 rgn
->rdh
.iType
= RDH_RECTANGLES
;
2534 /***********************************************************************
2535 * REGION_InsertEdgeInET
2537 * Insert the given edge into the edge table.
2538 * First we must find the correct bucket in the
2539 * Edge table, then find the right slot in the
2540 * bucket. Finally, we can insert it.
2543 static void FASTCALL
2544 REGION_InsertEdgeInET(
2546 EdgeTableEntry
*ETE
,
2548 ScanLineListBlock
**SLLBlock
,
2552 EdgeTableEntry
*start
, *prev
;
2553 ScanLineList
*pSLL
, *pPrevSLL
;
2554 ScanLineListBlock
*tmpSLLBlock
;
2557 * find the right bucket to put the edge into
2559 pPrevSLL
= &ET
->scanlines
;
2560 pSLL
= pPrevSLL
->next
;
2561 while (pSLL
&& (pSLL
->scanline
< scanline
))
2568 * reassign pSLL (pointer to ScanLineList) if necessary
2570 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
2572 if (*iSLLBlock
> SLLSPERBLOCK
-1)
2574 tmpSLLBlock
= ExAllocatePoolWithTag(PagedPool
, sizeof(ScanLineListBlock
), TAG_REGION
);
2577 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2578 /* FIXME - free resources? */
2581 (*SLLBlock
)->next
= tmpSLLBlock
;
2582 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2583 *SLLBlock
= tmpSLLBlock
;
2586 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
2588 pSLL
->next
= pPrevSLL
->next
;
2589 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
2590 pPrevSLL
->next
= pSLL
;
2592 pSLL
->scanline
= scanline
;
2595 * now insert the edge in the right bucket
2597 prev
= (EdgeTableEntry
*)NULL
;
2598 start
= pSLL
->edgelist
;
2599 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2602 start
= start
->next
;
2609 pSLL
->edgelist
= ETE
;
2612 /***********************************************************************
2615 * This routine moves EdgeTableEntries from the
2616 * EdgeTable into the Active Edge Table,
2617 * leaving them sorted by smaller x coordinate.
2620 static void FASTCALL
2622 EdgeTableEntry
*AET
,
2623 EdgeTableEntry
*ETEs
2626 EdgeTableEntry
*pPrevAET
;
2627 EdgeTableEntry
*tmp
;
2633 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2642 ETEs
->back
= pPrevAET
;
2643 pPrevAET
->next
= ETEs
;
2650 /***********************************************************************
2651 * REGION_computeWAET
2653 * This routine links the AET by the
2654 * nextWETE (winding EdgeTableEntry) link for
2655 * use by the winding number rule. The final
2656 * Active Edge Table (AET) might look something
2660 * ---------- --------- ---------
2661 * |ymax | |ymax | |ymax |
2662 * | ... | |... | |... |
2663 * |next |->|next |->|next |->...
2664 * |nextWETE| |nextWETE| |nextWETE|
2665 * --------- --------- ^--------
2667 * V-------------------> V---> ...
2670 static void FASTCALL
2671 REGION_computeWAET(EdgeTableEntry
*AET
)
2673 register EdgeTableEntry
*pWETE
;
2674 register int inside
= 1;
2675 register int isInside
= 0;
2677 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2687 if ( (!inside
&& !isInside
) ||
2688 ( inside
&& isInside
) )
2690 pWETE
->nextWETE
= AET
;
2696 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2699 /***********************************************************************
2700 * REGION_InsertionSort
2702 * Just a simple insertion sort using
2703 * pointers and back pointers to sort the Active
2707 static BOOL FASTCALL
2708 REGION_InsertionSort(EdgeTableEntry
*AET
)
2710 EdgeTableEntry
*pETEchase
;
2711 EdgeTableEntry
*pETEinsert
;
2712 EdgeTableEntry
*pETEchaseBackTMP
;
2713 BOOL changed
= FALSE
;
2720 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2721 pETEchase
= pETEchase
->back
;
2724 if (pETEchase
!= pETEinsert
)
2726 pETEchaseBackTMP
= pETEchase
->back
;
2727 pETEinsert
->back
->next
= AET
;
2729 AET
->back
= pETEinsert
->back
;
2730 pETEinsert
->next
= pETEchase
;
2731 pETEchase
->back
->next
= pETEinsert
;
2732 pETEchase
->back
= pETEinsert
;
2733 pETEinsert
->back
= pETEchaseBackTMP
;
2740 /***********************************************************************
2741 * REGION_FreeStorage
2745 static void FASTCALL
2746 REGION_FreeStorage(ScanLineListBlock
*pSLLBlock
)
2748 ScanLineListBlock
*tmpSLLBlock
;
2752 tmpSLLBlock
= pSLLBlock
->next
;
2753 ExFreePool(pSLLBlock
);
2754 pSLLBlock
= tmpSLLBlock
;
2759 /***********************************************************************
2760 * REGION_PtsToRegion
2762 * Create an array of rectangles from a list of points.
2766 int numFullPtBlocks
,
2768 POINTBLOCK
*FirstPtBlock
,
2773 POINTBLOCK
*CurPtBlock
;
2775 RECTL
*extents
, *temp
;
2778 extents
= ®
->rdh
.rcBound
;
2780 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
2782 if (!(temp
= ExAllocatePoolWithTag(PagedPool
, numRects
* sizeof(RECT
), TAG_REGION
)))
2786 if (reg
->Buffer
!= NULL
)
2788 COPY_RECTS(temp
, reg
->Buffer
, reg
->rdh
.nCount
);
2789 if (reg
->Buffer
!= ®
->rdh
.rcBound
)
2790 ExFreePoolWithTag(reg
->Buffer
, TAG_REGION
);
2794 reg
->rdh
.nCount
= numRects
;
2795 CurPtBlock
= FirstPtBlock
;
2796 rects
= reg
->Buffer
- 1;
2798 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
2800 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--)
2802 /* the loop uses 2 points per iteration */
2803 i
= NUMPTSTOBUFFER
>> 1;
2804 if (!numFullPtBlocks
)
2805 i
= iCurPtBlock
>> 1;
2806 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2)
2808 if (pts
->x
== pts
[1].x
)
2810 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
2811 pts
[1].x
== rects
->right
&&
2812 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
2813 (i
&& pts
[2].y
> pts
[1].y
))
2815 rects
->bottom
= pts
[1].y
+ 1;
2820 rects
->left
= pts
->x
;
2821 rects
->top
= pts
->y
;
2822 rects
->right
= pts
[1].x
;
2823 rects
->bottom
= pts
[1].y
+ 1;
2824 if (rects
->left
< extents
->left
)
2825 extents
->left
= rects
->left
;
2826 if (rects
->right
> extents
->right
)
2827 extents
->right
= rects
->right
;
2829 CurPtBlock
= CurPtBlock
->next
;
2834 extents
->top
= reg
->Buffer
->top
;
2835 extents
->bottom
= rects
->bottom
;
2842 extents
->bottom
= 0;
2844 reg
->rdh
.nCount
= numRects
;
2849 /***********************************************************************
2850 * REGION_CreateEdgeTable
2852 * This routine creates the edge table for
2853 * scan converting polygons.
2854 * The Edge Table (ET) looks like:
2858 * | ymax | ScanLineLists
2859 * |scanline|-->------------>-------------->...
2860 * -------- |scanline| |scanline|
2861 * |edgelist| |edgelist|
2862 * --------- ---------
2866 * list of ETEs list of ETEs
2868 * where ETE is an EdgeTableEntry data structure,
2869 * and there is one ScanLineList per scanline at
2870 * which an edge is initially entered.
2873 static void FASTCALL
2874 REGION_CreateETandAET(
2879 EdgeTableEntry
*AET
,
2880 EdgeTableEntry
*pETEs
,
2881 ScanLineListBlock
*pSLLBlock
2884 const POINT
*top
, *bottom
;
2885 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
2892 * initialize the Active Edge Table
2894 AET
->next
= (EdgeTableEntry
*)NULL
;
2895 AET
->back
= (EdgeTableEntry
*)NULL
;
2896 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2897 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
2900 * initialize the Edge Table.
2902 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
2903 ET
->ymax
= SMALL_COORDINATE
;
2904 ET
->ymin
= LARGE_COORDINATE
;
2905 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2908 for (poly
= 0; poly
< nbpolygons
; poly
++)
2910 count
= Count
[poly
];
2918 * for each vertex in the array of points.
2919 * In this loop we are dealing with two vertices at
2920 * a time -- these make up one edge of the polygon.
2927 * find out which point is above and which is below.
2929 if (PrevPt
->y
> CurrPt
->y
)
2931 bottom
= PrevPt
, top
= CurrPt
;
2932 pETEs
->ClockWise
= 0;
2936 bottom
= CurrPt
, top
= PrevPt
;
2937 pETEs
->ClockWise
= 1;
2941 * don't add horizontal edges to the Edge table.
2943 if (bottom
->y
!= top
->y
)
2945 pETEs
->ymax
= bottom
->y
-1;
2946 /* -1 so we don't get last scanline */
2949 * initialize integer edge algorithm
2951 dy
= bottom
->y
- top
->y
;
2952 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
2954 REGION_InsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
,
2957 if (PrevPt
->y
> ET
->ymax
)
2958 ET
->ymax
= PrevPt
->y
;
2959 if (PrevPt
->y
< ET
->ymin
)
2960 ET
->ymin
= PrevPt
->y
;
2970 IntCreatePolyPolygonRgn(
2979 EdgeTableEntry
*pAET
; /* Active Edge Table */
2980 INT y
; /* current scanline */
2981 int iPts
= 0; /* number of pts in buffer */
2982 EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry*/
2983 ScanLineList
*pSLL
; /* current scanLineList */
2984 POINT
*pts
; /* output buffer */
2985 EdgeTableEntry
*pPrevAET
; /* ptr to previous AET */
2986 EdgeTable ET
; /* header node for ET */
2987 EdgeTableEntry AET
; /* header node for AET */
2988 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
2989 ScanLineListBlock SLLBlock
; /* header for scanlinelist */
2990 int fixWAET
= FALSE
;
2991 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
2992 POINTBLOCK
*tmpPtBlock
;
2993 int numFullPtBlocks
= 0;
2996 if (mode
== 0 || mode
> 2) return 0;
2998 if (!(region
= REGION_AllocRgnWithHandle(nbpolygons
)))
3000 hrgn
= region
->BaseObject
.hHmgr
;
3002 /* special case a rectangle */
3004 if (((nbpolygons
== 1) && ((*Count
== 4) ||
3005 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
3006 (((Pts
[0].y
== Pts
[1].y
) &&
3007 (Pts
[1].x
== Pts
[2].x
) &&
3008 (Pts
[2].y
== Pts
[3].y
) &&
3009 (Pts
[3].x
== Pts
[0].x
)) ||
3010 ((Pts
[0].x
== Pts
[1].x
) &&
3011 (Pts
[1].y
== Pts
[2].y
) &&
3012 (Pts
[2].x
== Pts
[3].x
) &&
3013 (Pts
[3].y
== Pts
[0].y
))))
3015 RGNOBJAPI_Unlock(region
);
3016 NtGdiSetRectRgn(hrgn
, min(Pts
[0].x
, Pts
[2].x
), min(Pts
[0].y
, Pts
[2].y
),
3017 max(Pts
[0].x
, Pts
[2].x
), max(Pts
[0].y
, Pts
[2].y
));
3021 for (poly
= total
= 0; poly
< nbpolygons
; poly
++)
3022 total
+= Count
[poly
];
3023 if (! (pETEs
= ExAllocatePoolWithTag(PagedPool
, sizeof(EdgeTableEntry
) * total
, TAG_REGION
)) )
3025 GreDeleteObject(hrgn
);
3028 pts
= FirstPtBlock
.pts
;
3029 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
3030 pSLL
= ET
.scanlines
.next
;
3031 curPtBlock
= &FirstPtBlock
;
3033 if (mode
!= WINDING
)
3038 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3041 * Add a new edge to the active edge table when we
3042 * get to the next edge.
3044 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3046 REGION_loadAET(&AET
, pSLL
->edgelist
);
3053 * for each active edge
3057 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3061 * send out the buffer
3063 if (iPts
== NUMPTSTOBUFFER
)
3065 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
, sizeof(POINTBLOCK
), TAG_REGION
);
3068 DPRINT1("Can't alloc tPB\n");
3069 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3072 curPtBlock
->next
= tmpPtBlock
;
3073 curPtBlock
= tmpPtBlock
;
3074 pts
= curPtBlock
->pts
;
3078 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
3080 REGION_InsertionSort(&AET
);
3088 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++)
3091 * Add a new edge to the active edge table when we
3092 * get to the next edge.
3094 if (pSLL
!= NULL
&& y
== pSLL
->scanline
)
3096 REGION_loadAET(&AET
, pSLL
->edgelist
);
3097 REGION_computeWAET(&AET
);
3105 * for each active edge
3110 * add to the buffer only those edges that
3111 * are in the Winding active edge table.
3115 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3119 * send out the buffer
3121 if (iPts
== NUMPTSTOBUFFER
)
3123 tmpPtBlock
= ExAllocatePoolWithTag(PagedPool
,
3124 sizeof(POINTBLOCK
), TAG_REGION
);
3127 DPRINT1("Can't alloc tPB\n");
3128 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3129 GreDeleteObject(hrgn
);
3132 curPtBlock
->next
= tmpPtBlock
;
3133 curPtBlock
= tmpPtBlock
;
3134 pts
= curPtBlock
->pts
;
3138 pWETE
= pWETE
->nextWETE
;
3140 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
3144 * recompute the winding active edge table if
3145 * we just resorted or have exited an edge.
3147 if (REGION_InsertionSort(&AET
) || fixWAET
)
3149 REGION_computeWAET(&AET
);
3154 REGION_FreeStorage(SLLBlock
.next
);
3155 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, region
);
3157 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;)
3159 tmpPtBlock
= curPtBlock
->next
;
3160 ExFreePoolWithTag(curPtBlock
, TAG_REGION
);
3161 curPtBlock
= tmpPtBlock
;
3163 ExFreePoolWithTag(pETEs
, TAG_REGION
);
3164 RGNOBJAPI_Unlock(region
);
3169 // NtGdi Exported Functions
3173 NtGdiCombineRgn(HRGN hDest
,
3179 PROSRGNDATA destRgn
, src1Rgn
, src2Rgn
= NULL
;
3181 if ( CombineMode
> RGN_COPY
&& CombineMode
< RGN_AND
)
3183 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
3187 destRgn
= RGNOBJAPI_Lock(hDest
, NULL
);
3190 SetLastWin32Error(ERROR_INVALID_HANDLE
);
3194 src1Rgn
= RGNOBJAPI_Lock(hSrc1
, NULL
);
3197 RGNOBJAPI_Unlock(destRgn
);
3198 SetLastWin32Error(ERROR_INVALID_HANDLE
);
3203 src2Rgn
= RGNOBJAPI_Lock(hSrc2
, NULL
);
3205 result
= IntGdiCombineRgn( destRgn
, src1Rgn
, src2Rgn
, CombineMode
);
3208 RGNOBJAPI_Unlock(src2Rgn
);
3209 RGNOBJAPI_Unlock(src1Rgn
);
3210 RGNOBJAPI_Unlock(destRgn
);
3217 NtGdiCreateEllipticRgn(
3224 return NtGdiCreateRoundRectRgn(Left
, Top
, Right
, Bottom
,
3225 Right
- Left
, Bottom
- Top
);
3229 NtGdiCreateRectRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
3234 /* Allocate region data structure with space for 1 RECTL */
3235 if (!(pRgn
= REGION_AllocRgnWithHandle(1)))
3237 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3240 hRgn
= pRgn
->BaseObject
.hHmgr
;
3242 REGION_SetRectRgn(pRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3243 RGNOBJAPI_Unlock(pRgn
);
3250 NtGdiCreateRoundRectRgn(
3261 int asq
, bsq
, d
, xd
, yd
;
3264 /* Make the dimensions sensible */
3279 ellipse_width
= abs(ellipse_width
);
3280 ellipse_height
= abs(ellipse_height
);
3282 /* Check parameters */
3284 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
3285 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
3287 /* Check if we can do a normal rectangle instead */
3289 if ((ellipse_width
< 2) || (ellipse_height
< 2))
3290 return NtGdiCreateRectRgn(left
, top
, right
, bottom
);
3294 d
= (ellipse_height
< 128) ? ((3 * ellipse_height
) >> 2) : 64;
3295 if (!(obj
= REGION_AllocRgnWithHandle(d
))) return 0;
3296 hrgn
= obj
->BaseObject
.hHmgr
;
3298 /* Ellipse algorithm, based on an article by K. Porter */
3299 /* in DDJ Graphics Programming Column, 8/89 */
3301 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
3302 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
3303 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
3305 yd
= asq
* ellipse_height
; /* 2a^2b */
3307 rect
.left
= left
+ ellipse_width
/ 2;
3308 rect
.right
= right
- ellipse_width
/ 2;
3310 /* Loop to draw first half of quadrant */
3314 if (d
> 0) /* if nearest pixel is toward the center */
3316 /* move toward center */
3318 rect
.bottom
= rect
.top
+ 1;
3319 REGION_UnionRectWithRgn(obj
, &rect
);
3320 rect
.top
= --bottom
;
3321 rect
.bottom
= rect
.top
+ 1;
3322 REGION_UnionRectWithRgn(obj
, &rect
);
3326 rect
.left
--; /* next horiz point */
3331 /* Loop to draw second half of quadrant */
3333 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
3336 /* next vertical point */
3338 rect
.bottom
= rect
.top
+ 1;
3339 REGION_UnionRectWithRgn(obj
, &rect
);
3340 rect
.top
= --bottom
;
3341 rect
.bottom
= rect
.top
+ 1;
3342 REGION_UnionRectWithRgn(obj
, &rect
);
3343 if (d
< 0) /* if nearest pixel is outside ellipse */
3345 rect
.left
--; /* move away from center */
3353 /* Add the inside rectangle */
3358 rect
.bottom
= bottom
;
3359 REGION_UnionRectWithRgn(obj
, &rect
);
3362 RGNOBJAPI_Unlock(obj
);
3373 PROSRGNDATA rgn1
, rgn2
;
3374 PRECTL tRect1
, tRect2
;
3378 if ( !(rgn1
= RGNOBJAPI_Lock(hSrcRgn1
, NULL
)) )
3381 if ( !(rgn2
= RGNOBJAPI_Lock(hSrcRgn2
, NULL
)) )
3383 RGNOBJAPI_Unlock(rgn1
);
3387 if (rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
||
3388 rgn1
->rdh
.nCount
== 0 ||
3389 rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
||
3390 rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
||
3391 rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
||
3392 rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
)
3395 tRect1
= rgn1
->Buffer
;
3396 tRect2
= rgn2
->Buffer
;
3398 if (!tRect1
|| !tRect2
)
3401 for (i
=0; i
< rgn1
->rdh
.nCount
; i
++)
3403 if (tRect1
[i
].left
!= tRect2
[i
].left
||
3404 tRect1
[i
].right
!= tRect2
[i
].right
||
3405 tRect1
[i
].top
!= tRect2
[i
].top
||
3406 tRect1
[i
].bottom
!= tRect2
[i
].bottom
)
3412 RGNOBJAPI_Unlock(rgn1
);
3413 RGNOBJAPI_Unlock(rgn2
);
3419 NtGdiExtCreateRegion(
3420 OPTIONAL LPXFORM Xform
,
3430 NTSTATUS Status
= STATUS_SUCCESS
;
3433 DPRINT("NtGdiExtCreateRegion\n");
3436 ProbeForRead(RgnData
, Count
, 1);
3437 nCount
= RgnData
->rdh
.nCount
;
3438 iType
= RgnData
->rdh
.iType
;
3439 dwSize
= RgnData
->rdh
.dwSize
;
3441 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3443 Status
= _SEH2_GetExceptionCode();
3446 if (!NT_SUCCESS(Status
))
3448 SetLastNtError(Status
);
3452 /* Check parameters, but don't set last error here */
3453 if (Count
< sizeof(RGNDATAHEADER
) + nCount
* sizeof(RECT
) ||
3454 iType
!= RDH_RECTANGLES
||
3455 dwSize
!= sizeof(RGNDATAHEADER
))
3460 Region
= REGION_AllocRgnWithHandle(nCount
);
3464 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3467 hRgn
= Region
->BaseObject
.hHmgr
;
3475 /* Init the XFORMOBJ from the Xform struct */
3476 Status
= STATUS_INVALID_PARAMETER
;
3477 ret
= XFORMOBJ_iSetXform((XFORMOBJ
*)&matrix
, (XFORML
*)Xform
);
3479 /* Check for error, also no scale and shear allowed */
3480 if (ret
!= DDI_ERROR
&& ret
!= GX_GENERAL
)
3482 /* Apply the coordinate transformation on the rects */
3483 if (XFORMOBJ_bApplyXform((XFORMOBJ
*)&matrix
,
3489 Status
= STATUS_SUCCESS
;
3495 /* Copy rect coordinates */
3496 RtlCopyMemory(Region
->Buffer
,
3498 nCount
* sizeof(RECT
));
3501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3503 Status
= _SEH2_GetExceptionCode();
3506 if (!NT_SUCCESS(Status
))
3508 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
3509 RGNOBJAPI_Unlock(Region
);
3510 GreDeleteObject(hRgn
);
3514 RGNOBJAPI_Unlock(Region
);
3531 if (NULL
== (rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3536 if (NULL
== (oldhBrush
= NtGdiSelectBrush(hDC
, hBrush
)))
3538 RGNOBJAPI_Unlock(rgn
);
3542 for (r
= rgn
->Buffer
; r
< rgn
->Buffer
+ rgn
->rdh
.nCount
; r
++)
3544 NtGdiPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
3547 RGNOBJAPI_Unlock(rgn
);
3548 NtGdiSelectBrush(hDC
, oldhBrush
);
3566 if (!(FrameRgn
= NtGdiCreateRectRgn(0, 0, 0, 0)))
3570 if (!REGION_CreateFrameRgn(FrameRgn
, hRgn
, Width
, Height
))
3572 GreDeleteObject(FrameRgn
);
3576 Ret
= NtGdiFillRgn(hDC
, FrameRgn
, hBrush
);
3578 GreDeleteObject(FrameRgn
);
3583 /* See wine, msdn, osr and Feng Yuan - Windows Graphics Programming Win32 Gdi And Directdraw
3585 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
3587 The intersection of the clip with the meta region is not Rao it's API!
3588 Go back and read 7.2 Clipping pages 418-19:
3590 1) The Rao region is the intersection of the API region and the system region,
3591 named after the Microsoft engineer who initially proposed it.
3592 2) The Rao region can be calculated from the API region and the system region.
3595 API region is the intersection of the meta region and the clipping region,
3596 clearly named after the fact that it is controlled by GDI API calls.
3610 pDC
= DC_LockDc(hDC
);
3613 SetLastWin32Error(ERROR_INVALID_HANDLE
);
3620 hSrc
= pDC
->rosdc
.hClipRgn
;
3621 // if (pDC->dclevel.prgnClip) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.hHmgr;
3624 if (pDC
->dclevel
.prgnMeta
) hSrc
= ((PROSRGNDATA
)pDC
->dclevel
.prgnMeta
)->BaseObject
.hHmgr
;
3627 hSrc
= pDC
->rosdc
.hClipRgn
;
3628 // if (pDC->prgnAPI) hSrc = ((PROSRGNDATA)pDC->prgnAPI)->BaseObject.hHmgr;
3629 // else if (pDC->dclevel.prgnClip) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.hHmgr;
3630 // else if (pDC->dclevel.prgnMeta) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.hHmgr;
3633 hSrc
= pDC
->rosdc
.hVisRgn
;
3634 // if (pDC->prgnVis) hSrc = ((PROSRGNDATA)pDC->prgnVis)->BaseObject.hHmgr;
3641 if (NtGdiCombineRgn(hDest
, hSrc
, 0, RGN_COPY
) == ERROR
)
3650 if (iCode
== SYSRGN
)
3652 IntGdiGetDCOrg(pDC
, &org
);
3653 NtGdiOffsetRgn(hDest
, org
.x
, org
.y
);
3670 NTSTATUS Status
= STATUS_SUCCESS
;
3672 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3677 ret
= REGION_GetRgnBox(Rgn
, &SafeRect
);
3678 RGNOBJAPI_Unlock(Rgn
);
3686 ProbeForWrite(pRect
, sizeof(RECT
), 1);
3689 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3691 Status
= _SEH2_GetExceptionCode();
3694 if (!NT_SUCCESS(Status
))
3709 PROSRGNDATA RgnData
;
3713 if (!(RgnData
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3715 SetLastWin32Error(ERROR_INVALID_HANDLE
);
3719 rc
= RgnData
->Buffer
;
3720 for (i
= 0; i
< RgnData
->rdh
.nCount
; i
++)
3723 if (!NtGdiPatBlt(hDC
, rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, DSTINVERT
))
3725 RGNOBJAPI_Unlock(RgnData
);
3731 RGNOBJAPI_Unlock(RgnData
);
3743 PROSRGNDATA rgn
= RGNOBJAPI_Lock(hRgn
, NULL
);
3746 DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn
, XOffset
, YOffset
, rgn
);
3750 DPRINT("NtGdiOffsetRgn: hRgn error\n");
3754 if (XOffset
|| YOffset
)
3756 int nbox
= rgn
->rdh
.nCount
;
3757 PRECTL pbox
= rgn
->Buffer
;
3763 pbox
->left
+= XOffset
;
3764 pbox
->right
+= XOffset
;
3765 pbox
->top
+= YOffset
;
3766 pbox
->bottom
+= YOffset
;
3769 if (rgn
->Buffer
!= &rgn
->rdh
.rcBound
)
3771 rgn
->rdh
.rcBound
.left
+= XOffset
;
3772 rgn
->rdh
.rcBound
.right
+= XOffset
;
3773 rgn
->rdh
.rcBound
.top
+= YOffset
;
3774 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
3778 ret
= REGION_Complexity(rgn
);
3779 RGNOBJAPI_Unlock(rgn
);
3795 if (!(rgn
= RGNOBJAPI_Lock(hRgn
, NULL
) ) )
3798 if (rgn
->rdh
.nCount
> 0 && INRECT(rgn
->rdh
.rcBound
, X
, Y
))
3801 for (i
= 0; i
< rgn
->rdh
.nCount
; i
++)
3803 if (INRECT(*r
, X
, Y
))
3805 RGNOBJAPI_Unlock(rgn
);
3811 RGNOBJAPI_Unlock(rgn
);
3825 NTSTATUS Status
= STATUS_SUCCESS
;
3827 if (!(Rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)))
3834 ProbeForRead(unsaferc
, sizeof(RECT
), 1);
3837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3839 Status
= _SEH2_GetExceptionCode();
3843 if (!NT_SUCCESS(Status
))
3845 RGNOBJAPI_Unlock(Rgn
);
3846 SetLastNtError(Status
);
3847 DPRINT1("NtGdiRectInRegion: bogus rc\n");
3851 Ret
= REGION_RectInRegion(Rgn
, &rc
);
3852 RGNOBJAPI_Unlock(Rgn
);
3868 if ( !(rgn
= RGNOBJAPI_Lock(hRgn
, NULL
)) )
3870 return 0; //per documentation
3873 REGION_SetRectRgn(rgn
, LeftRect
, TopRect
, RightRect
, BottomRect
);
3875 RGNOBJAPI_Unlock(rgn
);
3880 NtGdiUnionRectWithRgn(
3882 const RECTL
*UnsafeRect
3885 RECTL SafeRect
= {0};
3887 NTSTATUS Status
= STATUS_SUCCESS
;
3889 if (!(Rgn
= RGNOBJAPI_Lock(hDest
, NULL
)))
3891 SetLastWin32Error(ERROR_INVALID_HANDLE
);
3897 ProbeForRead(UnsafeRect
, sizeof(RECT
), 1);
3898 SafeRect
= *UnsafeRect
;
3900 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3902 Status
= _SEH2_GetExceptionCode();
3906 if (! NT_SUCCESS(Status
))
3908 RGNOBJAPI_Unlock(Rgn
);
3909 SetLastNtError(Status
);
3913 REGION_UnionRectWithRgn(Rgn
, &SafeRect
);
3914 RGNOBJAPI_Unlock(Rgn
);
3919 * MSDN: GetRegionData, Return Values:
3921 * "If the function succeeds and dwCount specifies an adequate number of bytes,
3922 * the return value is always dwCount. If dwCount is too small or the function
3923 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
3924 * required number of bytes.
3926 * If the function fails, the return value is zero."
3936 PROSRGNDATA obj
= RGNOBJAPI_Lock(hrgn
, NULL
);
3937 NTSTATUS Status
= STATUS_SUCCESS
;
3942 size
= obj
->rdh
.nCount
* sizeof(RECT
);
3943 if (count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
3945 RGNOBJAPI_Unlock(obj
);
3946 if (rgndata
) /* buffer is too small, signal it by return 0 */
3948 else /* user requested buffer size with rgndata NULL */
3949 return size
+ sizeof(RGNDATAHEADER
);
3954 ProbeForWrite(rgndata
, count
, 1);
3955 RtlCopyMemory(rgndata
, &obj
->rdh
, sizeof(RGNDATAHEADER
));
3956 RtlCopyMemory(rgndata
->Buffer
, obj
->Buffer
, size
);
3958 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3960 Status
= _SEH2_GetExceptionCode();
3964 if (!NT_SUCCESS(Status
))
3966 SetLastNtError(Status
);
3967 RGNOBJAPI_Unlock(obj
);
3971 RGNOBJAPI_Unlock(obj
);
3972 return size
+ sizeof(RGNDATAHEADER
);