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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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...
118 #include <win32k/float.h>
123 // Internal Functions
126 #define COPY_RECTS(dest, src, nRects) \
128 PRECT xDest = (dest); \
129 PRECT xSrc = (src); \
130 UINT xRects = (nRects); \
131 while(xRects-- > 0) { \
132 *(xDest++) = *(xSrc++); \
136 #define COPY_RECTS(dest, src, nRects) RtlCopyMemory(dest, src, (nRects) * sizeof(RECT))
139 #define EMPTY_REGION(pReg) { \
140 (pReg)->rdh.nCount = 0; \
141 (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
142 (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
143 (pReg)->rdh.iType = NULLREGION; \
146 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
148 #define INRECT(r, x, y) \
149 ( ( ((r).right > x)) && \
150 ( ((r).left <= x)) && \
151 ( ((r).bottom > y)) && \
154 /* 1 if two RECTs overlap.
155 * 0 if two RECTs do not overlap.
157 #define EXTENTCHECK(r1, r2) \
158 ((r1)->right > (r2)->left && \
159 (r1)->left < (r2)->right && \
160 (r1)->bottom > (r2)->top && \
161 (r1)->top < (r2)->bottom)
164 * In scan converting polygons, we want to choose those pixels
165 * which are inside the polygon. Thus, we add .5 to the starting
166 * x coordinate for both left and right edges. Now we choose the
167 * first pixel which is inside the pgon for the left edge and the
168 * first pixel which is outside the pgon for the right edge.
169 * Draw the left pixel, but not the right.
171 * How to add .5 to the starting x coordinate:
172 * If the edge is moving to the right, then subtract dy from the
173 * error term from the general form of the algorithm.
174 * If the edge is moving to the left, then add dy to the error term.
176 * The reason for the difference between edges moving to the left
177 * and edges moving to the right is simple: If an edge is moving
178 * to the right, then we want the algorithm to flip immediately.
179 * If it is moving to the left, then we don't want it to flip until
180 * we traverse an entire pixel.
182 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
183 int dx; /* local storage */ \
186 * if the edge is horizontal, then it is ignored \
187 * and assumed not to be processed. Otherwise, do this stuff. \
191 dx = (x2) - xStart; \
195 incr1 = -2 * dx + 2 * (dy) * m1; \
196 incr2 = -2 * dx + 2 * (dy) * m; \
197 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
201 incr1 = 2 * dx - 2 * (dy) * m1; \
202 incr2 = 2 * dx - 2 * (dy) * m; \
203 d = -2 * m * (dy) + 2 * dx; \
208 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
231 * This structure contains all of the information needed
232 * to run the bresenham algorithm.
233 * The variables may be hardcoded into the declarations
234 * instead of using this structure to make use of
235 * register declarations.
238 INT minor_axis
; /* minor axis */
239 INT d
; /* decision variable */
240 INT m
, m1
; /* slope and slope+1 */
241 INT incr1
, incr2
; /* error increments */
245 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
246 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
247 bres.m, bres.m1, bres.incr1, bres.incr2)
249 #define BRESINCRPGONSTRUCT(bres) \
250 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
255 * These are the data structures needed to scan
256 * convert regions. Two different scan conversion
257 * methods are available -- the even-odd method, and
258 * the winding number method.
259 * The even-odd rule states that a point is inside
260 * the polygon if a ray drawn from that point in any
261 * direction will pass through an odd number of
263 * By the winding number rule, a point is decided
264 * to be inside the polygon if a ray drawn from that
265 * point in any direction passes through a different
266 * number of clockwise and counter-clockwise path
269 * These data structures are adapted somewhat from
270 * the algorithm in (Foley/Van Dam) for scan converting
272 * The basic algorithm is to start at the top (smallest y)
273 * of the polygon, stepping down to the bottom of
274 * the polygon by incrementing the y coordinate. We
275 * keep a list of edges which the current scanline crosses,
276 * sorted by x. This list is called the Active Edge Table (AET)
277 * As we change the y-coordinate, we update each entry in
278 * in the active edge table to reflect the edges new xcoord.
279 * This list must be sorted at each scanline in case
280 * two edges intersect.
281 * We also keep a data structure known as the Edge Table (ET),
282 * which keeps track of all the edges which the current
283 * scanline has not yet reached. The ET is basically a
284 * list of ScanLineList structures containing a list of
285 * edges which are entered at a given scanline. There is one
286 * ScanLineList per scanline at which an edge is entered.
287 * When we enter a new edge, we move it from the ET to the AET.
289 * From the AET, we can implement the even-odd rule as in
291 * The winding number rule is a little trickier. We also
292 * keep the EdgeTableEntries in the AET linked by the
293 * nextWETE (winding EdgeTableEntry) link. This allows
294 * the edges to be linked just as before for updating
295 * purposes, but only uses the edges linked by the nextWETE
296 * link as edges representing spans of the polygon to
297 * drawn (as with the even-odd rule).
301 * for the winding number rule
304 #define COUNTERCLOCKWISE -1
306 typedef struct _EdgeTableEntry
{
307 INT ymax
; /* ycoord at which we exit this edge. */
308 BRESINFO bres
; /* Bresenham info to run the edge */
309 struct _EdgeTableEntry
*next
; /* next in the list */
310 struct _EdgeTableEntry
*back
; /* for insertion sort */
311 struct _EdgeTableEntry
*nextWETE
; /* for winding num rule */
312 int ClockWise
; /* flag for winding number rule */
316 typedef struct _ScanLineList
{
317 INT scanline
; /* the scanline represented */
318 EdgeTableEntry
*edgelist
; /* header node */
319 struct _ScanLineList
*next
; /* next in the list */
324 INT ymax
; /* ymax for the polygon */
325 INT ymin
; /* ymin for the polygon */
326 ScanLineList scanlines
; /* header node */
331 * Here is a struct to help with storage allocation
332 * so we can allocate a big chunk at a time, and then take
333 * pieces from this heap when we need to.
335 #define SLLSPERBLOCK 25
337 typedef struct _ScanLineListBlock
{
338 ScanLineList SLLs
[SLLSPERBLOCK
];
339 struct _ScanLineListBlock
*next
;
345 * a few macros for the inner loops of the fill code where
346 * performance considerations don't allow a procedure call.
348 * Evaluate the given edge at the given scanline.
349 * If the edge has expired, then we leave it and fix up
350 * the active edge table; otherwise, we increment the
351 * x value to be ready for the next scanline.
352 * The winding number rule is in effect, so we must notify
353 * the caller when the edge has been removed so he
354 * can reorder the Winding Active Edge Table.
356 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
357 if (pAET->ymax == y) { /* leaving this edge */ \
358 pPrevAET->next = pAET->next; \
359 pAET = pPrevAET->next; \
362 pAET->back = pPrevAET; \
365 BRESINCRPGONSTRUCT(pAET->bres); \
373 * Evaluate the given edge at the given scanline.
374 * If the edge has expired, then we leave it and fix up
375 * the active edge table; otherwise, we increment the
376 * x value to be ready for the next scanline.
377 * The even-odd rule is in effect.
379 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
380 if (pAET->ymax == y) { /* leaving this edge */ \
381 pPrevAET->next = pAET->next; \
382 pAET = pPrevAET->next; \
384 pAET->back = pPrevAET; \
387 BRESINCRPGONSTRUCT(pAET->bres); \
393 /**************************************************************************
397 *************************************************************************/
399 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
400 #define SMALL_COORDINATE 0x80000000
403 * Check to see if there is enough memory in the present region.
405 static inline int xmemcheck(ROSRGNDATA
*reg
, PRECT
*rect
, PRECT
*firstrect
) {
406 if ( (reg
->rdh
.nCount
+1)*sizeof( RECT
) >= reg
->rdh
.nRgnSize
) {
408 temp
= ExAllocatePoolWithTag( PagedPool
, (2 * (reg
->rdh
.nRgnSize
)), TAG_REGION
);
413 /* copy the rectangles */
414 COPY_RECTS(temp
, *firstrect
, reg
->rdh
.nCount
);
416 reg
->rdh
.nRgnSize
*= 2;
417 if (*firstrect
!= ®
->rdh
.rcBound
)
418 ExFreePool( *firstrect
);
420 *rect
= (*firstrect
)+reg
->rdh
.nCount
;
425 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(LPRECT *)&(firstrect))
427 typedef void FASTCALL (*overlapProcp
)(PROSRGNDATA
, PRECT
, PRECT
, PRECT
, PRECT
, INT
, INT
);
428 typedef void FASTCALL (*nonOverlapProcp
)(PROSRGNDATA
, PRECT
, PRECT
, INT
, INT
);
430 // Number of points to buffer before sending them off to scanlines() : Must be an even number
431 #define NUMPTSTOBUFFER 200
433 #define RGN_DEFAULT_RECTS 2
435 // used to allocate buffers for points and link the buffers together
437 typedef struct _POINTBLOCK
{
438 POINT pts
[NUMPTSTOBUFFER
];
439 struct _POINTBLOCK
*next
;
444 * This function is left there for debugging purposes.
448 IntDumpRegion(HRGN hRgn
)
452 Data
= RGNDATA_LockRgn(hRgn
);
455 DbgPrint("IntDumpRegion called with invalid region!\n");
459 DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
461 Data
->rdh
.rcBound
.left
,
462 Data
->rdh
.rcBound
.top
,
463 Data
->rdh
.rcBound
.right
,
464 Data
->rdh
.rcBound
.bottom
,
467 RGNDATA_UnlockRgn(Data
);
471 static BOOL FASTCALL
REGION_CopyRegion(PROSRGNDATA dst
, PROSRGNDATA src
)
473 if(dst
!= src
) // don't want to copy to itself
475 if (dst
->rdh
.nRgnSize
< src
->rdh
.nCount
* sizeof(RECT
))
479 temp
= ExAllocatePoolWithTag(PagedPool
, src
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
483 if( dst
->Buffer
&& dst
->Buffer
!= &dst
->rdh
.rcBound
)
484 ExFreePool( dst
->Buffer
); //free the old buffer
486 dst
->rdh
.nRgnSize
= src
->rdh
.nCount
* sizeof(RECT
); //size of region buffer
488 dst
->rdh
.nCount
= src
->rdh
.nCount
; //number of rectangles present in Buffer
489 dst
->rdh
.rcBound
.left
= src
->rdh
.rcBound
.left
;
490 dst
->rdh
.rcBound
.top
= src
->rdh
.rcBound
.top
;
491 dst
->rdh
.rcBound
.right
= src
->rdh
.rcBound
.right
;
492 dst
->rdh
.rcBound
.bottom
= src
->rdh
.rcBound
.bottom
;
493 dst
->rdh
.iType
= src
->rdh
.iType
;
494 COPY_RECTS(dst
->Buffer
, src
->Buffer
, src
->rdh
.nCount
);
499 static void FASTCALL
REGION_SetExtents (ROSRGNDATA
*pReg
)
501 RECT
*pRect
, *pRectEnd
, *pExtents
;
503 if (pReg
->rdh
.nCount
== 0)
505 pReg
->rdh
.rcBound
.left
= 0;
506 pReg
->rdh
.rcBound
.top
= 0;
507 pReg
->rdh
.rcBound
.right
= 0;
508 pReg
->rdh
.rcBound
.bottom
= 0;
509 pReg
->rdh
.iType
= NULLREGION
;
513 pExtents
= &pReg
->rdh
.rcBound
;
514 pRect
= (PRECT
)pReg
->Buffer
;
515 pRectEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
- 1;
518 * Since pRect is the first rectangle in the region, it must have the
519 * smallest top and since pRectEnd is the last rectangle in the region,
520 * it must have the largest bottom, because of banding. Initialize left and
521 * right from pRect and pRectEnd, resp., as good things to initialize them
524 pExtents
->left
= pRect
->left
;
525 pExtents
->top
= pRect
->top
;
526 pExtents
->right
= pRectEnd
->right
;
527 pExtents
->bottom
= pRectEnd
->bottom
;
529 while (pRect
<= pRectEnd
)
531 if (pRect
->left
< pExtents
->left
)
532 pExtents
->left
= pRect
->left
;
533 if (pRect
->right
> pExtents
->right
)
534 pExtents
->right
= pRect
->right
;
537 pReg
->rdh
.iType
= (1 == pReg
->rdh
.nCount
? SIMPLEREGION
: COMPLEXREGION
);
541 /***********************************************************************
542 * REGION_CropAndOffsetRegion
544 static BOOL FASTCALL
REGION_CropAndOffsetRegion(const PPOINT off
, const PRECT rect
, PROSRGNDATA rgnSrc
, PROSRGNDATA rgnDst
)
546 if(!rect
) // just copy and offset
552 xrect
= (PRECT
)rgnDst
->Buffer
;
557 xrect
= ExAllocatePoolWithTag(PagedPool
, rgnSrc
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
558 if( rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
559 ExFreePool( rgnDst
->Buffer
); //free the old buffer. will be assigned to xrect below.
573 for(i
= 0; i
< rgnDst
->rdh
.nCount
; i
++)
575 xrect
[i
].left
= ((PRECT
)rgnSrc
->Buffer
+ i
)->left
+ off
->x
;
576 xrect
[i
].right
= ((PRECT
)rgnSrc
->Buffer
+ i
)->right
+ off
->x
;
577 xrect
[i
].top
= ((PRECT
)rgnSrc
->Buffer
+ i
)->top
+ off
->y
;
578 xrect
[i
].bottom
= ((PRECT
)rgnSrc
->Buffer
+ i
)->bottom
+ off
->y
;
580 rgnDst
->rdh
.rcBound
.left
+= off
->x
;
581 rgnDst
->rdh
.rcBound
.right
+= off
->x
;
582 rgnDst
->rdh
.rcBound
.top
+= off
->y
;
583 rgnDst
->rdh
.rcBound
.bottom
+= off
->y
;
587 COPY_RECTS(xrect
, rgnSrc
->Buffer
, rgnDst
->rdh
.nCount
);
590 rgnDst
->Buffer
= xrect
;
594 else if ((rect
->left
>= rect
->right
) ||
595 (rect
->top
>= rect
->bottom
) ||
596 !EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
))
600 else // region box and clipping rect appear to intersect
603 ULONG i
, j
, clipa
, clipb
;
604 INT left
= rgnSrc
->rdh
.rcBound
.right
+ off
->x
;
605 INT right
= rgnSrc
->rdh
.rcBound
.left
+ off
->x
;
607 for(clipa
= 0; ((PRECT
)rgnSrc
->Buffer
+ clipa
)->bottom
<= rect
->top
; clipa
++)
608 //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
609 ; // skip bands above the clipping rectangle
611 for(clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
612 if(((PRECT
)rgnSrc
->Buffer
+ clipb
)->top
>= rect
->bottom
)
613 break; // and below it
615 // clipa - index of the first rect in the first intersecting band
616 // clipb - index of the last rect in the last intersecting band
618 if((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nCount
< (i
= (clipb
- clipa
))))
621 temp
= ExAllocatePoolWithTag( PagedPool
, i
* sizeof(RECT
), TAG_REGION
);
625 if( rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
626 ExFreePool( rgnDst
->Buffer
); //free the old buffer
627 rgnDst
->Buffer
= temp
;
628 rgnDst
->rdh
.nCount
= i
;
629 rgnDst
->rdh
.nRgnSize
= i
* sizeof(RECT
);
632 for(i
= clipa
, j
= 0; i
< clipb
; i
++)
634 // i - src index, j - dst index, j is always <= i for obvious reasons
636 lpr
= (PRECT
)rgnSrc
->Buffer
+ i
;
638 if(lpr
->left
< rect
->right
&& lpr
->right
> rect
->left
)
640 rpr
= (PRECT
)rgnDst
->Buffer
+ j
;
642 rpr
->top
= lpr
->top
+ off
->y
;
643 rpr
->bottom
= lpr
->bottom
+ off
->y
;
644 rpr
->left
= ((lpr
->left
> rect
->left
) ? lpr
->left
: rect
->left
) + off
->x
;
645 rpr
->right
= ((lpr
->right
< rect
->right
) ? lpr
->right
: rect
->right
) + off
->x
;
647 if(rpr
->left
< left
) left
= rpr
->left
;
648 if(rpr
->right
> right
) right
= rpr
->right
;
654 if(j
== 0) goto empty
;
656 rgnDst
->rdh
.rcBound
.left
= left
;
657 rgnDst
->rdh
.rcBound
.right
= right
;
659 left
= rect
->top
+ off
->y
;
660 right
= rect
->bottom
+ off
->y
;
662 rgnDst
->rdh
.nCount
= j
--;
663 for(i
= 0; i
<= j
; i
++) // fixup top band
664 if((rgnDst
->Buffer
+ i
)->top
< left
)
665 (rgnDst
->Buffer
+ i
)->top
= left
;
669 for(i
= j
; i
>= 0; i
--) // fixup bottom band
670 if(((PRECT
)rgnDst
->Buffer
+ i
)->bottom
> right
)
671 ((PRECT
)rgnDst
->Buffer
+ i
)->bottom
= right
;
675 rgnDst
->rdh
.rcBound
.top
= ((PRECT
)rgnDst
->Buffer
)->top
;
676 rgnDst
->rdh
.rcBound
.bottom
= ((PRECT
)rgnDst
->Buffer
+ j
)->bottom
;
678 rgnDst
->rdh
.iType
= (j
>= 1) ? COMPLEXREGION
: SIMPLEREGION
;
686 rgnDst
->Buffer
= (PRECT
)ExAllocatePoolWithTag(PagedPool
, RGN_DEFAULT_RECTS
* sizeof(RECT
), TAG_REGION
);
688 rgnDst
->rdh
.nCount
= RGN_DEFAULT_RECTS
;
689 rgnDst
->rdh
.nRgnSize
= RGN_DEFAULT_RECTS
* sizeof(RECT
);
694 EMPTY_REGION(rgnDst
);
700 * hSrc: Region to crop and offset.
701 * lpRect: Clipping rectangle. Can be NULL (no clipping).
702 * lpPt: Points to offset the cropped region. Can be NULL (no offset).
704 * hDst: Region to hold the result (a new region is created if it's 0).
705 * Allowed to be the same region as hSrc in which case everything
706 * will be done in place, with no memory reallocations.
708 * \return hDst if success, 0 otherwise.
710 HRGN FASTCALL
REGION_CropRgn(HRGN hDst
, HRGN hSrc
, const PRECT lpRect
, PPOINT lpPt
)
712 PROSRGNDATA objSrc
, rgnDst
;
718 if( !( hDst
= RGNDATA_AllocRgn(1) ) )
724 rgnDst
= RGNDATA_LockRgn(hDst
);
730 objSrc
= RGNDATA_LockRgn(hSrc
);
733 RGNDATA_UnlockRgn(rgnDst
);
739 if(REGION_CropAndOffsetRegion(lpPt
, lpRect
, objSrc
, rgnDst
) == FALSE
)
740 { // ve failed cleanup and return
743 else{ // ve are fine. unlock the correct pointer and return correct handle
747 RGNDATA_UnlockRgn(objSrc
);
748 RGNDATA_UnlockRgn(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.
767 static INT FASTCALL
REGION_Coalesce (
768 PROSRGNDATA pReg
, /* Region to coalesce */
769 INT prevStart
, /* Index of start of previous band */
770 INT curStart
/* Index of start of current band */
772 RECT
*pPrevRect
; /* Current rect in previous band */
773 RECT
*pCurRect
; /* Current rect in current band */
774 RECT
*pRegEnd
; /* End of region */
775 INT curNumRects
; /* Number of rectangles in current band */
776 INT prevNumRects
; /* Number of rectangles in previous band */
777 INT bandtop
; /* top coordinate for current band */
779 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
780 pPrevRect
= (PRECT
)pReg
->Buffer
+ prevStart
;
781 prevNumRects
= curStart
- prevStart
;
784 * Figure out how many rectangles are in the current band. Have to do
785 * this because multiple bands could have been added in REGION_RegionOp
786 * at the end when one region has been exhausted.
788 pCurRect
= (PRECT
)pReg
->Buffer
+ curStart
;
789 bandtop
= pCurRect
->top
;
790 for (curNumRects
= 0;
791 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
797 if (pCurRect
!= pRegEnd
)
800 * If more than one band was added, we have to find the start
801 * of the last band added so the next coalescing job can start
802 * at the right place... (given when multiple bands are added,
803 * this may be pointless -- see above).
806 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
810 curStart
= pRegEnd
- (PRECT
)pReg
->Buffer
;
811 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
814 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0)) {
815 pCurRect
-= curNumRects
;
817 * The bands may only be coalesced if the bottom of the previous
818 * matches the top scanline of the current.
820 if (pPrevRect
->bottom
== pCurRect
->top
)
823 * Make sure the bands have rects in the same places. This
824 * assumes that rects have been added in such a way that they
825 * cover the most area possible. I.e. two rects in a band must
826 * have some horizontal space between them.
830 if ((pPrevRect
->left
!= pCurRect
->left
) ||
831 (pPrevRect
->right
!= pCurRect
->right
))
834 * 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
;
858 } while (curNumRects
!= 0);
861 * If only one band was added to the region, we have to backup
862 * curStart to the start of the previous band.
864 * If more than one band was added to the region, copy the
865 * other bands down. The assumption here is that the other bands
866 * came from the same region as the current one and no further
867 * coalescing can be done on them since it's all been done
868 * already... curStart is already in the right place.
870 if (pCurRect
== pRegEnd
)
872 curStart
= prevStart
;
878 *pPrevRect
++ = *pCurRect
++;
879 } while (pCurRect
!= pRegEnd
);
887 * Apply an operation to two regions. Called by REGION_Union,
888 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
894 * The new region is overwritten.
896 *\note The idea behind this function is to view the two regions as sets.
897 * Together they cover a rectangle of area that this function divides
898 * into horizontal bands where points are covered only by one region
899 * or by both. For the first case, the nonOverlapFunc is called with
900 * each the band and the band's upper and lower extents. For the
901 * second, the overlapFunc is called to process the entire band. It
902 * is responsible for clipping the rectangles in the band, though
903 * this function provides the boundaries.
904 * At the end of each band, the new region is coalesced, if possible,
905 * to reduce the number of rectangles in the region.
910 ROSRGNDATA
*newReg
, /* Place to store result */
911 ROSRGNDATA
*reg1
, /* First region in operation */
912 ROSRGNDATA
*reg2
, /* 2nd region in operation */
913 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
914 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
915 nonOverlapProcp nonOverlap2Func
/* Function to call for non-overlapping bands in region 2 */
918 RECT
*r1
; /* Pointer into first region */
919 RECT
*r2
; /* Pointer into 2d region */
920 RECT
*r1End
; /* End of 1st region */
921 RECT
*r2End
; /* End of 2d region */
922 INT ybot
; /* Bottom of intersection */
923 INT ytop
; /* Top of intersection */
924 RECT
*oldRects
; /* Old rects for newReg */
925 ULONG prevBand
; /* Index of start of
926 * previous band in newReg */
927 ULONG curBand
; /* Index of start of current band in newReg */
928 RECT
*r1BandEnd
; /* End of current band in r1 */
929 RECT
*r2BandEnd
; /* End of current band in r2 */
930 ULONG top
; /* Top of non-overlapping band */
931 ULONG bot
; /* Bottom of non-overlapping band */
935 * set r1, r2, r1End and r2End appropriately, preserve the important
936 * parts of the destination region until the end in case it's one of
937 * the two source regions, then mark the "new" region empty, allocating
938 * another array of rectangles for it to use.
940 r1
= (PRECT
)reg1
->Buffer
;
941 r2
= (PRECT
)reg2
->Buffer
;
942 r1End
= r1
+ reg1
->rdh
.nCount
;
943 r2End
= r2
+ reg2
->rdh
.nCount
;
947 * newReg may be one of the src regions so we can't empty it. We keep a
948 * note of its rects pointer (so that we can free them later), preserve its
949 * extents and simply set numRects to zero.
952 oldRects
= (PRECT
)newReg
->Buffer
;
953 newReg
->rdh
.nCount
= 0;
956 * Allocate a reasonable number of rectangles for the new region. The idea
957 * is to allocate enough so the individual functions don't need to
958 * reallocate and copy the array, which is time consuming, yet we don't
959 * have to worry about using too much memory. I hope to be able to
960 * nuke the Xrealloc() at the end of this function eventually.
962 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
,reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
964 if (! (newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, newReg
->rdh
.nRgnSize
, TAG_REGION
)))
966 newReg
->rdh
.nRgnSize
= 0;
971 * Initialize ybot and ytop.
972 * In the upcoming loop, ybot and ytop serve different functions depending
973 * on whether the band being handled is an overlapping or non-overlapping
975 * In the case of a non-overlapping band (only one of the regions
976 * has points in the band), ybot is the bottom of the most recent
977 * intersection and thus clips the top of the rectangles in that band.
978 * ytop is the top of the next intersection between the two regions and
979 * serves to clip the bottom of the rectangles in the current band.
980 * For an overlapping band (where the two regions intersect), ytop clips
981 * the top of the rectangles of both regions and ybot clips the bottoms.
983 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
984 ybot
= reg1
->rdh
.rcBound
.top
;
986 ybot
= reg2
->rdh
.rcBound
.top
;
989 * prevBand serves to mark the start of the previous band so rectangles
990 * can be coalesced into larger rectangles. qv. miCoalesce, above.
991 * In the beginning, there is no previous band, so prevBand == curBand
992 * (curBand is set later on, of course, but the first band will always
993 * start at index 0). prevBand and curBand must be indices because of
994 * the possible expansion, and resultant moving, of the new region's
995 * array of rectangles.
1001 curBand
= newReg
->rdh
.nCount
;
1004 * This algorithm proceeds one source-band (as opposed to a
1005 * destination band, which is determined by where the two regions
1006 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1007 * rectangle after the last one in the current band for their
1008 * respective regions.
1011 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1017 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1023 * First handle the band that doesn't intersect, if any.
1025 * Note that attention is restricted to one band in the
1026 * non-intersecting region at once, so if a region has n
1027 * bands between the current position and the next place it overlaps
1028 * the other, this entire loop will be passed through n times.
1030 if (r1
->top
< r2
->top
)
1032 top
= max(r1
->top
,ybot
);
1033 bot
= min(r1
->bottom
,r2
->top
);
1035 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
1037 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
1042 else if (r2
->top
< r1
->top
)
1044 top
= max(r2
->top
,ybot
);
1045 bot
= min(r2
->bottom
,r1
->top
);
1047 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
1049 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
1060 * If any rectangles got added to the region, try and coalesce them
1061 * with rectangles from the previous band. Note we could just do
1062 * this test in miCoalesce, but some machines incur a not
1063 * inconsiderable cost for function calls, so...
1065 if (newReg
->rdh
.nCount
!= curBand
)
1067 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1071 * Now see if we've hit an intersecting band. The two bands only
1072 * intersect if ybot > ytop
1074 ybot
= min(r1
->bottom
, r2
->bottom
);
1075 curBand
= newReg
->rdh
.nCount
;
1078 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1081 if (newReg
->rdh
.nCount
!= curBand
)
1083 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1087 * If we've finished with a band (bottom == ybot) we skip forward
1088 * in the region to the next band.
1090 if (r1
->bottom
== ybot
)
1094 if (r2
->bottom
== ybot
)
1098 } while ((r1
!= r1End
) && (r2
!= r2End
));
1101 * Deal with whichever region still has rectangles left.
1103 curBand
= newReg
->rdh
.nCount
;
1106 if (nonOverlap1Func
!= NULL
)
1111 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1115 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
1116 max(r1
->top
,ybot
), r1
->bottom
);
1118 } while (r1
!= r1End
);
1121 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
1126 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1130 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
1131 max(r2
->top
,ybot
), r2
->bottom
);
1133 } while (r2
!= r2End
);
1136 if (newReg
->rdh
.nCount
!= curBand
)
1138 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
1142 * A bit of cleanup. To keep regions from growing without bound,
1143 * we shrink the array of rectangles to match the new number of
1144 * rectangles in the region. This never goes to 0, however...
1146 * Only do this stuff if the number of rectangles allocated is more than
1147 * twice the number of rectangles in the region (a simple optimization...).
1149 if ((2 * newReg
->rdh
.nCount
*sizeof(RECT
) < newReg
->rdh
.nRgnSize
&& (newReg
->rdh
.nCount
> 2)))
1151 if (REGION_NOT_EMPTY(newReg
))
1153 RECT
*prev_rects
= (PRECT
)newReg
->Buffer
;
1154 newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, newReg
->rdh
.nCount
*sizeof(RECT
), TAG_REGION
);
1156 if (! newReg
->Buffer
)
1157 newReg
->Buffer
= prev_rects
;
1159 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
1160 COPY_RECTS(newReg
->Buffer
, prev_rects
, newReg
->rdh
.nCount
);
1161 if (prev_rects
!= &newReg
->rdh
.rcBound
)
1162 ExFreePool( prev_rects
);
1168 * No point in doing the extra work involved in an Xrealloc if
1169 * the region is empty
1171 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
1172 if (newReg
->Buffer
!= &newReg
->rdh
.rcBound
)
1173 ExFreePool( newReg
->Buffer
);
1174 newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, sizeof(RECT
), TAG_REGION
);
1175 ASSERT( newReg
->Buffer
);
1179 if( newReg
->rdh
.nCount
== 0 )
1180 newReg
->rdh
.iType
= NULLREGION
;
1182 newReg
->rdh
.iType
= (newReg
->rdh
.nCount
> 1)? COMPLEXREGION
: SIMPLEREGION
;
1184 if (oldRects
!= &newReg
->rdh
.rcBound
)
1185 ExFreePool( oldRects
);
1189 /***********************************************************************
1190 * Region Intersection
1191 ***********************************************************************/
1195 * Handle an overlapping band for REGION_Intersect.
1200 * \note Side Effects:
1201 * Rectangles may be added to the region.
1204 static void FASTCALL
1218 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1220 while ((r1
!= r1End
) && (r2
!= r2End
))
1222 left
= max(r1
->left
, r2
->left
);
1223 right
= min(r1
->right
, r2
->right
);
1226 * If there's any overlap between the two rectangles, add that
1227 * overlap to the new region.
1228 * There's no need to check for subsumption because the only way
1229 * such a need could arise is if some region has two rectangles
1230 * right next to each other. Since that should never happen...
1234 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1235 pNextRect
->left
= left
;
1236 pNextRect
->top
= top
;
1237 pNextRect
->right
= right
;
1238 pNextRect
->bottom
= bottom
;
1239 pReg
->rdh
.nCount
+= 1;
1244 * Need to advance the pointers. Shift the one that extends
1245 * to the right the least, since the other still has a chance to
1246 * overlap with that region's next rectangle, if you see what I mean.
1248 if (r1
->right
< r2
->right
)
1252 else if (r2
->right
< r1
->right
)
1265 /***********************************************************************
1266 * REGION_IntersectRegion
1268 static void FASTCALL
REGION_IntersectRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
1271 /* check for trivial reject */
1272 if ( (!(reg1
->rdh
.nCount
)) || (!(reg2
->rdh
.nCount
)) ||
1273 (!EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
)))
1274 newReg
->rdh
.nCount
= 0;
1276 REGION_RegionOp (newReg
, reg1
, reg2
,
1277 REGION_IntersectO
, NULL
, NULL
);
1280 * Can't alter newReg's extents before we call miRegionOp because
1281 * it might be one of the source regions and miRegionOp depends
1282 * on the extents of those regions being the same. Besides, this
1283 * way there's no checking against rectangles that will be nuked
1284 * due to coalescing, so we have to examine fewer rectangles.
1287 REGION_SetExtents(newReg
);
1290 /***********************************************************************
1292 ***********************************************************************/
1295 * Handle a non-overlapping band for the union operation. Just
1296 * Adds the rectangles into the region. Doesn't have to check for
1297 * subsumption or anything.
1302 * \note Side Effects:
1303 * pReg->numRects is incremented and the final rectangles overwritten
1304 * with the rectangles we're passed.
1307 static void FASTCALL
1318 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1322 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1323 pNextRect
->left
= r
->left
;
1324 pNextRect
->top
= top
;
1325 pNextRect
->right
= r
->right
;
1326 pNextRect
->bottom
= bottom
;
1327 pReg
->rdh
.nCount
+= 1;
1335 * Handle an overlapping band for the union operation. Picks the
1336 * left-most rectangle each time and merges it into the region.
1341 * \note Side Effects:
1342 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1346 static void FASTCALL
1359 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1361 #define MERGERECT(r) \
1362 if ((pReg->rdh.nCount != 0) && \
1363 ((pNextRect-1)->top == top) && \
1364 ((pNextRect-1)->bottom == bottom) && \
1365 ((pNextRect-1)->right >= r->left)) \
1367 if ((pNextRect-1)->right < r->right) \
1369 (pNextRect-1)->right = r->right; \
1374 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1375 pNextRect->top = top; \
1376 pNextRect->bottom = bottom; \
1377 pNextRect->left = r->left; \
1378 pNextRect->right = r->right; \
1379 pReg->rdh.nCount += 1; \
1384 while ((r1
!= r1End
) && (r2
!= r2End
))
1386 if (r1
->left
< r2
->left
)
1401 } while (r1
!= r1End
);
1403 else while (r2
!= r2End
)
1410 /***********************************************************************
1411 * REGION_UnionRegion
1413 static void FASTCALL
REGION_UnionRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
1416 /* checks all the simple cases */
1419 * Region 1 and 2 are the same or region 1 is empty
1421 if (reg1
== reg2
|| 0 == reg1
->rdh
.nCount
||
1422 reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
||
1423 reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
)
1427 REGION_CopyRegion(newReg
, reg2
);
1433 * if nothing to union (region 2 empty)
1435 if (0 == reg2
->rdh
.nCount
||
1436 reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
||
1437 reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
)
1441 REGION_CopyRegion(newReg
, reg1
);
1447 * Region 1 completely subsumes region 2
1449 if (1 == reg1
->rdh
.nCount
&&
1450 reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
&&
1451 reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
&&
1452 reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
&&
1453 reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
)
1457 REGION_CopyRegion(newReg
, reg1
);
1463 * Region 2 completely subsumes region 1
1465 if (1 == reg2
->rdh
.nCount
&&
1466 reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
&&
1467 reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
&&
1468 reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
&&
1469 reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
)
1473 REGION_CopyRegion(newReg
, reg2
);
1478 REGION_RegionOp ( newReg
, reg1
, reg2
, REGION_UnionO
,
1479 REGION_UnionNonO
, REGION_UnionNonO
);
1480 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1481 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1482 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1483 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1486 /***********************************************************************
1487 * Region Subtraction
1488 ***********************************************************************/
1491 * Deal with non-overlapping band for subtraction. Any parts from
1492 * region 2 we discard. Anything from region 1 we add to the region.
1497 * \note Side Effects:
1498 * pReg may be affected.
1501 static void FASTCALL
1502 REGION_SubtractNonO1 (
1512 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1516 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1517 pNextRect
->left
= r
->left
;
1518 pNextRect
->top
= top
;
1519 pNextRect
->right
= r
->right
;
1520 pNextRect
->bottom
= bottom
;
1521 pReg
->rdh
.nCount
+= 1;
1530 * Overlapping band subtraction. x1 is the left-most point not yet
1536 * \note Side Effects:
1537 * pReg may have rectangles added to it.
1540 static void FASTCALL
1555 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1557 while ((r1
!= r1End
) && (r2
!= r2End
))
1559 if (r2
->right
<= left
)
1562 * Subtrahend missed the boat: go to next subtrahend.
1566 else if (r2
->left
<= left
)
1569 * Subtrahend preceeds minuend: nuke left edge of minuend.
1572 if (left
>= r1
->right
)
1575 * Minuend completely covered: advance to next minuend and
1576 * reset left fence to edge of new minuend.
1585 * Subtrahend now used up since it doesn't extend beyond
1591 else if (r2
->left
< r1
->right
)
1594 * Left part of subtrahend covers part of minuend: add uncovered
1595 * part of minuend to region and skip to next subtrahend.
1597 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1598 pNextRect
->left
= left
;
1599 pNextRect
->top
= top
;
1600 pNextRect
->right
= r2
->left
;
1601 pNextRect
->bottom
= bottom
;
1602 pReg
->rdh
.nCount
+= 1;
1605 if (left
>= r1
->right
)
1608 * Minuend used up: advance to new...
1617 * Subtrahend used up
1625 * Minuend used up: add any remaining piece before advancing.
1627 if (r1
->right
> left
)
1629 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1630 pNextRect
->left
= left
;
1631 pNextRect
->top
= top
;
1632 pNextRect
->right
= r1
->right
;
1633 pNextRect
->bottom
= bottom
;
1634 pReg
->rdh
.nCount
+= 1;
1643 * Add remaining minuend rectangles to region.
1647 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1648 pNextRect
->left
= left
;
1649 pNextRect
->top
= top
;
1650 pNextRect
->right
= r1
->right
;
1651 pNextRect
->bottom
= bottom
;
1652 pReg
->rdh
.nCount
+= 1;
1664 * Subtract regS from regM and leave the result in regD.
1665 * S stands for subtrahend, M for minuend and D for difference.
1670 * \note Side Effects:
1671 * regD is overwritten.
1674 static void FASTCALL
REGION_SubtractRegion(ROSRGNDATA
*regD
, ROSRGNDATA
*regM
,
1677 /* check for trivial reject */
1678 if ( (!(regM
->rdh
.nCount
)) || (!(regS
->rdh
.nCount
)) ||
1679 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1681 REGION_CopyRegion(regD
, regM
);
1685 REGION_RegionOp (regD
, regM
, regS
, REGION_SubtractO
,
1686 REGION_SubtractNonO1
, NULL
);
1689 * Can't alter newReg's extents before we call miRegionOp because
1690 * it might be one of the source regions and miRegionOp depends
1691 * on the extents of those regions being the unaltered. Besides, this
1692 * way there's no checking against rectangles that will be nuked
1693 * due to coalescing, so we have to examine fewer rectangles.
1695 REGION_SetExtents (regD
);
1698 /***********************************************************************
1701 static void FASTCALL
REGION_XorRegion(ROSRGNDATA
*dr
, ROSRGNDATA
*sra
,
1705 ROSRGNDATA
*tra
, *trb
;
1707 if(!(htra
= RGNDATA_AllocRgn(sra
->rdh
.nCount
+ 1)))
1709 if(!(htrb
= RGNDATA_AllocRgn(srb
->rdh
.nCount
+ 1)))
1711 NtGdiDeleteObject( htra
);
1714 tra
= RGNDATA_LockRgn( htra
);
1716 NtGdiDeleteObject( htra
);
1717 NtGdiDeleteObject( htrb
);
1721 trb
= RGNDATA_LockRgn( htrb
);
1723 RGNDATA_UnlockRgn( tra
);
1724 NtGdiDeleteObject( htra
);
1725 NtGdiDeleteObject( htrb
);
1729 REGION_SubtractRegion(tra
,sra
,srb
);
1730 REGION_SubtractRegion(trb
,srb
,sra
);
1731 REGION_UnionRegion(dr
,tra
,trb
);
1732 RGNDATA_UnlockRgn( tra
);
1733 RGNDATA_UnlockRgn( trb
);
1735 NtGdiDeleteObject( htra
);
1736 NtGdiDeleteObject( htrb
);
1742 * Adds a rectangle to a REGION
1744 void FASTCALL
REGION_UnionRectWithRegion(const RECT
*rect
, ROSRGNDATA
*rgn
)
1748 region
.Buffer
= ®ion
.rdh
.rcBound
;
1749 region
.rdh
.nCount
= 1;
1750 region
.rdh
.nRgnSize
= sizeof( RECT
);
1751 region
.rdh
.rcBound
= *rect
;
1752 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1755 BOOL FASTCALL
REGION_CreateFrameRgn(HRGN hDest
, HRGN hSrc
, INT x
, INT y
)
1757 PROSRGNDATA srcObj
, destObj
;
1761 if (!(srcObj
= (PROSRGNDATA
)RGNDATA_LockRgn(hSrc
)))
1765 if (!REGION_NOT_EMPTY(srcObj
))
1767 RGNDATA_UnlockRgn(srcObj
);
1770 if (!(destObj
= (PROSRGNDATA
)RGNDATA_LockRgn(hDest
)))
1772 RGNDATA_UnlockRgn(srcObj
);
1776 EMPTY_REGION(destObj
);
1777 if (!REGION_CopyRegion(destObj
, srcObj
))
1779 RGNDATA_UnlockRgn(destObj
);
1780 RGNDATA_UnlockRgn(srcObj
);
1784 /* Original region moved to right */
1785 rc
= (PRECT
)srcObj
->Buffer
;
1786 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1792 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1794 /* Original region moved to left */
1795 rc
= (PRECT
)srcObj
->Buffer
;
1796 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1802 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1804 /* Original region moved down */
1805 rc
= (PRECT
)srcObj
->Buffer
;
1806 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1814 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1816 /* Original region moved up */
1817 rc
= (PRECT
)srcObj
->Buffer
;
1818 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1821 rc
->bottom
-= 2 * y
;
1824 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1826 /* Restore the original region */
1827 rc
= (PRECT
)srcObj
->Buffer
;
1828 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1834 REGION_SubtractRegion(destObj
, srcObj
, destObj
);
1836 RGNDATA_UnlockRgn(destObj
);
1837 RGNDATA_UnlockRgn(srcObj
);
1842 BOOL FASTCALL
REGION_LPTODP(HDC hdc
, HRGN hDest
, HRGN hSrc
)
1844 RECT
*pCurRect
, *pEndRect
;
1845 PROSRGNDATA srcObj
= NULL
;
1846 PROSRGNDATA destObj
= NULL
;
1848 DC
* dc
= DC_LockDc(hdc
);
1855 if(dc
->w
.MapMode
== MM_TEXT
) // Requires only a translation
1857 if(NtGdiCombineRgn(hDest
, hSrc
, 0, RGN_COPY
) == ERROR
)
1860 NtGdiOffsetRgn(hDest
, dc
->vportOrgX
- dc
->wndOrgX
, dc
->vportOrgY
- dc
->wndOrgY
);
1865 if(!( srcObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hSrc
) ))
1867 if(!( destObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hDest
) ))
1869 RGNDATA_UnlockRgn( srcObj
);
1872 EMPTY_REGION(destObj
);
1874 pEndRect
= (PRECT
)srcObj
->Buffer
+ srcObj
->rdh
.nCount
;
1875 for(pCurRect
= (PRECT
)srcObj
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
1877 tmpRect
= *pCurRect
;
1878 tmpRect
.left
= XLPTODP(dc
, tmpRect
.left
);
1879 tmpRect
.top
= YLPTODP(dc
, tmpRect
.top
);
1880 tmpRect
.right
= XLPTODP(dc
, tmpRect
.right
);
1881 tmpRect
.bottom
= YLPTODP(dc
, tmpRect
.bottom
);
1883 if(tmpRect
.left
> tmpRect
.right
)
1884 { INT tmp
= tmpRect
.left
; tmpRect
.left
= tmpRect
.right
; tmpRect
.right
= tmp
; }
1885 if(tmpRect
.top
> tmpRect
.bottom
)
1886 { INT tmp
= tmpRect
.top
; tmpRect
.top
= tmpRect
.bottom
; tmpRect
.bottom
= tmp
; }
1888 REGION_UnionRectWithRegion(&tmpRect
, destObj
);
1892 RGNDATA_UnlockRgn( srcObj
);
1893 RGNDATA_UnlockRgn( destObj
);
1900 HRGN FASTCALL
RGNDATA_AllocRgn(INT n
)
1905 if ((hReg
= (HRGN
) GDIOBJ_AllocObj(GDI_OBJECT_TYPE_REGION
)))
1907 if (NULL
!= (pReg
= RGNDATA_LockRgn(hReg
)))
1911 /* Testing shows that > 95% of all regions have only 1 rect.
1912 Including that here saves us from having to do another
1914 pReg
->Buffer
= &pReg
->rdh
.rcBound
;
1918 pReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, n
* sizeof(RECT
), TAG_REGION
);
1920 if (NULL
!= pReg
->Buffer
)
1923 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
1924 pReg
->rdh
.nCount
= n
;
1925 pReg
->rdh
.nRgnSize
= n
*sizeof(RECT
);
1927 RGNDATA_UnlockRgn(pReg
);
1934 RGNDATA_FreeRgn(hReg
);
1942 RGNDATA_Cleanup(PVOID ObjectBody
)
1944 PROSRGNDATA pRgn
= (PROSRGNDATA
)ObjectBody
;
1945 if(pRgn
->Buffer
&& pRgn
->Buffer
!= &pRgn
->rdh
.rcBound
)
1946 ExFreePool(pRgn
->Buffer
);
1950 // NtGdi Exported Functions
1953 NtGdiCombineRgn(HRGN hDest
,
1959 PROSRGNDATA destRgn
, src1Rgn
, src2Rgn
;
1961 destRgn
= RGNDATA_LockRgn(hDest
);
1964 src1Rgn
= RGNDATA_LockRgn(hSrc1
);
1967 if (CombineMode
== RGN_COPY
)
1969 if( !REGION_CopyRegion(destRgn
, src1Rgn
) )
1971 result
= destRgn
->rdh
.iType
;
1975 src2Rgn
= RGNDATA_LockRgn(hSrc2
);
1978 switch (CombineMode
)
1981 REGION_IntersectRegion(destRgn
, src1Rgn
, src2Rgn
);
1984 REGION_UnionRegion(destRgn
, src1Rgn
, src2Rgn
);
1987 REGION_XorRegion(destRgn
, src1Rgn
, src2Rgn
);
1990 REGION_SubtractRegion(destRgn
, src1Rgn
, src2Rgn
);
1993 RGNDATA_UnlockRgn(src2Rgn
);
1994 result
= destRgn
->rdh
.iType
;
1996 else if(hSrc2
== NULL
)
1998 DPRINT1("NtGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode
);
2002 RGNDATA_UnlockRgn(src1Rgn
);
2005 RGNDATA_UnlockRgn(destRgn
);
2009 DPRINT("NtGdiCombineRgn: hDest unavailable\n");
2018 NtGdiCreateEllipticRgn(INT Left
,
2023 return NtGdiCreateRoundRectRgn(Left
, Top
, Right
, Bottom
,
2024 Right
- Left
, Bottom
- Top
);
2029 NtGdiCreateEllipticRgnIndirect(CONST PRECT Rect
)
2031 RECT SafeRect
= {0};
2032 NTSTATUS Status
= STATUS_SUCCESS
;
2043 Status
= _SEH_GetExceptionCode();
2046 if(!NT_SUCCESS(Status
))
2048 SetLastNtError(Status
);
2052 return NtGdiCreateRoundRectRgn(SafeRect
.left
, SafeRect
.top
, SafeRect
.right
, SafeRect
.bottom
,
2053 SafeRect
.right
- SafeRect
.left
, SafeRect
.bottom
- SafeRect
.top
);
2057 NtGdiCreateRectRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
2061 /* Allocate region data structure with space for 1 RECT */
2062 if ((hRgn
= RGNDATA_AllocRgn(1)))
2064 if (NtGdiSetRectRgn(hRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
))
2066 NtGdiDeleteObject(hRgn
);
2069 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2074 NtGdiCreateRectRgnIndirect(CONST PRECT rc
)
2077 NTSTATUS Status
= STATUS_SUCCESS
;
2088 Status
= _SEH_GetExceptionCode();
2091 if (!NT_SUCCESS(Status
))
2095 return(UnsafeIntCreateRectRgnIndirect(&SafeRc
));
2100 NtGdiCreateRoundRectRgn(INT left
, INT top
, INT right
, INT bottom
,
2101 INT ellipse_width
, INT ellipse_height
)
2105 int asq
, bsq
, d
, xd
, yd
;
2108 /* Make the dimensions sensible */
2110 if (left
> right
) { INT tmp
= left
; left
= right
; right
= tmp
; }
2111 if (top
> bottom
) { INT tmp
= top
; top
= bottom
; bottom
= tmp
; }
2113 ellipse_width
= abs(ellipse_width
);
2114 ellipse_height
= abs(ellipse_height
);
2116 /* Check parameters */
2118 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
2119 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
2121 /* Check if we can do a normal rectangle instead */
2123 if ((ellipse_width
< 2) || (ellipse_height
< 2))
2124 return NtGdiCreateRectRgn( left
, top
, right
, bottom
);
2128 d
= (ellipse_height
< 128) ? ((3 * ellipse_height
) >> 2) : 64;
2129 if (!(hrgn
= RGNDATA_AllocRgn(d
))) return 0;
2130 if (!(obj
= RGNDATA_LockRgn(hrgn
))) return 0;
2132 /* Ellipse algorithm, based on an article by K. Porter */
2133 /* in DDJ Graphics Programming Column, 8/89 */
2135 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
2136 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
2137 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
2139 yd
= asq
* ellipse_height
; /* 2a^2b */
2141 rect
.left
= left
+ ellipse_width
/ 2;
2142 rect
.right
= right
- ellipse_width
/ 2;
2144 /* Loop to draw first half of quadrant */
2148 if (d
> 0) /* if nearest pixel is toward the center */
2150 /* move toward center */
2152 rect
.bottom
= rect
.top
+ 1;
2153 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2154 rect
.top
= --bottom
;
2155 rect
.bottom
= rect
.top
+ 1;
2156 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2160 rect
.left
--; /* next horiz point */
2165 /* Loop to draw second half of quadrant */
2167 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
2170 /* next vertical point */
2172 rect
.bottom
= rect
.top
+ 1;
2173 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2174 rect
.top
= --bottom
;
2175 rect
.bottom
= rect
.top
+ 1;
2176 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2177 if (d
< 0) /* if nearest pixel is outside ellipse */
2179 rect
.left
--; /* move away from center */
2187 /* Add the inside rectangle */
2192 rect
.bottom
= bottom
;
2193 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2195 RGNDATA_UnlockRgn( obj
);
2201 NtGdiEqualRgn(HRGN hSrcRgn1
,
2204 PROSRGNDATA rgn1
, rgn2
;
2205 PRECT tRect1
, tRect2
;
2209 if( !(rgn1
= RGNDATA_LockRgn(hSrcRgn1
)))
2212 if( !(rgn2
= RGNDATA_LockRgn(hSrcRgn2
))){
2213 RGNDATA_UnlockRgn( rgn1
);
2217 if(rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
||
2218 rgn1
->rdh
.nCount
== 0 ||
2219 rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
||
2220 rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
||
2221 rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
||
2222 rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
)
2225 tRect1
= (PRECT
)rgn1
->Buffer
;
2226 tRect2
= (PRECT
)rgn2
->Buffer
;
2228 if( !tRect1
|| !tRect2
)
2231 for(i
=0; i
< rgn1
->rdh
.nCount
; i
++)
2233 if(tRect1
[i
].left
!= tRect2
[i
].left
||
2234 tRect1
[i
].right
!= tRect2
[i
].right
||
2235 tRect1
[i
].top
!= tRect2
[i
].top
||
2236 tRect1
[i
].bottom
!= tRect2
[i
].bottom
)
2242 RGNDATA_UnlockRgn( rgn1
);
2243 RGNDATA_UnlockRgn( rgn2
);
2249 NtGdiExtCreateRegion(CONST XFORM
*Xform
,
2251 CONST RGNDATA
*RgnData
)
2256 NTSTATUS Status
= STATUS_SUCCESS
;
2258 if (Count
< FIELD_OFFSET(RGNDATA
, Buffer
))
2260 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2266 ProbeForRead(RgnData
,
2269 nCount
= RgnData
->rdh
.nCount
;
2270 if((Count
- FIELD_OFFSET(RGNDATA
, Buffer
)) / sizeof(RECT
) < nCount
)
2272 Status
= STATUS_INVALID_PARAMETER
;
2278 Status
= _SEH_GetExceptionCode();
2281 if (!NT_SUCCESS(Status
))
2283 SetLastNtError(Status
);
2287 hRgn
= RGNDATA_AllocRgn(nCount
);
2290 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2294 Region
= RGNDATA_LockRgn(hRgn
);
2297 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2303 RtlCopyMemory(&Region
->rdh
,
2305 FIELD_OFFSET(RGNDATA
, Buffer
));
2306 RtlCopyMemory(Region
->Buffer
,
2308 Count
- FIELD_OFFSET(RGNDATA
, Buffer
));
2312 Status
= _SEH_GetExceptionCode();
2315 if (!NT_SUCCESS(Status
))
2317 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2318 RGNDATA_UnlockRgn(Region
);
2319 NtGdiDeleteObject(hRgn
);
2323 RGNDATA_UnlockRgn(Region
);
2330 NtGdiFillRgn(HDC hDC
, HRGN hRgn
, HBRUSH hBrush
)
2336 if (NULL
== (rgn
= RGNDATA_LockRgn(hRgn
)))
2341 if (NULL
== (oldhBrush
= NtGdiSelectObject(hDC
, hBrush
)))
2343 RGNDATA_UnlockRgn(rgn
);
2347 for (r
= rgn
->Buffer
; r
< rgn
->Buffer
+ rgn
->rdh
.nCount
; r
++)
2349 NtGdiPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
2352 RGNDATA_UnlockRgn( rgn
);
2353 NtGdiSelectObject(hDC
, oldhBrush
);
2360 NtGdiFrameRgn(HDC hDC
, HRGN hRgn
, HBRUSH hBrush
, INT Width
, INT Height
)
2365 if(!(FrameRgn
= NtGdiCreateRectRgn(0, 0, 0, 0)))
2369 if(!REGION_CreateFrameRgn(FrameRgn
, hRgn
, Width
, Height
))
2371 NtGdiDeleteObject(FrameRgn
);
2375 Ret
= NtGdiFillRgn(hDC
, FrameRgn
, hBrush
);
2377 NtGdiDeleteObject(FrameRgn
);
2382 UnsafeIntGetRgnBox(PROSRGNDATA Rgn
,
2389 *pRect
= Rgn
->rdh
.rcBound
;
2390 ret
= Rgn
->rdh
.iType
;
2394 return 0; //if invalid region return zero
2399 NtGdiGetRgnBox(HRGN hRgn
,
2405 NTSTATUS Status
= STATUS_SUCCESS
;
2407 if (!(Rgn
= RGNDATA_LockRgn(hRgn
)))
2412 ret
= UnsafeIntGetRgnBox(Rgn
, &SafeRect
);
2413 RGNDATA_UnlockRgn(Rgn
);
2421 ProbeForWrite(pRect
,
2428 Status
= _SEH_GetExceptionCode();
2431 if (!NT_SUCCESS(Status
))
2441 NtGdiInvertRgn(HDC hDC
,
2444 PROSRGNDATA RgnData
;
2448 if(!(RgnData
= RGNDATA_LockRgn(hRgn
)))
2450 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2454 rc
= (PRECT
)RgnData
->Buffer
;
2455 for(i
= 0; i
< RgnData
->rdh
.nCount
; i
++)
2458 if(!NtGdiPatBlt(hDC
, rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, DSTINVERT
))
2460 RGNDATA_UnlockRgn(RgnData
);
2466 RGNDATA_UnlockRgn(RgnData
);
2472 NtGdiOffsetRgn(HRGN hRgn
,
2476 PROSRGNDATA rgn
= RGNDATA_LockRgn(hRgn
);
2479 DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn
, XOffset
, YOffset
, rgn
);
2482 DPRINT("NtGdiOffsetRgn: hRgn error\n");
2486 if(XOffset
|| YOffset
) {
2487 int nbox
= rgn
->rdh
.nCount
;
2488 PRECT pbox
= (PRECT
)rgn
->Buffer
;
2492 pbox
->left
+= XOffset
;
2493 pbox
->right
+= XOffset
;
2494 pbox
->top
+= YOffset
;
2495 pbox
->bottom
+= YOffset
;
2498 if (rgn
->Buffer
!= &rgn
->rdh
.rcBound
)
2500 rgn
->rdh
.rcBound
.left
+= XOffset
;
2501 rgn
->rdh
.rcBound
.right
+= XOffset
;
2502 rgn
->rdh
.rcBound
.top
+= YOffset
;
2503 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
2507 ret
= rgn
->rdh
.iType
;
2508 RGNDATA_UnlockRgn( rgn
);
2514 NtGdiPaintRgn(HDC hDC
,
2518 HRGN tmpVisRgn
; //, prevVisRgn;
2519 DC
*dc
= DC_LockDc(hDC
);
2521 CLIPOBJ
* ClipRegion
;
2523 PGDIBRUSHOBJ pBrush
;
2524 GDIBRUSHINST BrushInst
;
2526 BITMAPOBJ
*BitmapObj
;
2531 if(!(tmpVisRgn
= NtGdiCreateRectRgn(0, 0, 0, 0))){
2537 // Transform region into device co-ords
2538 if(!REGION_LPTODP(hDC, tmpVisRgn, hRgn) || NtGdiOffsetRgn(tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY) == ERROR) {
2539 NtGdiDeleteObject( tmpVisRgn );
2544 /* enable when clipping is implemented
2545 NtGdiCombineRgn(tmpVisRgn, tmpVisRgn, dc->w.hGCClipRgn, RGN_AND);
2548 //visrgn = RGNDATA_LockRgn(tmpVisRgn);
2549 visrgn
= RGNDATA_LockRgn(hRgn
);
2556 ClipRegion
= IntEngCreateClipRegion (
2557 visrgn
->rdh
.nCount
, (PRECTL
)visrgn
->Buffer
, (PRECTL
)&visrgn
->rdh
.rcBound
);
2558 ASSERT( ClipRegion
);
2559 pBrush
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
2561 IntGdiInitBrushInstance(&BrushInst
, pBrush
, dc
->XlateBrush
);
2563 BrushOrigin
.x
= dc
->w
.brushOrgX
;
2564 BrushOrigin
.y
= dc
->w
.brushOrgY
;
2565 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
2566 /* FIXME - Handle BitmapObj == NULL !!!! */
2568 bRet
= IntEngPaint(&BitmapObj
->SurfObj
,
2570 &BrushInst
.BrushObject
,
2572 0xFFFF);//FIXME:don't know what to put here
2574 BITMAPOBJ_UnlockBitmap(BitmapObj
);
2575 RGNDATA_UnlockRgn( visrgn
);
2584 NtGdiPtInRegion(HRGN hRgn
,
2592 if(!(rgn
= RGNDATA_LockRgn(hRgn
) ) )
2595 if(rgn
->rdh
.nCount
> 0 && INRECT(rgn
->rdh
.rcBound
, X
, Y
)){
2596 r
= (PRECT
) rgn
->Buffer
;
2597 for(i
= 0; i
< rgn
->rdh
.nCount
; i
++) {
2598 if(INRECT(*r
, X
, Y
)){
2599 RGNDATA_UnlockRgn(rgn
);
2605 RGNDATA_UnlockRgn(rgn
);
2611 UnsafeIntRectInRegion(PROSRGNDATA Rgn
,
2614 PRECT pCurRect
, pRectEnd
;
2616 // this is (just) a useful optimization
2617 if((Rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&Rgn
->rdh
.rcBound
, rc
))
2619 for (pCurRect
= (PRECT
)Rgn
->Buffer
, pRectEnd
= pCurRect
+ Rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
2621 if (pCurRect
->bottom
<= rc
->top
) continue; // not far enough down yet
2622 if (pCurRect
->top
>= rc
->bottom
) break; // too far down
2623 if (pCurRect
->right
<= rc
->left
) continue; // not far enough over yet
2624 if (pCurRect
->left
>= rc
->right
) continue;
2634 NtGdiRectInRegion(HRGN hRgn
,
2635 CONST LPRECT unsaferc
)
2640 NTSTATUS Status
= STATUS_SUCCESS
;
2642 if(!(Rgn
= RGNDATA_LockRgn(hRgn
)))
2649 ProbeForRead(unsaferc
,
2656 Status
= _SEH_GetExceptionCode();
2660 if (!NT_SUCCESS(Status
))
2662 RGNDATA_UnlockRgn(Rgn
);
2663 SetLastNtError(Status
);
2664 DPRINT1("NtGdiRectInRegion: bogus rc\n");
2668 Ret
= UnsafeIntRectInRegion(Rgn
, &rc
);
2669 RGNDATA_UnlockRgn(Rgn
);
2675 NtGdiSetRectRgn(HRGN hRgn
,
2686 if( !( rgn
= RGNDATA_LockRgn(hRgn
) ) )
2687 return 0; //per documentation
2689 if (LeftRect
> RightRect
) { INT tmp
= LeftRect
; LeftRect
= RightRect
; RightRect
= tmp
; }
2690 if (TopRect
> BottomRect
) { INT tmp
= TopRect
; TopRect
= BottomRect
; BottomRect
= tmp
; }
2692 if((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
2694 firstRect
= (PRECT
)rgn
->Buffer
;
2695 ASSERT( firstRect
);
2696 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
2697 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
2698 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
2699 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
2700 rgn
->rdh
.nCount
= 1;
2701 rgn
->rdh
.iType
= SIMPLEREGION
;
2705 RGNDATA_UnlockRgn( rgn
);
2710 NtGdiUnionRectWithRgn(HRGN hDest
, CONST PRECT UnsafeRect
)
2714 NTSTATUS Status
= STATUS_SUCCESS
;
2716 if(!(Rgn
= (PROSRGNDATA
)RGNDATA_LockRgn(hDest
)))
2718 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2724 ProbeForRead(UnsafeRect
,
2727 SafeRect
= *UnsafeRect
;
2731 Status
= _SEH_GetExceptionCode();
2735 if (! NT_SUCCESS(Status
))
2737 RGNDATA_UnlockRgn(Rgn
);
2738 SetLastNtError(Status
);
2742 UnsafeIntUnionRectWithRgn(Rgn
, &SafeRect
);
2743 RGNDATA_UnlockRgn(Rgn
);
2748 * MSDN: GetRegionData, Return Values:
2750 * "If the function succeeds and dwCount specifies an adequate number of bytes,
2751 * the return value is always dwCount. If dwCount is too small or the function
2752 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
2753 * required number of bytes.
2755 * If the function fails, the return value is zero."
2757 DWORD STDCALL
NtGdiGetRegionData(HRGN hrgn
, DWORD count
, LPRGNDATA rgndata
)
2760 PROSRGNDATA obj
= RGNDATA_LockRgn( hrgn
);
2761 NTSTATUS Status
= STATUS_SUCCESS
;
2766 size
= obj
->rdh
.nCount
* sizeof(RECT
);
2767 if(count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
2769 RGNDATA_UnlockRgn( obj
);
2770 if (rgndata
) /* buffer is too small, signal it by return 0 */
2772 else /* user requested buffer size with rgndata NULL */
2773 return size
+ sizeof(RGNDATAHEADER
);
2778 ProbeForWrite(rgndata
,
2781 RtlCopyMemory(rgndata
,
2783 sizeof(RGNDATAHEADER
));
2784 RtlCopyMemory((PVOID
)((ULONG_PTR
)rgndata
+ (ULONG_PTR
)sizeof(RGNDATAHEADER
)),
2790 Status
= _SEH_GetExceptionCode();
2794 if(!NT_SUCCESS(Status
))
2796 SetLastNtError(Status
);
2797 RGNDATA_UnlockRgn( obj
);
2801 RGNDATA_UnlockRgn( obj
);
2802 return size
+ sizeof(RGNDATAHEADER
);
2806 /***********************************************************************
2807 * REGION_InsertEdgeInET
2809 * Insert the given edge into the edge table.
2810 * First we must find the correct bucket in the
2811 * Edge table, then find the right slot in the
2812 * bucket. Finally, we can insert it.
2815 static void FASTCALL
REGION_InsertEdgeInET(EdgeTable
*ET
, EdgeTableEntry
*ETE
,
2816 INT scanline
, ScanLineListBlock
**SLLBlock
, INT
*iSLLBlock
)
2819 EdgeTableEntry
*start
, *prev
;
2820 ScanLineList
*pSLL
, *pPrevSLL
;
2821 ScanLineListBlock
*tmpSLLBlock
;
2824 * find the right bucket to put the edge into
2826 pPrevSLL
= &ET
->scanlines
;
2827 pSLL
= pPrevSLL
->next
;
2828 while (pSLL
&& (pSLL
->scanline
< scanline
))
2835 * reassign pSLL (pointer to ScanLineList) if necessary
2837 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
2839 if (*iSLLBlock
> SLLSPERBLOCK
-1)
2841 tmpSLLBlock
= ExAllocatePoolWithTag( PagedPool
, sizeof(ScanLineListBlock
), TAG_REGION
);
2844 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2845 /* FIXME - free resources? */
2848 (*SLLBlock
)->next
= tmpSLLBlock
;
2849 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2850 *SLLBlock
= tmpSLLBlock
;
2853 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
2855 pSLL
->next
= pPrevSLL
->next
;
2856 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
2857 pPrevSLL
->next
= pSLL
;
2859 pSLL
->scanline
= scanline
;
2862 * now insert the edge in the right bucket
2864 prev
= (EdgeTableEntry
*)NULL
;
2865 start
= pSLL
->edgelist
;
2866 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2869 start
= start
->next
;
2876 pSLL
->edgelist
= ETE
;
2879 /***********************************************************************
2882 * This routine moves EdgeTableEntries from the
2883 * EdgeTable into the Active Edge Table,
2884 * leaving them sorted by smaller x coordinate.
2887 static void FASTCALL
REGION_loadAET(EdgeTableEntry
*AET
, EdgeTableEntry
*ETEs
)
2889 EdgeTableEntry
*pPrevAET
;
2890 EdgeTableEntry
*tmp
;
2896 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2905 ETEs
->back
= pPrevAET
;
2906 pPrevAET
->next
= ETEs
;
2913 /***********************************************************************
2914 * REGION_computeWAET
2916 * This routine links the AET by the
2917 * nextWETE (winding EdgeTableEntry) link for
2918 * use by the winding number rule. The final
2919 * Active Edge Table (AET) might look something
2923 * ---------- --------- ---------
2924 * |ymax | |ymax | |ymax |
2925 * | ... | |... | |... |
2926 * |next |->|next |->|next |->...
2927 * |nextWETE| |nextWETE| |nextWETE|
2928 * --------- --------- ^--------
2930 * V-------------------> V---> ...
2933 static void FASTCALL
REGION_computeWAET(EdgeTableEntry
*AET
)
2935 register EdgeTableEntry
*pWETE
;
2936 register int inside
= 1;
2937 register int isInside
= 0;
2939 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2949 if ((!inside
&& !isInside
) ||
2950 ( inside
&& isInside
))
2952 pWETE
->nextWETE
= AET
;
2958 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2961 /***********************************************************************
2962 * REGION_InsertionSort
2964 * Just a simple insertion sort using
2965 * pointers and back pointers to sort the Active
2969 static BOOL FASTCALL
REGION_InsertionSort(EdgeTableEntry
*AET
)
2971 EdgeTableEntry
*pETEchase
;
2972 EdgeTableEntry
*pETEinsert
;
2973 EdgeTableEntry
*pETEchaseBackTMP
;
2974 BOOL changed
= FALSE
;
2981 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2982 pETEchase
= pETEchase
->back
;
2985 if (pETEchase
!= pETEinsert
)
2987 pETEchaseBackTMP
= pETEchase
->back
;
2988 pETEinsert
->back
->next
= AET
;
2990 AET
->back
= pETEinsert
->back
;
2991 pETEinsert
->next
= pETEchase
;
2992 pETEchase
->back
->next
= pETEinsert
;
2993 pETEchase
->back
= pETEinsert
;
2994 pETEinsert
->back
= pETEchaseBackTMP
;
3001 /***********************************************************************
3002 * REGION_FreeStorage
3006 static void FASTCALL
REGION_FreeStorage(ScanLineListBlock
*pSLLBlock
)
3008 ScanLineListBlock
*tmpSLLBlock
;
3012 tmpSLLBlock
= pSLLBlock
->next
;
3013 ExFreePool( pSLLBlock
);
3014 pSLLBlock
= tmpSLLBlock
;
3019 /***********************************************************************
3020 * REGION_PtsToRegion
3022 * Create an array of rectangles from a list of points.
3024 static int FASTCALL
REGION_PtsToRegion(int numFullPtBlocks
, int iCurPtBlock
,
3025 POINTBLOCK
*FirstPtBlock
, ROSRGNDATA
*reg
)
3029 POINTBLOCK
*CurPtBlock
;
3031 RECT
*extents
, *temp
;
3034 extents
= ®
->rdh
.rcBound
;
3036 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
3038 if(!(temp
= ExAllocatePoolWithTag(PagedPool
, numRects
* sizeof(RECT
), TAG_REGION
)))
3042 if(reg
->Buffer
!= NULL
)
3044 COPY_RECTS(temp
, reg
->Buffer
, reg
->rdh
.nCount
);
3045 if(reg
->Buffer
!= ®
->rdh
.rcBound
)
3046 ExFreePool(reg
->Buffer
);
3050 reg
->rdh
.nCount
= numRects
;
3051 CurPtBlock
= FirstPtBlock
;
3052 rects
= reg
->Buffer
- 1;
3054 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
3056 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--) {
3057 /* the loop uses 2 points per iteration */
3058 i
= NUMPTSTOBUFFER
>> 1;
3059 if (!numFullPtBlocks
)
3060 i
= iCurPtBlock
>> 1;
3061 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2) {
3062 if (pts
->x
== pts
[1].x
)
3064 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
3065 pts
[1].x
== rects
->right
&&
3066 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
3067 (i
&& pts
[2].y
> pts
[1].y
)) {
3068 rects
->bottom
= pts
[1].y
+ 1;
3073 rects
->left
= pts
->x
; rects
->top
= pts
->y
;
3074 rects
->right
= pts
[1].x
; rects
->bottom
= pts
[1].y
+ 1;
3075 if (rects
->left
< extents
->left
)
3076 extents
->left
= rects
->left
;
3077 if (rects
->right
> extents
->right
)
3078 extents
->right
= rects
->right
;
3080 CurPtBlock
= CurPtBlock
->next
;
3084 extents
->top
= reg
->Buffer
->top
;
3085 extents
->bottom
= rects
->bottom
;
3090 extents
->bottom
= 0;
3092 reg
->rdh
.nCount
= numRects
;
3097 /***********************************************************************
3098 * REGION_CreateEdgeTable
3100 * This routine creates the edge table for
3101 * scan converting polygons.
3102 * The Edge Table (ET) looks like:
3106 * | ymax | ScanLineLists
3107 * |scanline|-->------------>-------------->...
3108 * -------- |scanline| |scanline|
3109 * |edgelist| |edgelist|
3110 * --------- ---------
3114 * list of ETEs list of ETEs
3116 * where ETE is an EdgeTableEntry data structure,
3117 * and there is one ScanLineList per scanline at
3118 * which an edge is initially entered.
3121 static void FASTCALL
REGION_CreateETandAET(const INT
*Count
, INT nbpolygons
,
3122 const POINT
*pts
, EdgeTable
*ET
, EdgeTableEntry
*AET
,
3123 EdgeTableEntry
*pETEs
, ScanLineListBlock
*pSLLBlock
)
3125 const POINT
*top
, *bottom
;
3126 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
3133 * initialize the Active Edge Table
3135 AET
->next
= (EdgeTableEntry
*)NULL
;
3136 AET
->back
= (EdgeTableEntry
*)NULL
;
3137 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
3138 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
3141 * initialize the Edge Table.
3143 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
3144 ET
->ymax
= SMALL_COORDINATE
;
3145 ET
->ymin
= LARGE_COORDINATE
;
3146 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
3149 for(poly
= 0; poly
< nbpolygons
; poly
++)
3151 count
= Count
[poly
];
3159 * for each vertex in the array of points.
3160 * In this loop we are dealing with two vertices at
3161 * a time -- these make up one edge of the polygon.
3168 * find out which point is above and which is below.
3170 if (PrevPt
->y
> CurrPt
->y
)
3172 bottom
= PrevPt
, top
= CurrPt
;
3173 pETEs
->ClockWise
= 0;
3177 bottom
= CurrPt
, top
= PrevPt
;
3178 pETEs
->ClockWise
= 1;
3182 * don't add horizontal edges to the Edge table.
3184 if (bottom
->y
!= top
->y
)
3186 pETEs
->ymax
= bottom
->y
-1;
3187 /* -1 so we don't get last scanline */
3190 * initialize integer edge algorithm
3192 dy
= bottom
->y
- top
->y
;
3193 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
3195 REGION_InsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
,
3198 if (PrevPt
->y
> ET
->ymax
)
3199 ET
->ymax
= PrevPt
->y
;
3200 if (PrevPt
->y
< ET
->ymin
)
3201 ET
->ymin
= PrevPt
->y
;
3211 IntCreatePolyPolgonRgn(POINT
*Pts
,
3218 EdgeTableEntry
*pAET
; /* Active Edge Table */
3219 INT y
; /* current scanline */
3220 int iPts
= 0; /* number of pts in buffer */
3221 EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry*/
3222 ScanLineList
*pSLL
; /* current scanLineList */
3223 POINT
*pts
; /* output buffer */
3224 EdgeTableEntry
*pPrevAET
; /* ptr to previous AET */
3225 EdgeTable ET
; /* header node for ET */
3226 EdgeTableEntry AET
; /* header node for AET */
3227 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
3228 ScanLineListBlock SLLBlock
; /* header for scanlinelist */
3229 int fixWAET
= FALSE
;
3230 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
3231 POINTBLOCK
*tmpPtBlock
;
3232 int numFullPtBlocks
= 0;
3235 if(!(hrgn
= RGNDATA_AllocRgn(nbpolygons
)))
3237 if(!(region
= RGNDATA_LockRgn(hrgn
)))
3239 NtGdiDeleteObject(hrgn
);
3243 /* special case a rectangle */
3245 if (((nbpolygons
== 1) && ((*Count
== 4) ||
3246 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
3247 (((Pts
[0].y
== Pts
[1].y
) &&
3248 (Pts
[1].x
== Pts
[2].x
) &&
3249 (Pts
[2].y
== Pts
[3].y
) &&
3250 (Pts
[3].x
== Pts
[0].x
)) ||
3251 ((Pts
[0].x
== Pts
[1].x
) &&
3252 (Pts
[1].y
== Pts
[2].y
) &&
3253 (Pts
[2].x
== Pts
[3].x
) &&
3254 (Pts
[3].y
== Pts
[0].y
))))
3256 RGNDATA_UnlockRgn( region
);
3257 NtGdiSetRectRgn( hrgn
, min(Pts
[0].x
, Pts
[2].x
), min(Pts
[0].y
, Pts
[2].y
),
3258 max(Pts
[0].x
, Pts
[2].x
), max(Pts
[0].y
, Pts
[2].y
) );
3262 for(poly
= total
= 0; poly
< nbpolygons
; poly
++)
3263 total
+= Count
[poly
];
3264 if (! (pETEs
= ExAllocatePoolWithTag( PagedPool
, sizeof(EdgeTableEntry
) * total
, TAG_REGION
)))
3266 NtGdiDeleteObject( hrgn
);
3269 pts
= FirstPtBlock
.pts
;
3270 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
3271 pSLL
= ET
.scanlines
.next
;
3272 curPtBlock
= &FirstPtBlock
;
3274 if (mode
!= WINDING
) {
3278 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
3280 * Add a new edge to the active edge table when we
3281 * get to the next edge.
3283 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
3284 REGION_loadAET(&AET
, pSLL
->edgelist
);
3291 * for each active edge
3294 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3298 * send out the buffer
3300 if (iPts
== NUMPTSTOBUFFER
) {
3301 tmpPtBlock
= ExAllocatePoolWithTag( PagedPool
, sizeof(POINTBLOCK
), TAG_REGION
);
3303 DPRINT1("Can't alloc tPB\n");
3307 curPtBlock
->next
= tmpPtBlock
;
3308 curPtBlock
= tmpPtBlock
;
3309 pts
= curPtBlock
->pts
;
3313 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
3315 REGION_InsertionSort(&AET
);
3322 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
3324 * Add a new edge to the active edge table when we
3325 * get to the next edge.
3327 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
3328 REGION_loadAET(&AET
, pSLL
->edgelist
);
3329 REGION_computeWAET(&AET
);
3337 * for each active edge
3341 * add to the buffer only those edges that
3342 * are in the Winding active edge table.
3344 if (pWETE
== pAET
) {
3345 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3349 * send out the buffer
3351 if (iPts
== NUMPTSTOBUFFER
) {
3352 tmpPtBlock
= ExAllocatePoolWithTag( PagedPool
,
3353 sizeof(POINTBLOCK
), TAG_REGION
);
3355 DPRINT1("Can't alloc tPB\n");
3357 NtGdiDeleteObject( hrgn
);
3360 curPtBlock
->next
= tmpPtBlock
;
3361 curPtBlock
= tmpPtBlock
;
3362 pts
= curPtBlock
->pts
;
3363 numFullPtBlocks
++; iPts
= 0;
3365 pWETE
= pWETE
->nextWETE
;
3367 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
3371 * recompute the winding active edge table if
3372 * we just resorted or have exited an edge.
3374 if (REGION_InsertionSort(&AET
) || fixWAET
) {
3375 REGION_computeWAET(&AET
);
3380 REGION_FreeStorage(SLLBlock
.next
);
3381 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, region
);
3383 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;) {
3384 tmpPtBlock
= curPtBlock
->next
;
3385 ExFreePool( curPtBlock
);
3386 curPtBlock
= tmpPtBlock
;
3388 ExFreePool( pETEs
);
3389 RGNDATA_UnlockRgn( region
);
3395 NtGdiCreatePolygonRgn(CONST PPOINT pt
,
3400 NTSTATUS Status
= STATUS_SUCCESS
;
3404 if (pt
== NULL
|| Count
== 0 ||
3405 (PolyFillMode
!= WINDING
&& PolyFillMode
!= ALTERNATE
))
3407 /* Windows doesn't set a last error here */
3413 /* can't create a region with only one point! */
3414 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
3420 /* Windows creates an empty region! */
3423 if(!(hRgn
= RGNDATA_AllocRgn(1)))
3427 if(!(rgn
= RGNDATA_LockRgn(hRgn
)))
3429 NtGdiDeleteObject(hRgn
);
3435 RGNDATA_UnlockRgn(rgn
);
3442 Count
* sizeof(POINT
),
3447 Status
= _SEH_GetExceptionCode();
3451 if (!NT_SUCCESS(Status
))
3453 SetLastNtError(Status
);
3457 if (!(SafePoints
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(POINT
), TAG_REGION
)))
3459 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3465 /* pointers were already probed! */
3466 RtlCopyMemory(SafePoints
,
3468 Count
* sizeof(POINT
));
3472 Status
= _SEH_GetExceptionCode();
3475 if (!NT_SUCCESS(Status
))
3477 ExFreePool(SafePoints
);
3478 SetLastNtError(Status
);
3482 hRgn
= IntCreatePolyPolgonRgn(SafePoints
, &Count
, 1, PolyFillMode
);
3484 ExFreePool(SafePoints
);
3490 NtGdiCreatePolyPolygonRgn(CONST PPOINT pt
,
3491 CONST PINT PolyCounts
,
3496 INT
*SafePolyCounts
;
3497 INT nPoints
, nEmpty
, nInvalid
, i
;
3499 NTSTATUS Status
= STATUS_SUCCESS
;
3501 if (pt
== NULL
|| PolyCounts
== NULL
|| Count
== 0 ||
3502 (PolyFillMode
!= WINDING
&& PolyFillMode
!= ALTERNATE
))
3504 /* Windows doesn't set a last error here */
3510 ProbeForRead(PolyCounts
,
3511 Count
* sizeof(INT
),
3513 /* just probe one point for now, we don't know the length of the array yet */
3520 Status
= _SEH_GetExceptionCode();
3524 if (!NT_SUCCESS(Status
))
3526 SetLastNtError(Status
);
3530 if (!(SafePolyCounts
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(INT
), TAG_REGION
)))
3532 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3538 /* pointers were already probed! */
3539 RtlCopyMemory(SafePolyCounts
,
3541 Count
* sizeof(INT
));
3545 Status
= _SEH_GetExceptionCode();
3549 if (!NT_SUCCESS(Status
))
3551 ExFreePool(SafePolyCounts
);
3552 SetLastNtError(Status
);
3556 /* validate poligons */
3560 for (i
= 0; i
< Count
; i
++)
3562 if (SafePolyCounts
[i
] == 0)
3566 if (SafePolyCounts
[i
] == 1)
3570 nPoints
+= SafePolyCounts
[i
];
3573 if (nEmpty
== Count
)
3575 /* if all polygon counts are zero, return without setting a last error code. */
3576 ExFreePool(SafePolyCounts
);
3581 /* if at least one poly count is 1, fail */
3582 ExFreePool(SafePolyCounts
);
3583 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
3588 if (!(Safept
= ExAllocatePoolWithTag(PagedPool
, nPoints
* sizeof(POINT
), TAG_REGION
)))
3590 ExFreePool(SafePolyCounts
);
3591 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3598 nPoints
* sizeof(POINT
),
3600 /* pointers were already probed! */
3601 RtlCopyMemory(Safept
,
3603 nPoints
* sizeof(POINT
));
3607 Status
= _SEH_GetExceptionCode();
3610 if (!NT_SUCCESS(Status
))
3613 ExFreePool(SafePolyCounts
);
3614 SetLastNtError(Status
);
3618 /* now we're ready to calculate the region safely */
3619 hRgn
= IntCreatePolyPolgonRgn(Safept
, SafePolyCounts
, Count
, PolyFillMode
);
3622 ExFreePool(SafePolyCounts
);