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...
122 // Internal Functions
125 #define COPY_RECTS(dest, src, nRects) \
127 PRECT xDest = (dest); \
128 PRECT xSrc = (src); \
129 UINT xRects = (nRects); \
130 while(xRects-- > 0) { \
131 *(xDest++) = *(xSrc++); \
135 #define COPY_RECTS(dest, src, nRects) RtlCopyMemory(dest, src, (nRects) * sizeof(RECT))
138 #define EMPTY_REGION(pReg) { \
139 (pReg)->rdh.nCount = 0; \
140 (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
141 (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
142 (pReg)->rdh.iType = NULLREGION; \
145 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
147 #define INRECT(r, x, y) \
148 ( ( ((r).right > x)) && \
149 ( ((r).left <= x)) && \
150 ( ((r).bottom > y)) && \
153 /* 1 if two RECTs overlap.
154 * 0 if two RECTs do not overlap.
156 #define EXTENTCHECK(r1, r2) \
157 ((r1)->right > (r2)->left && \
158 (r1)->left < (r2)->right && \
159 (r1)->bottom > (r2)->top && \
160 (r1)->top < (r2)->bottom)
163 * In scan converting polygons, we want to choose those pixels
164 * which are inside the polygon. Thus, we add .5 to the starting
165 * x coordinate for both left and right edges. Now we choose the
166 * first pixel which is inside the pgon for the left edge and the
167 * first pixel which is outside the pgon for the right edge.
168 * Draw the left pixel, but not the right.
170 * How to add .5 to the starting x coordinate:
171 * If the edge is moving to the right, then subtract dy from the
172 * error term from the general form of the algorithm.
173 * If the edge is moving to the left, then add dy to the error term.
175 * The reason for the difference between edges moving to the left
176 * and edges moving to the right is simple: If an edge is moving
177 * to the right, then we want the algorithm to flip immediately.
178 * If it is moving to the left, then we don't want it to flip until
179 * we traverse an entire pixel.
181 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
182 int dx; /* local storage */ \
185 * if the edge is horizontal, then it is ignored \
186 * and assumed not to be processed. Otherwise, do this stuff. \
190 dx = (x2) - xStart; \
194 incr1 = -2 * dx + 2 * (dy) * m1; \
195 incr2 = -2 * dx + 2 * (dy) * m; \
196 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
200 incr1 = 2 * dx - 2 * (dy) * m1; \
201 incr2 = 2 * dx - 2 * (dy) * m; \
202 d = -2 * m * (dy) + 2 * dx; \
207 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
230 * This structure contains all of the information needed
231 * to run the bresenham algorithm.
232 * The variables may be hardcoded into the declarations
233 * instead of using this structure to make use of
234 * register declarations.
237 INT minor_axis
; /* minor axis */
238 INT d
; /* decision variable */
239 INT m
, m1
; /* slope and slope+1 */
240 INT incr1
, incr2
; /* error increments */
244 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
245 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
246 bres.m, bres.m1, bres.incr1, bres.incr2)
248 #define BRESINCRPGONSTRUCT(bres) \
249 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
254 * These are the data structures needed to scan
255 * convert regions. Two different scan conversion
256 * methods are available -- the even-odd method, and
257 * the winding number method.
258 * The even-odd rule states that a point is inside
259 * the polygon if a ray drawn from that point in any
260 * direction will pass through an odd number of
262 * By the winding number rule, a point is decided
263 * to be inside the polygon if a ray drawn from that
264 * point in any direction passes through a different
265 * number of clockwise and counter-clockwise path
268 * These data structures are adapted somewhat from
269 * the algorithm in (Foley/Van Dam) for scan converting
271 * The basic algorithm is to start at the top (smallest y)
272 * of the polygon, stepping down to the bottom of
273 * the polygon by incrementing the y coordinate. We
274 * keep a list of edges which the current scanline crosses,
275 * sorted by x. This list is called the Active Edge Table (AET)
276 * As we change the y-coordinate, we update each entry in
277 * in the active edge table to reflect the edges new xcoord.
278 * This list must be sorted at each scanline in case
279 * two edges intersect.
280 * We also keep a data structure known as the Edge Table (ET),
281 * which keeps track of all the edges which the current
282 * scanline has not yet reached. The ET is basically a
283 * list of ScanLineList structures containing a list of
284 * edges which are entered at a given scanline. There is one
285 * ScanLineList per scanline at which an edge is entered.
286 * When we enter a new edge, we move it from the ET to the AET.
288 * From the AET, we can implement the even-odd rule as in
290 * The winding number rule is a little trickier. We also
291 * keep the EdgeTableEntries in the AET linked by the
292 * nextWETE (winding EdgeTableEntry) link. This allows
293 * the edges to be linked just as before for updating
294 * purposes, but only uses the edges linked by the nextWETE
295 * link as edges representing spans of the polygon to
296 * drawn (as with the even-odd rule).
300 * for the winding number rule
303 #define COUNTERCLOCKWISE -1
305 typedef struct _EdgeTableEntry
{
306 INT ymax
; /* ycoord at which we exit this edge. */
307 BRESINFO bres
; /* Bresenham info to run the edge */
308 struct _EdgeTableEntry
*next
; /* next in the list */
309 struct _EdgeTableEntry
*back
; /* for insertion sort */
310 struct _EdgeTableEntry
*nextWETE
; /* for winding num rule */
311 int ClockWise
; /* flag for winding number rule */
315 typedef struct _ScanLineList
{
316 INT scanline
; /* the scanline represented */
317 EdgeTableEntry
*edgelist
; /* header node */
318 struct _ScanLineList
*next
; /* next in the list */
323 INT ymax
; /* ymax for the polygon */
324 INT ymin
; /* ymin for the polygon */
325 ScanLineList scanlines
; /* header node */
330 * Here is a struct to help with storage allocation
331 * so we can allocate a big chunk at a time, and then take
332 * pieces from this heap when we need to.
334 #define SLLSPERBLOCK 25
336 typedef struct _ScanLineListBlock
{
337 ScanLineList SLLs
[SLLSPERBLOCK
];
338 struct _ScanLineListBlock
*next
;
344 * a few macros for the inner loops of the fill code where
345 * performance considerations don't allow a procedure call.
347 * Evaluate the given edge at the given scanline.
348 * If the edge has expired, then we leave it and fix up
349 * the active edge table; otherwise, we increment the
350 * x value to be ready for the next scanline.
351 * The winding number rule is in effect, so we must notify
352 * the caller when the edge has been removed so he
353 * can reorder the Winding Active Edge Table.
355 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
356 if (pAET->ymax == y) { /* leaving this edge */ \
357 pPrevAET->next = pAET->next; \
358 pAET = pPrevAET->next; \
361 pAET->back = pPrevAET; \
364 BRESINCRPGONSTRUCT(pAET->bres); \
372 * Evaluate the given edge at the given scanline.
373 * If the edge has expired, then we leave it and fix up
374 * the active edge table; otherwise, we increment the
375 * x value to be ready for the next scanline.
376 * The even-odd rule is in effect.
378 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
379 if (pAET->ymax == y) { /* leaving this edge */ \
380 pPrevAET->next = pAET->next; \
381 pAET = pPrevAET->next; \
383 pAET->back = pPrevAET; \
386 BRESINCRPGONSTRUCT(pAET->bres); \
392 /**************************************************************************
396 *************************************************************************/
398 #define LARGE_COORDINATE 0x7fffffff /* FIXME */
399 #define SMALL_COORDINATE 0x80000000
402 * Check to see if there is enough memory in the present region.
404 static __inline
int xmemcheck(ROSRGNDATA
*reg
, PRECT
*rect
, PRECT
*firstrect
) {
405 if ( (reg
->rdh
.nCount
+1)*sizeof( RECT
) >= reg
->rdh
.nRgnSize
) {
407 DWORD NewSize
= 2 * reg
->rdh
.nRgnSize
;
408 if (NewSize
< (reg
->rdh
.nCount
+ 1) * sizeof(RECT
)) {
409 NewSize
= (reg
->rdh
.nCount
+ 1) * sizeof(RECT
);
411 temp
= ExAllocatePoolWithTag( PagedPool
, NewSize
, TAG_REGION
);
416 /* copy the rectangles */
417 COPY_RECTS(temp
, *firstrect
, reg
->rdh
.nCount
);
419 reg
->rdh
.nRgnSize
= NewSize
;
420 if (*firstrect
!= ®
->rdh
.rcBound
)
421 ExFreePool( *firstrect
);
423 *rect
= (*firstrect
)+reg
->rdh
.nCount
;
428 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(LPRECT *)&(firstrect))
430 typedef void FASTCALL (*overlapProcp
)(PROSRGNDATA
, PRECT
, PRECT
, PRECT
, PRECT
, INT
, INT
);
431 typedef void FASTCALL (*nonOverlapProcp
)(PROSRGNDATA
, PRECT
, PRECT
, INT
, INT
);
433 // Number of points to buffer before sending them off to scanlines() : Must be an even number
434 #define NUMPTSTOBUFFER 200
436 #define RGN_DEFAULT_RECTS 2
438 // used to allocate buffers for points and link the buffers together
440 typedef struct _POINTBLOCK
{
441 POINT pts
[NUMPTSTOBUFFER
];
442 struct _POINTBLOCK
*next
;
447 * This function is left there for debugging purposes.
451 IntDumpRegion(HRGN hRgn
)
455 Data
= RGNDATA_LockRgn(hRgn
);
458 DbgPrint("IntDumpRegion called with invalid region!\n");
462 DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
464 Data
->rdh
.rcBound
.left
,
465 Data
->rdh
.rcBound
.top
,
466 Data
->rdh
.rcBound
.right
,
467 Data
->rdh
.rcBound
.bottom
,
470 RGNDATA_UnlockRgn(Data
);
474 static BOOL FASTCALL
REGION_CopyRegion(PROSRGNDATA dst
, PROSRGNDATA src
)
476 if(dst
!= src
) // don't want to copy to itself
478 if (dst
->rdh
.nRgnSize
< src
->rdh
.nCount
* sizeof(RECT
))
482 temp
= ExAllocatePoolWithTag(PagedPool
, src
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
486 if( dst
->Buffer
&& dst
->Buffer
!= &dst
->rdh
.rcBound
)
487 ExFreePool( dst
->Buffer
); //free the old buffer
489 dst
->rdh
.nRgnSize
= src
->rdh
.nCount
* sizeof(RECT
); //size of region buffer
491 dst
->rdh
.nCount
= src
->rdh
.nCount
; //number of rectangles present in Buffer
492 dst
->rdh
.rcBound
.left
= src
->rdh
.rcBound
.left
;
493 dst
->rdh
.rcBound
.top
= src
->rdh
.rcBound
.top
;
494 dst
->rdh
.rcBound
.right
= src
->rdh
.rcBound
.right
;
495 dst
->rdh
.rcBound
.bottom
= src
->rdh
.rcBound
.bottom
;
496 dst
->rdh
.iType
= src
->rdh
.iType
;
497 COPY_RECTS(dst
->Buffer
, src
->Buffer
, src
->rdh
.nCount
);
502 static void FASTCALL
REGION_SetExtents (ROSRGNDATA
*pReg
)
504 RECT
*pRect
, *pRectEnd
, *pExtents
;
506 if (pReg
->rdh
.nCount
== 0)
508 pReg
->rdh
.rcBound
.left
= 0;
509 pReg
->rdh
.rcBound
.top
= 0;
510 pReg
->rdh
.rcBound
.right
= 0;
511 pReg
->rdh
.rcBound
.bottom
= 0;
512 pReg
->rdh
.iType
= NULLREGION
;
516 pExtents
= &pReg
->rdh
.rcBound
;
517 pRect
= (PRECT
)pReg
->Buffer
;
518 pRectEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
- 1;
521 * Since pRect is the first rectangle in the region, it must have the
522 * smallest top and since pRectEnd is the last rectangle in the region,
523 * it must have the largest bottom, because of banding. Initialize left and
524 * right from pRect and pRectEnd, resp., as good things to initialize them
527 pExtents
->left
= pRect
->left
;
528 pExtents
->top
= pRect
->top
;
529 pExtents
->right
= pRectEnd
->right
;
530 pExtents
->bottom
= pRectEnd
->bottom
;
532 while (pRect
<= pRectEnd
)
534 if (pRect
->left
< pExtents
->left
)
535 pExtents
->left
= pRect
->left
;
536 if (pRect
->right
> pExtents
->right
)
537 pExtents
->right
= pRect
->right
;
540 pReg
->rdh
.iType
= (1 == pReg
->rdh
.nCount
? SIMPLEREGION
: COMPLEXREGION
);
544 /***********************************************************************
545 * REGION_CropAndOffsetRegion
547 static BOOL FASTCALL
REGION_CropAndOffsetRegion(const PPOINT off
, const PRECT rect
, PROSRGNDATA rgnSrc
, PROSRGNDATA rgnDst
)
549 if(!rect
) // just copy and offset
555 xrect
= (PRECT
)rgnDst
->Buffer
;
560 xrect
= ExAllocatePoolWithTag(PagedPool
, rgnSrc
->rdh
.nCount
* sizeof(RECT
), TAG_REGION
);
561 if( rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
562 ExFreePool( rgnDst
->Buffer
); //free the old buffer. will be assigned to xrect below.
576 for(i
= 0; i
< rgnDst
->rdh
.nCount
; i
++)
578 xrect
[i
].left
= ((PRECT
)rgnSrc
->Buffer
+ i
)->left
+ off
->x
;
579 xrect
[i
].right
= ((PRECT
)rgnSrc
->Buffer
+ i
)->right
+ off
->x
;
580 xrect
[i
].top
= ((PRECT
)rgnSrc
->Buffer
+ i
)->top
+ off
->y
;
581 xrect
[i
].bottom
= ((PRECT
)rgnSrc
->Buffer
+ i
)->bottom
+ off
->y
;
583 rgnDst
->rdh
.rcBound
.left
+= off
->x
;
584 rgnDst
->rdh
.rcBound
.right
+= off
->x
;
585 rgnDst
->rdh
.rcBound
.top
+= off
->y
;
586 rgnDst
->rdh
.rcBound
.bottom
+= off
->y
;
590 COPY_RECTS(xrect
, rgnSrc
->Buffer
, rgnDst
->rdh
.nCount
);
593 rgnDst
->Buffer
= xrect
;
597 else if ((rect
->left
>= rect
->right
) ||
598 (rect
->top
>= rect
->bottom
) ||
599 !EXTENTCHECK(rect
, &rgnSrc
->rdh
.rcBound
))
603 else // region box and clipping rect appear to intersect
606 ULONG i
, j
, clipa
, clipb
;
607 INT left
= rgnSrc
->rdh
.rcBound
.right
+ off
->x
;
608 INT right
= rgnSrc
->rdh
.rcBound
.left
+ off
->x
;
610 for(clipa
= 0; ((PRECT
)rgnSrc
->Buffer
+ clipa
)->bottom
<= rect
->top
; clipa
++)
611 //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
612 ; // skip bands above the clipping rectangle
614 for(clipb
= clipa
; clipb
< rgnSrc
->rdh
.nCount
; clipb
++)
615 if(((PRECT
)rgnSrc
->Buffer
+ clipb
)->top
>= rect
->bottom
)
616 break; // and below it
618 // clipa - index of the first rect in the first intersecting band
619 // clipb - index of the last rect in the last intersecting band
621 if((rgnDst
!= rgnSrc
) && (rgnDst
->rdh
.nCount
< (i
= (clipb
- clipa
))))
624 temp
= ExAllocatePoolWithTag( PagedPool
, i
* sizeof(RECT
), TAG_REGION
);
628 if( rgnDst
->Buffer
&& rgnDst
->Buffer
!= &rgnDst
->rdh
.rcBound
)
629 ExFreePool( rgnDst
->Buffer
); //free the old buffer
630 rgnDst
->Buffer
= temp
;
631 rgnDst
->rdh
.nCount
= i
;
632 rgnDst
->rdh
.nRgnSize
= i
* sizeof(RECT
);
635 for(i
= clipa
, j
= 0; i
< clipb
; i
++)
637 // i - src index, j - dst index, j is always <= i for obvious reasons
639 lpr
= (PRECT
)rgnSrc
->Buffer
+ i
;
641 if(lpr
->left
< rect
->right
&& lpr
->right
> rect
->left
)
643 rpr
= (PRECT
)rgnDst
->Buffer
+ j
;
645 rpr
->top
= lpr
->top
+ off
->y
;
646 rpr
->bottom
= lpr
->bottom
+ off
->y
;
647 rpr
->left
= ((lpr
->left
> rect
->left
) ? lpr
->left
: rect
->left
) + off
->x
;
648 rpr
->right
= ((lpr
->right
< rect
->right
) ? lpr
->right
: rect
->right
) + off
->x
;
650 if(rpr
->left
< left
) left
= rpr
->left
;
651 if(rpr
->right
> right
) right
= rpr
->right
;
657 if(j
== 0) goto empty
;
659 rgnDst
->rdh
.rcBound
.left
= left
;
660 rgnDst
->rdh
.rcBound
.right
= right
;
662 left
= rect
->top
+ off
->y
;
663 right
= rect
->bottom
+ off
->y
;
665 rgnDst
->rdh
.nCount
= j
--;
666 for(i
= 0; i
<= j
; i
++) // fixup top band
667 if((rgnDst
->Buffer
+ i
)->top
< left
)
668 (rgnDst
->Buffer
+ i
)->top
= left
;
672 for(i
= j
; i
>= 0; i
--) // fixup bottom band
673 if(((PRECT
)rgnDst
->Buffer
+ i
)->bottom
> right
)
674 ((PRECT
)rgnDst
->Buffer
+ i
)->bottom
= right
;
678 rgnDst
->rdh
.rcBound
.top
= ((PRECT
)rgnDst
->Buffer
)->top
;
679 rgnDst
->rdh
.rcBound
.bottom
= ((PRECT
)rgnDst
->Buffer
+ j
)->bottom
;
681 rgnDst
->rdh
.iType
= (j
>= 1) ? COMPLEXREGION
: SIMPLEREGION
;
689 rgnDst
->Buffer
= (PRECT
)ExAllocatePoolWithTag(PagedPool
, RGN_DEFAULT_RECTS
* sizeof(RECT
), TAG_REGION
);
691 rgnDst
->rdh
.nCount
= RGN_DEFAULT_RECTS
;
692 rgnDst
->rdh
.nRgnSize
= RGN_DEFAULT_RECTS
* sizeof(RECT
);
697 EMPTY_REGION(rgnDst
);
703 * hSrc: Region to crop and offset.
704 * lpRect: Clipping rectangle. Can be NULL (no clipping).
705 * lpPt: Points to offset the cropped region. Can be NULL (no offset).
707 * hDst: Region to hold the result (a new region is created if it's 0).
708 * Allowed to be the same region as hSrc in which case everything
709 * will be done in place, with no memory reallocations.
711 * \return hDst if success, 0 otherwise.
713 HRGN FASTCALL
REGION_CropRgn(HRGN hDst
, HRGN hSrc
, const PRECT lpRect
, PPOINT lpPt
)
715 PROSRGNDATA objSrc
, rgnDst
;
721 if( !( hDst
= RGNDATA_AllocRgn(1) ) )
727 rgnDst
= RGNDATA_LockRgn(hDst
);
733 objSrc
= RGNDATA_LockRgn(hSrc
);
736 RGNDATA_UnlockRgn(rgnDst
);
742 if(REGION_CropAndOffsetRegion(lpPt
, lpRect
, objSrc
, rgnDst
) == FALSE
)
743 { // ve failed cleanup and return
746 else{ // ve are fine. unlock the correct pointer and return correct handle
750 RGNDATA_UnlockRgn(objSrc
);
751 RGNDATA_UnlockRgn(rgnDst
);
757 * Attempt to merge the rects in the current band with those in the
758 * previous one. Used only by REGION_RegionOp.
761 * The new index for the previous band.
763 * \note Side Effects:
764 * If coalescing takes place:
765 * - rectangles in the previous band will have their bottom fields
767 * - pReg->numRects will be decreased.
770 static INT FASTCALL
REGION_Coalesce (
771 PROSRGNDATA pReg
, /* Region to coalesce */
772 INT prevStart
, /* Index of start of previous band */
773 INT curStart
/* Index of start of current band */
775 RECT
*pPrevRect
; /* Current rect in previous band */
776 RECT
*pCurRect
; /* Current rect in current band */
777 RECT
*pRegEnd
; /* End of region */
778 INT curNumRects
; /* Number of rectangles in current band */
779 INT prevNumRects
; /* Number of rectangles in previous band */
780 INT bandtop
; /* top coordinate for current band */
782 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
783 pPrevRect
= (PRECT
)pReg
->Buffer
+ prevStart
;
784 prevNumRects
= curStart
- prevStart
;
787 * Figure out how many rectangles are in the current band. Have to do
788 * this because multiple bands could have been added in REGION_RegionOp
789 * at the end when one region has been exhausted.
791 pCurRect
= (PRECT
)pReg
->Buffer
+ curStart
;
792 bandtop
= pCurRect
->top
;
793 for (curNumRects
= 0;
794 (pCurRect
!= pRegEnd
) && (pCurRect
->top
== bandtop
);
800 if (pCurRect
!= pRegEnd
)
803 * If more than one band was added, we have to find the start
804 * of the last band added so the next coalescing job can start
805 * at the right place... (given when multiple bands are added,
806 * this may be pointless -- see above).
809 while ((pRegEnd
-1)->top
== pRegEnd
->top
)
813 curStart
= pRegEnd
- (PRECT
)pReg
->Buffer
;
814 pRegEnd
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
817 if ((curNumRects
== prevNumRects
) && (curNumRects
!= 0)) {
818 pCurRect
-= curNumRects
;
820 * The bands may only be coalesced if the bottom of the previous
821 * matches the top scanline of the current.
823 if (pPrevRect
->bottom
== pCurRect
->top
)
826 * Make sure the bands have rects in the same places. This
827 * assumes that rects have been added in such a way that they
828 * cover the most area possible. I.e. two rects in a band must
829 * have some horizontal space between them.
833 if ((pPrevRect
->left
!= pCurRect
->left
) ||
834 (pPrevRect
->right
!= pCurRect
->right
))
837 * The bands don't line up so they can't be coalesced.
844 } while (prevNumRects
!= 0);
846 pReg
->rdh
.nCount
-= curNumRects
;
847 pCurRect
-= curNumRects
;
848 pPrevRect
-= curNumRects
;
851 * The bands may be merged, so set the bottom of each rect
852 * in the previous band to that of the corresponding rect in
857 pPrevRect
->bottom
= pCurRect
->bottom
;
861 } while (curNumRects
!= 0);
864 * If only one band was added to the region, we have to backup
865 * curStart to the start of the previous band.
867 * If more than one band was added to the region, copy the
868 * other bands down. The assumption here is that the other bands
869 * came from the same region as the current one and no further
870 * coalescing can be done on them since it's all been done
871 * already... curStart is already in the right place.
873 if (pCurRect
== pRegEnd
)
875 curStart
= prevStart
;
881 *pPrevRect
++ = *pCurRect
++;
882 } while (pCurRect
!= pRegEnd
);
890 * Apply an operation to two regions. Called by REGION_Union,
891 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
897 * The new region is overwritten.
899 *\note The idea behind this function is to view the two regions as sets.
900 * Together they cover a rectangle of area that this function divides
901 * into horizontal bands where points are covered only by one region
902 * or by both. For the first case, the nonOverlapFunc is called with
903 * each the band and the band's upper and lower extents. For the
904 * second, the overlapFunc is called to process the entire band. It
905 * is responsible for clipping the rectangles in the band, though
906 * this function provides the boundaries.
907 * At the end of each band, the new region is coalesced, if possible,
908 * to reduce the number of rectangles in the region.
913 ROSRGNDATA
*newReg
, /* Place to store result */
914 ROSRGNDATA
*reg1
, /* First region in operation */
915 ROSRGNDATA
*reg2
, /* 2nd region in operation */
916 overlapProcp overlapFunc
, /* Function to call for over-lapping bands */
917 nonOverlapProcp nonOverlap1Func
, /* Function to call for non-overlapping bands in region 1 */
918 nonOverlapProcp nonOverlap2Func
/* Function to call for non-overlapping bands in region 2 */
921 RECT
*r1
; /* Pointer into first region */
922 RECT
*r2
; /* Pointer into 2d region */
923 RECT
*r1End
; /* End of 1st region */
924 RECT
*r2End
; /* End of 2d region */
925 INT ybot
; /* Bottom of intersection */
926 INT ytop
; /* Top of intersection */
927 RECT
*oldRects
; /* Old rects for newReg */
928 ULONG prevBand
; /* Index of start of
929 * previous band in newReg */
930 ULONG curBand
; /* Index of start of current band in newReg */
931 RECT
*r1BandEnd
; /* End of current band in r1 */
932 RECT
*r2BandEnd
; /* End of current band in r2 */
933 ULONG top
; /* Top of non-overlapping band */
934 ULONG bot
; /* Bottom of non-overlapping band */
938 * set r1, r2, r1End and r2End appropriately, preserve the important
939 * parts of the destination region until the end in case it's one of
940 * the two source regions, then mark the "new" region empty, allocating
941 * another array of rectangles for it to use.
943 r1
= (PRECT
)reg1
->Buffer
;
944 r2
= (PRECT
)reg2
->Buffer
;
945 r1End
= r1
+ reg1
->rdh
.nCount
;
946 r2End
= r2
+ reg2
->rdh
.nCount
;
950 * newReg may be one of the src regions so we can't empty it. We keep a
951 * note of its rects pointer (so that we can free them later), preserve its
952 * extents and simply set numRects to zero.
955 oldRects
= (PRECT
)newReg
->Buffer
;
956 newReg
->rdh
.nCount
= 0;
959 * Allocate a reasonable number of rectangles for the new region. The idea
960 * is to allocate enough so the individual functions don't need to
961 * reallocate and copy the array, which is time consuming, yet we don't
962 * have to worry about using too much memory. I hope to be able to
963 * nuke the Xrealloc() at the end of this function eventually.
965 newReg
->rdh
.nRgnSize
= max(reg1
->rdh
.nCount
,reg2
->rdh
.nCount
) * 2 * sizeof(RECT
);
967 if (! (newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, newReg
->rdh
.nRgnSize
, TAG_REGION
)))
969 newReg
->rdh
.nRgnSize
= 0;
974 * Initialize ybot and ytop.
975 * In the upcoming loop, ybot and ytop serve different functions depending
976 * on whether the band being handled is an overlapping or non-overlapping
978 * In the case of a non-overlapping band (only one of the regions
979 * has points in the band), ybot is the bottom of the most recent
980 * intersection and thus clips the top of the rectangles in that band.
981 * ytop is the top of the next intersection between the two regions and
982 * serves to clip the bottom of the rectangles in the current band.
983 * For an overlapping band (where the two regions intersect), ytop clips
984 * the top of the rectangles of both regions and ybot clips the bottoms.
986 if (reg1
->rdh
.rcBound
.top
< reg2
->rdh
.rcBound
.top
)
987 ybot
= reg1
->rdh
.rcBound
.top
;
989 ybot
= reg2
->rdh
.rcBound
.top
;
992 * prevBand serves to mark the start of the previous band so rectangles
993 * can be coalesced into larger rectangles. qv. miCoalesce, above.
994 * In the beginning, there is no previous band, so prevBand == curBand
995 * (curBand is set later on, of course, but the first band will always
996 * start at index 0). prevBand and curBand must be indices because of
997 * the possible expansion, and resultant moving, of the new region's
998 * array of rectangles.
1004 curBand
= newReg
->rdh
.nCount
;
1007 * This algorithm proceeds one source-band (as opposed to a
1008 * destination band, which is determined by where the two regions
1009 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1010 * rectangle after the last one in the current band for their
1011 * respective regions.
1014 while ((r1BandEnd
!= r1End
) && (r1BandEnd
->top
== r1
->top
))
1020 while ((r2BandEnd
!= r2End
) && (r2BandEnd
->top
== r2
->top
))
1026 * First handle the band that doesn't intersect, if any.
1028 * Note that attention is restricted to one band in the
1029 * non-intersecting region at once, so if a region has n
1030 * bands between the current position and the next place it overlaps
1031 * the other, this entire loop will be passed through n times.
1033 if (r1
->top
< r2
->top
)
1035 top
= max(r1
->top
,ybot
);
1036 bot
= min(r1
->bottom
,r2
->top
);
1038 if ((top
!= bot
) && (nonOverlap1Func
!= NULL
))
1040 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
, top
, bot
);
1045 else if (r2
->top
< r1
->top
)
1047 top
= max(r2
->top
,ybot
);
1048 bot
= min(r2
->bottom
,r1
->top
);
1050 if ((top
!= bot
) && (nonOverlap2Func
!= NULL
))
1052 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
, top
, bot
);
1063 * If any rectangles got added to the region, try and coalesce them
1064 * with rectangles from the previous band. Note we could just do
1065 * this test in miCoalesce, but some machines incur a not
1066 * inconsiderable cost for function calls, so...
1068 if (newReg
->rdh
.nCount
!= curBand
)
1070 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1074 * Now see if we've hit an intersecting band. The two bands only
1075 * intersect if ybot > ytop
1077 ybot
= min(r1
->bottom
, r2
->bottom
);
1078 curBand
= newReg
->rdh
.nCount
;
1081 (* overlapFunc
) (newReg
, r1
, r1BandEnd
, r2
, r2BandEnd
, ytop
, ybot
);
1084 if (newReg
->rdh
.nCount
!= curBand
)
1086 prevBand
= REGION_Coalesce (newReg
, prevBand
, curBand
);
1090 * If we've finished with a band (bottom == ybot) we skip forward
1091 * in the region to the next band.
1093 if (r1
->bottom
== ybot
)
1097 if (r2
->bottom
== ybot
)
1101 } while ((r1
!= r1End
) && (r2
!= r2End
));
1104 * Deal with whichever region still has rectangles left.
1106 curBand
= newReg
->rdh
.nCount
;
1109 if (nonOverlap1Func
!= NULL
)
1114 while ((r1BandEnd
< r1End
) && (r1BandEnd
->top
== r1
->top
))
1118 (* nonOverlap1Func
) (newReg
, r1
, r1BandEnd
,
1119 max(r1
->top
,ybot
), r1
->bottom
);
1121 } while (r1
!= r1End
);
1124 else if ((r2
!= r2End
) && (nonOverlap2Func
!= NULL
))
1129 while ((r2BandEnd
< r2End
) && (r2BandEnd
->top
== r2
->top
))
1133 (* nonOverlap2Func
) (newReg
, r2
, r2BandEnd
,
1134 max(r2
->top
,ybot
), r2
->bottom
);
1136 } while (r2
!= r2End
);
1139 if (newReg
->rdh
.nCount
!= curBand
)
1141 (void) REGION_Coalesce (newReg
, prevBand
, curBand
);
1145 * A bit of cleanup. To keep regions from growing without bound,
1146 * we shrink the array of rectangles to match the new number of
1147 * rectangles in the region. This never goes to 0, however...
1149 * Only do this stuff if the number of rectangles allocated is more than
1150 * twice the number of rectangles in the region (a simple optimization...).
1152 if ((2 * newReg
->rdh
.nCount
*sizeof(RECT
) < newReg
->rdh
.nRgnSize
&& (newReg
->rdh
.nCount
> 2)))
1154 if (REGION_NOT_EMPTY(newReg
))
1156 RECT
*prev_rects
= (PRECT
)newReg
->Buffer
;
1157 newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, newReg
->rdh
.nCount
*sizeof(RECT
), TAG_REGION
);
1159 if (! newReg
->Buffer
)
1160 newReg
->Buffer
= prev_rects
;
1162 newReg
->rdh
.nRgnSize
= newReg
->rdh
.nCount
*sizeof(RECT
);
1163 COPY_RECTS(newReg
->Buffer
, prev_rects
, newReg
->rdh
.nCount
);
1164 if (prev_rects
!= &newReg
->rdh
.rcBound
)
1165 ExFreePool( prev_rects
);
1171 * No point in doing the extra work involved in an Xrealloc if
1172 * the region is empty
1174 newReg
->rdh
.nRgnSize
= sizeof(RECT
);
1175 if (newReg
->Buffer
!= &newReg
->rdh
.rcBound
)
1176 ExFreePool( newReg
->Buffer
);
1177 newReg
->Buffer
= ExAllocatePoolWithTag( PagedPool
, sizeof(RECT
), TAG_REGION
);
1178 ASSERT( newReg
->Buffer
);
1182 if( newReg
->rdh
.nCount
== 0 )
1183 newReg
->rdh
.iType
= NULLREGION
;
1185 newReg
->rdh
.iType
= (newReg
->rdh
.nCount
> 1)? COMPLEXREGION
: SIMPLEREGION
;
1187 if (oldRects
!= &newReg
->rdh
.rcBound
)
1188 ExFreePool( oldRects
);
1192 /***********************************************************************
1193 * Region Intersection
1194 ***********************************************************************/
1198 * Handle an overlapping band for REGION_Intersect.
1203 * \note Side Effects:
1204 * Rectangles may be added to the region.
1207 static void FASTCALL
1221 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1223 while ((r1
!= r1End
) && (r2
!= r2End
))
1225 left
= max(r1
->left
, r2
->left
);
1226 right
= min(r1
->right
, r2
->right
);
1229 * If there's any overlap between the two rectangles, add that
1230 * overlap to the new region.
1231 * There's no need to check for subsumption because the only way
1232 * such a need could arise is if some region has two rectangles
1233 * right next to each other. Since that should never happen...
1237 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1238 pNextRect
->left
= left
;
1239 pNextRect
->top
= top
;
1240 pNextRect
->right
= right
;
1241 pNextRect
->bottom
= bottom
;
1242 pReg
->rdh
.nCount
+= 1;
1247 * Need to advance the pointers. Shift the one that extends
1248 * to the right the least, since the other still has a chance to
1249 * overlap with that region's next rectangle, if you see what I mean.
1251 if (r1
->right
< r2
->right
)
1255 else if (r2
->right
< r1
->right
)
1268 /***********************************************************************
1269 * REGION_IntersectRegion
1271 static void FASTCALL
REGION_IntersectRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
1274 /* check for trivial reject */
1275 if ( (!(reg1
->rdh
.nCount
)) || (!(reg2
->rdh
.nCount
)) ||
1276 (!EXTENTCHECK(®1
->rdh
.rcBound
, ®2
->rdh
.rcBound
)))
1277 newReg
->rdh
.nCount
= 0;
1279 REGION_RegionOp (newReg
, reg1
, reg2
,
1280 REGION_IntersectO
, NULL
, NULL
);
1283 * Can't alter newReg's extents before we call miRegionOp because
1284 * it might be one of the source regions and miRegionOp depends
1285 * on the extents of those regions being the same. Besides, this
1286 * way there's no checking against rectangles that will be nuked
1287 * due to coalescing, so we have to examine fewer rectangles.
1290 REGION_SetExtents(newReg
);
1293 /***********************************************************************
1295 ***********************************************************************/
1298 * Handle a non-overlapping band for the union operation. Just
1299 * Adds the rectangles into the region. Doesn't have to check for
1300 * subsumption or anything.
1305 * \note Side Effects:
1306 * pReg->numRects is incremented and the final rectangles overwritten
1307 * with the rectangles we're passed.
1310 static void FASTCALL
1321 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1325 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1326 pNextRect
->left
= r
->left
;
1327 pNextRect
->top
= top
;
1328 pNextRect
->right
= r
->right
;
1329 pNextRect
->bottom
= bottom
;
1330 pReg
->rdh
.nCount
+= 1;
1338 * Handle an overlapping band for the union operation. Picks the
1339 * left-most rectangle each time and merges it into the region.
1344 * \note Side Effects:
1345 * Rectangles are overwritten in pReg->rects and pReg->numRects will
1349 static void FASTCALL
1362 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1364 #define MERGERECT(r) \
1365 if ((pReg->rdh.nCount != 0) && \
1366 ((pNextRect-1)->top == top) && \
1367 ((pNextRect-1)->bottom == bottom) && \
1368 ((pNextRect-1)->right >= r->left)) \
1370 if ((pNextRect-1)->right < r->right) \
1372 (pNextRect-1)->right = r->right; \
1377 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
1378 pNextRect->top = top; \
1379 pNextRect->bottom = bottom; \
1380 pNextRect->left = r->left; \
1381 pNextRect->right = r->right; \
1382 pReg->rdh.nCount += 1; \
1387 while ((r1
!= r1End
) && (r2
!= r2End
))
1389 if (r1
->left
< r2
->left
)
1404 } while (r1
!= r1End
);
1406 else while (r2
!= r2End
)
1413 /***********************************************************************
1414 * REGION_UnionRegion
1416 static void FASTCALL
REGION_UnionRegion(ROSRGNDATA
*newReg
, ROSRGNDATA
*reg1
,
1419 /* checks all the simple cases */
1422 * Region 1 and 2 are the same or region 1 is empty
1424 if (reg1
== reg2
|| 0 == reg1
->rdh
.nCount
||
1425 reg1
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.left
||
1426 reg1
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.top
)
1430 REGION_CopyRegion(newReg
, reg2
);
1436 * if nothing to union (region 2 empty)
1438 if (0 == reg2
->rdh
.nCount
||
1439 reg2
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.left
||
1440 reg2
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.top
)
1444 REGION_CopyRegion(newReg
, reg1
);
1450 * Region 1 completely subsumes region 2
1452 if (1 == reg1
->rdh
.nCount
&&
1453 reg1
->rdh
.rcBound
.left
<= reg2
->rdh
.rcBound
.left
&&
1454 reg1
->rdh
.rcBound
.top
<= reg2
->rdh
.rcBound
.top
&&
1455 reg2
->rdh
.rcBound
.right
<= reg1
->rdh
.rcBound
.right
&&
1456 reg2
->rdh
.rcBound
.bottom
<= reg1
->rdh
.rcBound
.bottom
)
1460 REGION_CopyRegion(newReg
, reg1
);
1466 * Region 2 completely subsumes region 1
1468 if (1 == reg2
->rdh
.nCount
&&
1469 reg2
->rdh
.rcBound
.left
<= reg1
->rdh
.rcBound
.left
&&
1470 reg2
->rdh
.rcBound
.top
<= reg1
->rdh
.rcBound
.top
&&
1471 reg1
->rdh
.rcBound
.right
<= reg2
->rdh
.rcBound
.right
&&
1472 reg1
->rdh
.rcBound
.bottom
<= reg2
->rdh
.rcBound
.bottom
)
1476 REGION_CopyRegion(newReg
, reg2
);
1481 REGION_RegionOp ( newReg
, reg1
, reg2
, REGION_UnionO
,
1482 REGION_UnionNonO
, REGION_UnionNonO
);
1483 newReg
->rdh
.rcBound
.left
= min(reg1
->rdh
.rcBound
.left
, reg2
->rdh
.rcBound
.left
);
1484 newReg
->rdh
.rcBound
.top
= min(reg1
->rdh
.rcBound
.top
, reg2
->rdh
.rcBound
.top
);
1485 newReg
->rdh
.rcBound
.right
= max(reg1
->rdh
.rcBound
.right
, reg2
->rdh
.rcBound
.right
);
1486 newReg
->rdh
.rcBound
.bottom
= max(reg1
->rdh
.rcBound
.bottom
, reg2
->rdh
.rcBound
.bottom
);
1489 /***********************************************************************
1490 * Region Subtraction
1491 ***********************************************************************/
1494 * Deal with non-overlapping band for subtraction. Any parts from
1495 * region 2 we discard. Anything from region 1 we add to the region.
1500 * \note Side Effects:
1501 * pReg may be affected.
1504 static void FASTCALL
1505 REGION_SubtractNonO1 (
1515 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1519 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1520 pNextRect
->left
= r
->left
;
1521 pNextRect
->top
= top
;
1522 pNextRect
->right
= r
->right
;
1523 pNextRect
->bottom
= bottom
;
1524 pReg
->rdh
.nCount
+= 1;
1533 * Overlapping band subtraction. x1 is the left-most point not yet
1539 * \note Side Effects:
1540 * pReg may have rectangles added to it.
1543 static void FASTCALL
1558 pNextRect
= (PRECT
)pReg
->Buffer
+ pReg
->rdh
.nCount
;
1560 while ((r1
!= r1End
) && (r2
!= r2End
))
1562 if (r2
->right
<= left
)
1565 * Subtrahend missed the boat: go to next subtrahend.
1569 else if (r2
->left
<= left
)
1572 * Subtrahend preceeds minuend: nuke left edge of minuend.
1575 if (left
>= r1
->right
)
1578 * Minuend completely covered: advance to next minuend and
1579 * reset left fence to edge of new minuend.
1588 * Subtrahend now used up since it doesn't extend beyond
1594 else if (r2
->left
< r1
->right
)
1597 * Left part of subtrahend covers part of minuend: add uncovered
1598 * part of minuend to region and skip to next subtrahend.
1600 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1601 pNextRect
->left
= left
;
1602 pNextRect
->top
= top
;
1603 pNextRect
->right
= r2
->left
;
1604 pNextRect
->bottom
= bottom
;
1605 pReg
->rdh
.nCount
+= 1;
1608 if (left
>= r1
->right
)
1611 * Minuend used up: advance to new...
1620 * Subtrahend used up
1628 * Minuend used up: add any remaining piece before advancing.
1630 if (r1
->right
> left
)
1632 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1633 pNextRect
->left
= left
;
1634 pNextRect
->top
= top
;
1635 pNextRect
->right
= r1
->right
;
1636 pNextRect
->bottom
= bottom
;
1637 pReg
->rdh
.nCount
+= 1;
1646 * Add remaining minuend rectangles to region.
1650 MEMCHECK(pReg
, pNextRect
, pReg
->Buffer
);
1651 pNextRect
->left
= left
;
1652 pNextRect
->top
= top
;
1653 pNextRect
->right
= r1
->right
;
1654 pNextRect
->bottom
= bottom
;
1655 pReg
->rdh
.nCount
+= 1;
1667 * Subtract regS from regM and leave the result in regD.
1668 * S stands for subtrahend, M for minuend and D for difference.
1673 * \note Side Effects:
1674 * regD is overwritten.
1677 static void FASTCALL
REGION_SubtractRegion(ROSRGNDATA
*regD
, ROSRGNDATA
*regM
,
1680 /* check for trivial reject */
1681 if ( (!(regM
->rdh
.nCount
)) || (!(regS
->rdh
.nCount
)) ||
1682 (!EXTENTCHECK(®M
->rdh
.rcBound
, ®S
->rdh
.rcBound
)) )
1684 REGION_CopyRegion(regD
, regM
);
1688 REGION_RegionOp (regD
, regM
, regS
, REGION_SubtractO
,
1689 REGION_SubtractNonO1
, NULL
);
1692 * Can't alter newReg's extents before we call miRegionOp because
1693 * it might be one of the source regions and miRegionOp depends
1694 * on the extents of those regions being the unaltered. Besides, this
1695 * way there's no checking against rectangles that will be nuked
1696 * due to coalescing, so we have to examine fewer rectangles.
1698 REGION_SetExtents (regD
);
1701 /***********************************************************************
1704 static void FASTCALL
REGION_XorRegion(ROSRGNDATA
*dr
, ROSRGNDATA
*sra
,
1708 ROSRGNDATA
*tra
, *trb
;
1710 if(!(htra
= RGNDATA_AllocRgn(sra
->rdh
.nCount
+ 1)))
1712 if(!(htrb
= RGNDATA_AllocRgn(srb
->rdh
.nCount
+ 1)))
1714 NtGdiDeleteObject( htra
);
1717 tra
= RGNDATA_LockRgn( htra
);
1719 NtGdiDeleteObject( htra
);
1720 NtGdiDeleteObject( htrb
);
1724 trb
= RGNDATA_LockRgn( htrb
);
1726 RGNDATA_UnlockRgn( tra
);
1727 NtGdiDeleteObject( htra
);
1728 NtGdiDeleteObject( htrb
);
1732 REGION_SubtractRegion(tra
,sra
,srb
);
1733 REGION_SubtractRegion(trb
,srb
,sra
);
1734 REGION_UnionRegion(dr
,tra
,trb
);
1735 RGNDATA_UnlockRgn( tra
);
1736 RGNDATA_UnlockRgn( trb
);
1738 NtGdiDeleteObject( htra
);
1739 NtGdiDeleteObject( htrb
);
1745 * Adds a rectangle to a REGION
1747 void FASTCALL
REGION_UnionRectWithRegion(const RECT
*rect
, ROSRGNDATA
*rgn
)
1751 region
.Buffer
= ®ion
.rdh
.rcBound
;
1752 region
.rdh
.nCount
= 1;
1753 region
.rdh
.nRgnSize
= sizeof( RECT
);
1754 region
.rdh
.rcBound
= *rect
;
1755 REGION_UnionRegion(rgn
, rgn
, ®ion
);
1758 BOOL FASTCALL
REGION_CreateFrameRgn(HRGN hDest
, HRGN hSrc
, INT x
, INT y
)
1760 PROSRGNDATA srcObj
, destObj
;
1764 if (!(srcObj
= (PROSRGNDATA
)RGNDATA_LockRgn(hSrc
)))
1768 if (!REGION_NOT_EMPTY(srcObj
))
1770 RGNDATA_UnlockRgn(srcObj
);
1773 if (!(destObj
= (PROSRGNDATA
)RGNDATA_LockRgn(hDest
)))
1775 RGNDATA_UnlockRgn(srcObj
);
1779 EMPTY_REGION(destObj
);
1780 if (!REGION_CopyRegion(destObj
, srcObj
))
1782 RGNDATA_UnlockRgn(destObj
);
1783 RGNDATA_UnlockRgn(srcObj
);
1787 /* Original region moved to right */
1788 rc
= (PRECT
)srcObj
->Buffer
;
1789 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1795 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1797 /* Original region moved to left */
1798 rc
= (PRECT
)srcObj
->Buffer
;
1799 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1805 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1807 /* Original region moved down */
1808 rc
= (PRECT
)srcObj
->Buffer
;
1809 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1817 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1819 /* Original region moved up */
1820 rc
= (PRECT
)srcObj
->Buffer
;
1821 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1824 rc
->bottom
-= 2 * y
;
1827 REGION_IntersectRegion(destObj
, destObj
, srcObj
);
1829 /* Restore the original region */
1830 rc
= (PRECT
)srcObj
->Buffer
;
1831 for (i
= 0; i
< srcObj
->rdh
.nCount
; i
++)
1837 REGION_SubtractRegion(destObj
, srcObj
, destObj
);
1839 RGNDATA_UnlockRgn(destObj
);
1840 RGNDATA_UnlockRgn(srcObj
);
1845 BOOL FASTCALL
REGION_LPTODP(HDC hdc
, HRGN hDest
, HRGN hSrc
)
1847 RECT
*pCurRect
, *pEndRect
;
1848 PROSRGNDATA srcObj
= NULL
;
1849 PROSRGNDATA destObj
= NULL
;
1851 DC
* dc
= DC_LockDc(hdc
);
1858 if(dc
->w
.MapMode
== MM_TEXT
) // Requires only a translation
1860 if(NtGdiCombineRgn(hDest
, hSrc
, 0, RGN_COPY
) == ERROR
)
1863 NtGdiOffsetRgn(hDest
, dc
->vportOrgX
- dc
->wndOrgX
, dc
->vportOrgY
- dc
->wndOrgY
);
1868 if(!( srcObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hSrc
) ))
1870 if(!( destObj
= (PROSRGNDATA
) RGNDATA_LockRgn( hDest
) ))
1872 RGNDATA_UnlockRgn( srcObj
);
1875 EMPTY_REGION(destObj
);
1877 pEndRect
= (PRECT
)srcObj
->Buffer
+ srcObj
->rdh
.nCount
;
1878 for(pCurRect
= (PRECT
)srcObj
->Buffer
; pCurRect
< pEndRect
; pCurRect
++)
1880 tmpRect
= *pCurRect
;
1881 tmpRect
.left
= XLPTODP(dc
, tmpRect
.left
);
1882 tmpRect
.top
= YLPTODP(dc
, tmpRect
.top
);
1883 tmpRect
.right
= XLPTODP(dc
, tmpRect
.right
);
1884 tmpRect
.bottom
= YLPTODP(dc
, tmpRect
.bottom
);
1886 if(tmpRect
.left
> tmpRect
.right
)
1887 { INT tmp
= tmpRect
.left
; tmpRect
.left
= tmpRect
.right
; tmpRect
.right
= tmp
; }
1888 if(tmpRect
.top
> tmpRect
.bottom
)
1889 { INT tmp
= tmpRect
.top
; tmpRect
.top
= tmpRect
.bottom
; tmpRect
.bottom
= tmp
; }
1891 REGION_UnionRectWithRegion(&tmpRect
, destObj
);
1895 RGNDATA_UnlockRgn( srcObj
);
1896 RGNDATA_UnlockRgn( destObj
);
1903 HRGN FASTCALL
RGNDATA_AllocRgn(INT n
)
1908 if ((hReg
= (HRGN
) GDIOBJ_AllocObj(GDI_OBJECT_TYPE_REGION
)))
1910 if (NULL
!= (pReg
= RGNDATA_LockRgn(hReg
)))
1914 /* Testing shows that > 95% of all regions have only 1 rect.
1915 Including that here saves us from having to do another
1917 pReg
->Buffer
= &pReg
->rdh
.rcBound
;
1921 pReg
->Buffer
= ExAllocatePoolWithTag(PagedPool
, n
* sizeof(RECT
), TAG_REGION
);
1923 if (NULL
!= pReg
->Buffer
)
1926 pReg
->rdh
.dwSize
= sizeof(RGNDATAHEADER
);
1927 pReg
->rdh
.nCount
= n
;
1928 pReg
->rdh
.nRgnSize
= n
*sizeof(RECT
);
1930 RGNDATA_UnlockRgn(pReg
);
1937 RGNDATA_FreeRgn(hReg
);
1945 RGNDATA_Cleanup(PVOID ObjectBody
)
1947 PROSRGNDATA pRgn
= (PROSRGNDATA
)ObjectBody
;
1948 if(pRgn
->Buffer
&& pRgn
->Buffer
!= &pRgn
->rdh
.rcBound
)
1949 ExFreePool(pRgn
->Buffer
);
1953 // NtGdi Exported Functions
1956 NtGdiCombineRgn(HRGN hDest
,
1962 PROSRGNDATA destRgn
, src1Rgn
, src2Rgn
;
1964 destRgn
= RGNDATA_LockRgn(hDest
);
1967 src1Rgn
= RGNDATA_LockRgn(hSrc1
);
1970 if (CombineMode
== RGN_COPY
)
1972 if( !REGION_CopyRegion(destRgn
, src1Rgn
) )
1974 result
= destRgn
->rdh
.iType
;
1978 src2Rgn
= RGNDATA_LockRgn(hSrc2
);
1981 switch (CombineMode
)
1984 REGION_IntersectRegion(destRgn
, src1Rgn
, src2Rgn
);
1987 REGION_UnionRegion(destRgn
, src1Rgn
, src2Rgn
);
1990 REGION_XorRegion(destRgn
, src1Rgn
, src2Rgn
);
1993 REGION_SubtractRegion(destRgn
, src1Rgn
, src2Rgn
);
1996 RGNDATA_UnlockRgn(src2Rgn
);
1997 result
= destRgn
->rdh
.iType
;
1999 else if(hSrc2
== NULL
)
2001 DPRINT1("NtGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode
);
2005 RGNDATA_UnlockRgn(src1Rgn
);
2008 RGNDATA_UnlockRgn(destRgn
);
2012 DPRINT("NtGdiCombineRgn: hDest unavailable\n");
2021 NtGdiCreateEllipticRgn(INT Left
,
2026 return NtGdiCreateRoundRectRgn(Left
, Top
, Right
, Bottom
,
2027 Right
- Left
, Bottom
- Top
);
2032 NtGdiCreateEllipticRgnIndirect(CONST PRECT Rect
)
2034 RECT SafeRect
= {0};
2035 NTSTATUS Status
= STATUS_SUCCESS
;
2046 Status
= _SEH_GetExceptionCode();
2049 if(!NT_SUCCESS(Status
))
2051 SetLastNtError(Status
);
2055 return NtGdiCreateRoundRectRgn(SafeRect
.left
, SafeRect
.top
, SafeRect
.right
, SafeRect
.bottom
,
2056 SafeRect
.right
- SafeRect
.left
, SafeRect
.bottom
- SafeRect
.top
);
2060 NtGdiCreateRectRgn(INT LeftRect
, INT TopRect
, INT RightRect
, INT BottomRect
)
2064 /* Allocate region data structure with space for 1 RECT */
2065 if ((hRgn
= RGNDATA_AllocRgn(1)))
2067 if (NtGdiSetRectRgn(hRgn
, LeftRect
, TopRect
, RightRect
, BottomRect
))
2069 NtGdiDeleteObject(hRgn
);
2072 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2077 NtGdiCreateRectRgnIndirect(CONST PRECT rc
)
2080 NTSTATUS Status
= STATUS_SUCCESS
;
2091 Status
= _SEH_GetExceptionCode();
2094 if (!NT_SUCCESS(Status
))
2098 return(UnsafeIntCreateRectRgnIndirect(&SafeRc
));
2103 NtGdiCreateRoundRectRgn(INT left
, INT top
, INT right
, INT bottom
,
2104 INT ellipse_width
, INT ellipse_height
)
2108 int asq
, bsq
, d
, xd
, yd
;
2111 /* Make the dimensions sensible */
2113 if (left
> right
) { INT tmp
= left
; left
= right
; right
= tmp
; }
2114 if (top
> bottom
) { INT tmp
= top
; top
= bottom
; bottom
= tmp
; }
2116 ellipse_width
= abs(ellipse_width
);
2117 ellipse_height
= abs(ellipse_height
);
2119 /* Check parameters */
2121 if (ellipse_width
> right
-left
) ellipse_width
= right
-left
;
2122 if (ellipse_height
> bottom
-top
) ellipse_height
= bottom
-top
;
2124 /* Check if we can do a normal rectangle instead */
2126 if ((ellipse_width
< 2) || (ellipse_height
< 2))
2127 return NtGdiCreateRectRgn( left
, top
, right
, bottom
);
2131 d
= (ellipse_height
< 128) ? ((3 * ellipse_height
) >> 2) : 64;
2132 if (!(hrgn
= RGNDATA_AllocRgn(d
))) return 0;
2133 if (!(obj
= RGNDATA_LockRgn(hrgn
))) return 0;
2135 /* Ellipse algorithm, based on an article by K. Porter */
2136 /* in DDJ Graphics Programming Column, 8/89 */
2138 asq
= ellipse_width
* ellipse_width
/ 4; /* a^2 */
2139 bsq
= ellipse_height
* ellipse_height
/ 4; /* b^2 */
2140 d
= bsq
- asq
* ellipse_height
/ 2 + asq
/ 4; /* b^2 - a^2b + a^2/4 */
2142 yd
= asq
* ellipse_height
; /* 2a^2b */
2144 rect
.left
= left
+ ellipse_width
/ 2;
2145 rect
.right
= right
- ellipse_width
/ 2;
2147 /* Loop to draw first half of quadrant */
2151 if (d
> 0) /* if nearest pixel is toward the center */
2153 /* move toward center */
2155 rect
.bottom
= rect
.top
+ 1;
2156 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2157 rect
.top
= --bottom
;
2158 rect
.bottom
= rect
.top
+ 1;
2159 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2163 rect
.left
--; /* next horiz point */
2168 /* Loop to draw second half of quadrant */
2170 d
+= (3 * (asq
-bsq
) / 2 - (xd
+yd
)) / 2;
2173 /* next vertical point */
2175 rect
.bottom
= rect
.top
+ 1;
2176 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2177 rect
.top
= --bottom
;
2178 rect
.bottom
= rect
.top
+ 1;
2179 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2180 if (d
< 0) /* if nearest pixel is outside ellipse */
2182 rect
.left
--; /* move away from center */
2190 /* Add the inside rectangle */
2195 rect
.bottom
= bottom
;
2196 UnsafeIntUnionRectWithRgn( obj
, &rect
);
2198 RGNDATA_UnlockRgn( obj
);
2204 NtGdiEqualRgn(HRGN hSrcRgn1
,
2207 PROSRGNDATA rgn1
, rgn2
;
2208 PRECT tRect1
, tRect2
;
2212 if( !(rgn1
= RGNDATA_LockRgn(hSrcRgn1
)))
2215 if( !(rgn2
= RGNDATA_LockRgn(hSrcRgn2
))){
2216 RGNDATA_UnlockRgn( rgn1
);
2220 if(rgn1
->rdh
.nCount
!= rgn2
->rdh
.nCount
||
2221 rgn1
->rdh
.nCount
== 0 ||
2222 rgn1
->rdh
.rcBound
.left
!= rgn2
->rdh
.rcBound
.left
||
2223 rgn1
->rdh
.rcBound
.right
!= rgn2
->rdh
.rcBound
.right
||
2224 rgn1
->rdh
.rcBound
.top
!= rgn2
->rdh
.rcBound
.top
||
2225 rgn1
->rdh
.rcBound
.bottom
!= rgn2
->rdh
.rcBound
.bottom
)
2228 tRect1
= (PRECT
)rgn1
->Buffer
;
2229 tRect2
= (PRECT
)rgn2
->Buffer
;
2231 if( !tRect1
|| !tRect2
)
2234 for(i
=0; i
< rgn1
->rdh
.nCount
; i
++)
2236 if(tRect1
[i
].left
!= tRect2
[i
].left
||
2237 tRect1
[i
].right
!= tRect2
[i
].right
||
2238 tRect1
[i
].top
!= tRect2
[i
].top
||
2239 tRect1
[i
].bottom
!= tRect2
[i
].bottom
)
2245 RGNDATA_UnlockRgn( rgn1
);
2246 RGNDATA_UnlockRgn( rgn2
);
2252 NtGdiExtCreateRegion(OPTIONAL LPXFORM Xform
,
2259 NTSTATUS Status
= STATUS_SUCCESS
;
2261 if (Count
< FIELD_OFFSET(RGNDATA
, Buffer
))
2263 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2269 ProbeForRead(RgnData
,
2272 nCount
= RgnData
->rdh
.nCount
;
2273 if((Count
- FIELD_OFFSET(RGNDATA
, Buffer
)) / sizeof(RECT
) < nCount
)
2275 Status
= STATUS_INVALID_PARAMETER
;
2281 Status
= _SEH_GetExceptionCode();
2284 if (!NT_SUCCESS(Status
))
2286 SetLastNtError(Status
);
2290 hRgn
= RGNDATA_AllocRgn(nCount
);
2293 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2297 Region
= RGNDATA_LockRgn(hRgn
);
2300 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
2306 RtlCopyMemory(&Region
->rdh
,
2308 FIELD_OFFSET(RGNDATA
, Buffer
));
2309 RtlCopyMemory(Region
->Buffer
,
2311 Count
- FIELD_OFFSET(RGNDATA
, Buffer
));
2315 Status
= _SEH_GetExceptionCode();
2318 if (!NT_SUCCESS(Status
))
2320 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
2321 RGNDATA_UnlockRgn(Region
);
2322 NtGdiDeleteObject(hRgn
);
2326 RGNDATA_UnlockRgn(Region
);
2333 NtGdiFillRgn(HDC hDC
, HRGN hRgn
, HBRUSH hBrush
)
2339 if (NULL
== (rgn
= RGNDATA_LockRgn(hRgn
)))
2344 if (NULL
== (oldhBrush
= NtGdiSelectObject(hDC
, hBrush
)))
2346 RGNDATA_UnlockRgn(rgn
);
2350 for (r
= rgn
->Buffer
; r
< rgn
->Buffer
+ rgn
->rdh
.nCount
; r
++)
2352 NtGdiPatBlt(hDC
, r
->left
, r
->top
, r
->right
- r
->left
, r
->bottom
- r
->top
, PATCOPY
);
2355 RGNDATA_UnlockRgn( rgn
);
2356 NtGdiSelectObject(hDC
, oldhBrush
);
2363 NtGdiFrameRgn(HDC hDC
, HRGN hRgn
, HBRUSH hBrush
, INT Width
, INT Height
)
2368 if(!(FrameRgn
= NtGdiCreateRectRgn(0, 0, 0, 0)))
2372 if(!REGION_CreateFrameRgn(FrameRgn
, hRgn
, Width
, Height
))
2374 NtGdiDeleteObject(FrameRgn
);
2378 Ret
= NtGdiFillRgn(hDC
, FrameRgn
, hBrush
);
2380 NtGdiDeleteObject(FrameRgn
);
2385 UnsafeIntGetRgnBox(PROSRGNDATA Rgn
,
2392 *pRect
= Rgn
->rdh
.rcBound
;
2393 ret
= Rgn
->rdh
.iType
;
2397 return 0; //if invalid region return zero
2402 NtGdiGetRgnBox(HRGN hRgn
,
2408 NTSTATUS Status
= STATUS_SUCCESS
;
2410 if (!(Rgn
= RGNDATA_LockRgn(hRgn
)))
2415 ret
= UnsafeIntGetRgnBox(Rgn
, &SafeRect
);
2416 RGNDATA_UnlockRgn(Rgn
);
2424 ProbeForWrite(pRect
,
2431 Status
= _SEH_GetExceptionCode();
2434 if (!NT_SUCCESS(Status
))
2444 NtGdiInvertRgn(HDC hDC
,
2447 PROSRGNDATA RgnData
;
2451 if(!(RgnData
= RGNDATA_LockRgn(hRgn
)))
2453 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2457 rc
= (PRECT
)RgnData
->Buffer
;
2458 for(i
= 0; i
< RgnData
->rdh
.nCount
; i
++)
2461 if(!NtGdiPatBlt(hDC
, rc
->left
, rc
->top
, rc
->right
- rc
->left
, rc
->bottom
- rc
->top
, DSTINVERT
))
2463 RGNDATA_UnlockRgn(RgnData
);
2469 RGNDATA_UnlockRgn(RgnData
);
2475 NtGdiOffsetRgn(HRGN hRgn
,
2479 PROSRGNDATA rgn
= RGNDATA_LockRgn(hRgn
);
2482 DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn
, XOffset
, YOffset
, rgn
);
2485 DPRINT("NtGdiOffsetRgn: hRgn error\n");
2489 if(XOffset
|| YOffset
) {
2490 int nbox
= rgn
->rdh
.nCount
;
2491 PRECT pbox
= (PRECT
)rgn
->Buffer
;
2495 pbox
->left
+= XOffset
;
2496 pbox
->right
+= XOffset
;
2497 pbox
->top
+= YOffset
;
2498 pbox
->bottom
+= YOffset
;
2501 if (rgn
->Buffer
!= &rgn
->rdh
.rcBound
)
2503 rgn
->rdh
.rcBound
.left
+= XOffset
;
2504 rgn
->rdh
.rcBound
.right
+= XOffset
;
2505 rgn
->rdh
.rcBound
.top
+= YOffset
;
2506 rgn
->rdh
.rcBound
.bottom
+= YOffset
;
2510 ret
= rgn
->rdh
.iType
;
2511 RGNDATA_UnlockRgn( rgn
);
2517 NtGdiPaintRgn(HDC hDC
,
2521 HRGN tmpVisRgn
; //, prevVisRgn;
2522 DC
*dc
= DC_LockDc(hDC
);
2524 CLIPOBJ
* ClipRegion
;
2526 PGDIBRUSHOBJ pBrush
;
2527 GDIBRUSHINST BrushInst
;
2529 BITMAPOBJ
*BitmapObj
;
2534 if(!(tmpVisRgn
= NtGdiCreateRectRgn(0, 0, 0, 0))){
2540 // Transform region into device co-ords
2541 if(!REGION_LPTODP(hDC, tmpVisRgn, hRgn) || NtGdiOffsetRgn(tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY) == ERROR) {
2542 NtGdiDeleteObject( tmpVisRgn );
2547 /* enable when clipping is implemented
2548 NtGdiCombineRgn(tmpVisRgn, tmpVisRgn, dc->w.hGCClipRgn, RGN_AND);
2551 //visrgn = RGNDATA_LockRgn(tmpVisRgn);
2552 visrgn
= RGNDATA_LockRgn(hRgn
);
2559 ClipRegion
= IntEngCreateClipRegion (
2560 visrgn
->rdh
.nCount
, (PRECTL
)visrgn
->Buffer
, (PRECTL
)&visrgn
->rdh
.rcBound
);
2561 ASSERT( ClipRegion
);
2562 pBrush
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
2564 IntGdiInitBrushInstance(&BrushInst
, pBrush
, dc
->XlateBrush
);
2566 BrushOrigin
.x
= dc
->w
.brushOrgX
;
2567 BrushOrigin
.y
= dc
->w
.brushOrgY
;
2568 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
2569 /* FIXME - Handle BitmapObj == NULL !!!! */
2571 bRet
= IntEngPaint(&BitmapObj
->SurfObj
,
2573 &BrushInst
.BrushObject
,
2575 0xFFFF);//FIXME:don't know what to put here
2577 BITMAPOBJ_UnlockBitmap(BitmapObj
);
2578 RGNDATA_UnlockRgn( visrgn
);
2587 NtGdiPtInRegion(HRGN hRgn
,
2595 if(!(rgn
= RGNDATA_LockRgn(hRgn
) ) )
2598 if(rgn
->rdh
.nCount
> 0 && INRECT(rgn
->rdh
.rcBound
, X
, Y
)){
2599 r
= (PRECT
) rgn
->Buffer
;
2600 for(i
= 0; i
< rgn
->rdh
.nCount
; i
++) {
2601 if(INRECT(*r
, X
, Y
)){
2602 RGNDATA_UnlockRgn(rgn
);
2608 RGNDATA_UnlockRgn(rgn
);
2614 UnsafeIntRectInRegion(PROSRGNDATA Rgn
,
2617 PRECT pCurRect
, pRectEnd
;
2619 // this is (just) a useful optimization
2620 if((Rgn
->rdh
.nCount
> 0) && EXTENTCHECK(&Rgn
->rdh
.rcBound
, rc
))
2622 for (pCurRect
= (PRECT
)Rgn
->Buffer
, pRectEnd
= pCurRect
+ Rgn
->rdh
.nCount
; pCurRect
< pRectEnd
; pCurRect
++)
2624 if (pCurRect
->bottom
<= rc
->top
) continue; // not far enough down yet
2625 if (pCurRect
->top
>= rc
->bottom
) break; // too far down
2626 if (pCurRect
->right
<= rc
->left
) continue; // not far enough over yet
2627 if (pCurRect
->left
>= rc
->right
) continue;
2637 NtGdiRectInRegion(HRGN hRgn
,
2638 CONST LPRECT unsaferc
)
2643 NTSTATUS Status
= STATUS_SUCCESS
;
2645 if(!(Rgn
= RGNDATA_LockRgn(hRgn
)))
2652 ProbeForRead(unsaferc
,
2659 Status
= _SEH_GetExceptionCode();
2663 if (!NT_SUCCESS(Status
))
2665 RGNDATA_UnlockRgn(Rgn
);
2666 SetLastNtError(Status
);
2667 DPRINT1("NtGdiRectInRegion: bogus rc\n");
2671 Ret
= UnsafeIntRectInRegion(Rgn
, &rc
);
2672 RGNDATA_UnlockRgn(Rgn
);
2678 NtGdiSetRectRgn(HRGN hRgn
,
2689 if( !( rgn
= RGNDATA_LockRgn(hRgn
) ) )
2690 return 0; //per documentation
2692 if (LeftRect
> RightRect
) { INT tmp
= LeftRect
; LeftRect
= RightRect
; RightRect
= tmp
; }
2693 if (TopRect
> BottomRect
) { INT tmp
= TopRect
; TopRect
= BottomRect
; BottomRect
= tmp
; }
2695 if((LeftRect
!= RightRect
) && (TopRect
!= BottomRect
))
2697 firstRect
= (PRECT
)rgn
->Buffer
;
2698 ASSERT( firstRect
);
2699 firstRect
->left
= rgn
->rdh
.rcBound
.left
= LeftRect
;
2700 firstRect
->top
= rgn
->rdh
.rcBound
.top
= TopRect
;
2701 firstRect
->right
= rgn
->rdh
.rcBound
.right
= RightRect
;
2702 firstRect
->bottom
= rgn
->rdh
.rcBound
.bottom
= BottomRect
;
2703 rgn
->rdh
.nCount
= 1;
2704 rgn
->rdh
.iType
= SIMPLEREGION
;
2708 RGNDATA_UnlockRgn( rgn
);
2713 NtGdiUnionRectWithRgn(HRGN hDest
, CONST PRECT UnsafeRect
)
2717 NTSTATUS Status
= STATUS_SUCCESS
;
2719 if(!(Rgn
= (PROSRGNDATA
)RGNDATA_LockRgn(hDest
)))
2721 SetLastWin32Error(ERROR_INVALID_HANDLE
);
2727 ProbeForRead(UnsafeRect
,
2730 SafeRect
= *UnsafeRect
;
2734 Status
= _SEH_GetExceptionCode();
2738 if (! NT_SUCCESS(Status
))
2740 RGNDATA_UnlockRgn(Rgn
);
2741 SetLastNtError(Status
);
2745 UnsafeIntUnionRectWithRgn(Rgn
, &SafeRect
);
2746 RGNDATA_UnlockRgn(Rgn
);
2751 * MSDN: GetRegionData, Return Values:
2753 * "If the function succeeds and dwCount specifies an adequate number of bytes,
2754 * the return value is always dwCount. If dwCount is too small or the function
2755 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
2756 * required number of bytes.
2758 * If the function fails, the return value is zero."
2760 DWORD STDCALL
NtGdiGetRegionData(HRGN hrgn
, DWORD count
, LPRGNDATA rgndata
)
2763 PROSRGNDATA obj
= RGNDATA_LockRgn( hrgn
);
2764 NTSTATUS Status
= STATUS_SUCCESS
;
2769 size
= obj
->rdh
.nCount
* sizeof(RECT
);
2770 if(count
< (size
+ sizeof(RGNDATAHEADER
)) || rgndata
== NULL
)
2772 RGNDATA_UnlockRgn( obj
);
2773 if (rgndata
) /* buffer is too small, signal it by return 0 */
2775 else /* user requested buffer size with rgndata NULL */
2776 return size
+ sizeof(RGNDATAHEADER
);
2781 ProbeForWrite(rgndata
,
2784 RtlCopyMemory(rgndata
,
2786 sizeof(RGNDATAHEADER
));
2787 RtlCopyMemory((PVOID
)((ULONG_PTR
)rgndata
+ (ULONG_PTR
)sizeof(RGNDATAHEADER
)),
2793 Status
= _SEH_GetExceptionCode();
2797 if(!NT_SUCCESS(Status
))
2799 SetLastNtError(Status
);
2800 RGNDATA_UnlockRgn( obj
);
2804 RGNDATA_UnlockRgn( obj
);
2805 return size
+ sizeof(RGNDATAHEADER
);
2809 /***********************************************************************
2810 * REGION_InsertEdgeInET
2812 * Insert the given edge into the edge table.
2813 * First we must find the correct bucket in the
2814 * Edge table, then find the right slot in the
2815 * bucket. Finally, we can insert it.
2818 static void FASTCALL
REGION_InsertEdgeInET(EdgeTable
*ET
, EdgeTableEntry
*ETE
,
2819 INT scanline
, ScanLineListBlock
**SLLBlock
, INT
*iSLLBlock
)
2822 EdgeTableEntry
*start
, *prev
;
2823 ScanLineList
*pSLL
, *pPrevSLL
;
2824 ScanLineListBlock
*tmpSLLBlock
;
2827 * find the right bucket to put the edge into
2829 pPrevSLL
= &ET
->scanlines
;
2830 pSLL
= pPrevSLL
->next
;
2831 while (pSLL
&& (pSLL
->scanline
< scanline
))
2838 * reassign pSLL (pointer to ScanLineList) if necessary
2840 if ((!pSLL
) || (pSLL
->scanline
> scanline
))
2842 if (*iSLLBlock
> SLLSPERBLOCK
-1)
2844 tmpSLLBlock
= ExAllocatePoolWithTag( PagedPool
, sizeof(ScanLineListBlock
), TAG_REGION
);
2847 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2848 /* FIXME - free resources? */
2851 (*SLLBlock
)->next
= tmpSLLBlock
;
2852 tmpSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
2853 *SLLBlock
= tmpSLLBlock
;
2856 pSLL
= &((*SLLBlock
)->SLLs
[(*iSLLBlock
)++]);
2858 pSLL
->next
= pPrevSLL
->next
;
2859 pSLL
->edgelist
= (EdgeTableEntry
*)NULL
;
2860 pPrevSLL
->next
= pSLL
;
2862 pSLL
->scanline
= scanline
;
2865 * now insert the edge in the right bucket
2867 prev
= (EdgeTableEntry
*)NULL
;
2868 start
= pSLL
->edgelist
;
2869 while (start
&& (start
->bres
.minor_axis
< ETE
->bres
.minor_axis
))
2872 start
= start
->next
;
2879 pSLL
->edgelist
= ETE
;
2882 /***********************************************************************
2885 * This routine moves EdgeTableEntries from the
2886 * EdgeTable into the Active Edge Table,
2887 * leaving them sorted by smaller x coordinate.
2890 static void FASTCALL
REGION_loadAET(EdgeTableEntry
*AET
, EdgeTableEntry
*ETEs
)
2892 EdgeTableEntry
*pPrevAET
;
2893 EdgeTableEntry
*tmp
;
2899 while (AET
&& (AET
->bres
.minor_axis
< ETEs
->bres
.minor_axis
))
2908 ETEs
->back
= pPrevAET
;
2909 pPrevAET
->next
= ETEs
;
2916 /***********************************************************************
2917 * REGION_computeWAET
2919 * This routine links the AET by the
2920 * nextWETE (winding EdgeTableEntry) link for
2921 * use by the winding number rule. The final
2922 * Active Edge Table (AET) might look something
2926 * ---------- --------- ---------
2927 * |ymax | |ymax | |ymax |
2928 * | ... | |... | |... |
2929 * |next |->|next |->|next |->...
2930 * |nextWETE| |nextWETE| |nextWETE|
2931 * --------- --------- ^--------
2933 * V-------------------> V---> ...
2936 static void FASTCALL
REGION_computeWAET(EdgeTableEntry
*AET
)
2938 register EdgeTableEntry
*pWETE
;
2939 register int inside
= 1;
2940 register int isInside
= 0;
2942 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
2952 if ((!inside
&& !isInside
) ||
2953 ( inside
&& isInside
))
2955 pWETE
->nextWETE
= AET
;
2961 pWETE
->nextWETE
= (EdgeTableEntry
*)NULL
;
2964 /***********************************************************************
2965 * REGION_InsertionSort
2967 * Just a simple insertion sort using
2968 * pointers and back pointers to sort the Active
2972 static BOOL FASTCALL
REGION_InsertionSort(EdgeTableEntry
*AET
)
2974 EdgeTableEntry
*pETEchase
;
2975 EdgeTableEntry
*pETEinsert
;
2976 EdgeTableEntry
*pETEchaseBackTMP
;
2977 BOOL changed
= FALSE
;
2984 while (pETEchase
->back
->bres
.minor_axis
> AET
->bres
.minor_axis
)
2985 pETEchase
= pETEchase
->back
;
2988 if (pETEchase
!= pETEinsert
)
2990 pETEchaseBackTMP
= pETEchase
->back
;
2991 pETEinsert
->back
->next
= AET
;
2993 AET
->back
= pETEinsert
->back
;
2994 pETEinsert
->next
= pETEchase
;
2995 pETEchase
->back
->next
= pETEinsert
;
2996 pETEchase
->back
= pETEinsert
;
2997 pETEinsert
->back
= pETEchaseBackTMP
;
3004 /***********************************************************************
3005 * REGION_FreeStorage
3009 static void FASTCALL
REGION_FreeStorage(ScanLineListBlock
*pSLLBlock
)
3011 ScanLineListBlock
*tmpSLLBlock
;
3015 tmpSLLBlock
= pSLLBlock
->next
;
3016 ExFreePool( pSLLBlock
);
3017 pSLLBlock
= tmpSLLBlock
;
3022 /***********************************************************************
3023 * REGION_PtsToRegion
3025 * Create an array of rectangles from a list of points.
3027 static int FASTCALL
REGION_PtsToRegion(int numFullPtBlocks
, int iCurPtBlock
,
3028 POINTBLOCK
*FirstPtBlock
, ROSRGNDATA
*reg
)
3032 POINTBLOCK
*CurPtBlock
;
3034 RECT
*extents
, *temp
;
3037 extents
= ®
->rdh
.rcBound
;
3039 numRects
= ((numFullPtBlocks
* NUMPTSTOBUFFER
) + iCurPtBlock
) >> 1;
3041 if(!(temp
= ExAllocatePoolWithTag(PagedPool
, numRects
* sizeof(RECT
), TAG_REGION
)))
3045 if(reg
->Buffer
!= NULL
)
3047 COPY_RECTS(temp
, reg
->Buffer
, reg
->rdh
.nCount
);
3048 if(reg
->Buffer
!= ®
->rdh
.rcBound
)
3049 ExFreePool(reg
->Buffer
);
3053 reg
->rdh
.nCount
= numRects
;
3054 CurPtBlock
= FirstPtBlock
;
3055 rects
= reg
->Buffer
- 1;
3057 extents
->left
= LARGE_COORDINATE
, extents
->right
= SMALL_COORDINATE
;
3059 for ( ; numFullPtBlocks
>= 0; numFullPtBlocks
--) {
3060 /* the loop uses 2 points per iteration */
3061 i
= NUMPTSTOBUFFER
>> 1;
3062 if (!numFullPtBlocks
)
3063 i
= iCurPtBlock
>> 1;
3064 for (pts
= CurPtBlock
->pts
; i
--; pts
+= 2) {
3065 if (pts
->x
== pts
[1].x
)
3067 if (numRects
&& pts
->x
== rects
->left
&& pts
->y
== rects
->bottom
&&
3068 pts
[1].x
== rects
->right
&&
3069 (numRects
== 1 || rects
[-1].top
!= rects
->top
) &&
3070 (i
&& pts
[2].y
> pts
[1].y
)) {
3071 rects
->bottom
= pts
[1].y
+ 1;
3076 rects
->left
= pts
->x
; rects
->top
= pts
->y
;
3077 rects
->right
= pts
[1].x
; rects
->bottom
= pts
[1].y
+ 1;
3078 if (rects
->left
< extents
->left
)
3079 extents
->left
= rects
->left
;
3080 if (rects
->right
> extents
->right
)
3081 extents
->right
= rects
->right
;
3083 CurPtBlock
= CurPtBlock
->next
;
3087 extents
->top
= reg
->Buffer
->top
;
3088 extents
->bottom
= rects
->bottom
;
3093 extents
->bottom
= 0;
3095 reg
->rdh
.nCount
= numRects
;
3100 /***********************************************************************
3101 * REGION_CreateEdgeTable
3103 * This routine creates the edge table for
3104 * scan converting polygons.
3105 * The Edge Table (ET) looks like:
3109 * | ymax | ScanLineLists
3110 * |scanline|-->------------>-------------->...
3111 * -------- |scanline| |scanline|
3112 * |edgelist| |edgelist|
3113 * --------- ---------
3117 * list of ETEs list of ETEs
3119 * where ETE is an EdgeTableEntry data structure,
3120 * and there is one ScanLineList per scanline at
3121 * which an edge is initially entered.
3124 static void FASTCALL
REGION_CreateETandAET(const INT
*Count
, INT nbpolygons
,
3125 const POINT
*pts
, EdgeTable
*ET
, EdgeTableEntry
*AET
,
3126 EdgeTableEntry
*pETEs
, ScanLineListBlock
*pSLLBlock
)
3128 const POINT
*top
, *bottom
;
3129 const POINT
*PrevPt
, *CurrPt
, *EndPt
;
3136 * initialize the Active Edge Table
3138 AET
->next
= (EdgeTableEntry
*)NULL
;
3139 AET
->back
= (EdgeTableEntry
*)NULL
;
3140 AET
->nextWETE
= (EdgeTableEntry
*)NULL
;
3141 AET
->bres
.minor_axis
= SMALL_COORDINATE
;
3144 * initialize the Edge Table.
3146 ET
->scanlines
.next
= (ScanLineList
*)NULL
;
3147 ET
->ymax
= SMALL_COORDINATE
;
3148 ET
->ymin
= LARGE_COORDINATE
;
3149 pSLLBlock
->next
= (ScanLineListBlock
*)NULL
;
3152 for(poly
= 0; poly
< nbpolygons
; poly
++)
3154 count
= Count
[poly
];
3162 * for each vertex in the array of points.
3163 * In this loop we are dealing with two vertices at
3164 * a time -- these make up one edge of the polygon.
3171 * find out which point is above and which is below.
3173 if (PrevPt
->y
> CurrPt
->y
)
3175 bottom
= PrevPt
, top
= CurrPt
;
3176 pETEs
->ClockWise
= 0;
3180 bottom
= CurrPt
, top
= PrevPt
;
3181 pETEs
->ClockWise
= 1;
3185 * don't add horizontal edges to the Edge table.
3187 if (bottom
->y
!= top
->y
)
3189 pETEs
->ymax
= bottom
->y
-1;
3190 /* -1 so we don't get last scanline */
3193 * initialize integer edge algorithm
3195 dy
= bottom
->y
- top
->y
;
3196 BRESINITPGONSTRUCT(dy
, top
->x
, bottom
->x
, pETEs
->bres
);
3198 REGION_InsertEdgeInET(ET
, pETEs
, top
->y
, &pSLLBlock
,
3201 if (PrevPt
->y
> ET
->ymax
)
3202 ET
->ymax
= PrevPt
->y
;
3203 if (PrevPt
->y
< ET
->ymin
)
3204 ET
->ymin
= PrevPt
->y
;
3214 IntCreatePolyPolgonRgn(POINT
*Pts
,
3221 EdgeTableEntry
*pAET
; /* Active Edge Table */
3222 INT y
; /* current scanline */
3223 int iPts
= 0; /* number of pts in buffer */
3224 EdgeTableEntry
*pWETE
; /* Winding Edge Table Entry*/
3225 ScanLineList
*pSLL
; /* current scanLineList */
3226 POINT
*pts
; /* output buffer */
3227 EdgeTableEntry
*pPrevAET
; /* ptr to previous AET */
3228 EdgeTable ET
; /* header node for ET */
3229 EdgeTableEntry AET
; /* header node for AET */
3230 EdgeTableEntry
*pETEs
; /* EdgeTableEntries pool */
3231 ScanLineListBlock SLLBlock
; /* header for scanlinelist */
3232 int fixWAET
= FALSE
;
3233 POINTBLOCK FirstPtBlock
, *curPtBlock
; /* PtBlock buffers */
3234 POINTBLOCK
*tmpPtBlock
;
3235 int numFullPtBlocks
= 0;
3238 if(!(hrgn
= RGNDATA_AllocRgn(nbpolygons
)))
3240 if(!(region
= RGNDATA_LockRgn(hrgn
)))
3242 NtGdiDeleteObject(hrgn
);
3246 /* special case a rectangle */
3248 if (((nbpolygons
== 1) && ((*Count
== 4) ||
3249 ((*Count
== 5) && (Pts
[4].x
== Pts
[0].x
) && (Pts
[4].y
== Pts
[0].y
)))) &&
3250 (((Pts
[0].y
== Pts
[1].y
) &&
3251 (Pts
[1].x
== Pts
[2].x
) &&
3252 (Pts
[2].y
== Pts
[3].y
) &&
3253 (Pts
[3].x
== Pts
[0].x
)) ||
3254 ((Pts
[0].x
== Pts
[1].x
) &&
3255 (Pts
[1].y
== Pts
[2].y
) &&
3256 (Pts
[2].x
== Pts
[3].x
) &&
3257 (Pts
[3].y
== Pts
[0].y
))))
3259 RGNDATA_UnlockRgn( region
);
3260 NtGdiSetRectRgn( hrgn
, min(Pts
[0].x
, Pts
[2].x
), min(Pts
[0].y
, Pts
[2].y
),
3261 max(Pts
[0].x
, Pts
[2].x
), max(Pts
[0].y
, Pts
[2].y
) );
3265 for(poly
= total
= 0; poly
< nbpolygons
; poly
++)
3266 total
+= Count
[poly
];
3267 if (! (pETEs
= ExAllocatePoolWithTag( PagedPool
, sizeof(EdgeTableEntry
) * total
, TAG_REGION
)))
3269 NtGdiDeleteObject( hrgn
);
3272 pts
= FirstPtBlock
.pts
;
3273 REGION_CreateETandAET(Count
, nbpolygons
, Pts
, &ET
, &AET
, pETEs
, &SLLBlock
);
3274 pSLL
= ET
.scanlines
.next
;
3275 curPtBlock
= &FirstPtBlock
;
3277 if (mode
!= WINDING
) {
3281 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
3283 * Add a new edge to the active edge table when we
3284 * get to the next edge.
3286 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
3287 REGION_loadAET(&AET
, pSLL
->edgelist
);
3294 * for each active edge
3297 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3301 * send out the buffer
3303 if (iPts
== NUMPTSTOBUFFER
) {
3304 tmpPtBlock
= ExAllocatePoolWithTag( PagedPool
, sizeof(POINTBLOCK
), TAG_REGION
);
3306 DPRINT1("Can't alloc tPB\n");
3310 curPtBlock
->next
= tmpPtBlock
;
3311 curPtBlock
= tmpPtBlock
;
3312 pts
= curPtBlock
->pts
;
3316 EVALUATEEDGEEVENODD(pAET
, pPrevAET
, y
);
3318 REGION_InsertionSort(&AET
);
3325 for (y
= ET
.ymin
; y
< ET
.ymax
; y
++) {
3327 * Add a new edge to the active edge table when we
3328 * get to the next edge.
3330 if (pSLL
!= NULL
&& y
== pSLL
->scanline
) {
3331 REGION_loadAET(&AET
, pSLL
->edgelist
);
3332 REGION_computeWAET(&AET
);
3340 * for each active edge
3344 * add to the buffer only those edges that
3345 * are in the Winding active edge table.
3347 if (pWETE
== pAET
) {
3348 pts
->x
= pAET
->bres
.minor_axis
, pts
->y
= y
;
3352 * send out the buffer
3354 if (iPts
== NUMPTSTOBUFFER
) {
3355 tmpPtBlock
= ExAllocatePoolWithTag( PagedPool
,
3356 sizeof(POINTBLOCK
), TAG_REGION
);
3358 DPRINT1("Can't alloc tPB\n");
3360 NtGdiDeleteObject( hrgn
);
3363 curPtBlock
->next
= tmpPtBlock
;
3364 curPtBlock
= tmpPtBlock
;
3365 pts
= curPtBlock
->pts
;
3366 numFullPtBlocks
++; iPts
= 0;
3368 pWETE
= pWETE
->nextWETE
;
3370 EVALUATEEDGEWINDING(pAET
, pPrevAET
, y
, fixWAET
);
3374 * recompute the winding active edge table if
3375 * we just resorted or have exited an edge.
3377 if (REGION_InsertionSort(&AET
) || fixWAET
) {
3378 REGION_computeWAET(&AET
);
3383 REGION_FreeStorage(SLLBlock
.next
);
3384 REGION_PtsToRegion(numFullPtBlocks
, iPts
, &FirstPtBlock
, region
);
3386 for (curPtBlock
= FirstPtBlock
.next
; --numFullPtBlocks
>= 0;) {
3387 tmpPtBlock
= curPtBlock
->next
;
3388 ExFreePool( curPtBlock
);
3389 curPtBlock
= tmpPtBlock
;
3391 ExFreePool( pETEs
);
3392 RGNDATA_UnlockRgn( region
);
3398 NtGdiCreatePolygonRgn(CONST PPOINT pt
,
3403 NTSTATUS Status
= STATUS_SUCCESS
;
3407 if (pt
== NULL
|| Count
== 0 ||
3408 (PolyFillMode
!= WINDING
&& PolyFillMode
!= ALTERNATE
))
3410 /* Windows doesn't set a last error here */
3416 /* can't create a region with only one point! */
3417 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
3423 /* Windows creates an empty region! */
3426 if(!(hRgn
= RGNDATA_AllocRgn(1)))
3430 if(!(rgn
= RGNDATA_LockRgn(hRgn
)))
3432 NtGdiDeleteObject(hRgn
);
3438 RGNDATA_UnlockRgn(rgn
);
3445 Count
* sizeof(POINT
),
3450 Status
= _SEH_GetExceptionCode();
3454 if (!NT_SUCCESS(Status
))
3456 SetLastNtError(Status
);
3460 if (!(SafePoints
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(POINT
), TAG_REGION
)))
3462 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3468 /* pointers were already probed! */
3469 RtlCopyMemory(SafePoints
,
3471 Count
* sizeof(POINT
));
3475 Status
= _SEH_GetExceptionCode();
3478 if (!NT_SUCCESS(Status
))
3480 ExFreePool(SafePoints
);
3481 SetLastNtError(Status
);
3485 hRgn
= IntCreatePolyPolgonRgn(SafePoints
, &Count
, 1, PolyFillMode
);
3487 ExFreePool(SafePoints
);
3493 NtGdiCreatePolyPolygonRgn(CONST PPOINT pt
,
3494 CONST PINT PolyCounts
,
3499 INT
*SafePolyCounts
;
3500 INT nPoints
, nEmpty
, nInvalid
, i
;
3502 NTSTATUS Status
= STATUS_SUCCESS
;
3504 if (pt
== NULL
|| PolyCounts
== NULL
|| Count
== 0 ||
3505 (PolyFillMode
!= WINDING
&& PolyFillMode
!= ALTERNATE
))
3507 /* Windows doesn't set a last error here */
3513 ProbeForRead(PolyCounts
,
3514 Count
* sizeof(INT
),
3516 /* just probe one point for now, we don't know the length of the array yet */
3523 Status
= _SEH_GetExceptionCode();
3527 if (!NT_SUCCESS(Status
))
3529 SetLastNtError(Status
);
3533 if (!(SafePolyCounts
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(INT
), TAG_REGION
)))
3535 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3541 /* pointers were already probed! */
3542 RtlCopyMemory(SafePolyCounts
,
3544 Count
* sizeof(INT
));
3548 Status
= _SEH_GetExceptionCode();
3552 if (!NT_SUCCESS(Status
))
3554 ExFreePool(SafePolyCounts
);
3555 SetLastNtError(Status
);
3559 /* validate poligons */
3563 for (i
= 0; i
< Count
; i
++)
3565 if (SafePolyCounts
[i
] == 0)
3569 if (SafePolyCounts
[i
] == 1)
3573 nPoints
+= SafePolyCounts
[i
];
3576 if (nEmpty
== Count
)
3578 /* if all polygon counts are zero, return without setting a last error code. */
3579 ExFreePool(SafePolyCounts
);
3584 /* if at least one poly count is 1, fail */
3585 ExFreePool(SafePolyCounts
);
3586 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
3591 if (!(Safept
= ExAllocatePoolWithTag(PagedPool
, nPoints
* sizeof(POINT
), TAG_REGION
)))
3593 ExFreePool(SafePolyCounts
);
3594 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
3601 nPoints
* sizeof(POINT
),
3603 /* pointers were already probed! */
3604 RtlCopyMemory(Safept
,
3606 nPoints
* sizeof(POINT
));
3610 Status
= _SEH_GetExceptionCode();
3613 if (!NT_SUCCESS(Status
))
3616 ExFreePool(SafePolyCounts
);
3617 SetLastNtError(Status
);
3621 /* now we're ready to calculate the region safely */
3622 hRgn
= IntCreatePolyPolgonRgn(Safept
, SafePolyCounts
, Count
, PolyFillMode
);
3625 ExFreePool(SafePolyCounts
);