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>
120 // Internal Functions
123 #define COPY_RECTS(dest, src, nRects) \
125 PRECT xDest = (dest); \
126 PRECT xSrc = (src); \
127 UINT xRects = (nRects); \
128 while(xRects-- > 0) { \
129 *(xDest++) = *(xSrc++); \
133 #define COPY_RECTS(dest, src, nRects) RtlCopyMemory(dest, src, (nRects) * sizeof(RECT))
136 #define EMPTY_REGION(pReg) { \
137 (pReg)->rdh.nCount = 0; \
138 (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
139 (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
140 (pReg)->rdh.iType = NULLREGION; \
143 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
145 #define INRECT(r, x, y) \
146 ( ( ((r).right > x)) && \
147 ( ((r).left <= x)) && \
148 ( ((r).bottom > y)) && \
151 /* 1 if two RECTs overlap.
152 * 0 if two RECTs do not overlap.
154 #define EXTENTCHECK(r1, r2) \
155 ((r1)->right > (r2)->left && \
156 (r1)->left < (r2)->right && \
157 (r1)->bottom > (r2)->top && \
158 (r1)->top < (r2)->bottom)
161 * In scan converting polygons, we want to choose those pixels
162 * which are inside the polygon. Thus, we add .5 to the starting
163 * x coordinate for both left and right edges. Now we choose the
164 * first pixel which is inside the pgon for the left edge and the
165 * first pixel which is outside the pgon for the right edge.
166 * Draw the left pixel, but not the right.
168 * How to add .5 to the starting x coordinate:
169 * If the edge is moving to the right, then subtract dy from the
170 * error term from the general form of the algorithm.
171 * If the edge is moving to the left, then add dy to the error term.
173 * The reason for the difference between edges moving to the left
174 * and edges moving to the right is simple: If an edge is moving
175 * to the right, then we want the algorithm to flip immediately.
176 * If it is moving to the left, then we don't want it to flip until
177 * we traverse an entire pixel.
179 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
180 int dx; /* local storage */ \
183 * if the edge is horizontal, then it is ignored \
184 * and assumed not to be processed. Otherwise, do this stuff. \
188 dx = (x2) - xStart; \
192 incr1 = -2 * dx + 2 * (dy) * m1; \
193 incr2 = -2 * dx + 2 * (dy) * m; \
194 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
198 incr1 = 2 * dx - 2 * (dy) * m1; \
199 incr2 = 2 * dx - 2 * (dy) * m; \
200 d = -2 * m * (dy) + 2 * dx; \
205 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
228 * This structure contains all of the information needed
229 * to run the bresenham algorithm.
230 * The variables may be hardcoded into the declarations
231 * instead of using this structure to make use of
232 * register declarations.
235 INT minor_axis
; /* minor axis */
236 INT d
; /* decision variable */
237 INT m
, m1
; /* slope and slope+1 */
238 INT incr1
, incr2
; /* error increments */
242 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
243 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
244 bres.m, bres.m1, bres.incr1, bres.incr2)
246 #define BRESINCRPGONSTRUCT(bres) \
247 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
252 * These are the data structures needed to scan
253 * convert regions. Two different scan conversion
254 * methods are available -- the even-odd method, and
255 * the winding number method.
256 * The even-odd rule states that a point is inside
257 * the polygon if a ray drawn from that point in any
258 * direction will pass through an odd number of
260 * By the winding number rule, a point is decided
261 * to be inside the polygon if a ray drawn from that
262 * point in any direction passes through a different
263 * number of clockwise and counter-clockwise path
266 * These data structures are adapted somewhat from
267 * the algorithm in (Foley/Van Dam) for scan converting
269 * The basic algorithm is to start at the top (smallest y)
270 * of the polygon, stepping down to the bottom of
271 * the polygon by incrementing the y coordinate. We
272 * keep a list of edges which the current scanline crosses,
273 * sorted by x. This list is called the Active Edge Table (AET)
274 * As we change the y-coordinate, we update each entry in
275 * in the active edge table to reflect the edges new xcoord.
276 * This list must be sorted at each scanline in case
277 * two edges intersect.
278 * We also keep a data structure known as the Edge Table (ET),
279 * which keeps track of all the edges which the current
280 * scanline has not yet reached. The ET is basically a
281 * list of ScanLineList structures containing a list of
282 * edges which are entered at a given scanline. There is one
283 * ScanLineList per scanline at which an edge is entered.
284 * When we enter a new edge, we move it from the ET to the AET.
286 * From the AET, we can implement the even-odd rule as in
288 * The winding number rule is a little trickier. We also
289 * keep the EdgeTableEntries in the AET linked by the
290 * nextWETE (winding EdgeTableEntry) link. This allows
291 * the edges to be linked just as before for updating
292 * purposes, but only uses the edges linked by the nextWETE
293 * link as edges representing spans of the polygon to
294 * drawn (as with the even-odd rule).
298 * for the winding number rule
301 #define COUNTERCLOCKWISE -1
303 typedef struct _EdgeTableEntry
{
304 INT ymax
; /* ycoord at which we exit this edge. */
305 BRESINFO bres
; /* Bresenham info to run the edge */
306 struct _EdgeTableEntry
*next
; /* next in the list */
307 struct _EdgeTableEntry
*back
; /* for insertion sort */
308 struct _EdgeTableEntry
*nextWETE
; /* for winding num rule */
309 int ClockWise
; /* flag for winding number rule */
313 typedef struct _ScanLineList
{
314 INT scanline
; /* the scanline represented */
315 EdgeTableEntry
*edgelist
; /* header node */
316 struct _ScanLineList
*next
; /* next in the list */
321 INT ymax
; /* ymax for the polygon */
322 INT ymin
; /* ymin for the polygon */
323 ScanLineList scanlines
; /* header node */
328 * Here is a struct to help with storage allocation
329 * so we can allocate a big chunk at a time, and then take
330 * pieces from this heap when we need to.
332 #define SLLSPERBLOCK 25
334 typedef struct _ScanLineListBlock
{
335 ScanLineList SLLs
[SLLSPERBLOCK
];
336 struct _ScanLineListBlock
*next
;
342 * a few macros for the inner loops of the fill code where
343 * performance considerations don't allow a procedure call.
345 * Evaluate the given edge at the given scanline.
346 * If the edge has expired, then we leave it and fix up
347 * the active edge table; otherwise, we increment the
348 * x value to be ready for the next scanline.
349 * The winding number rule is in effect, so we must notify
350 * the caller when the edge has been removed so he
351 * can reorder the Winding Active Edge Table.
353 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
354 if (pAET->ymax == y) { /* leaving this edge */ \
355 pPrevAET->next = pAET->next; \
356 pAET = pPrevAET->next; \
359 pAET->back = pPrevAET; \
362 BRESINCRPGONSTRUCT(pAET->bres); \
370 * Evaluate the given edge at the given scanline.
371 * If the edge has expired, then we leave it and fix up
372 * the active edge table; otherwise, we increment the
373 * x value to be ready for the next scanline.
374 * The even-odd rule is in effect.
376 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
377 if (pAET->ymax == y) { /* leaving this edge */ \
378 pPrevAET->next = pAET->next; \
379 pAET = pPrevAET->next; \
381 pAET->back = pPrevAET; \
384 BRESINCRPGONSTRUCT(pAET->bres); \
390 /**************************************************************************
394 *************************************************************************/
396 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
397 #define SMALL_COORDINATE 0x80000000
400 * Check to see if there is enough memory in the present region.
402 static inline int xmemcheck(ROSRGNDATA
*reg
, PRECT
*rect
, PRECT
*firstrect
) {
403 if ( (reg
->rdh
.nCount
+1)*sizeof( RECT
) >= reg
->rdh
.nRgnSize
) {
405 temp
= ExAllocatePoolWithTag( PagedPool
, (2 * (reg
->rdh
.nRgnSize
)), TAG_REGION
);
410 /* copy the rectangles */
411 COPY_RECTS(temp
, *firstrect
, reg
->rdh
.nCount
);
413 reg
->rdh
.nRgnSize
*= 2;
414 if (*firstrect
!= ®
->rdh
.rcBound
)
415 ExFreePool( *firstrect
);
417 *rect
= (*firstrect
)+reg
->rdh
.nCount
;
422 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(LPRECT *)&(firstrect))
424 typedef void FASTCALL (*overlapProcp
)(PROSRGNDATA
, PRECT
, PRECT
, PRECT
, PRECT
, INT
, INT
);
425 typedef void FASTCALL (*nonOverlapProcp
)(PROSRGNDATA
, PRECT
, PRECT
, INT
, INT
);
427 // Number of points to buffer before sending them off to scanlines() : Must be an even number
428 #define NUMPTSTOBUFFER 200
430 #define RGN_DEFAULT_RECTS 2
432 // used to allocate buffers for points and link the buffers together
434 typedef struct _POINTBLOCK
{
435 POINT pts
[NUMPTSTOBUFFER
];
436 struct _POINTBLOCK
*next
;
441 * This function is left there for debugging purposes.
445 IntDumpRegion(HRGN hRgn
)
449 Data
= RGNDATA_LockRgn(hRgn
);
452 DbgPrint("IntDumpRegion called with invalid region!\n");
456 DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
458 Data
->rdh
.rcBound
.left
,
459 Data
->rdh
.rcBound
.top
,
460 Data
->rdh
.rcBound
.right
,
461 Data
->rdh
.rcBound
.bottom
,
464 RGNDATA_UnlockRgn(Data
);
468 static BOOL FASTCALL
REGION_CopyRegion(PROSRGNDATA dst
, PROSRGNDATA src
)
470 if(dst
!= src
) // don't want to copy to itself
472 if (dst
->rdh
.nRgnSize
< src
->rdh
.nCount
* sizeof(RECT
))
476 temp
= ExAllocatePoolWithTag(PagedPool
, src
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
480 if( dst
->Buffer
&& dst
->Buffer
!= &dst
->rdh
.rcBound
)
481 ExFreePool( dst
->Buffer
); //free the old buffer
483 dst
->rdh
.nRgnSize
= src
->rdh
.nCount
* sizeof(RECT
); //size of region buffer
485 dst
->rdh
.nCount
= src
->rdh
.nCount
; //number of rectangles present in Buffer
486 dst
->rdh
.rcBound
.left
= src
->rdh
.rcBound
.left
;
487 dst
->rdh
.rcBound
.top
= src
->rdh
.rcBound
.top
;
488 dst
->rdh
.rcBound
.right
= src
->rdh
.rcBound
.right
;
489 dst
->rdh
.rcBound
.bottom
= src
->rdh
.rcBound
.bottom
;
490 dst
->rdh
.iType
= src
->rdh
.iType
;
491 COPY_RECTS(dst
->Buffer
, src
->Buffer
, src
->rdh
.nCount
);
496 static void FASTCALL
REGION_SetExtents (ROSRGNDATA
*pReg
)
498 RECT
*pRect
, *pRectEnd
, *pExtents
;
500 if (pReg
->rdh
.nCount
== 0)
502 pReg
->rdh
.rcBound
.left
= 0;
503 pReg
->rdh
.rcBound
.top
= 0;
504 pReg
->rdh
.rcBound
.right
= 0;
505 pReg
->rdh
.rcBound
.bottom
= 0;
506 pReg
->rdh
.iType
= NULLREGION
;
510 pExtents
= &pReg
->rdh
.rcBound
;
511 pRect
= (PRECT
)pReg
->Buffer
;
512 pRectEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
- 1;
515 * Since pRect is the first rectangle in the region, it must have the
516 * smallest top and since pRectEnd is the last rectangle in the region,
517 * it must have the largest bottom, because of banding. Initialize left and
518 * right from pRect and pRectEnd, resp., as good things to initialize them
521 pExtents
->left
= pRect
->left
;
522 pExtents
->top
= pRect
->top
;
523 pExtents
->right
= pRectEnd
->right
;
524 pExtents
->bottom
= pRectEnd
->bottom
;
526 while (pRect
<= pRectEnd
)
528 if (pRect
->left
< pExtents
->left
)
529 pExtents
->left
= pRect
->left
;
530 if (pRect
->right
> pExtents
->right
)
531 pExtents
->right
= pRect
->right
;
534 pReg
->rdh
.iType
= (1 == pReg
->rdh
.nCount
? SIMPLEREGION
: COMPLEXREGION
);
538 /***********************************************************************
539 * REGION_CropAndOffsetRegion
541 static BOOL FASTCALL
REGION_CropAndOffsetRegion(const PPOINT off
, const PRECT rect
, PROSRGNDATA rgnSrc
, PROSRGNDATA rgnDst
)
543 if(!rect
) // just copy and offset
549 xrect
= (PRECT
)rgnDst
->Buffer
;
554 xrect
= ExAllocatePoolWithTag(PagedPool
, rgnSrc
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
555 if( rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
556 ExFreePool( rgnDst
->Buffer
); //free the old buffer. will be assigned to xrect below.
570 for(i
= 0; i
< rgnDst
->rdh
.nCount
; i
++)
572 xrect
[i
].left
= ((PRECT
)rgnSrc
->Buffer
+ i
)->left
+ off
->x
;
573 xrect
[i
].right
= ((PRECT
)rgnSrc
->Buffer
+ i
)->right
+ off
->x
;
574 xrect
[i
].top
= ((PRECT
)rgnSrc
->Buffer
+ i
)->top
+ off
->y
;
575 xrect
[i
].bottom
= ((PRECT
)rgnSrc
->Buffer
+ i
)->bottom
+ off
->y
;
577 rgnDst
->rdh
.rcBound
.left
+= off
->x
;
578 rgnDst
->rdh
.rcBound
.right
+= off
->x
;
579 rgnDst
->rdh
.rcBound
.top
+= off
->y
;
580 rgnDst
->rdh
.rcBound
.bottom
+= off
->y
;
584 COPY_RECTS(xrect
, rgnSrc
->Buffer
, rgnDst
->rdh
.nCount
);
587 rgnDst
->Buffer
= xrect
;
591 else if ((rect
->left
>= rect
->right
) ||
592 (rect
->top
>= rect
->bottom
) ||
593 !EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
))
597 else // region box and clipping rect appear to intersect
600 ULONG i
, j
, clipa
, clipb
;
601 INT left
= rgnSrc
->rdh
.rcBound
.right
+ off
->x
;
602 INT right
= rgnSrc
->rdh
.rcBound
.left
+ off
->x
;
604 for(clipa
= 0; ((PRECT
)rgnSrc
->Buffer
+ clipa
)->bottom
<= rect
->top
; clipa
++)
605 //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
606 ; // skip bands above the clipping rectangle
608 for(clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
609 if(((PRECT
)rgnSrc
->Buffer
+ clipb
)->top
>= rect
->bottom
)
610 break; // and below it
612 // clipa - index of the first rect in the first intersecting band
613 // clipb - index of the last rect in the last intersecting band
615 if((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nCount
< (i
= (clipb
- clipa
))))
618 temp
= ExAllocatePoolWithTag( PagedPool
, i
* sizeof(RECT
), TAG_REGION
);
622 if( rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
623 ExFreePool( rgnDst
->Buffer
); //free the old buffer
624 rgnDst
->Buffer
= temp
;
625 rgnDst
->rdh
.nCount
= i
;
626 rgnDst
->rdh
.nRgnSize
= i
* sizeof(RECT
);
629 for(i
= clipa
, j
= 0; i
< clipb
; i
++)
631 // i - src index, j - dst index, j is always <= i for obvious reasons
633 lpr
= (PRECT
)rgnSrc
->Buffer
+ i
;
635 if(lpr
->left
< rect
->right
&& lpr
->right
> rect
->left
)
637 rpr
= (PRECT
)rgnDst
->Buffer
+ j
;
639 rpr
->top
= lpr
->top
+ off
->y
;
640 rpr
->bottom
= lpr
->bottom
+ off
->y
;
641 rpr
->left
= ((lpr
->left
> rect
->left
) ? lpr
->left
: rect
->left
) + off
->x
;
642 rpr
->right
= ((lpr
->right
< rect
->right
) ? lpr
->right
: rect
->right
) + off
->x
;
644 if(rpr
->left
< left
) left
= rpr
->left
;
645 if(rpr
->right
> right
) right
= rpr
->right
;
651 if(j
== 0) goto empty
;
653 rgnDst
->rdh
.rcBound
.left
= left
;
654 rgnDst
->rdh
.rcBound
.right
= right
;
656 left
= rect
->top
+ off
->y
;
657 right
= rect
->bottom
+ off
->y
;
659 rgnDst
->rdh
.nCount
= j
--;
660 for(i
= 0; i
<= j
; i
++) // fixup top band
661 if((rgnDst
->Buffer
+ i
)->top
< left
)
662 (rgnDst
->Buffer
+ i
)->top
= left
;
666 for(i
= j
; i
>= 0; i
--) // fixup bottom band
667 if(((PRECT
)rgnDst
->Buffer
+ i
)->bottom
> right
)
668 ((PRECT
)rgnDst
->Buffer
+ i
)->bottom
= right
;
672 rgnDst
->rdh
.rcBound
.top
= ((PRECT
)rgnDst
->Buffer
)->top
;
673 rgnDst
->rdh
.rcBound
.bottom
= ((PRECT
)rgnDst
->Buffer
+ j
)->bottom
;
675 rgnDst
->rdh
.iType
= (j
>= 1) ? COMPLEXREGION
: SIMPLEREGION
;
683 rgnDst
->Buffer
= (PRECT
)ExAllocatePoolWithTag(PagedPool
, RGN_DEFAULT_RECTS
* sizeof(RECT
), TAG_REGION
);
685 rgnDst
->rdh
.nCount
= RGN_DEFAULT_RECTS
;
686 rgnDst
->rdh
.nRgnSize
= RGN_DEFAULT_RECTS
* sizeof(RECT
);
691 EMPTY_REGION(rgnDst
);
697 * hSrc: Region to crop and offset.
698 * lpRect: Clipping rectangle. Can be NULL (no clipping).
699 * lpPt: Points to offset the cropped region. Can be NULL (no offset).
701 * hDst: Region to hold the result (a new region is created if it's 0).
702 * Allowed to be the same region as hSrc in which case everything
703 * will be done in place, with no memory reallocations.
705 * \return hDst if success, 0 otherwise.
707 HRGN FASTCALL
REGION_CropRgn(HRGN hDst
, HRGN hSrc
, const PRECT lpRect
, PPOINT lpPt
)
709 PROSRGNDATA objSrc
, rgnDst
;
715 if( !( hDst
= RGNDATA_AllocRgn(1) ) )
721 rgnDst
= RGNDATA_LockRgn(hDst
);
727 objSrc
= RGNDATA_LockRgn(hSrc
);
730 RGNDATA_UnlockRgn(rgnDst
);
736 if(REGION_CropAndOffsetRegion(lpPt
, lpRect
, objSrc
, rgnDst
) == FALSE
)
737 { // ve failed cleanup and return
740 else{ // ve are fine. unlock the correct pointer and return correct handle
744 RGNDATA_UnlockRgn(objSrc
);
745 RGNDATA_UnlockRgn(rgnDst
);
751 * Attempt to merge the rects in the current band with those in the
752 * previous one. Used only by REGION_RegionOp.
755 * The new index for the previous band.
757 * \note Side Effects:
758 * If coalescing takes place:
759 * - rectangles in the previous band will have their bottom fields
761 * - pReg->numRects will be decreased.
764 static INT FASTCALL
REGION_Coalesce (
765 PROSRGNDATA pReg
, /* Region to coalesce */
766 INT prevStart
, /* Index of start of previous band */
767 INT curStart
/* Index of start of current band */
769 RECT
*pPrevRect
; /* Current rect in previous band */
770 RECT
*pCurRect
; /* Current rect in current band */
771 RECT
*pRegEnd
; /* End of region */
772 INT curNumRects
; /* Number of rectangles in current band */
773 INT prevNumRects
; /* Number of rectangles in previous band */
774 INT bandtop
; /* top coordinate for current band */
776 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
777 pPrevRect
= (PRECT
)pReg
->Buffer
+ prevStart
;
778 prevNumRects
= curStart
- prevStart
;
781 * Figure out how many rectangles are in the current band. Have to do
782 * this because multiple bands could have been added in REGION_RegionOp
783 * at the end when one region has been exhausted.
785 pCurRect
= (PRECT
)pReg
->Buffer
+ curStart
;
786 bandtop
= pCurRect
->top
;
787 for (curNumRects
= 0;
788 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
794 if (pCurRect
!= pRegEnd
)
797 * If more than one band was added, we have to find the start
798 * of the last band added so the next coalescing job can start
799 * at the right place... (given when multiple bands are added,
800 * this may be pointless -- see above).
803 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
807 curStart
= pRegEnd
- (PRECT
)pReg
->Buffer
;
808 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
811 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0)) {
812 pCurRect
-= curNumRects
;
814 * The bands may only be coalesced if the bottom of the previous
815 * matches the top scanline of the current.
817 if (pPrevRect
->bottom
== pCurRect
->top
)
820 * Make sure the bands have rects in the same places. This
821 * assumes that rects have been added in such a way that they
822 * cover the most area possible. I.e. two rects in a band must
823 * have some horizontal space between them.
827 if ((pPrevRect
->left
!= pCurRect
->left
) ||
828 (pPrevRect
->right
!= pCurRect
->right
))
831 * The bands don't line up so they can't be coalesced.
838 } while (prevNumRects
!= 0);
840 pReg
->rdh
.nCount
-= curNumRects
;
841 pCurRect
-= curNumRects
;
842 pPrevRect
-= curNumRects
;
845 * The bands may be merged, so set the bottom of each rect
846 * in the previous band to that of the corresponding rect in
851 pPrevRect
->bottom
= pCurRect
->bottom
;
855 } while (curNumRects
!= 0);
858 * If only one band was added to the region, we have to backup
859 * curStart to the start of the previous band.
861 * If more than one band was added to the region, copy the
862 * other bands down. The assumption here is that the other bands
863 * came from the same region as the current one and no further
864 * coalescing can be done on them since it's all been done
865 * already... curStart is already in the right place.
867 if (pCurRect
== pRegEnd
)
869 curStart
= prevStart
;
875 *pPrevRect
++ = *pCurRect
++;
876 } while (pCurRect
!= pRegEnd
);
884 * Apply an operation to two regions. Called by REGION_Union,
885 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
891 * The new region is overwritten.
893 *\note The idea behind this function is to view the two regions as sets.
894 * Together they cover a rectangle of area that this function divides
895 * into horizontal bands where points are covered only by one region
896 * or by both. For the first case, the nonOverlapFunc is called with
897 * each the band and the band's upper and lower extents. For the
898 * second, the overlapFunc is called to process the entire band. It
899 * is responsible for clipping the rectangles in the band, though
900 * this function provides the boundaries.
901 * At the end of each band, the new region is coalesced, if possible,
902 * to reduce the number of rectangles in the region.
907 ROSRGNDATA
*newReg
, /* Place to store result */
908 ROSRGNDATA
*reg1
, /* First region in operation */
909 ROSRGNDATA
*reg2
, /* 2nd region in operation */
910 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
911 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
912 nonOverlapProcp nonOverlap2Func
/* Function to call for non-overlapping bands in region 2 */
915 RECT
*r1
; /* Pointer into first region */
916 RECT
*r2
; /* Pointer into 2d region */
917 RECT
*r1End
; /* End of 1st region */
918 RECT
*r2End
; /* End of 2d region */
919 INT ybot
; /* Bottom of intersection */
920 INT ytop
; /* Top of intersection */
921 RECT
*oldRects
; /* Old rects for newReg */
922 ULONG prevBand
; /* Index of start of
923 * previous band in newReg */
924 ULONG curBand
; /* Index of start of current band in newReg */
925 RECT
*r1BandEnd
; /* End of current band in r1 */
926 RECT
*r2BandEnd
; /* End of current band in r2 */
927 ULONG top
; /* Top of non-overlapping band */
928 ULONG bot
; /* Bottom of non-overlapping band */
932 * set r1, r2, r1End and r2End appropriately, preserve the important
933 * parts of the destination region until the end in case it's one of
934 * the two source regions, then mark the "new" region empty, allocating
935 * another array of rectangles for it to use.
937 r1
= (PRECT
)reg1
->Buffer
;
938 r2
= (PRECT
)reg2
->Buffer
;
939 r1End
= r1
+ reg1
->rdh
.nCount
;
940 r2End
= r2
+ reg2
->rdh
.nCount
;
944 * newReg may be one of the src regions so we can't empty it. We keep a
945 * note of its rects pointer (so that we can free them later), preserve its
946 * extents and simply set numRects to zero.
949 oldRects
= (PRECT
)newReg
->Buffer
;
950 newReg
->rdh
.nCount
= 0;
953 * Allocate a reasonable number of rectangles for the new region. The idea
954 * is to allocate enough so the individual functions don't need to
955 * reallocate and copy the array, which is time consuming, yet we don't
956 * have to worry about using too much memory. I hope to be able to
957 * nuke the Xrealloc() at the end of this function eventually.
959 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
,reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
961 if (! (newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, newReg
->rdh
.nRgnSize
, TAG_REGION
)))
963 newReg
->rdh
.nRgnSize
= 0;
968 * Initialize ybot and ytop.
969 * In the upcoming loop, ybot and ytop serve different functions depending
970 * on whether the band being handled is an overlapping or non-overlapping
972 * In the case of a non-overlapping band (only one of the regions
973 * has points in the band), ybot is the bottom of the most recent
974 * intersection and thus clips the top of the rectangles in that band.
975 * ytop is the top of the next intersection between the two regions and
976 * serves to clip the bottom of the rectangles in the current band.
977 * For an overlapping band (where the two regions intersect), ytop clips
978 * the top of the rectangles of both regions and ybot clips the bottoms.
980 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
981 ybot
= reg1
->rdh
.rcBound
.top
;
983 ybot
= reg2
->rdh
.rcBound
.top
;
986 * prevBand serves to mark the start of the previous band so rectangles
987 * can be coalesced into larger rectangles. qv. miCoalesce, above.
988 * In the beginning, there is no previous band, so prevBand == curBand
989 * (curBand is set later on, of course, but the first band will always
990 * start at index 0). prevBand and curBand must be indices because of
991 * the possible expansion, and resultant moving, of the new region's
992 * array of rectangles.
998 curBand
= newReg
->rdh
.nCount
;
1001 * This algorithm proceeds one source-band (as opposed to a
1002 * destination band, which is determined by where the two regions
1003 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1004 * rectangle after the last one in the current band for their
1005 * respective regions.
1008 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1014 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1020 * First handle the band that doesn't intersect, if any.
1022 * Note that attention is restricted to one band in the
1023 * non-intersecting region at once, so if a region has n
1024 * bands between the current position and the next place it overlaps
1025 * the other, this entire loop will be passed through n times.
1027 if (r1
->top
< r2
->top
)
1029 top
= max(r1
->top
,ybot
);
1030 bot
= min(r1
->bottom
,r2
->top
);
1032 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
1034 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
1039 else if (r2
->top
< r1
->top
)
1041 top
= max(r2
->top
,ybot
);
1042 bot
= min(r2
->bottom
,r1
->top
);
1044 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
1046 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
1057 * If any rectangles got added to the region, try and coalesce them
1058 * with rectangles from the previous band. Note we could just do
1059 * this test in miCoalesce, but some machines incur a not
1060 * inconsiderable cost for function calls, so...
1062 if (newReg
->rdh
.nCount
!= curBand
)
1064 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1068 * Now see if we've hit an intersecting band. The two bands only
1069 * intersect if ybot > ytop
1071 ybot
= min(r1
->bottom
, r2
->bottom
);
1072 curBand
= newReg
->rdh
.nCount
;
1075 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1078 if (newReg
->rdh
.nCount
!= curBand
)
1080 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1084 * If we've finished with a band (bottom == ybot) we skip forward
1085 * in the region to the next band.
1087 if (r1
->bottom
== ybot
)
1091 if (r2
->bottom
== ybot
)
1095 } while ((r1
!= r1End
) && (r2
!= r2End
));
1098 * Deal with whichever region still has rectangles left.
1100 curBand
= newReg
->rdh
.nCount
;
1103 if (nonOverlap1Func
!= NULL
)
1108 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1112 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
1113 max(r1
->top
,ybot
), r1
->bottom
);
1115 } while (r1
!= r1End
);
1118 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
1123 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1127 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
1128 max(r2
->top
,ybot
), r2
->bottom
);
1130 } while (r2
!= r2End
);
1133 if (newReg
->rdh
.nCount
!= curBand
)
1135 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
1139 * A bit of cleanup. To keep regions from growing without bound,
1140 * we shrink the array of rectangles to match the new number of
1141 * rectangles in the region. This never goes to 0, however...
1143 * Only do this stuff if the number of rectangles allocated is more than
1144 * twice the number of rectangles in the region (a simple optimization...).
1146 if ((2 * newReg
->rdh
.nCount
*sizeof(RECT
) < newReg
->rdh
.nRgnSize
&& (newReg
->rdh
.nCount
> 2)))
1148 if (REGION_NOT_EMPTY(newReg
))
1150 RECT
*prev_rects
= (PRECT
)newReg
->Buffer
;
1151 newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, newReg
->rdh
.nCount
*sizeof(RECT
), TAG_REGION
);
1153 if (! newReg
->Buffer
)
1154 newReg
->Buffer
= prev_rects
;
1156 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
1157 COPY_RECTS(newReg
->Buffer
, prev_rects
, newReg
->rdh
.nCount
);
1158 if (prev_rects
!= &newReg
->rdh
.rcBound
)
1159 ExFreePool( prev_rects
);
1165 * No point in doing the extra work involved in an Xrealloc if
1166 * the region is empty
1168 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
1169 if (newReg
->Buffer
!= &newReg
->rdh
.rcBound
)
1170 ExFreePool( newReg
->Buffer
);
1171 newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, sizeof(RECT
), TAG_REGION
);
1172 ASSERT( newReg
->Buffer
);
1176 if( newReg
->rdh
.nCount
== 0 )
1177 newReg
->rdh
.iType
= NULLREGION
;
1179 newReg
->rdh
.iType
= (newReg
->rdh
.nCount
> 1)? COMPLEXREGION
: SIMPLEREGION
;
1181 if (oldRects
!= &newReg
->rdh
.rcBound
)
1182 ExFreePool( oldRects
);
1186 /***********************************************************************
1187 * Region Intersection
1188 ***********************************************************************/
1192 * Handle an overlapping band for REGION_Intersect.
1197 * \note Side Effects:
1198 * Rectangles may be added to the region.
1201 static void FASTCALL
1215 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1217 while ((r1
!= r1End
) && (r2
!= r2End
))
1219 left
= max(r1
->left
, r2
->left
);
1220 right
= min(r1
->right
, r2
->right
);
1223 * If there's any overlap between the two rectangles, add that
1224 * overlap to the new region.
1225 * There's no need to check for subsumption because the only way
1226 * such a need could arise is if some region has two rectangles
1227 * right next to each other. Since that should never happen...
1231 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1232 pNextRect
->left
= left
;
1233 pNextRect
->top
= top
;
1234 pNextRect
->right
= right
;
1235 pNextRect
->bottom
= bottom
;
1236 pReg
->rdh
.nCount
+= 1;
1241 * Need to advance the pointers. Shift the one that extends
1242 * to the right the least, since the other still has a chance to
1243 * overlap with that region's next rectangle, if you see what I mean.
1245 if (r1
->right
< r2
->right
)
1249 else if (r2
->right
< r1
->right
)
1262 /***********************************************************************
1263 * REGION_IntersectRegion
1265 static void FASTCALL
REGION_IntersectRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
1268 /* check for trivial reject */
1269 if ( (!(reg1
->rdh
.nCount
)) || (!(reg2
->rdh
.nCount
)) ||
1270 (!EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
)))
1271 newReg
->rdh
.nCount
= 0;
1273 REGION_RegionOp (newReg
, reg1
, reg2
,
1274 REGION_IntersectO
, NULL
, NULL
);
1277 * Can't alter newReg's extents before we call miRegionOp because
1278 * it might be one of the source regions and miRegionOp depends
1279 * on the extents of those regions being the same. Besides, this
1280 * way there's no checking against rectangles that will be nuked
1281 * due to coalescing, so we have to examine fewer rectangles.
1284 REGION_SetExtents(newReg
);
1287 /***********************************************************************
1289 ***********************************************************************/
1292 * Handle a non-overlapping band for the union operation. Just
1293 * Adds the rectangles into the region. Doesn't have to check for
1294 * subsumption or anything.
1299 * \note Side Effects:
1300 * pReg->numRects is incremented and the final rectangles overwritten
1301 * with the rectangles we're passed.
1304 static void FASTCALL
1315 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1319 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1320 pNextRect
->left
= r
->left
;
1321 pNextRect
->top
= top
;
1322 pNextRect
->right
= r
->right
;
1323 pNextRect
->bottom
= bottom
;
1324 pReg
->rdh
.nCount
+= 1;
1332 * Handle an overlapping band for the union operation. Picks the
1333 * left-most rectangle each time and merges it into the region.
1338 * \note Side Effects:
1339 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1343 static void FASTCALL
1356 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1358 #define MERGERECT(r) \
1359 if ((pReg->rdh.nCount != 0) && \
1360 ((pNextRect-1)->top == top) && \
1361 ((pNextRect-1)->bottom == bottom) && \
1362 ((pNextRect-1)->right >= r->left)) \
1364 if ((pNextRect-1)->right < r->right) \
1366 (pNextRect-1)->right = r->right; \
1371 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1372 pNextRect->top = top; \
1373 pNextRect->bottom = bottom; \
1374 pNextRect->left = r->left; \
1375 pNextRect->right = r->right; \
1376 pReg->rdh.nCount += 1; \
1381 while ((r1
!= r1End
) && (r2
!= r2End
))
1383 if (r1
->left
< r2
->left
)
1398 } while (r1
!= r1End
);
1400 else while (r2
!= r2End
)
1407 /***********************************************************************
1408 * REGION_UnionRegion
1410 static void FASTCALL
REGION_UnionRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
1413 /* checks all the simple cases */
1416 * Region 1 and 2 are the same or region 1 is empty
1418 if (reg1
== reg2
|| 0 == reg1
->rdh
.nCount
||
1419 reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
||
1420 reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
)
1424 REGION_CopyRegion(newReg
, reg2
);
1430 * if nothing to union (region 2 empty)
1432 if (0 == reg2
->rdh
.nCount
||
1433 reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
||
1434 reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
)
1438 REGION_CopyRegion(newReg
, reg1
);
1444 * Region 1 completely subsumes region 2
1446 if (1 == reg1
->rdh
.nCount
&&
1447 reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
&&
1448 reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
&&
1449 reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
&&
1450 reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
)
1454 REGION_CopyRegion(newReg
, reg1
);
1460 * Region 2 completely subsumes region 1
1462 if (1 == reg2
->rdh
.nCount
&&
1463 reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
&&
1464 reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
&&
1465 reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
&&
1466 reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
)
1470 REGION_CopyRegion(newReg
, reg2
);
1475 REGION_RegionOp ( newReg
, reg1
, reg2
, REGION_UnionO
,
1476 REGION_UnionNonO
, REGION_UnionNonO
);
1477 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1478 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1479 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1480 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1483 /***********************************************************************
1484 * Region Subtraction
1485 ***********************************************************************/
1488 * Deal with non-overlapping band for subtraction. Any parts from
1489 * region 2 we discard. Anything from region 1 we add to the region.
1494 * \note Side Effects:
1495 * pReg may be affected.
1498 static void FASTCALL
1499 REGION_SubtractNonO1 (
1509 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1513 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1514 pNextRect
->left
= r
->left
;
1515 pNextRect
->top
= top
;
1516 pNextRect
->right
= r
->right
;
1517 pNextRect
->bottom
= bottom
;
1518 pReg
->rdh
.nCount
+= 1;
1527 * Overlapping band subtraction. x1 is the left-most point not yet
1533 * \note Side Effects:
1534 * pReg may have rectangles added to it.
1537 static void FASTCALL
1552 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1554 while ((r1
!= r1End
) && (r2
!= r2End
))
1556 if (r2
->right
<= left
)
1559 * Subtrahend missed the boat: go to next subtrahend.
1563 else if (r2
->left
<= left
)
1566 * Subtrahend preceeds minuend: nuke left edge of minuend.
1569 if (left
>= r1
->right
)
1572 * Minuend completely covered: advance to next minuend and
1573 * reset left fence to edge of new minuend.
1582 * Subtrahend now used up since it doesn't extend beyond
1588 else if (r2
->left
< r1
->right
)
1591 * Left part of subtrahend covers part of minuend: add uncovered
1592 * part of minuend to region and skip to next subtrahend.
1594 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1595 pNextRect
->left
= left
;
1596 pNextRect
->top
= top
;
1597 pNextRect
->right
= r2
->left
;
1598 pNextRect
->bottom
= bottom
;
1599 pReg
->rdh
.nCount
+= 1;
1602 if (left
>= r1
->right
)
1605 * Minuend used up: advance to new...
1614 * Subtrahend used up
1622 * Minuend used up: add any remaining piece before advancing.
1624 if (r1
->right
> left
)
1626 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1627 pNextRect
->left
= left
;
1628 pNextRect
->top
= top
;
1629 pNextRect
->right
= r1
->right
;
1630 pNextRect
->bottom
= bottom
;
1631 pReg
->rdh
.nCount
+= 1;
1640 * Add remaining minuend rectangles to region.
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;
1661 * Subtract regS from regM and leave the result in regD.
1662 * S stands for subtrahend, M for minuend and D for difference.
1667 * \note Side Effects:
1668 * regD is overwritten.
1671 static void FASTCALL
REGION_SubtractRegion(ROSRGNDATA
*regD
, ROSRGNDATA
*regM
,
1674 /* check for trivial reject */
1675 if ( (!(regM
->rdh
.nCount
)) || (!(regS
->rdh
.nCount
)) ||
1676 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1678 REGION_CopyRegion(regD
, regM
);
1682 REGION_RegionOp (regD
, regM
, regS
, REGION_SubtractO
,
1683 REGION_SubtractNonO1
, NULL
);
1686 * Can't alter newReg's extents before we call miRegionOp because
1687 * it might be one of the source regions and miRegionOp depends
1688 * on the extents of those regions being the unaltered. Besides, this
1689 * way there's no checking against rectangles that will be nuked
1690 * due to coalescing, so we have to examine fewer rectangles.
1692 REGION_SetExtents (regD
);
1695 /***********************************************************************
1698 static void FASTCALL
REGION_XorRegion(ROSRGNDATA
*dr
, ROSRGNDATA
*sra
,
1702 ROSRGNDATA
*tra
, *trb
;
1704 if(!(htra
= RGNDATA_AllocRgn(sra
->rdh
.nCount
+ 1)))
1706 if(!(htrb
= RGNDATA_AllocRgn(srb
->rdh
.nCount
+ 1)))
1708 NtGdiDeleteObject( htra
);
1711 tra
= RGNDATA_LockRgn( htra
);
1713 NtGdiDeleteObject( htra
);
1714 NtGdiDeleteObject( htrb
);
1718 trb
= RGNDATA_LockRgn( htrb
);
1720 RGNDATA_UnlockRgn( tra
);
1721 NtGdiDeleteObject( htra
);
1722 NtGdiDeleteObject( htrb
);
1726 REGION_SubtractRegion(tra
,sra
,srb
);
1727 REGION_SubtractRegion(trb
,srb
,sra
);
1728 REGION_UnionRegion(dr
,tra
,trb
);
1729 RGNDATA_UnlockRgn( tra
);
1730 RGNDATA_UnlockRgn( trb
);
1732 NtGdiDeleteObject( htra
);
1733 NtGdiDeleteObject( htrb
);
1739 * Adds a rectangle to a REGION
1741 void FASTCALL
REGION_UnionRectWithRegion(const RECT
*rect
, ROSRGNDATA
*rgn
)
1745 region
.Buffer
= ®ion
.rdh
.rcBound
;
1746 region
.rdh
.nCount
= 1;
1747 region
.rdh
.nRgnSize
= sizeof( RECT
);
1748 region
.rdh
.rcBound
= *rect
;
1749 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1752 BOOL FASTCALL
REGION_CreateFrameRgn(HRGN hDest
, HRGN hSrc
, INT x
, INT y
)
1754 PROSRGNDATA srcObj
, destObj
;
1758 if (!(srcObj
= (PROSRGNDATA
)RGNDATA_LockRgn(hSrc
)))
1762 if (!REGION_NOT_EMPTY(srcObj
))
1764 RGNDATA_UnlockRgn(srcObj
);
1767 if (!(destObj
= (PROSRGNDATA
)RGNDATA_LockRgn(hDest
)))
1769 RGNDATA_UnlockRgn(srcObj
);
1773 EMPTY_REGION(destObj
);
1774 if (!REGION_CopyRegion(destObj
, srcObj
))
1776 RGNDATA_UnlockRgn(destObj
);
1777 RGNDATA_UnlockRgn(srcObj
);
1781 /* Original region moved to right */
1782 rc
= (PRECT
)srcObj
->Buffer
;
1783 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1789 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1791 /* Original region moved to left */
1792 rc
= (PRECT
)srcObj
->Buffer
;
1793 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1799 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1801 /* Original region moved down */
1802 rc
= (PRECT
)srcObj
->Buffer
;
1803 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1811 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1813 /* Original region moved up */
1814 rc
= (PRECT
)srcObj
->Buffer
;
1815 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1818 rc
->bottom
-= 2 * y
;
1821 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1823 /* Restore the original region */
1824 rc
= (PRECT
)srcObj
->Buffer
;
1825 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1831 REGION_SubtractRegion(destObj
, srcObj
, destObj
);
1833 RGNDATA_UnlockRgn(destObj
);
1834 RGNDATA_UnlockRgn(srcObj
);
1839 BOOL FASTCALL
REGION_LPTODP(HDC hdc
, HRGN hDest
, HRGN hSrc
)
1841 RECT
*pCurRect
, *pEndRect
;
1842 PROSRGNDATA srcObj
= NULL
;
1843 PROSRGNDATA destObj
= NULL
;
1845 DC
* dc
= DC_LockDc(hdc
);
1852 if(dc
->w
.MapMode
== MM_TEXT
) // Requires only a translation
1854 if(NtGdiCombineRgn(hDest
, hSrc
, 0, RGN_COPY
) == ERROR
)
1857 NtGdiOffsetRgn(hDest
, dc
->vportOrgX
- dc
->wndOrgX
, dc
->vportOrgY
- dc
->wndOrgY
);
1862 if(!( srcObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hSrc
) ))
1864 if(!( destObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hDest
) ))
1866 RGNDATA_UnlockRgn( srcObj
);
1869 EMPTY_REGION(destObj
);
1871 pEndRect
= (PRECT
)srcObj
->Buffer
+ srcObj
->rdh
.nCount
;
1872 for(pCurRect
= (PRECT
)srcObj
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
1874 tmpRect
= *pCurRect
;
1875 tmpRect
.left
= XLPTODP(dc
, tmpRect
.left
);
1876 tmpRect
.top
= YLPTODP(dc
, tmpRect
.top
);
1877 tmpRect
.right
= XLPTODP(dc
, tmpRect
.right
);
1878 tmpRect
.bottom
= YLPTODP(dc
, tmpRect
.bottom
);
1880 if(tmpRect
.left
> tmpRect
.right
)
1881 { INT tmp
= tmpRect
.left
; tmpRect
.left
= tmpRect
.right
; tmpRect
.right
= tmp
; }
1882 if(tmpRect
.top
> tmpRect
.bottom
)
1883 { INT tmp
= tmpRect
.top
; tmpRect
.top
= tmpRect
.bottom
; tmpRect
.bottom
= tmp
; }
1885 REGION_UnionRectWithRegion(&tmpRect
, destObj
);
1889 RGNDATA_UnlockRgn( srcObj
);
1890 RGNDATA_UnlockRgn( destObj
);
1897 HRGN FASTCALL
RGNDATA_AllocRgn(INT n
)
1902 if ((hReg
= (HRGN
) GDIOBJ_AllocObj(GDI_OBJECT_TYPE_REGION
)))
1904 if (NULL
!= (pReg
= RGNDATA_LockRgn(hReg
)))
1908 /* Testing shows that > 95% of all regions have only 1 rect.
1909 Including that here saves us from having to do another
1911 pReg
->Buffer
= &pReg
->rdh
.rcBound
;
1915 pReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, n
* sizeof(RECT
), TAG_REGION
);
1917 if (NULL
!= pReg
->Buffer
)
1920 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
1921 pReg
->rdh
.nCount
= n
;
1922 pReg
->rdh
.nRgnSize
= n
*sizeof(RECT
);
1924 RGNDATA_UnlockRgn(pReg
);
1931 RGNDATA_FreeRgn(hReg
);
1939 RGNDATA_Cleanup(PVOID ObjectBody
)
1941 PROSRGNDATA pRgn
= (PROSRGNDATA
)ObjectBody
;
1942 if(pRgn
->Buffer
&& pRgn
->Buffer
!= &pRgn
->rdh
.rcBound
)
1943 ExFreePool(pRgn
->Buffer
);
1947 // NtGdi Exported Functions
1950 NtGdiCombineRgn(HRGN hDest
,
1956 PROSRGNDATA destRgn
, src1Rgn
, src2Rgn
;
1958 destRgn
= RGNDATA_LockRgn(hDest
);
1961 src1Rgn
= RGNDATA_LockRgn(hSrc1
);
1964 if (CombineMode
== RGN_COPY
)
1966 if( !REGION_CopyRegion(destRgn
, src1Rgn
) )
1968 result
= destRgn
->rdh
.iType
;
1972 src2Rgn
= RGNDATA_LockRgn(hSrc2
);
1975 switch (CombineMode
)
1978 REGION_IntersectRegion(destRgn
, src1Rgn
, src2Rgn
);
1981 REGION_UnionRegion(destRgn
, src1Rgn
, src2Rgn
);
1984 REGION_XorRegion(destRgn
, src1Rgn
, src2Rgn
);
1987 REGION_SubtractRegion(destRgn
, src1Rgn
, src2Rgn
);
1990 RGNDATA_UnlockRgn(src2Rgn
);
1991 result
= destRgn
->rdh
.iType
;
1993 else if(hSrc2
== NULL
)
1995 DPRINT1("NtGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode
);
1999 RGNDATA_UnlockRgn(src1Rgn
);
2002 RGNDATA_UnlockRgn(destRgn
);
2006 DPRINT("NtGdiCombineRgn: hDest unavailable\n");
2015 NtGdiCreateEllipticRgn(INT Left
,
2020 return NtGdiCreateRoundRectRgn(Left
, Top
, Right
, Bottom
,
2021 Right
- Left
, Bottom
- Top
);
2026 NtGdiCreateEllipticRgnIndirect(CONST PRECT Rect
)
2031 Status
= MmCopyFromCaller(&SafeRect
, Rect
, sizeof(RECT
));
2032 if(!NT_SUCCESS(Status
))
2034 SetLastNtError(Status
);
2038 return NtGdiCreateRoundRectRgn(SafeRect
.left
, SafeRect
.top
, SafeRect
.right
, SafeRect
.bottom
,
2039 SafeRect
.right
- SafeRect
.left
, SafeRect
.bottom
- SafeRect
.top
);
2043 NtGdiCreateRectRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
2047 /* Allocate region data structure with space for 1 RECT */
2048 if ((hRgn
= RGNDATA_AllocRgn(1)))
2050 if (NtGdiSetRectRgn(hRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
))
2052 NtGdiDeleteObject(hRgn
);
2055 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2060 NtGdiCreateRectRgnIndirect(CONST PRECT rc
)
2065 Status
= MmCopyFromCaller(&SafeRc
, rc
, sizeof(RECT
));
2066 if (!NT_SUCCESS(Status
))
2070 return(UnsafeIntCreateRectRgnIndirect(&SafeRc
));
2075 NtGdiCreateRoundRectRgn(INT left
, INT top
, INT right
, INT bottom
,
2076 INT ellipse_width
, INT ellipse_height
)
2080 int asq
, bsq
, d
, xd
, yd
;
2083 /* Make the dimensions sensible */
2085 if (left
> right
) { INT tmp
= left
; left
= right
; right
= tmp
; }
2086 if (top
> bottom
) { INT tmp
= top
; top
= bottom
; bottom
= tmp
; }
2088 ellipse_width
= abs(ellipse_width
);
2089 ellipse_height
= abs(ellipse_height
);
2091 /* Check parameters */
2093 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
2094 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
2096 /* Check if we can do a normal rectangle instead */
2098 if ((ellipse_width
< 2) || (ellipse_height
< 2))
2099 return NtGdiCreateRectRgn( left
, top
, right
, bottom
);
2103 d
= (ellipse_height
< 128) ? ((3 * ellipse_height
) >> 2) : 64;
2104 if (!(hrgn
= RGNDATA_AllocRgn(d
))) return 0;
2105 if (!(obj
= RGNDATA_LockRgn(hrgn
))) return 0;
2107 /* Ellipse algorithm, based on an article by K. Porter */
2108 /* in DDJ Graphics Programming Column, 8/89 */
2110 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
2111 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
2112 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
2114 yd
= asq
* ellipse_height
; /* 2a^2b */
2116 rect
.left
= left
+ ellipse_width
/ 2;
2117 rect
.right
= right
- ellipse_width
/ 2;
2119 /* Loop to draw first half of quadrant */
2123 if (d
> 0) /* if nearest pixel is toward the center */
2125 /* move toward center */
2127 rect
.bottom
= rect
.top
+ 1;
2128 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2129 rect
.top
= --bottom
;
2130 rect
.bottom
= rect
.top
+ 1;
2131 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2135 rect
.left
--; /* next horiz point */
2140 /* Loop to draw second half of quadrant */
2142 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
2145 /* next vertical point */
2147 rect
.bottom
= rect
.top
+ 1;
2148 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2149 rect
.top
= --bottom
;
2150 rect
.bottom
= rect
.top
+ 1;
2151 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2152 if (d
< 0) /* if nearest pixel is outside ellipse */
2154 rect
.left
--; /* move away from center */
2162 /* Add the inside rectangle */
2167 rect
.bottom
= bottom
;
2168 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2170 RGNDATA_UnlockRgn( obj
);
2176 NtGdiEqualRgn(HRGN hSrcRgn1
,
2179 PROSRGNDATA rgn1
, rgn2
;
2180 PRECT tRect1
, tRect2
;
2184 if( !(rgn1
= RGNDATA_LockRgn(hSrcRgn1
)))
2187 if( !(rgn2
= RGNDATA_LockRgn(hSrcRgn2
))){
2188 RGNDATA_UnlockRgn( rgn1
);
2192 if(rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
||
2193 rgn1
->rdh
.nCount
== 0 ||
2194 rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
||
2195 rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
||
2196 rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
||
2197 rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
)
2200 tRect1
= (PRECT
)rgn1
->Buffer
;
2201 tRect2
= (PRECT
)rgn2
->Buffer
;
2203 if( !tRect1
|| !tRect2
)
2206 for(i
=0; i
< rgn1
->rdh
.nCount
; i
++)
2208 if(tRect1
[i
].left
!= tRect2
[i
].left
||
2209 tRect1
[i
].right
!= tRect2
[i
].right
||
2210 tRect1
[i
].top
!= tRect2
[i
].top
||
2211 tRect1
[i
].bottom
!= tRect2
[i
].bottom
)
2217 RGNDATA_UnlockRgn( rgn1
);
2218 RGNDATA_UnlockRgn( rgn2
);
2224 NtGdiExtCreateRegion(CONST XFORM
*Xform
,
2226 CONST RGNDATA
*RgnData
)
2229 RGNDATA SafeRgnData
;
2233 if (Count
< FIELD_OFFSET(RGNDATA
, Buffer
))
2235 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2239 Status
= MmCopyFromCaller(&SafeRgnData
, RgnData
, min(Count
, sizeof(RGNDATA
)));
2240 if (!NT_SUCCESS(Status
))
2242 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2246 hRgn
= RGNDATA_AllocRgn(SafeRgnData
.rdh
.nCount
);
2249 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2253 Region
= RGNDATA_LockRgn(hRgn
);
2256 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2260 RtlCopyMemory(&Region
->rdh
, &SafeRgnData
, FIELD_OFFSET(RGNDATA
, Buffer
));
2262 Status
= MmCopyFromCaller(Region
->Buffer
, RgnData
->Buffer
,
2263 Count
- FIELD_OFFSET(RGNDATA
, Buffer
));
2264 if (!NT_SUCCESS(Status
))
2266 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2267 RGNDATA_UnlockRgn(Region
);
2268 NtGdiDeleteObject(hRgn
);
2272 RGNDATA_UnlockRgn(Region
);
2279 NtGdiFillRgn(HDC hDC
, HRGN hRgn
, HBRUSH hBrush
)
2285 if (NULL
== (rgn
= RGNDATA_LockRgn(hRgn
)))
2290 if (NULL
== (oldhBrush
= NtGdiSelectObject(hDC
, hBrush
)))
2292 RGNDATA_UnlockRgn(rgn
);
2296 for (r
= rgn
->Buffer
; r
< rgn
->Buffer
+ rgn
->rdh
.nCount
; r
++)
2298 NtGdiPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
2301 RGNDATA_UnlockRgn( rgn
);
2302 NtGdiSelectObject(hDC
, oldhBrush
);
2309 NtGdiFrameRgn(HDC hDC
, HRGN hRgn
, HBRUSH hBrush
, INT Width
, INT Height
)
2314 if(!(FrameRgn
= NtGdiCreateRectRgn(0, 0, 0, 0)))
2318 if(!REGION_CreateFrameRgn(FrameRgn
, hRgn
, Width
, Height
))
2320 NtGdiDeleteObject(FrameRgn
);
2324 Ret
= NtGdiFillRgn(hDC
, FrameRgn
, hBrush
);
2326 NtGdiDeleteObject(FrameRgn
);
2331 UnsafeIntGetRgnBox(PROSRGNDATA Rgn
,
2338 *pRect
= Rgn
->rdh
.rcBound
;
2339 ret
= Rgn
->rdh
.iType
;
2343 return 0; //if invalid region return zero
2348 NtGdiGetRgnBox(HRGN hRgn
,
2355 if (!(Rgn
= RGNDATA_LockRgn(hRgn
)))
2360 ret
= UnsafeIntGetRgnBox(Rgn
, &SafeRect
);
2361 RGNDATA_UnlockRgn(Rgn
);
2367 if (!NT_SUCCESS(MmCopyToCaller(pRect
, &SafeRect
, sizeof(RECT
))))
2377 NtGdiInvertRgn(HDC hDC
,
2380 PROSRGNDATA RgnData
;
2384 if(!(RgnData
= RGNDATA_LockRgn(hRgn
)))
2386 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2390 rc
= (PRECT
)RgnData
->Buffer
;
2391 for(i
= 0; i
< RgnData
->rdh
.nCount
; i
++)
2394 if(!NtGdiPatBlt(hDC
, rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, DSTINVERT
))
2396 RGNDATA_UnlockRgn(RgnData
);
2402 RGNDATA_UnlockRgn(RgnData
);
2408 NtGdiOffsetRgn(HRGN hRgn
,
2412 PROSRGNDATA rgn
= RGNDATA_LockRgn(hRgn
);
2415 DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn
, XOffset
, YOffset
, rgn
);
2418 DPRINT("NtGdiOffsetRgn: hRgn error\n");
2422 if(XOffset
|| YOffset
) {
2423 int nbox
= rgn
->rdh
.nCount
;
2424 PRECT pbox
= (PRECT
)rgn
->Buffer
;
2428 pbox
->left
+= XOffset
;
2429 pbox
->right
+= XOffset
;
2430 pbox
->top
+= YOffset
;
2431 pbox
->bottom
+= YOffset
;
2434 if (rgn
->Buffer
!= &rgn
->rdh
.rcBound
)
2436 rgn
->rdh
.rcBound
.left
+= XOffset
;
2437 rgn
->rdh
.rcBound
.right
+= XOffset
;
2438 rgn
->rdh
.rcBound
.top
+= YOffset
;
2439 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
2443 ret
= rgn
->rdh
.iType
;
2444 RGNDATA_UnlockRgn( rgn
);
2450 NtGdiPaintRgn(HDC hDC
,
2454 HRGN tmpVisRgn
; //, prevVisRgn;
2455 DC
*dc
= DC_LockDc(hDC
);
2457 CLIPOBJ
* ClipRegion
;
2459 PGDIBRUSHOBJ pBrush
;
2460 GDIBRUSHINST BrushInst
;
2462 BITMAPOBJ
*BitmapObj
;
2467 if(!(tmpVisRgn
= NtGdiCreateRectRgn(0, 0, 0, 0))){
2473 // Transform region into device co-ords
2474 if(!REGION_LPTODP(hDC, tmpVisRgn, hRgn) || NtGdiOffsetRgn(tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY) == ERROR) {
2475 NtGdiDeleteObject( tmpVisRgn );
2480 /* enable when clipping is implemented
2481 NtGdiCombineRgn(tmpVisRgn, tmpVisRgn, dc->w.hGCClipRgn, RGN_AND);
2484 //visrgn = RGNDATA_LockRgn(tmpVisRgn);
2485 visrgn
= RGNDATA_LockRgn(hRgn
);
2492 ClipRegion
= IntEngCreateClipRegion (
2493 visrgn
->rdh
.nCount
, (PRECTL
)visrgn
->Buffer
, (PRECTL
)&visrgn
->rdh
.rcBound
);
2494 ASSERT( ClipRegion
);
2495 pBrush
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
2497 IntGdiInitBrushInstance(&BrushInst
, pBrush
, dc
->XlateBrush
);
2499 BrushOrigin
.x
= dc
->w
.brushOrgX
;
2500 BrushOrigin
.y
= dc
->w
.brushOrgY
;
2501 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
2502 /* FIXME - Handle BitmapObj == NULL !!!! */
2504 bRet
= IntEngPaint(&BitmapObj
->SurfObj
,
2506 &BrushInst
.BrushObject
,
2508 0xFFFF);//FIXME:don't know what to put here
2510 BITMAPOBJ_UnlockBitmap(BitmapObj
);
2511 RGNDATA_UnlockRgn( visrgn
);
2520 NtGdiPtInRegion(HRGN hRgn
,
2528 if(!(rgn
= RGNDATA_LockRgn(hRgn
) ) )
2531 if(rgn
->rdh
.nCount
> 0 && INRECT(rgn
->rdh
.rcBound
, X
, Y
)){
2532 r
= (PRECT
) rgn
->Buffer
;
2533 for(i
= 0; i
< rgn
->rdh
.nCount
; i
++) {
2534 if(INRECT(*r
, X
, Y
)){
2535 RGNDATA_UnlockRgn(rgn
);
2541 RGNDATA_UnlockRgn(rgn
);
2547 UnsafeIntRectInRegion(PROSRGNDATA Rgn
,
2550 PRECT pCurRect
, pRectEnd
;
2552 // this is (just) a useful optimization
2553 if((Rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&Rgn
->rdh
.rcBound
, rc
))
2555 for (pCurRect
= (PRECT
)Rgn
->Buffer
, pRectEnd
= pCurRect
+ Rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
2557 if (pCurRect
->bottom
<= rc
->top
) continue; // not far enough down yet
2558 if (pCurRect
->top
>= rc
->bottom
) break; // too far down
2559 if (pCurRect
->right
<= rc
->left
) continue; // not far enough over yet
2560 if (pCurRect
->left
>= rc
->right
) continue;
2570 NtGdiRectInRegion(HRGN hRgn
,
2571 CONST LPRECT unsaferc
)
2577 if(!(Rgn
= RGNDATA_LockRgn(hRgn
)))
2582 if (!NT_SUCCESS(MmCopyFromCaller(&rc
, unsaferc
, sizeof(RECT
))))
2584 RGNDATA_UnlockRgn(Rgn
);
2585 DPRINT1("NtGdiRectInRegion: bogus rc\n");
2589 Ret
= UnsafeIntRectInRegion(Rgn
, &rc
);
2590 RGNDATA_UnlockRgn(Rgn
);
2596 NtGdiSetRectRgn(HRGN hRgn
,
2607 if( !( rgn
= RGNDATA_LockRgn(hRgn
) ) )
2608 return 0; //per documentation
2610 if (LeftRect
> RightRect
) { INT tmp
= LeftRect
; LeftRect
= RightRect
; RightRect
= tmp
; }
2611 if (TopRect
> BottomRect
) { INT tmp
= TopRect
; TopRect
= BottomRect
; BottomRect
= tmp
; }
2613 if((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
2615 firstRect
= (PRECT
)rgn
->Buffer
;
2616 ASSERT( firstRect
);
2617 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
2618 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
2619 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
2620 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
2621 rgn
->rdh
.nCount
= 1;
2622 rgn
->rdh
.iType
= SIMPLEREGION
;
2626 RGNDATA_UnlockRgn( rgn
);
2631 NtGdiUnionRectWithRgn(HRGN hDest
, CONST PRECT UnsafeRect
)
2636 if(!(Rgn
= (PROSRGNDATA
)RGNDATA_LockRgn(hDest
)))
2638 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2642 if (! NT_SUCCESS(MmCopyFromCaller(&SafeRect
, UnsafeRect
, sizeof(RECT
))))
2644 RGNDATA_UnlockRgn(Rgn
);
2645 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2649 UnsafeIntUnionRectWithRgn(Rgn
, &SafeRect
);
2650 RGNDATA_UnlockRgn(Rgn
);
2655 * MSDN: GetRegionData, Return Values:
2657 * "If the function succeeds and dwCount specifies an adequate number of bytes,
2658 * the return value is always dwCount. If dwCount is too small or the function
2659 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
2660 * required number of bytes.
2662 * If the function fails, the return value is zero."
2664 DWORD STDCALL
NtGdiGetRegionData(HRGN hrgn
, DWORD count
, LPRGNDATA rgndata
)
2667 PROSRGNDATA obj
= RGNDATA_LockRgn( hrgn
);
2672 size
= obj
->rdh
.nCount
* sizeof(RECT
);
2673 if(count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
2675 RGNDATA_UnlockRgn( obj
);
2676 if (rgndata
) /* buffer is too small, signal it by return 0 */
2678 else /* user requested buffer size with rgndata NULL */
2679 return size
+ sizeof(RGNDATAHEADER
);
2682 //first we copy the header then we copy buffer
2683 if( !NT_SUCCESS( MmCopyToCaller( rgndata
, obj
, sizeof( RGNDATAHEADER
)))){
2684 RGNDATA_UnlockRgn( obj
);
2687 if( !NT_SUCCESS( MmCopyToCaller( (char*)rgndata
+sizeof( RGNDATAHEADER
), obj
->Buffer
, size
))){
2688 RGNDATA_UnlockRgn( obj
);
2692 RGNDATA_UnlockRgn( obj
);
2693 return size
+ sizeof(RGNDATAHEADER
);
2697 /***********************************************************************
2698 * REGION_InsertEdgeInET
2700 * Insert the given edge into the edge table.
2701 * First we must find the correct bucket in the
2702 * Edge table, then find the right slot in the
2703 * bucket. Finally, we can insert it.
2706 static void FASTCALL
REGION_InsertEdgeInET(EdgeTable
*ET
, EdgeTableEntry
*ETE
,
2707 INT scanline
, ScanLineListBlock
**SLLBlock
, INT
*iSLLBlock
)
2710 EdgeTableEntry
*start
, *prev
;
2711 ScanLineList
*pSLL
, *pPrevSLL
;
2712 ScanLineListBlock
*tmpSLLBlock
;
2715 * find the right bucket to put the edge into
2717 pPrevSLL
= &ET
->scanlines
;
2718 pSLL
= pPrevSLL
->next
;
2719 while (pSLL
&& (pSLL
->scanline
< scanline
))
2726 * reassign pSLL (pointer to ScanLineList) if necessary
2728 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
2730 if (*iSLLBlock
> SLLSPERBLOCK
-1)
2732 tmpSLLBlock
= ExAllocatePoolWithTag( PagedPool
, sizeof(ScanLineListBlock
), TAG_REGION
);
2735 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2736 /* FIXME - free resources? */
2739 (*SLLBlock
)->next
= tmpSLLBlock
;
2740 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2741 *SLLBlock
= tmpSLLBlock
;
2744 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
2746 pSLL
->next
= pPrevSLL
->next
;
2747 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
2748 pPrevSLL
->next
= pSLL
;
2750 pSLL
->scanline
= scanline
;
2753 * now insert the edge in the right bucket
2755 prev
= (EdgeTableEntry
*)NULL
;
2756 start
= pSLL
->edgelist
;
2757 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2760 start
= start
->next
;
2767 pSLL
->edgelist
= ETE
;
2770 /***********************************************************************
2773 * This routine moves EdgeTableEntries from the
2774 * EdgeTable into the Active Edge Table,
2775 * leaving them sorted by smaller x coordinate.
2778 static void FASTCALL
REGION_loadAET(EdgeTableEntry
*AET
, EdgeTableEntry
*ETEs
)
2780 EdgeTableEntry
*pPrevAET
;
2781 EdgeTableEntry
*tmp
;
2787 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2796 ETEs
->back
= pPrevAET
;
2797 pPrevAET
->next
= ETEs
;
2804 /***********************************************************************
2805 * REGION_computeWAET
2807 * This routine links the AET by the
2808 * nextWETE (winding EdgeTableEntry) link for
2809 * use by the winding number rule. The final
2810 * Active Edge Table (AET) might look something
2814 * ---------- --------- ---------
2815 * |ymax | |ymax | |ymax |
2816 * | ... | |... | |... |
2817 * |next |->|next |->|next |->...
2818 * |nextWETE| |nextWETE| |nextWETE|
2819 * --------- --------- ^--------
2821 * V-------------------> V---> ...
2824 static void FASTCALL
REGION_computeWAET(EdgeTableEntry
*AET
)
2826 register EdgeTableEntry
*pWETE
;
2827 register int inside
= 1;
2828 register int isInside
= 0;
2830 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2840 if ((!inside
&& !isInside
) ||
2841 ( inside
&& isInside
))
2843 pWETE
->nextWETE
= AET
;
2849 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2852 /***********************************************************************
2853 * REGION_InsertionSort
2855 * Just a simple insertion sort using
2856 * pointers and back pointers to sort the Active
2860 static BOOL FASTCALL
REGION_InsertionSort(EdgeTableEntry
*AET
)
2862 EdgeTableEntry
*pETEchase
;
2863 EdgeTableEntry
*pETEinsert
;
2864 EdgeTableEntry
*pETEchaseBackTMP
;
2865 BOOL changed
= FALSE
;
2872 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2873 pETEchase
= pETEchase
->back
;
2876 if (pETEchase
!= pETEinsert
)
2878 pETEchaseBackTMP
= pETEchase
->back
;
2879 pETEinsert
->back
->next
= AET
;
2881 AET
->back
= pETEinsert
->back
;
2882 pETEinsert
->next
= pETEchase
;
2883 pETEchase
->back
->next
= pETEinsert
;
2884 pETEchase
->back
= pETEinsert
;
2885 pETEinsert
->back
= pETEchaseBackTMP
;
2892 /***********************************************************************
2893 * REGION_FreeStorage
2897 static void FASTCALL
REGION_FreeStorage(ScanLineListBlock
*pSLLBlock
)
2899 ScanLineListBlock
*tmpSLLBlock
;
2903 tmpSLLBlock
= pSLLBlock
->next
;
2904 ExFreePool( pSLLBlock
);
2905 pSLLBlock
= tmpSLLBlock
;
2910 /***********************************************************************
2911 * REGION_PtsToRegion
2913 * Create an array of rectangles from a list of points.
2915 static int FASTCALL
REGION_PtsToRegion(int numFullPtBlocks
, int iCurPtBlock
,
2916 POINTBLOCK
*FirstPtBlock
, ROSRGNDATA
*reg
)
2920 POINTBLOCK
*CurPtBlock
;
2922 RECT
*extents
, *temp
;
2925 extents
= ®
->rdh
.rcBound
;
2927 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
2929 if(!(temp
= ExAllocatePoolWithTag(PagedPool
, numRects
* sizeof(RECT
), TAG_REGION
)))
2933 if(reg
->Buffer
!= NULL
)
2935 COPY_RECTS(temp
, reg
->Buffer
, reg
->rdh
.nCount
);
2936 if(reg
->Buffer
!= ®
->rdh
.rcBound
)
2937 ExFreePool(reg
->Buffer
);
2941 reg
->rdh
.nCount
= numRects
;
2942 CurPtBlock
= FirstPtBlock
;
2943 rects
= reg
->Buffer
- 1;
2945 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
2947 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--) {
2948 /* the loop uses 2 points per iteration */
2949 i
= NUMPTSTOBUFFER
>> 1;
2950 if (!numFullPtBlocks
)
2951 i
= iCurPtBlock
>> 1;
2952 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2) {
2953 if (pts
->x
== pts
[1].x
)
2955 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
2956 pts
[1].x
== rects
->right
&&
2957 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
2958 (i
&& pts
[2].y
> pts
[1].y
)) {
2959 rects
->bottom
= pts
[1].y
+ 1;
2964 rects
->left
= pts
->x
; rects
->top
= pts
->y
;
2965 rects
->right
= pts
[1].x
; rects
->bottom
= pts
[1].y
+ 1;
2966 if (rects
->left
< extents
->left
)
2967 extents
->left
= rects
->left
;
2968 if (rects
->right
> extents
->right
)
2969 extents
->right
= rects
->right
;
2971 CurPtBlock
= CurPtBlock
->next
;
2975 extents
->top
= reg
->Buffer
->top
;
2976 extents
->bottom
= rects
->bottom
;
2981 extents
->bottom
= 0;
2983 reg
->rdh
.nCount
= numRects
;
2988 /***********************************************************************
2989 * REGION_CreateEdgeTable
2991 * This routine creates the edge table for
2992 * scan converting polygons.
2993 * The Edge Table (ET) looks like:
2997 * | ymax | ScanLineLists
2998 * |scanline|-->------------>-------------->...
2999 * -------- |scanline| |scanline|
3000 * |edgelist| |edgelist|
3001 * --------- ---------
3005 * list of ETEs list of ETEs
3007 * where ETE is an EdgeTableEntry data structure,
3008 * and there is one ScanLineList per scanline at
3009 * which an edge is initially entered.
3012 static void FASTCALL
REGION_CreateETandAET(const INT
*Count
, INT nbpolygons
,
3013 const POINT
*pts
, EdgeTable
*ET
, EdgeTableEntry
*AET
,
3014 EdgeTableEntry
*pETEs
, ScanLineListBlock
*pSLLBlock
)
3016 const POINT
*top
, *bottom
;
3017 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
3024 * initialize the Active Edge Table
3026 AET
->next
= (EdgeTableEntry
*)NULL
;
3027 AET
->back
= (EdgeTableEntry
*)NULL
;
3028 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
3029 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
3032 * initialize the Edge Table.
3034 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
3035 ET
->ymax
= SMALL_COORDINATE
;
3036 ET
->ymin
= LARGE_COORDINATE
;
3037 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
3040 for(poly
= 0; poly
< nbpolygons
; poly
++)
3042 count
= Count
[poly
];
3050 * for each vertex in the array of points.
3051 * In this loop we are dealing with two vertices at
3052 * a time -- these make up one edge of the polygon.
3059 * find out which point is above and which is below.
3061 if (PrevPt
->y
> CurrPt
->y
)
3063 bottom
= PrevPt
, top
= CurrPt
;
3064 pETEs
->ClockWise
= 0;
3068 bottom
= CurrPt
, top
= PrevPt
;
3069 pETEs
->ClockWise
= 1;
3073 * don't add horizontal edges to the Edge table.
3075 if (bottom
->y
!= top
->y
)
3077 pETEs
->ymax
= bottom
->y
-1;
3078 /* -1 so we don't get last scanline */
3081 * initialize integer edge algorithm
3083 dy
= bottom
->y
- top
->y
;
3084 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
3086 REGION_InsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
,
3089 if (PrevPt
->y
> ET
->ymax
)
3090 ET
->ymax
= PrevPt
->y
;
3091 if (PrevPt
->y
< ET
->ymin
)
3092 ET
->ymin
= PrevPt
->y
;
3102 IntCreatePolyPolgonRgn(POINT
*Pts
,
3109 EdgeTableEntry
*pAET
; /* Active Edge Table */
3110 INT y
; /* current scanline */
3111 int iPts
= 0; /* number of pts in buffer */
3112 EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry*/
3113 ScanLineList
*pSLL
; /* current scanLineList */
3114 POINT
*pts
; /* output buffer */
3115 EdgeTableEntry
*pPrevAET
; /* ptr to previous AET */
3116 EdgeTable ET
; /* header node for ET */
3117 EdgeTableEntry AET
; /* header node for AET */
3118 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
3119 ScanLineListBlock SLLBlock
; /* header for scanlinelist */
3120 int fixWAET
= FALSE
;
3121 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
3122 POINTBLOCK
*tmpPtBlock
;
3123 int numFullPtBlocks
= 0;
3126 if(!(hrgn
= RGNDATA_AllocRgn(nbpolygons
)))
3128 if(!(region
= RGNDATA_LockRgn(hrgn
)))
3130 NtGdiDeleteObject(hrgn
);
3134 /* special case a rectangle */
3136 if (((nbpolygons
== 1) && ((*Count
== 4) ||
3137 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
3138 (((Pts
[0].y
== Pts
[1].y
) &&
3139 (Pts
[1].x
== Pts
[2].x
) &&
3140 (Pts
[2].y
== Pts
[3].y
) &&
3141 (Pts
[3].x
== Pts
[0].x
)) ||
3142 ((Pts
[0].x
== Pts
[1].x
) &&
3143 (Pts
[1].y
== Pts
[2].y
) &&
3144 (Pts
[2].x
== Pts
[3].x
) &&
3145 (Pts
[3].y
== Pts
[0].y
))))
3147 RGNDATA_UnlockRgn( region
);
3148 NtGdiSetRectRgn( hrgn
, min(Pts
[0].x
, Pts
[2].x
), min(Pts
[0].y
, Pts
[2].y
),
3149 max(Pts
[0].x
, Pts
[2].x
), max(Pts
[0].y
, Pts
[2].y
) );
3153 for(poly
= total
= 0; poly
< nbpolygons
; poly
++)
3154 total
+= Count
[poly
];
3155 if (! (pETEs
= ExAllocatePoolWithTag( PagedPool
, sizeof(EdgeTableEntry
) * total
, TAG_REGION
)))
3157 NtGdiDeleteObject( hrgn
);
3160 pts
= FirstPtBlock
.pts
;
3161 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
3162 pSLL
= ET
.scanlines
.next
;
3163 curPtBlock
= &FirstPtBlock
;
3165 if (mode
!= WINDING
) {
3169 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
3171 * Add a new edge to the active edge table when we
3172 * get to the next edge.
3174 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
3175 REGION_loadAET(&AET
, pSLL
->edgelist
);
3182 * for each active edge
3185 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3189 * send out the buffer
3191 if (iPts
== NUMPTSTOBUFFER
) {
3192 tmpPtBlock
= ExAllocatePoolWithTag( PagedPool
, sizeof(POINTBLOCK
), TAG_REGION
);
3194 DPRINT1("Can't alloc tPB\n");
3198 curPtBlock
->next
= tmpPtBlock
;
3199 curPtBlock
= tmpPtBlock
;
3200 pts
= curPtBlock
->pts
;
3204 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
3206 REGION_InsertionSort(&AET
);
3213 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
3215 * Add a new edge to the active edge table when we
3216 * get to the next edge.
3218 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
3219 REGION_loadAET(&AET
, pSLL
->edgelist
);
3220 REGION_computeWAET(&AET
);
3228 * for each active edge
3232 * add to the buffer only those edges that
3233 * are in the Winding active edge table.
3235 if (pWETE
== pAET
) {
3236 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3240 * send out the buffer
3242 if (iPts
== NUMPTSTOBUFFER
) {
3243 tmpPtBlock
= ExAllocatePoolWithTag( PagedPool
,
3244 sizeof(POINTBLOCK
), TAG_REGION
);
3246 DPRINT1("Can't alloc tPB\n");
3248 NtGdiDeleteObject( hrgn
);
3251 curPtBlock
->next
= tmpPtBlock
;
3252 curPtBlock
= tmpPtBlock
;
3253 pts
= curPtBlock
->pts
;
3254 numFullPtBlocks
++; iPts
= 0;
3256 pWETE
= pWETE
->nextWETE
;
3258 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
3262 * recompute the winding active edge table if
3263 * we just resorted or have exited an edge.
3265 if (REGION_InsertionSort(&AET
) || fixWAET
) {
3266 REGION_computeWAET(&AET
);
3271 REGION_FreeStorage(SLLBlock
.next
);
3272 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, region
);
3274 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;) {
3275 tmpPtBlock
= curPtBlock
->next
;
3276 ExFreePool( curPtBlock
);
3277 curPtBlock
= tmpPtBlock
;
3279 ExFreePool( pETEs
);
3280 RGNDATA_UnlockRgn( region
);
3286 NtGdiCreatePolygonRgn(CONST PPOINT pt
,
3295 if (pt
== NULL
|| Count
== 0 ||
3296 (PolyFillMode
!= WINDING
&& PolyFillMode
!= ALTERNATE
))
3298 /* Windows doesn't set a last error here */
3304 /* can't create a region with only one point! */
3305 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
3311 /* Windows creates an empty region! */
3314 if(!(hRgn
= RGNDATA_AllocRgn(1)))
3318 if(!(rgn
= RGNDATA_LockRgn(hRgn
)))
3320 NtGdiDeleteObject(hRgn
);
3326 RGNDATA_UnlockRgn(rgn
);
3330 if (!(SafePoints
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(POINT
), TAG_REGION
)))
3332 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3336 Status
= MmCopyFromCaller(SafePoints
, pt
, Count
* sizeof(POINT
));
3337 if (!NT_SUCCESS(Status
))
3339 ExFreePool(SafePoints
);
3340 SetLastNtError(Status
);
3344 hRgn
= IntCreatePolyPolgonRgn(SafePoints
, &Count
, 1, PolyFillMode
);
3346 ExFreePool(SafePoints
);
3352 NtGdiCreatePolyPolygonRgn(CONST PPOINT pt
,
3353 CONST PINT PolyCounts
,
3358 INT
*SafePolyCounts
;
3359 INT nPoints
, nEmpty
, nInvalid
, i
;
3363 if (pt
== NULL
|| PolyCounts
== NULL
|| Count
== 0 ||
3364 (PolyFillMode
!= WINDING
&& PolyFillMode
!= ALTERNATE
))
3366 /* Windows doesn't set a last error here */
3370 if (!(SafePolyCounts
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(INT
), TAG_REGION
)))
3372 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3376 Status
= MmCopyFromCaller(SafePolyCounts
, PolyCounts
, Count
* sizeof(INT
));
3377 if (!NT_SUCCESS(Status
))
3379 ExFreePool(SafePolyCounts
);
3380 SetLastNtError(Status
);
3384 /* validate poligons */
3388 for (i
= 0; i
< Count
; i
++)
3390 if (SafePolyCounts
[i
] == 0)
3394 if (SafePolyCounts
[i
] == 1)
3398 nPoints
+= SafePolyCounts
[i
];
3401 if (nEmpty
== Count
)
3403 /* if all polygon counts are zero, return without setting a last error code. */
3404 ExFreePool(SafePolyCounts
);
3409 /* if at least one poly count is 1, fail */
3410 ExFreePool(SafePolyCounts
);
3411 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
3416 if (!(Safept
= ExAllocatePoolWithTag(PagedPool
, nPoints
* sizeof(POINT
), TAG_REGION
)))
3418 ExFreePool(SafePolyCounts
);
3419 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3423 Status
= MmCopyFromCaller(Safept
, pt
, nPoints
* sizeof(POINT
));
3424 if (!NT_SUCCESS(Status
))
3427 ExFreePool(SafePolyCounts
);
3428 SetLastNtError(Status
);
3432 /* now we're ready to calculate the region safely */
3433 hRgn
= IntCreatePolyPolgonRgn(Safept
, SafePolyCounts
, Count
, PolyFillMode
);
3436 ExFreePool(SafePolyCounts
);