ReactOS 0.4.15-dev-6657-ged9973f
region.c
Go to the documentation of this file.
1/*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20/*
21 * GDI region objects. Shamelessly ripped out from the X11 distribution
22 * Thanks for the nice licence.
23 *
24 * Copyright 1993, 1994, 1995 Alexandre Julliard
25 * Modifications and additions: Copyright 1998 Huw Davies
26 * 1999 Alex Korobka
27 *
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.
32 *
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.
37 *
38 * You should have received a copy of the GNU Lesser General Public
39 * License along with this library; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
41 */
42
43/************************************************************************
44
45Copyright (c) 1987, 1988 X Consortium
46
47Permission is hereby granted, free of charge, to any person obtaining a copy
48of this software and associated documentation files (the "Software"), to deal
49in the Software without restriction, including without limitation the rights
50to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51copies of the Software, and to permit persons to whom the Software is
52furnished to do so, subject to the following conditions:
53
54The above copyright notice and this permission notice shall be included in
55all copies or substantial portions of the Software.
56
57THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
61AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
62CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
63
64Except as contained in this notice, the name of the X Consortium shall not be
65used in advertising or otherwise to promote the sale, use or other dealings
66in this Software without prior written authorization from the X Consortium.
67
68
69Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
70
71 All Rights Reserved
72
73Permission to use, copy, modify, and distribute this software and its
74documentation for any purpose and without fee is hereby granted,
75provided that the above copyright notice appear in all copies and that
76both that copyright notice and this permission notice appear in
77supporting documentation, and that the name of Digital not be
78used in advertising or publicity pertaining to distribution of the
79software without specific, written prior permission.
80
81DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
82ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
83DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
84ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
85WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
86ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
87SOFTWARE.
88
89************************************************************************/
90/*
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.
96 *
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".
104 *
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
107 * to touch.
108 *
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...
114 */
115
116// X11 sources for ReactOS region processing.
117//
118// libX11/src/PolyReg.c
119// libX11/src/Region.c
120//
121//
122
123
124#include <win32k.h>
125#include <suppress.h>
126
127#define NDEBUG
128#include <debug.h>
129
132
133// Internal Functions
134
135#if 1
136#define COPY_RECTS(dest, src, nRects) \
137 do { \
138 PRECTL xDest = (dest); \
139 PRECTL xSrc = (src); \
140 UINT xRects = (nRects); \
141 while (xRects-- > 0) { \
142 *(xDest++) = *(xSrc++); \
143 } \
144 } while (0)
145#else
146#define COPY_RECTS(dest, src, nRects) RtlCopyMemory(dest, src, (nRects) * sizeof(RECTL))
147#endif
148
149#define EMPTY_REGION(pReg) { \
150 (pReg)->rdh.nCount = 0; \
151 (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
152 (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
153 (pReg)->rdh.iType = RDH_RECTANGLES; \
154}
155
156#define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
157
158#define INRECT(r, x, y) \
159 ( ( ((r).right > x)) && \
160 ( ((r).left <= x)) && \
161 ( ((r).bottom > y)) && \
162 ( ((r).top <= y)) )
163
164/* 1 if two RECTs overlap.
165 * 0 if two RECTs do not overlap.
166 */
167#define EXTENTCHECK(r1, r2) \
168 ((r1)->right > (r2)->left && \
169 (r1)->left < (r2)->right && \
170 (r1)->bottom > (r2)->top && \
171 (r1)->top < (r2)->bottom)
172
173/*
174 * In scan converting polygons, we want to choose those pixels
175 * which are inside the polygon. Thus, we add .5 to the starting
176 * x coordinate for both left and right edges. Now we choose the
177 * first pixel which is inside the pgon for the left edge and the
178 * first pixel which is outside the pgon for the right edge.
179 * Draw the left pixel, but not the right.
180 *
181 * How to add .5 to the starting x coordinate:
182 * If the edge is moving to the right, then subtract dy from the
183 * error term from the general form of the algorithm.
184 * If the edge is moving to the left, then add dy to the error term.
185 *
186 * The reason for the difference between edges moving to the left
187 * and edges moving to the right is simple: If an edge is moving
188 * to the right, then we want the algorithm to flip immediately.
189 * If it is moving to the left, then we don't want it to flip until
190 * we traverse an entire pixel.
191 */
192#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
193 int dx; /* Local storage */ \
194\
195 /* \
196 * If the edge is horizontal, then it is ignored \
197 * and assumed not to be processed. Otherwise, do this stuff. \
198 */ \
199 if ((dy) != 0) { \
200 xStart = (x1); \
201 dx = (x2) - xStart; \
202 if (dx < 0) { \
203 m = dx / (dy); \
204 m1 = m - 1; \
205 incr1 = -2 * dx + 2 * (dy) * m1; \
206 incr2 = -2 * dx + 2 * (dy) * m; \
207 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
208 } else { \
209 m = dx / (dy); \
210 m1 = m + 1; \
211 incr1 = 2 * dx - 2 * (dy) * m1; \
212 incr2 = 2 * dx - 2 * (dy) * m; \
213 d = -2 * m * (dy) + 2 * dx; \
214 } \
215 } \
216}
217
218#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
219 if (m1 > 0) { \
220 if (d > 0) { \
221 minval += m1; \
222 d += incr1; \
223 } \
224 else { \
225 minval += m; \
226 d += incr2; \
227 } \
228 } else {\
229 if (d >= 0) { \
230 minval += m1; \
231 d += incr1; \
232 } \
233 else { \
234 minval += m; \
235 d += incr2; \
236 } \
237 } \
238}
239
240/*
241 * This structure contains all of the information needed
242 * to run the bresenham algorithm.
243 * The variables may be hardcoded into the declarations
244 * instead of using this structure to make use of
245 * register declarations.
246 */
247typedef struct
249 INT minor_axis; /* Minor axis */
250 INT d; /* Decision variable */
251 INT m, m1; /* Slope and slope+1 */
252 INT incr1, incr2; /* Error increments */
254
255
256#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
257 BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
258 bres.m, bres.m1, bres.incr1, bres.incr2)
259
260#define BRESINCRPGONSTRUCT(bres) \
261 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
262
263
264
265/*
266 * These are the data structures needed to scan
267 * convert regions. Two different scan conversion
268 * methods are available -- the even-odd method, and
269 * the winding number method.
270 * The even-odd rule states that a point is inside
271 * the polygon if a ray drawn from that point in any
272 * direction will pass through an odd number of
273 * path segments.
274 * By the winding number rule, a point is decided
275 * to be inside the polygon if a ray drawn from that
276 * point in any direction passes through a different
277 * number of clockwise and counter-clockwise path
278 * segments.
279 *
280 * These data structures are adapted somewhat from
281 * the algorithm in (Foley/Van Dam) for scan converting
282 * polygons.
283 * The basic algorithm is to start at the top (smallest y)
284 * of the polygon, stepping down to the bottom of
285 * the polygon by incrementing the y coordinate. We
286 * keep a list of edges which the current scanline crosses,
287 * sorted by x. This list is called the Active Edge Table (AET)
288 * As we change the y-coordinate, we update each entry in
289 * in the active edge table to reflect the edges new xcoord.
290 * This list must be sorted at each scanline in case
291 * two edges intersect.
292 * We also keep a data structure known as the Edge Table (ET),
293 * which keeps track of all the edges which the current
294 * scanline has not yet reached. The ET is basically a
295 * list of SCANLINE_LIST structures containing a list of
296 * edges which are entered at a given scanline. There is one
297 * SCANLINE_LIST per scanline at which an edge is entered.
298 * When we enter a new edge, we move it from the ET to the AET.
299 *
300 * From the AET, we can implement the even-odd rule as in
301 * (Foley/Van Dam).
302 * The winding number rule is a little trickier. We also
303 * keep the EDGE_TABLEEntries in the AET linked by the
304 * nextWETE (winding EDGE_TABLE_ENTRY) link. This allows
305 * the edges to be linked just as before for updating
306 * purposes, but only uses the edges linked by the nextWETE
307 * link as edges representing spans of the polygon to
308 * drawn (as with the even-odd rule).
309 */
310
312 * For the winding number rule
313 */
314#define CLOCKWISE 1
315#define COUNTERCLOCKWISE -1
317typedef struct _EDGE_TABLE_ENTRY
319 INT ymax; /* ycoord at which we exit this edge. */
320 BRESINFO bres; /* Bresenham info to run the edge */
321 struct _EDGE_TABLE_ENTRY *next; /* Next in the list */
322 struct _EDGE_TABLE_ENTRY *back; /* For insertion sort */
323 struct _EDGE_TABLE_ENTRY *nextWETE; /* For winding num rule */
324 INT ClockWise; /* Flag for winding number rule */
326
328typedef struct _SCANLINE_LIST
330 INT scanline; /* The scanline represented */
331 EDGE_TABLE_ENTRY *edgelist; /* Header node */
332 struct _SCANLINE_LIST *next; /* Next in the list */
334
336typedef struct
338 INT ymax; /* ymax for the polygon */
339 INT ymin; /* ymin for the polygon */
340 SCANLINE_LIST scanlines; /* Header node */
341} EDGE_TABLE;
342
343
344/*
345 * Here is a struct to help with storage allocation
346 * so we can allocate a big chunk at a time, and then take
347 * pieces from this heap when we need to.
348 */
349#define SLLSPERBLOCK 25
356
357
358/*
359 * A few macros for the inner loops of the fill code where
360 * performance considerations don't allow a procedure call.
361 *
362 * Evaluate the given edge at the given scanline.
363 * If the edge has expired, then we leave it and fix up
364 * the active edge table; otherwise, we increment the
365 * x value to be ready for the next scanline.
366 * The winding number rule is in effect, so we must notify
367 * the caller when the edge has been removed so he
368 * can reorder the Winding Active Edge Table.
369 */
370#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
371 if (pAET->ymax == y) { /* Leaving this edge */ \
372 pPrevAET->next = pAET->next; \
373 pAET = pPrevAET->next; \
374 fixWAET = 1; \
375 if (pAET) \
376 pAET->back = pPrevAET; \
377 } \
378 else { \
379 BRESINCRPGONSTRUCT(pAET->bres); \
380 pPrevAET = pAET; \
381 pAET = pAET->next; \
382 } \
383}
384
385
386/*
387 * Evaluate the given edge at the given scanline.
388 * If the edge has expired, then we leave it and fix up
389 * the active edge table; otherwise, we increment the
390 * x value to be ready for the next scanline.
391 * The even-odd rule is in effect.
392 */
393#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
394 if (pAET->ymax == y) { /* Leaving this edge */ \
395 pPrevAET->next = pAET->next; \
396 pAET = pPrevAET->next; \
397 if (pAET) \
398 pAET->back = pPrevAET; \
399 } \
400 else { \
401 BRESINCRPGONSTRUCT(pAET->bres); \
402 pPrevAET = pAET; \
403 pAET = pAET->next; \
404 } \
405}
406
407/**************************************************************************
408 *
409 * Poly Regions
411 *************************************************************************/
412
413#define LARGE_COORDINATE INT_MAX
414#define SMALL_COORDINATE INT_MIN
416static
417BOOL
419 _Inout_ PREGION prgn,
420 _In_ UINT cRects)
421{
422 ULONG cjNewSize;
423 PVOID pvBuffer;
424 NT_ASSERT(cRects > 0);
425
426 /* Make sure we don't overflow */
427 if (cRects > MAXULONG / sizeof(RECTL))
428 {
429 return FALSE;
430 }
431
432 /* Calculate new buffer size */
433 cjNewSize = cRects * sizeof(RECTL);
434
435 /* Avoid allocating too often, by duplicating the old buffer size
436 Note: we don't do an overflow check, since the old size will never
437 get that large before running out of memory. */
438 if (2 * prgn->rdh.nRgnSize > cjNewSize)
439 {
440 cjNewSize = 2 * prgn->rdh.nRgnSize;
441 }
442
443 /* Allocate the new buffer */
444 pvBuffer = ExAllocatePoolWithTag(PagedPool, cjNewSize, TAG_REGION);
445 if (pvBuffer == NULL)
446 {
447 return FALSE;
448 }
449
450 /* Copy the rects into the new buffer */
451 COPY_RECTS(pvBuffer, prgn->Buffer, prgn->rdh.nCount);
452
453 /* Free the old buffer */
454 if (prgn->Buffer != &prgn->rdh.rcBound)
455 {
456 ExFreePoolWithTag(prgn->Buffer, TAG_REGION);
457 }
458
459 /* Set the new buffer */
460 prgn->Buffer = pvBuffer;
461 prgn->rdh.nRgnSize = cjNewSize;
462
463 return TRUE;
464}
466static __inline
467BOOL
469 _Inout_ PREGION prgn,
470 _In_ UINT cRects)
471{
472 /* Check if the current region size is too small */
473 if (cRects > prgn->rdh.nRgnSize / sizeof(RECTL))
474 {
475 /* Allocate a new buffer */
476 return REGION_bGrowBufferSize(prgn, cRects);
477 }
478
479 return TRUE;
480}
483VOID
485 _Inout_ PREGION prgn,
486 _In_ LONG left,
487 _In_ LONG top,
490{
491 PRECTL prcl;
492 NT_ASSERT((prgn->rdh.nCount + 1) * sizeof(RECT) <= prgn->rdh.nRgnSize);
493
494 prcl = &prgn->Buffer[prgn->rdh.nCount];
495 prcl->left = left;
496 prcl->top = top;
497 prcl->right = right;
498 prcl->bottom = bottom;
499 prgn->rdh.nCount++;
500}
502static __inline
503BOOL
505 _Inout_ PREGION prgn,
506 _In_ LONG left,
507 _In_ LONG top,
510{
511 if (!REGION_bEnsureBufferSize(prgn, prgn->rdh.nCount + 1))
512 {
513 return FALSE;
514 }
515
517 return TRUE;
519
522
523// Number of points to buffer before sending them off to scanlines() : Must be an even number
524#define NUMPTSTOBUFFER 200
525
526#define RGN_DEFAULT_RECTS 2
527
528// Used to allocate buffers for points and link the buffers together
529typedef struct _POINTBLOCK
532 struct _POINTBLOCK *next;
533} POINTBLOCK;
534
535#ifndef NDEBUG
536/*
537 * This function is left there for debugging purposes.
538 */
539VOID
541IntDumpRegion(HRGN hRgn)
542{
544
546 if (Data == NULL)
547 {
548 DbgPrint("IntDumpRegion called with invalid region!\n");
549 return;
550 }
551
552 DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
553 hRgn,
554 Data->rdh.rcBound.left,
555 Data->rdh.rcBound.top,
556 Data->rdh.rcBound.right,
557 Data->rdh.rcBound.bottom,
558 Data->rdh.iType);
559
561}
562#endif /* Not NDEBUG */
563
565INT
568{
569 if (prgn == NULL)
570 return NULLREGION;
571
572 DPRINT("Region Complexity -> %lu", prgn->rdh.nCount);
573 switch (prgn->rdh.nCount)
574 {
575 case 0:
576 return NULLREGION;
577 case 1:
578 return SIMPLEREGION;
579 default:
580 return COMPLEXREGION;
581 }
582}
583
584static
585BOOL
588 PREGION dst,
589 PREGION src)
590{
591 /* Only copy if source and dest are not equal */
592 if (dst != src)
593 {
594 /* Check if we need to increase our buffer */
595 if (dst->rdh.nRgnSize < src->rdh.nCount * sizeof(RECT))
596 {
597 PRECTL temp;
598
599 /* Allocate a new buffer */
601 src->rdh.nCount * sizeof(RECT),
602 TAG_REGION);
603 if (temp == NULL)
604 return FALSE;
605
606 /* Free the old buffer */
607 if ((dst->Buffer != NULL) && (dst->Buffer != &dst->rdh.rcBound))
609
610 /* Set the new buffer and the size */
611 dst->Buffer = temp;
612 dst->rdh.nRgnSize = src->rdh.nCount * sizeof(RECT);
613 }
614
615 dst->rdh.nCount = src->rdh.nCount;
616 dst->rdh.rcBound.left = src->rdh.rcBound.left;
617 dst->rdh.rcBound.top = src->rdh.rcBound.top;
618 dst->rdh.rcBound.right = src->rdh.rcBound.right;
619 dst->rdh.rcBound.bottom = src->rdh.rcBound.bottom;
620 dst->rdh.iType = src->rdh.iType;
621 COPY_RECTS(dst->Buffer, src->Buffer, src->rdh.nCount);
622 }
623
624 return TRUE;
625}
626
627static
628VOID
631 PREGION pReg)
632{
633 RECTL *pRect, *pRectEnd, *pExtents;
634
635 /* Quick check for NULLREGION */
636 if (pReg->rdh.nCount == 0)
637 {
638 pReg->rdh.rcBound.left = 0;
639 pReg->rdh.rcBound.top = 0;
640 pReg->rdh.rcBound.right = 0;
641 pReg->rdh.rcBound.bottom = 0;
642 pReg->rdh.iType = RDH_RECTANGLES;
643 return;
644 }
645
646 pExtents = &pReg->rdh.rcBound;
647 pRect = pReg->Buffer;
648 pRectEnd = pReg->Buffer + pReg->rdh.nCount - 1;
649
650 /* Since pRect is the first rectangle in the region, it must have the
651 * smallest top and since pRectEnd is the last rectangle in the region,
652 * it must have the largest bottom, because of banding. Initialize left and
653 * right from pRect and pRectEnd, resp., as good things to initialize them
654 * to... */
655 pExtents->left = pRect->left;
656 pExtents->top = pRect->top;
657 pExtents->right = pRectEnd->right;
658 pExtents->bottom = pRectEnd->bottom;
659
660 while (pRect <= pRectEnd)
661 {
662 if (pRect->left < pExtents->left)
663 pExtents->left = pRect->left;
664 if (pRect->right > pExtents->right)
665 pExtents->right = pRect->right;
666 pRect++;
667 }
668
669 pReg->rdh.iType = RDH_RECTANGLES;
670}
671
672// FIXME: This function needs review and testing
673/***********************************************************************
674 * REGION_CropRegion
675 */
676INT
679 PREGION rgnDst,
680 PREGION rgnSrc,
681 const RECTL *rect)
682{
683 PRECTL lpr, rpr;
684 ULONG i, j, clipa, clipb, nRgnSize;
685 INT left = MAXLONG;
686 INT right = MINLONG;
687 INT top = MAXLONG;
689
690 if ((rect->left >= rect->right) ||
691 (rect->top >= rect->bottom) ||
692 (EXTENTCHECK(rect, &rgnSrc->rdh.rcBound) == 0))
693 {
694 goto empty;
695 }
696
697 /* Skip all rects that are completely above our intersect rect */
698 for (clipa = 0; clipa < rgnSrc->rdh.nCount; clipa++)
699 {
700 /* bottom is exclusive, so break when we go above it */
701 if (rgnSrc->Buffer[clipa].bottom > rect->top) break;
702 }
703
704 /* Bail out, if there is nothing left */
705 if (clipa == rgnSrc->rdh.nCount) goto empty;
706
707 /* Find the last rect that is still within the intersect rect (exclusive) */
708 for (clipb = clipa; clipb < rgnSrc->rdh.nCount; clipb++)
709 {
710 /* bottom is exclusive, so stop, when we start at that y pos */
711 if (rgnSrc->Buffer[clipb].top >= rect->bottom) break;
712 }
713
714 /* Bail out, if there is nothing left */
715 if (clipb == clipa) goto empty;
716
717 // clipa - index of the first rect in the first intersecting band
718 // clipb - index of the last rect in the last intersecting band plus 1
719
720 /* Check if the buffer in the dest region is large enough,
721 otherwise allocate a new one */
722 nRgnSize = (clipb - clipa) * sizeof(RECT);
723 if ((rgnDst != rgnSrc) && (rgnDst->rdh.nRgnSize < nRgnSize))
724 {
725 PRECTL temp;
727 if (temp == NULL)
728 return ERROR;
729
730 /* Free the old buffer */
731 if (rgnDst->Buffer && (rgnDst->Buffer != &rgnDst->rdh.rcBound))
733
734 rgnDst->Buffer = temp;
735 rgnDst->rdh.nCount = 0;
736 rgnDst->rdh.nRgnSize = nRgnSize;
737 rgnDst->rdh.iType = RDH_RECTANGLES;
738 }
739
740 /* Loop all rects within the intersect rect from the y perspective */
741 for (i = clipa, j = 0; i < clipb ; i++)
742 {
743 /* i - src index, j - dst index, j is always <= i for obvious reasons */
744
745 lpr = &rgnSrc->Buffer[i];
746
747 /* Make sure the source rect is not retarded */
748 ASSERT(lpr->bottom > lpr->top);
749 ASSERT(lpr->right > lpr->left);
750
751 /* We already checked above, this should hold true */
752 ASSERT(lpr->bottom > rect->top);
753 ASSERT(lpr->top < rect->bottom);
754
755 /* Check if this rect is really inside the intersect rect */
756 if ((lpr->left < rect->right) && (lpr->right > rect->left))
757 {
758 rpr = &rgnDst->Buffer[j];
759
760 /* Crop the rect with the intersect rect */
761 rpr->top = max(lpr->top, rect->top);
762 rpr->bottom = min(lpr->bottom, rect->bottom);
763 rpr->left = max(lpr->left, rect->left);
764 rpr->right = min(lpr->right, rect->right);
765
766 /* Make sure the resulting rect is not retarded */
767 ASSERT(rpr->bottom > rpr->top);
768 ASSERT(rpr->right > rpr->left);
769
770 /* Track new bounds */
771 if (rpr->left < left) left = rpr->left;
772 if (rpr->right > right) right = rpr->right;
773 if (rpr->top < top) top = rpr->top;
774 if (rpr->bottom > bottom) bottom = rpr->bottom;
775
776 /* Next target rect */
777 j++;
778 }
779 }
780
781 if (j == 0) goto empty;
782
783 /* Update the bounds rect */
784 rgnDst->rdh.rcBound.left = left;
785 rgnDst->rdh.rcBound.right = right;
786 rgnDst->rdh.rcBound.top = top;
787 rgnDst->rdh.rcBound.bottom = bottom;
788
789 /* Set new rect count */
790 rgnDst->rdh.nCount = j;
791
792 return REGION_Complexity(rgnDst);
793
794empty:
795 if (rgnDst->Buffer == NULL)
796 {
797 rgnDst->Buffer = &rgnDst->rdh.rcBound;
798 }
799
800 EMPTY_REGION(rgnDst);
801 return NULLREGION;
802}
803
804
819static
820INT
823 PREGION pReg, /* Region to coalesce */
824 INT prevStart, /* Index of start of previous band */
825 INT curStart) /* Index of start of current band */
826{
827 RECTL *pPrevRect; /* Current rect in previous band */
828 RECTL *pCurRect; /* Current rect in current band */
829 RECTL *pRegEnd; /* End of region */
830 INT curNumRects; /* Number of rectangles in current band */
831 INT prevNumRects; /* Number of rectangles in previous band */
832 INT bandtop; /* Top coordinate for current band */
833
834 pRegEnd = pReg->Buffer + pReg->rdh.nCount;
835 pPrevRect = pReg->Buffer + prevStart;
836 prevNumRects = curStart - prevStart;
837
838 /* Figure out how many rectangles are in the current band. Have to do
839 * this because multiple bands could have been added in REGION_RegionOp
840 * at the end when one region has been exhausted. */
841 pCurRect = pReg->Buffer + curStart;
842 bandtop = pCurRect->top;
843 for (curNumRects = 0;
844 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
845 curNumRects++)
846 {
847 pCurRect++;
848 }
849
850 if (pCurRect != pRegEnd)
851 {
852 /* If more than one band was added, we have to find the start
853 * of the last band added so the next coalescing job can start
854 * at the right place... (given when multiple bands are added,
855 * this may be pointless -- see above). */
856 pRegEnd--;
857 while ((pRegEnd-1)->top == pRegEnd->top)
858 {
859 pRegEnd--;
860 }
861
862 curStart = pRegEnd - pReg->Buffer;
863 pRegEnd = pReg->Buffer + pReg->rdh.nCount;
864 }
865
866 if ((curNumRects == prevNumRects) && (curNumRects != 0))
867 {
868 pCurRect -= curNumRects;
869
870 /* The bands may only be coalesced if the bottom of the previous
871 * matches the top scanline of the current. */
872 if (pPrevRect->bottom == pCurRect->top)
873 {
874 /* Make sure the bands have rects in the same places. This
875 * assumes that rects have been added in such a way that they
876 * cover the most area possible. I.e. two rects in a band must
877 * have some horizontal space between them. */
878 do
879 {
880 if ((pPrevRect->left != pCurRect->left) ||
881 (pPrevRect->right != pCurRect->right))
882 {
883 /* The bands don't line up so they can't be coalesced. */
884 return (curStart);
885 }
886
887 pPrevRect++;
888 pCurRect++;
889 prevNumRects -= 1;
890 }
891 while (prevNumRects != 0);
892
893 pReg->rdh.nCount -= curNumRects;
894 pCurRect -= curNumRects;
895 pPrevRect -= curNumRects;
896
897 /* The bands may be merged, so set the bottom of each rect
898 * in the previous band to that of the corresponding rect in
899 * the current band. */
900 do
901 {
902 pPrevRect->bottom = pCurRect->bottom;
903 pPrevRect++;
904 pCurRect++;
905 curNumRects -= 1;
906 }
907 while (curNumRects != 0);
908
909 /* If only one band was added to the region, we have to backup
910 * curStart to the start of the previous band.
911 *
912 * If more than one band was added to the region, copy the
913 * other bands down. The assumption here is that the other bands
914 * came from the same region as the current one and no further
915 * coalescing can be done on them since it's all been done
916 * already... curStart is already in the right place. */
917 if (pCurRect == pRegEnd)
918 {
919 curStart = prevStart;
920 }
921 else
922 {
923 do
924 {
925 *pPrevRect++ = *pCurRect++;
926 }
927 while (pCurRect != pRegEnd);
928 }
929 }
930 }
931
932 return (curStart);
933}
934
957static
958BOOL
961 PREGION newReg, /* Place to store result */
962 PREGION reg1, /* First region in operation */
963 PREGION reg2, /* 2nd region in operation */
964 overlapProcp overlapFunc, /* Function to call for over-lapping bands */
965 nonOverlapProcp nonOverlap1Func, /* Function to call for non-overlapping bands in region 1 */
966 nonOverlapProcp nonOverlap2Func) /* Function to call for non-overlapping bands in region 2 */
967{
968 RECTL *r1; /* Pointer into first region */
969 RECTL *r2; /* Pointer into 2d region */
970 RECTL *r1End; /* End of 1st region */
971 RECTL *r2End; /* End of 2d region */
972 INT ybot; /* Bottom of intersection */
973 INT ytop; /* Top of intersection */
974 RECTL *oldRects; /* Old rects for newReg */
975 ULONG prevBand; /* Index of start of
976 * Previous band in newReg */
977 ULONG curBand; /* Index of start of current band in newReg */
978 RECTL *r1BandEnd; /* End of current band in r1 */
979 RECTL *r2BandEnd; /* End of current band in r2 */
980 ULONG top; /* Top of non-overlapping band */
981 ULONG bot; /* Bottom of non-overlapping band */
982
983 /* Initialization:
984 * set r1, r2, r1End and r2End appropriately, preserve the important
985 * parts of the destination region until the end in case it's one of
986 * the two source regions, then mark the "new" region empty, allocating
987 * another array of rectangles for it to use. */
988 r1 = reg1->Buffer;
989 r2 = reg2->Buffer;
990 r1End = r1 + reg1->rdh.nCount;
991 r2End = r2 + reg2->rdh.nCount;
992
993 /* newReg may be one of the src regions so we can't empty it. We keep a
994 * note of its rects pointer (so that we can free them later), preserve its
995 * extents and simply set numRects to zero. */
996 oldRects = newReg->Buffer;
997 newReg->rdh.nCount = 0;
998
999 /* Allocate a reasonable number of rectangles for the new region. The idea
1000 * is to allocate enough so the individual functions don't need to
1001 * reallocate and copy the array, which is time consuming, yet we don't
1002 * have to worry about using too much memory. I hope to be able to
1003 * nuke the Xrealloc() at the end of this function eventually. */
1004 newReg->rdh.nRgnSize = max(reg1->rdh.nCount + 1, reg2->rdh.nCount) * 2 * sizeof(RECT);
1005
1007 newReg->rdh.nRgnSize,
1008 TAG_REGION);
1009 if (newReg->Buffer == NULL)
1010 {
1011 newReg->rdh.nRgnSize = 0;
1012 return FALSE;
1013 }
1014
1015 /* Initialize ybot and ytop.
1016 * In the upcoming loop, ybot and ytop serve different functions depending
1017 * on whether the band being handled is an overlapping or non-overlapping
1018 * band.
1019 * In the case of a non-overlapping band (only one of the regions
1020 * has points in the band), ybot is the bottom of the most recent
1021 * intersection and thus clips the top of the rectangles in that band.
1022 * ytop is the top of the next intersection between the two regions and
1023 * serves to clip the bottom of the rectangles in the current band.
1024 * For an overlapping band (where the two regions intersect), ytop clips
1025 * the top of the rectangles of both regions and ybot clips the bottoms. */
1026 if (reg1->rdh.rcBound.top < reg2->rdh.rcBound.top)
1027 ybot = reg1->rdh.rcBound.top;
1028 else
1029 ybot = reg2->rdh.rcBound.top;
1030
1031 /* prevBand serves to mark the start of the previous band so rectangles
1032 * can be coalesced into larger rectangles. qv. miCoalesce, above.
1033 * In the beginning, there is no previous band, so prevBand == curBand
1034 * (curBand is set later on, of course, but the first band will always
1035 * start at index 0). prevBand and curBand must be indices because of
1036 * the possible expansion, and resultant moving, of the new region's
1037 * array of rectangles. */
1038 prevBand = 0;
1039 do
1040 {
1041 curBand = newReg->rdh.nCount;
1042
1043 /* This algorithm proceeds one source-band (as opposed to a
1044 * destination band, which is determined by where the two regions
1045 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
1046 * rectangle after the last one in the current band for their
1047 * respective regions. */
1048 r1BandEnd = r1;
1049 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
1050 {
1051 r1BandEnd++;
1052 }
1053
1054 r2BandEnd = r2;
1055 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
1056 {
1057 r2BandEnd++;
1058 }
1059
1060 /* First handle the band that doesn't intersect, if any.
1061 *
1062 * Note that attention is restricted to one band in the
1063 * non-intersecting region at once, so if a region has n
1064 * bands between the current position and the next place it overlaps
1065 * the other, this entire loop will be passed through n times. */
1066 if (r1->top < r2->top)
1067 {
1068 top = max(r1->top,ybot);
1069 bot = min(r1->bottom,r2->top);
1070
1071 if ((top != bot) && (nonOverlap1Func != NULL))
1072 {
1073 if (!(*nonOverlap1Func)(newReg, r1, r1BandEnd, top, bot)) return FALSE;
1074 }
1075
1076 ytop = r2->top;
1077 }
1078 else if (r2->top < r1->top)
1079 {
1080 top = max(r2->top,ybot);
1081 bot = min(r2->bottom,r1->top);
1082
1083 if ((top != bot) && (nonOverlap2Func != NULL))
1084 {
1085 if (!(*nonOverlap2Func)(newReg, r2, r2BandEnd, top, bot) ) return FALSE;
1086 }
1087
1088 ytop = r1->top;
1089 }
1090 else
1091 {
1092 ytop = r1->top;
1093 }
1094
1095 /* If any rectangles got added to the region, try and coalesce them
1096 * with rectangles from the previous band. Note we could just do
1097 * this test in miCoalesce, but some machines incur a not
1098 * inconsiderable cost for function calls, so... */
1099 if (newReg->rdh.nCount != curBand)
1100 {
1101 prevBand = REGION_Coalesce(newReg, prevBand, curBand);
1102 }
1103
1104 /* Now see if we've hit an intersecting band. The two bands only
1105 * intersect if ybot > ytop */
1106 ybot = min(r1->bottom, r2->bottom);
1107 curBand = newReg->rdh.nCount;
1108 if (ybot > ytop)
1109 {
1110 if (!(*overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot)) return FALSE;
1111 }
1112
1113 if (newReg->rdh.nCount != curBand)
1114 {
1115 prevBand = REGION_Coalesce(newReg, prevBand, curBand);
1116 }
1117
1118 /* If we've finished with a band (bottom == ybot) we skip forward
1119 * in the region to the next band. */
1120 if (r1->bottom == ybot)
1121 {
1122 r1 = r1BandEnd;
1123 }
1124 if (r2->bottom == ybot)
1125 {
1126 r2 = r2BandEnd;
1127 }
1128 }
1129 while ((r1 != r1End) && (r2 != r2End));
1130
1131 /* Deal with whichever region still has rectangles left. */
1132 curBand = newReg->rdh.nCount;
1133 if (r1 != r1End)
1134 {
1135 if (nonOverlap1Func != NULL)
1136 {
1137 do
1138 {
1139 r1BandEnd = r1;
1140 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
1141 {
1142 r1BandEnd++;
1143 }
1144
1145 if (!(*nonOverlap1Func)(newReg,
1146 r1,
1147 r1BandEnd,
1148 max(r1->top,ybot),
1149 r1->bottom))
1150 return FALSE;
1151 r1 = r1BandEnd;
1152 }
1153 while (r1 != r1End);
1154 }
1155 }
1156 else if ((r2 != r2End) && (nonOverlap2Func != NULL))
1157 {
1158 do
1159 {
1160 r2BandEnd = r2;
1161 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
1162 {
1163 r2BandEnd++;
1164 }
1165
1166 if (!(*nonOverlap2Func)(newReg,
1167 r2,
1168 r2BandEnd,
1169 max(r2->top,ybot),
1170 r2->bottom))
1171 return FALSE;
1172 r2 = r2BandEnd;
1173 }
1174 while (r2 != r2End);
1175 }
1176
1177 if (newReg->rdh.nCount != curBand)
1178 {
1179 (VOID)REGION_Coalesce(newReg, prevBand, curBand);
1180 }
1181
1182 /* A bit of cleanup. To keep regions from growing without bound,
1183 * we shrink the array of rectangles to match the new number of
1184 * rectangles in the region. This never goes to 0, however...
1185 *
1186 * Only do this stuff if the number of rectangles allocated is more than
1187 * twice the number of rectangles in the region (a simple optimization...). */
1188 if ((newReg->rdh.nRgnSize > (2 * newReg->rdh.nCount * sizeof(RECT))) &&
1189 (newReg->rdh.nCount > 2))
1190 {
1191 if (REGION_NOT_EMPTY(newReg))
1192 {
1193 RECTL *prev_rects = newReg->Buffer;
1195 newReg->rdh.nCount * sizeof(RECT),
1196 TAG_REGION);
1197
1198 if (newReg->Buffer == NULL)
1199 {
1200 newReg->Buffer = prev_rects;
1201 }
1202 else
1203 {
1204 newReg->rdh.nRgnSize = newReg->rdh.nCount*sizeof(RECT);
1205 COPY_RECTS(newReg->Buffer, prev_rects, newReg->rdh.nCount);
1206 if (prev_rects != &newReg->rdh.rcBound)
1207 ExFreePoolWithTag(prev_rects, TAG_REGION);
1208 }
1209 }
1210 else
1211 {
1212 /* No point in doing the extra work involved in an Xrealloc if
1213 * the region is empty */
1214 newReg->rdh.nRgnSize = sizeof(RECT);
1215 if (newReg->Buffer != &newReg->rdh.rcBound)
1217
1219 sizeof(RECT),
1220 TAG_REGION);
1221 ASSERT(newReg->Buffer);
1222 }
1223 }
1224
1225 newReg->rdh.iType = RDH_RECTANGLES;
1226
1227 if (oldRects != &newReg->rdh.rcBound)
1228 ExFreePoolWithTag(oldRects, TAG_REGION);
1229 return TRUE;
1230}
1231
1232/***********************************************************************
1233 * Region Intersection
1234 ***********************************************************************/
1235
1236
1247static
1248BOOL
1251 PREGION pReg,
1252 PRECTL r1,
1253 PRECTL r1End,
1254 PRECTL r2,
1255 PRECTL r2End,
1256 INT top,
1257 INT bottom)
1258{
1259 INT left, right;
1260
1261 while ((r1 != r1End) && (r2 != r2End))
1262 {
1263 left = max(r1->left, r2->left);
1264 right = min(r1->right, r2->right);
1265
1266 /* If there's any overlap between the two rectangles, add that
1267 * overlap to the new region.
1268 * There's no need to check for subsumption because the only way
1269 * such a need could arise is if some region has two rectangles
1270 * right next to each other. Since that should never happen... */
1271 if (left < right)
1272 {
1273 if (!REGION_bAddRect(pReg, left, top, right, bottom))
1274 {
1275 return FALSE;
1276 }
1277 }
1278
1279 /* Need to advance the pointers. Shift the one that extends
1280 * to the right the least, since the other still has a chance to
1281 * overlap with that region's next rectangle, if you see what I mean. */
1282 if (r1->right < r2->right)
1283 {
1284 r1++;
1285 }
1286 else if (r2->right < r1->right)
1287 {
1288 r2++;
1289 }
1290 else
1291 {
1292 r1++;
1293 r2++;
1294 }
1295 }
1296
1297 return TRUE;
1298}
1299
1300/***********************************************************************
1301 * REGION_IntersectRegion
1302 */
1303static
1304BOOL
1307 PREGION newReg,
1308 PREGION reg1,
1309 PREGION reg2)
1310{
1311 /* Check for trivial reject */
1312 if ((reg1->rdh.nCount == 0) ||
1313 (reg2->rdh.nCount == 0) ||
1314 (EXTENTCHECK(&reg1->rdh.rcBound, &reg2->rdh.rcBound) == 0))
1315 {
1316 newReg->rdh.nCount = 0;
1317 }
1318 else
1319 {
1320 if (!REGION_RegionOp(newReg,
1321 reg1,
1322 reg2,
1324 NULL,
1325 NULL))
1326 return FALSE;
1327 }
1328
1329 /* Can't alter newReg's extents before we call miRegionOp because
1330 * it might be one of the source regions and miRegionOp depends
1331 * on the extents of those regions being the same. Besides, this
1332 * way there's no checking against rectangles that will be nuked
1333 * due to coalescing, so we have to examine fewer rectangles. */
1334 REGION_SetExtents(newReg);
1335 return TRUE;
1336}
1337
1338/***********************************************************************
1339 * Region Union
1340 ***********************************************************************/
1341
1355static
1356BOOL
1359 PREGION pReg,
1360 PRECTL r,
1361 PRECTL rEnd,
1362 INT top,
1363 INT bottom)
1364{
1365 if (r != rEnd)
1366 {
1367 if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (rEnd - r)))
1368 {
1369 return FALSE;
1370 }
1371
1372 do
1373 {
1374 REGION_vAddRect(pReg, r->left, top, r->right, bottom);
1375 r++;
1376 }
1377 while (r != rEnd);
1378 }
1379
1380 return TRUE;
1381}
1383static __inline
1384BOOL
1386 _Inout_ PREGION prgn,
1387 _In_ LONG left,
1388 _In_ LONG top,
1389 _In_ LONG right,
1391{
1392 if ((prgn->rdh.nCount != 0) &&
1393 (prgn->Buffer[prgn->rdh.nCount - 1].top == top) &&
1394 (prgn->Buffer[prgn->rdh.nCount - 1].bottom == bottom) &&
1395 (prgn->Buffer[prgn->rdh.nCount - 1].right >= left))
1396 {
1397 if (prgn->Buffer[prgn->rdh.nCount - 1].right < right)
1398 {
1399 prgn->Buffer[prgn->rdh.nCount - 1].right = right;
1400 }
1401 }
1402 else
1403 {
1404 if (!REGION_bAddRect(prgn, left, top, right, bottom))
1405 {
1406 return FALSE;
1407 }
1408 }
1409
1410 return TRUE;
1411}
1412
1425static
1426BOOL
1429 PREGION pReg,
1430 PRECTL r1,
1431 PRECTL r1End,
1432 PRECTL r2,
1433 PRECTL r2End,
1434 INT top,
1435 INT bottom)
1436{
1437 while ((r1 != r1End) && (r2 != r2End))
1438 {
1439 if (r1->left < r2->left)
1440 {
1441 if (!REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom)) return FALSE;
1442 r1++;
1443 }
1444 else
1445 {
1446 if (!REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom)) return FALSE;
1447 r2++;
1448 }
1449 }
1450
1451 if (r1 != r1End)
1452 {
1453 do
1454 {
1455 if (!REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom)) return FALSE;
1456 r1++;
1457 }
1458 while (r1 != r1End);
1459 }
1460 else
1461 {
1462 while (r2 != r2End)
1463 {
1464 if (!REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom)) return FALSE;
1465 r2++;
1466 }
1467 }
1468
1469 return TRUE;
1470}
1471
1472/***********************************************************************
1473 * REGION_UnionRegion
1474 */
1475static
1476BOOL
1479 PREGION newReg,
1480 PREGION reg1,
1481 PREGION reg2)
1482{
1483 BOOL ret = TRUE;
1484
1485 /* Checks all the simple cases
1486 * Region 1 and 2 are the same or region 1 is empty */
1487 if ((reg1 == reg2) || (reg1->rdh.nCount == 0) ||
1488 (reg1->rdh.rcBound.right <= reg1->rdh.rcBound.left) ||
1489 (reg1->rdh.rcBound.bottom <= reg1->rdh.rcBound.top))
1490 {
1491 if (newReg != reg2)
1492 {
1493 ret = REGION_CopyRegion(newReg, reg2);
1494 }
1495
1496 return ret;
1497 }
1498
1499 /* If nothing to union (region 2 empty) */
1500 if ((reg2->rdh.nCount == 0) ||
1501 (reg2->rdh.rcBound.right <= reg2->rdh.rcBound.left) ||
1502 (reg2->rdh.rcBound.bottom <= reg2->rdh.rcBound.top))
1503 {
1504 if (newReg != reg1)
1505 {
1506 ret = REGION_CopyRegion(newReg, reg1);
1507 }
1508
1509 return ret;
1510 }
1511
1512 /* Region 1 completely subsumes region 2 */
1513 if ((reg1->rdh.nCount == 1) &&
1514 (reg1->rdh.rcBound.left <= reg2->rdh.rcBound.left) &&
1515 (reg1->rdh.rcBound.top <= reg2->rdh.rcBound.top) &&
1516 (reg2->rdh.rcBound.right <= reg1->rdh.rcBound.right) &&
1517 (reg2->rdh.rcBound.bottom <= reg1->rdh.rcBound.bottom))
1518 {
1519 if (newReg != reg1)
1520 {
1521 ret = REGION_CopyRegion(newReg, reg1);
1522 }
1523
1524 return ret;
1525 }
1526
1527 /* Region 2 completely subsumes region 1 */
1528 if ((reg2->rdh.nCount == 1) &&
1529 (reg2->rdh.rcBound.left <= reg1->rdh.rcBound.left) &&
1530 (reg2->rdh.rcBound.top <= reg1->rdh.rcBound.top) &&
1531 (reg1->rdh.rcBound.right <= reg2->rdh.rcBound.right) &&
1532 (reg1->rdh.rcBound.bottom <= reg2->rdh.rcBound.bottom))
1533 {
1534 if (newReg != reg2)
1535 {
1536 ret = REGION_CopyRegion(newReg, reg2);
1537 }
1538
1539 return ret;
1540 }
1541
1542 if ((ret = REGION_RegionOp(newReg,
1543 reg1,
1544 reg2,
1548 {
1549 newReg->rdh.rcBound.left = min(reg1->rdh.rcBound.left, reg2->rdh.rcBound.left);
1550 newReg->rdh.rcBound.top = min(reg1->rdh.rcBound.top, reg2->rdh.rcBound.top);
1551 newReg->rdh.rcBound.right = max(reg1->rdh.rcBound.right, reg2->rdh.rcBound.right);
1552 newReg->rdh.rcBound.bottom = max(reg1->rdh.rcBound.bottom, reg2->rdh.rcBound.bottom);
1553 }
1554 return ret;
1555}
1556
1557/***********************************************************************
1558 * Region Subtraction
1559 ***********************************************************************/
1560
1572static
1573BOOL
1576 PREGION pReg,
1577 PRECTL r,
1578 PRECTL rEnd,
1579 INT top,
1580 INT bottom)
1581{
1582 if (r != rEnd)
1583 {
1584 if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (rEnd - r)))
1585 {
1586 return FALSE;
1587 }
1588
1589 do
1590 {
1591 REGION_vAddRect(pReg, r->left, top, r->right, bottom);
1592 r++;
1593 }
1594 while (r != rEnd);
1595 }
1596
1597 return TRUE;
1598}
1599
1600
1612static
1613BOOL
1616 PREGION pReg,
1617 PRECTL r1,
1618 PRECTL r1End,
1619 PRECTL r2,
1620 PRECTL r2End,
1621 INT top,
1622 INT bottom)
1623{
1624 INT left;
1625
1626 left = r1->left;
1627
1628 while ((r1 != r1End) && (r2 != r2End))
1629 {
1630 if (r2->right <= left)
1631 {
1632 /* Subtrahend missed the boat: go to next subtrahend. */
1633 r2++;
1634 }
1635 else if (r2->left <= left)
1636 {
1637 /* Subtrahend preceeds minuend: nuke left edge of minuend. */
1638 left = r2->right;
1639 if (left >= r1->right)
1640 {
1641 /* Minuend completely covered: advance to next minuend and
1642 * reset left fence to edge of new minuend. */
1643 r1++;
1644 if (r1 != r1End)
1645 left = r1->left;
1646 }
1647 else
1648 {
1649 /* Subtrahend now used up since it doesn't extend beyond
1650 * minuend */
1651 r2++;
1652 }
1653 }
1654 else if (r2->left < r1->right)
1655 {
1656 /* Left part of subtrahend covers part of minuend: add uncovered
1657 * part of minuend to region and skip to next subtrahend. */
1658 if (!REGION_bAddRect(pReg, left, top, r2->left, bottom))
1659 {
1660 return FALSE;
1661 }
1662
1663 left = r2->right;
1664 if (left >= r1->right)
1665 {
1666 /* Minuend used up: advance to new... */
1667 r1++;
1668 if (r1 != r1End)
1669 left = r1->left;
1670 }
1671 else
1672 {
1673 /* Subtrahend used up */
1674 r2++;
1675 }
1676 }
1677 else
1678 {
1679 /* Minuend used up: add any remaining piece before advancing. */
1680 if (r1->right > left)
1681 {
1682 if (!REGION_bAddRect(pReg, left, top, r1->right, bottom))
1683 {
1684 return FALSE;
1685 }
1686 }
1687
1688 r1++;
1689 if (r1 != r1End)
1690 left = r1->left;
1691 }
1692 }
1693
1694 /* Make sure the buffer is large enough for all remaining operations */
1695 if (r1 != r1End)
1696 {
1697 if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (r1End - r1)))
1698 {
1699 return FALSE;
1700 }
1701
1702 /* Add remaining minuend rectangles to region. */
1703 do
1704 {
1705 REGION_vAddRect(pReg, left, top, r1->right, bottom);
1706 r1++;
1707 if (r1 != r1End)
1708 {
1709 left = r1->left;
1710 }
1711 }
1712 while (r1 != r1End);
1713 }
1714
1715 return TRUE;
1716}
1717
1729static
1730BOOL
1733 PREGION regD,
1734 PREGION regM,
1735 PREGION regS)
1736{
1737 /* Check for trivial reject */
1738 if ((regM->rdh.nCount == 0) ||
1739 (regS->rdh.nCount == 0) ||
1740 (EXTENTCHECK(&regM->rdh.rcBound, &regS->rdh.rcBound) == 0))
1741 {
1742 return REGION_CopyRegion(regD, regM);
1743 }
1744
1745 if (!REGION_RegionOp(regD,
1746 regM,
1747 regS,
1750 NULL))
1751 return FALSE;
1752
1753 /* Can't alter newReg's extents before we call miRegionOp because
1754 * it might be one of the source regions and miRegionOp depends
1755 * on the extents of those regions being the unaltered. Besides, this
1756 * way there's no checking against rectangles that will be nuked
1757 * due to coalescing, so we have to examine fewer rectangles. */
1758 REGION_SetExtents(regD);
1759 return TRUE;
1760}
1761
1762/***********************************************************************
1763 * REGION_XorRegion
1764 */
1765static
1766BOOL
1769 PREGION dr,
1770 PREGION sra,
1771 PREGION srb)
1772{
1773 HRGN htra, htrb;
1774 PREGION tra, trb;
1775 BOOL ret;
1776
1777 // FIXME: Don't use a handle
1778 tra = REGION_AllocRgnWithHandle(sra->rdh.nCount + 1);
1779 if (tra == NULL)
1780 {
1781 return FALSE;
1782 }
1783 htra = tra->BaseObject.hHmgr;
1784
1785 // FIXME: Don't use a handle
1786 trb = REGION_AllocRgnWithHandle(srb->rdh.nCount + 1);
1787 if (trb == NULL)
1788 {
1789 REGION_UnlockRgn(tra);
1790 GreDeleteObject(htra);
1791 return FALSE;
1792 }
1793 htrb = trb->BaseObject.hHmgr;
1794
1795 ret = REGION_SubtractRegion(tra, sra, srb) &&
1796 REGION_SubtractRegion(trb, srb, sra) &&
1797 REGION_UnionRegion(dr, tra, trb);
1798 REGION_UnlockRgn(tra);
1799 REGION_UnlockRgn(trb);
1800
1801 GreDeleteObject(htra);
1802 GreDeleteObject(htrb);
1803 return ret;
1804}
1805
1806
1810BOOL
1813 PREGION rgn,
1814 const RECTL *rect)
1815{
1816 REGION region;
1817
1818 region.Buffer = &region.rdh.rcBound;
1819 region.rdh.nCount = 1;
1820 region.rdh.nRgnSize = sizeof(RECT);
1821 region.rdh.rcBound = *rect;
1822 return REGION_UnionRegion(rgn, rgn, &region);
1823}
1825INT
1828 PREGION prgnDest,
1829 PREGION prgnSrc,
1830 const RECTL *prcl)
1831{
1832 REGION rgnLocal;
1833
1834 rgnLocal.Buffer = &rgnLocal.rdh.rcBound;
1835 rgnLocal.rdh.nCount = 1;
1836 rgnLocal.rdh.nRgnSize = sizeof(RECT);
1837 rgnLocal.rdh.rcBound = *prcl;
1838 REGION_SubtractRegion(prgnDest, prgnSrc, &rgnLocal);
1839 return REGION_Complexity(prgnDest);
1840}
1842BOOL
1845 PREGION dst,
1846 PREGION src)
1847{
1848 if ( !dst || !src ) return FALSE;
1849 return REGION_CopyRegion( dst, src);
1850}
1852BOOL
1855 PREGION newReg,
1856 PREGION reg1,
1857 PREGION reg2)
1858{
1859 if ( !newReg || !reg1 || !reg2 ) return FALSE;
1860 return REGION_IntersectRegion( newReg, reg1, reg2);
1861}
1863static
1864BOOL
1866 _Inout_ PREGION prgn,
1868 _In_ INT cx,
1869 _In_ INT cy)
1870{
1871 RECTL arcl[4];
1872 UINT i;
1873
1874 NT_ASSERT((cx >= 0) && (cy >= 0));
1875 NT_ASSERT((prclSrc->bottom > prclSrc->top) &&
1876 (prclSrc->right > prclSrc->left));
1877
1878 /* Start with an empty region */
1879 EMPTY_REGION(prgn);
1880
1881 /* Check for the case where the frame covers the whole rect */
1882 if (((prclSrc->bottom - prclSrc->top) <= cy * 2) ||
1883 ((prclSrc->right - prclSrc->left) <= cx * 2))
1884 {
1885 prgn->rdh.rcBound = *prclSrc;
1886 prgn->Buffer[0] = *prclSrc;
1887 prgn->rdh.nCount = 1;
1888 return TRUE;
1889 }
1890
1891 i = 0;
1892
1893 if (cy != 0)
1894 {
1895 /* Top rectangle */
1896 arcl[i].left = prclSrc->left;
1897 arcl[i].top = prclSrc->top;
1898 arcl[i].right = prclSrc->right;
1899 arcl[i].bottom = prclSrc->top + cy;
1900 i++;
1901 }
1902
1903 if (cx != 0)
1904 {
1905 /* Left rectangle */
1906 arcl[i].left = prclSrc->left;
1907 arcl[i].top = prclSrc->top + cy;
1908 arcl[i].right = prclSrc->left + cx;
1909 arcl[i].bottom = prclSrc->bottom - cy;
1910 i++;
1911
1912 /* Right rectangle */
1913 arcl[i].left = prclSrc->right - cx;
1914 arcl[i].top = prclSrc->top + cy;
1915 arcl[i].right = prclSrc->right;
1916 arcl[i].bottom = prclSrc->bottom - cy;
1917 i++;
1918 }
1919
1920 if (cy != 0)
1921 {
1922 /* Bottom rectangle */
1923 arcl[i].left = prclSrc->left;
1924 arcl[i].top = prclSrc->bottom - cy;
1925 arcl[i].right = prclSrc->right;
1926 arcl[i].bottom = prclSrc->bottom;
1927 i++;
1928 }
1929
1930 if (i != 0)
1931 {
1932 /* The frame results in a complex region. rcBounds remains
1933 the same, though. */
1934 prgn->rdh.nCount = i;
1935 NT_ASSERT(prgn->rdh.nCount > 1);
1936 prgn->rdh.nRgnSize = prgn->rdh.nCount * sizeof(RECT);
1937 NT_ASSERT(prgn->Buffer == &prgn->rdh.rcBound);
1938 prgn->Buffer = ExAllocatePoolWithTag(PagedPool,
1939 prgn->rdh.nRgnSize,
1940 TAG_REGION);
1941 if (prgn->Buffer == NULL)
1942 {
1943 prgn->rdh.nRgnSize = 0;
1944 return FALSE;
1945 }
1946
1948 COPY_RECTS(prgn->Buffer, arcl, prgn->rdh.nCount);
1949 }
1950
1951 return TRUE;
1952}
1954static
1955BOOL
1957 _Inout_ PREGION prgnDest,
1958 _Inout_ PREGION prgnSrc,
1959 _In_ INT cx,
1960 _In_ INT cy)
1961{
1962 /* Handle negative cx / cy */
1963 cx = abs(cx);
1964 cy = abs(cy);
1965
1966 /* Check border size (the cast is necessary to catch cx/cy == INT_MIN!) */
1967 if (((UINT)cx > MAX_COORD) || ((UINT)cy > MAX_COORD))
1968 {
1969 return FALSE;
1970 }
1971
1972 /* Fail on empty source region */
1973 if (!REGION_NOT_EMPTY(prgnSrc))
1974 {
1975 return FALSE;
1976 }
1977
1978 /* Handle trivial case */
1979 if ((cx == 0) && (cy == 0))
1980 {
1981 EMPTY_REGION(prgnDest);
1982 return TRUE;
1983 }
1984
1985 /* Handle simple source region */
1986 if (REGION_Complexity(prgnSrc) == SIMPLEREGION)
1987 {
1988 return REGION_bMakeSimpleFrameRgn(prgnDest, &prgnSrc->rdh.rcBound, cx, cy);
1989 }
1990
1991 /* Check if we can move the region to create the frame region */
1992 if ((prgnSrc->rdh.rcBound.left < (MIN_COORD + cx)) ||
1993 (prgnSrc->rdh.rcBound.top < (MIN_COORD + cy)) ||
1994 (prgnSrc->rdh.rcBound.right > (MAX_COORD - cx)) ||
1995 (prgnSrc->rdh.rcBound.bottom > (MAX_COORD - cy)))
1996 {
1997 return FALSE;
1998 }
1999
2000 /* Copy the source region */
2001 if (!REGION_CopyRegion(prgnDest, prgnSrc))
2002 {
2003 return FALSE;
2004 }
2005
2006 /* Move the source region to the bottom-right */
2007 NT_VERIFY(REGION_bOffsetRgn(prgnSrc, cx, cy));
2008
2009 /* Intersect with the source region (this crops the top-left frame) */
2010 REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
2011
2012 /* Move the source region to the bottom-left */
2013 NT_VERIFY(REGION_bOffsetRgn(prgnSrc, -2 * cx, 0));
2014
2015 /* Intersect with the source region (this crops the top-right frame) */
2016 REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
2017
2018 /* Move the source region to the top-left */
2019 NT_VERIFY(REGION_bOffsetRgn(prgnSrc, 0, -2 * cy));
2020
2021 /* Intersect with the source region (this crops the bottom-right frame) */
2022 REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
2023
2024 /* Move the source region to the top-right */
2025 NT_VERIFY(REGION_bOffsetRgn(prgnSrc, 2 * cx, 0));
2026
2027 /* Intersect with the source region (this crops the bottom-left frame) */
2028 REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
2029
2030 /* Move the source region back to the original position */
2031 NT_VERIFY(REGION_bOffsetRgn(prgnSrc, -cx, cy));
2032
2033 /* Finally subtract the cropped region from the source */
2034 REGION_SubtractRegion(prgnDest, prgnSrc, prgnDest);
2035
2036 return TRUE;
2037}
2039HRGN
2042 HRGN hrgn,
2043 INT cx,
2044 INT cy)
2045{
2046 PREGION prgnFrame, prgnSrc;
2047 HRGN hrgnFrame;
2048
2049 /* Allocate a new region */
2050 prgnFrame = REGION_AllocUserRgnWithHandle(1);
2051 if (prgnFrame == NULL)
2052 {
2054 return NULL;
2055 }
2056
2057 /* Lock the source region */
2058 prgnSrc = REGION_LockRgn(hrgn);
2059 if (prgnSrc == NULL)
2060 {
2061 REGION_Delete(prgnFrame);
2062 return FALSE;
2063 }
2064
2065 if (REGION_bMakeFrameRegion(prgnFrame, prgnSrc, cx, cy))
2066 {
2067 hrgnFrame = prgnFrame->BaseObject.hHmgr;
2068 REGION_UnlockRgn(prgnFrame);
2069 }
2070 else
2071 {
2072 REGION_Delete(prgnFrame);
2073 hrgnFrame = NULL;
2074 }
2075
2076 REGION_UnlockRgn(prgnSrc);
2077 return hrgnFrame;
2078}
2080BOOL
2083 _Inout_ PREGION prgn,
2084 _In_ PMATRIX pmx)
2085{
2086 XFORMOBJ xo;
2087 ULONG i, cjSize;
2088 PPOINT ppt;
2089 PULONG pcPoints;
2090 RECT rect;
2091 BOOL bResult;
2092
2093 /* Check for zero rectangles and return TRUE for translation only matrices */
2094 if (prgn->rdh.nCount < 1)
2095 return (pmx->flAccel & XFORM_UNITY) != 0;
2096
2097 /* Check if this is a scaling only matrix (off-diagonal elements are 0 */
2098 if (pmx->flAccel & XFORM_SCALE)
2099 {
2100 /* Check if this is a translation only matrix */
2101 if (pmx->flAccel & XFORM_UNITY)
2102 {
2103 /* Just offset the region */
2104 return REGION_bOffsetRgn(prgn, (pmx->fxDx + 8) / 16, (pmx->fxDy + 8) / 16);
2105 }
2106 else
2107 {
2108 /* Initialize the xform object */
2109 XFORMOBJ_vInit(&xo, pmx);
2110
2111 /* Scaling can move the rects out of the coordinate space, so
2112 * we first need to check whether we can apply the transformation
2113 * on the bounds rect without modifying the region */
2114 if (!XFORMOBJ_bApplyXform(&xo, XF_LTOL, 2, &prgn->rdh.rcBound, &rect))
2115 {
2116 return FALSE;
2117 }
2118
2119 /* Apply the xform to the rects in the region */
2120 if (!XFORMOBJ_bApplyXform(&xo,
2121 XF_LTOL,
2122 prgn->rdh.nCount * 2,
2123 prgn->Buffer,
2124 prgn->Buffer))
2125 {
2126 /* This can not happen, since we already checked the bounds! */
2128 }
2129
2130 /* Reset bounds */
2131 RECTL_vSetEmptyRect(&prgn->rdh.rcBound);
2132
2133 /* Loop all rects in the region */
2134 for (i = 0; i < prgn->rdh.nCount; i++)
2135 {
2136 /* Make sure the rect is well-ordered after the xform */
2137 RECTL_vMakeWellOrdered(&prgn->Buffer[i]);
2138
2139 /* Update bounds */
2140 if (!RECTL_bUnionRect(&prgn->rdh.rcBound,
2141 &prgn->rdh.rcBound,
2142 &prgn->Buffer[i]))
2143 {
2144 DPRINT1("NULL Set in Union Rects\n");
2145 return FALSE;
2146 }
2147 }
2148
2149 /* Loop all rects in the region */
2150 for (i = 0; i < prgn->rdh.nCount - 1; i++)
2151 {
2152 NT_ASSERT(prgn->Buffer[i].top <= prgn->Buffer[i].bottom);
2153 NT_ASSERT(prgn->Buffer[i + 1].top >= prgn->Buffer[i].top);
2154 }
2155
2156 return TRUE;
2157 }
2158 }
2159 else
2160 {
2161 /* Allocate a buffer for the polygons */
2162 cjSize = prgn->rdh.nCount * (4 * sizeof(POINT) + sizeof(ULONG));
2164 if (ppt == NULL)
2165 {
2166 return FALSE;
2167 }
2168
2169 /* Fill the buffer with the rects */
2170 pcPoints = (PULONG)&ppt[4 * prgn->rdh.nCount];
2171 for (i = 0; i < prgn->rdh.nCount; i++)
2172 {
2173 /* Make sure the rect is within the legal range */
2174 pcPoints[i] = 4;
2175 ppt[4 * i + 0].x = prgn->Buffer[i].left;
2176 ppt[4 * i + 0].y = prgn->Buffer[i].top;
2177 ppt[4 * i + 1].x = prgn->Buffer[i].right;
2178 ppt[4 * i + 1].y = prgn->Buffer[i].top;
2179 ppt[4 * i + 2].x = prgn->Buffer[i].right;
2180 ppt[4 * i + 2].y = prgn->Buffer[i].bottom;
2181 ppt[4 * i + 3].x = prgn->Buffer[i].left;
2182 ppt[4 * i + 3].y = prgn->Buffer[i].bottom;
2183 }
2184
2185 /* Initialize the xform object */
2186 XFORMOBJ_vInit(&xo, pmx);
2187
2188 /* Apply the xform to the rects in the buffer */
2189 if (!XFORMOBJ_bApplyXform(&xo,
2190 XF_LTOL,
2191 prgn->rdh.nCount * 2,
2192 ppt,
2193 ppt))
2194 {
2195 /* This means, there were coordinates that would go outside of
2196 the coordinate space after the transformation */
2198 return FALSE;
2199 }
2200
2201 /* Now use the polygons to create a polygon region */
2202 bResult = REGION_SetPolyPolygonRgn(prgn,
2203 ppt,
2204 pcPoints,
2205 prgn->rdh.nCount,
2206 WINDING);
2207
2208 /* Free the polygon buffer */
2210
2211 return bResult;
2212 }
2213
2214}
2215
2217PREGION
2220 INT nReg)
2221{
2222 //HRGN hReg;
2223 PREGION pReg;
2224
2226 sizeof(REGION),
2228 if (pReg == NULL)
2229 {
2230 DPRINT1("Could not allocate a palette.\n");
2231 return NULL;
2232 }
2233
2234 //hReg = pReg->BaseObject.hHmgr;
2235
2236 if ((nReg == 0) || (nReg == 1))
2237 {
2238 /* Testing shows that > 95% of all regions have only 1 rect.
2239 Including that here saves us from having to do another allocation */
2240 pReg->Buffer = &pReg->rdh.rcBound;
2241 }
2242 else
2243 {
2245 nReg * sizeof(RECT),
2246 TAG_REGION);
2247 if (pReg->Buffer == NULL)
2248 {
2249 DPRINT1("Could not allocate region buffer\n");
2251 return NULL;
2252 }
2253 }
2254
2255 EMPTY_REGION(pReg);
2256 pReg->rdh.dwSize = sizeof(RGNDATAHEADER);
2257 pReg->rdh.nCount = nReg;
2258 pReg->rdh.nRgnSize = nReg * sizeof(RECT);
2259 pReg->prgnattr = &pReg->rgnattr;
2260
2261 /* Initialize the region attribute */
2262 pReg->rgnattr.AttrFlags = 0;
2264 pReg->rgnattr.Rect = pReg->rdh.rcBound;
2265
2266 /* Finally insert the region into the handle table */
2268 {
2269 DPRINT1("Could not insert palette into handle table.\n");
2271 return NULL;
2272 }
2273
2274 return pReg;
2275}
2277BOOL
2278NTAPI
2280 PREGION prgn)
2281{
2282 PPROCESSINFO ppi;
2283 PRGN_ATTR prgnattr;
2284
2285 NT_ASSERT(prgn->prgnattr == &prgn->rgnattr);
2286
2288 ASSERT(ppi);
2289
2290 prgnattr = GdiPoolAllocate(ppi->pPoolRgnAttr);
2291 if (prgnattr == NULL)
2292 {
2293 DPRINT1("Could not allocate RGN attr\n");
2294 return FALSE;
2295 }
2296
2297 /* Copy the current region attribute */
2298 *prgnattr = prgn->rgnattr;
2299
2300 /* Set the object attribute in the handle table */
2301 prgn->prgnattr = prgnattr;
2302 GDIOBJ_vSetObjectAttr(&prgn->BaseObject, prgnattr);
2303
2304 return TRUE;
2305}
2306
2307
2308//
2309// Allocate User Space Region Handle.
2311PREGION
2314 INT nRgn)
2315{
2316 PREGION prgn;
2317
2318 prgn = REGION_AllocRgnWithHandle(nRgn);
2319 if (prgn == NULL)
2320 {
2321 return NULL;
2322 }
2323
2324 if (!REGION_bAllocRgnAttr(prgn))
2325 {
2326 ASSERT(FALSE);
2327 }
2328
2329 return prgn;
2330}
2332static
2333VOID
2335 _In_ PREGION prgn)
2336{
2337 PRGN_ATTR prgnattr;
2338
2339 NT_ASSERT(prgn != NULL);
2340 NT_ASSERT(prgn->prgnattr != NULL);
2341 NT_ASSERT((prgn->prgnattr == &prgn->rgnattr) ||
2342 (prgn->prgnattr->AttrFlags & ATTR_RGN_VALID));
2343
2344 /* Get the region attribute and check if it's dirty (modified) */
2345 prgnattr = prgn->prgnattr;
2346 if (prgnattr->AttrFlags & ATTR_RGN_DIRTY)
2347 {
2348 NT_ASSERT(GreGetObjectOwner(prgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED);
2349 NT_ASSERT(prgnattr != &prgn->rgnattr);
2350
2351 if (prgnattr->iComplexity == NULLREGION)
2352 {
2353 EMPTY_REGION(prgn);
2354 }
2355 else if (prgnattr->iComplexity == SIMPLEREGION)
2356 {
2357 REGION_SetRectRgn(prgn,
2358 prgnattr->Rect.left,
2359 prgnattr->Rect.top,
2360 prgnattr->Rect.right,
2361 prgnattr->Rect.bottom);
2362 }
2363 else
2364 {
2365 /* Should not happen, region attribute is corrupted! */
2366 DPRINT1("Region attribute is corrupted, ignoring\n");
2368 }
2369 }
2370
2371 /* Reset the flags */
2372 prgnattr->AttrFlags &= ~(ATTR_RGN_DIRTY | ATTR_RGN_VALID);
2373}
2375PREGION
2378 _In_ HRGN hrgn)
2379{
2380 PREGION prgn;
2381
2383 if (prgn == NULL)
2384 return NULL;
2385
2386 REGION_vSyncRegion(prgn);
2387 return prgn;
2388}
2390VOID
2393 _In_ PREGION prgn)
2394{
2395 PRGN_ATTR prgnattr;
2396
2397 NT_ASSERT(prgn != NULL);
2398 NT_ASSERT(prgn->prgnattr != NULL);
2399
2400 /* Get the region attribute and check if it's user mode */
2401 prgnattr = prgn->prgnattr;
2402 if (prgnattr != &prgn->rgnattr)
2403 {
2404 NT_ASSERT(GreGetObjectOwner(prgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED);
2405 prgnattr->iComplexity = REGION_Complexity(prgn);
2406 prgnattr->Rect.left = prgn->rdh.rcBound.left;
2407 prgnattr->Rect.top = prgn->rdh.rcBound.top;
2408 prgnattr->Rect.right = prgn->rdh.rcBound.right;
2409 prgnattr->Rect.bottom = prgn->rdh.rcBound.bottom;
2410 prgnattr->AttrFlags |= ATTR_RGN_VALID;
2411 }
2412
2413 GDIOBJ_vUnlockObject(&prgn->BaseObject);
2414}
2415
2416/*
2417 System Regions:
2418 These regions do not use attribute sections and when allocated, use gdiobj
2419 level functions.
2420*/
2421//
2422// System Region Functions
2424PREGION
2427 INT LeftRect,
2428 INT TopRect,
2429 INT RightRect,
2430 INT BottomRect)
2431{
2432 PREGION prgn;
2433
2434 /* Allocate a region, without a handle */
2436 if (prgn == NULL)
2437 {
2438 return NULL;
2439 }
2440
2441 /* Initialize it */
2442 prgn->Buffer = &prgn->rdh.rcBound;
2443 prgn->prgnattr = &prgn->rgnattr;
2445 REGION_SetRectRgn(prgn, LeftRect, TopRect, RightRect, BottomRect);
2446
2447 return prgn;
2448}
2450VOID
2451NTAPI
2452REGION_vCleanup(PVOID ObjectBody)
2453{
2454 PREGION pRgn = (PREGION)ObjectBody;
2456 ASSERT(ppi);
2457
2458 ASSERT(pRgn->prgnattr);
2459 if (pRgn->prgnattr != &pRgn->rgnattr)
2460 GdiPoolFree(ppi->pPoolRgnAttr, pRgn->prgnattr);
2461
2462 if (pRgn->Buffer && pRgn->Buffer != &pRgn->rdh.rcBound)
2464}
2466VOID
2469{
2470 if (pRgn == prgnDefault)
2471 return;
2472
2474}
2476BOOL
2478IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
2479{
2480 PREGION prgn;
2481 PRGN_ATTR prgnattr;
2482 PPROCESSINFO ppi;
2483
2484 prgn = REGION_LockRgn(hRgn);
2485 if (prgn == NULL)
2486 {
2487 return FALSE;
2488 }
2489
2490 prgnattr = prgn->prgnattr;
2491 if (prgnattr != &prgn->rgnattr)
2492 {
2494 prgn->prgnattr = &prgn->rgnattr;
2496 GdiPoolFree(ppi->pPoolRgnAttr, prgnattr);
2497 }
2498
2499 REGION_UnlockRgn(prgn);
2500
2501 return GreSetObjectOwner(hRgn, OwnerMask);
2502}
2504INT
2507 PREGION prgnDest,
2508 PREGION prgnSrc1,
2509 PREGION prgnSrc2,
2510 INT iCombineMode)
2511{
2512 BOOL Ret = TRUE;
2513
2514 if (prgnDest == NULL)
2515 {
2516 DPRINT("IntGdiCombineRgn: hDest unavailable\n");
2517 return ERROR;
2518 }
2519
2520 if (prgnSrc1 == NULL)
2521 {
2522 DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
2523 return ERROR;
2524 }
2525
2526 if (iCombineMode == RGN_COPY)
2527 {
2528 if (!REGION_CopyRegion(prgnDest, prgnSrc1))
2529 return ERROR;
2530
2531 return REGION_Complexity(prgnDest);
2532 }
2533
2534 if (prgnSrc2 == NULL)
2535 {
2536 DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", iCombineMode);
2537 ASSERT(FALSE);
2538 return ERROR;
2539 }
2540
2541 switch (iCombineMode)
2542 {
2543 case RGN_AND:
2544 Ret = REGION_IntersectRegion(prgnDest, prgnSrc1, prgnSrc2);
2545 break;
2546 case RGN_OR:
2547 Ret = REGION_UnionRegion(prgnDest, prgnSrc1, prgnSrc2);
2548 break;
2549 case RGN_XOR:
2550 Ret = REGION_XorRegion(prgnDest, prgnSrc1, prgnSrc2);
2551 break;
2552 case RGN_DIFF:
2553 Ret = REGION_SubtractRegion(prgnDest, prgnSrc1, prgnSrc2);
2554 break;
2555 }
2556
2557 return Ret ? REGION_Complexity(prgnDest) : ERROR;
2558}
2560INT
2563 PREGION Rgn,
2564 PRECTL pRect)
2565{
2566 DWORD ret;
2567
2568 if (Rgn != NULL)
2569 {
2570 *pRect = Rgn->rdh.rcBound;
2571 ret = REGION_Complexity(Rgn);
2572
2573 return ret;
2574 }
2575 return 0; // If invalid region return zero
2576}
2578INT
2581 HRGN hRgn,
2582 PRECTL pRect)
2583{
2584 PREGION Rgn;
2585 DWORD ret;
2586
2587 Rgn = REGION_LockRgn(hRgn);
2588 if (Rgn == NULL)
2589 {
2590 return ERROR;
2591 }
2592
2593 ret = REGION_GetRgnBox(Rgn, pRect);
2594 REGION_UnlockRgn(Rgn);
2595
2596 return ret;
2597}
2598
2600BOOL
2603 PREGION prgn,
2604 INT X,
2605 INT Y)
2606{
2607 ULONG i;
2608 PRECT r;
2609
2610 if (prgn->rdh.nCount > 0 && INRECT(prgn->rdh.rcBound, X, Y))
2611 {
2612 r = prgn->Buffer;
2613 for (i = 0; i < prgn->rdh.nCount; i++)
2614 {
2615 if (INRECT(r[i], X, Y))
2616 return TRUE;
2617 }
2618 }
2619
2620 return FALSE;
2621}
2623BOOL
2626 PREGION Rgn,
2627 const RECTL *rect)
2628{
2629 PRECTL pCurRect, pRectEnd;
2630 RECT rc;
2631
2632 /* Swap the coordinates to make right >= left and bottom >= top */
2633 /* (region building rectangles are normalized the same way) */
2634 if (rect->top > rect->bottom)
2635 {
2636 rc.top = rect->bottom;
2637 rc.bottom = rect->top;
2638 }
2639 else
2640 {
2641 rc.top = rect->top;
2642 rc.bottom = rect->bottom;
2643 }
2644
2645 if (rect->right < rect->left)
2646 {
2647 rc.right = rect->left;
2648 rc.left = rect->right;
2649 }
2650 else
2651 {
2652 rc.right = rect->right;
2653 rc.left = rect->left;
2654 }
2655
2656 /* This is (just) a useful optimization */
2657 if ((Rgn->rdh.nCount > 0) && EXTENTCHECK(&Rgn->rdh.rcBound, &rc))
2658 {
2659 for (pCurRect = Rgn->Buffer, pRectEnd = pCurRect +
2660 Rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
2661 {
2662 if (pCurRect->bottom <= rc.top)
2663 continue; /* Not far enough down yet */
2664
2665 if (pCurRect->top >= rc.bottom)
2666 break; /* Too far down */
2667
2668 if (pCurRect->right <= rc.left)
2669 continue; /* Not far enough over yet */
2670
2671 if (pCurRect->left >= rc.right)
2672 {
2673 continue;
2674 }
2675
2676 return TRUE;
2677 }
2678 }
2679
2680 return FALSE;
2681}
2683VOID
2686 PREGION rgn,
2687 INT LeftRect,
2688 INT TopRect,
2689 INT RightRect,
2690 INT BottomRect)
2691{
2692 PRECTL firstRect;
2693
2694 if (LeftRect > RightRect)
2695 {
2696 INT tmp = LeftRect;
2697 LeftRect = RightRect;
2698 RightRect = tmp;
2699 }
2700
2701 if (TopRect > BottomRect)
2702 {
2703 INT tmp = TopRect;
2704 TopRect = BottomRect;
2705 BottomRect = tmp;
2706 }
2707
2708 if ((LeftRect != RightRect) && (TopRect != BottomRect))
2709 {
2710 firstRect = rgn->Buffer;
2711 ASSERT(firstRect);
2712 firstRect->left = rgn->rdh.rcBound.left = LeftRect;
2713 firstRect->top = rgn->rdh.rcBound.top = TopRect;
2714 firstRect->right = rgn->rdh.rcBound.right = RightRect;
2715 firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
2716 rgn->rdh.nCount = 1;
2717 rgn->rdh.iType = RDH_RECTANGLES;
2718 }
2719 else
2720 {
2721 EMPTY_REGION(rgn);
2722 }
2723}
2725BOOL
2728 _Inout_ PREGION prgn,
2729 _In_ INT cx,
2730 _In_ INT cy)
2731{
2732 PRECTL prcl;
2733 UINT i;
2734
2735 NT_ASSERT(prgn != NULL);
2736
2737 /* Check for trivial case */
2738 if ((cx == 0) && (cy == 0))
2739 {
2740 return TRUE;
2741 }
2742
2743 /* Check for empty regions, we ignore the offset values here */
2744 if (prgn->rdh.nCount == 0)
2745 {
2746 return TRUE;
2747 }
2748
2749 /* Make sure the offset is within the legal range */
2750 if ((cx > MAX_COORD) || (cx < MIN_COORD) ||
2751 (cy > MAX_COORD) || (cy < MIN_COORD))
2752 {
2753 return FALSE;
2754 }
2755
2756 /* Are we moving right? */
2757 if (cx > 0)
2758 {
2759 /* Check if we stay inside the bounds on the right side */
2760 if (prgn->rdh.rcBound.right > (MAX_COORD - cx))
2761 {
2762 return FALSE;
2763 }
2764 }
2765 else
2766 {
2767 /* Check if we stay inside the bounds on the left side */
2768 if (prgn->rdh.rcBound.left < (MIN_COORD - cx))
2769 {
2770 return FALSE;
2771 }
2772 }
2773
2774 /* Are we moving down? */
2775 if (cy > 0)
2776 {
2777 /* Check if we stay inside the bounds on the right side */
2778 if (prgn->rdh.rcBound.bottom > (MAX_COORD - cy))
2779 {
2780 return FALSE;
2781 }
2782 }
2783 else
2784 {
2785 /* Check if we stay inside the bounds on the left side */
2786 if (prgn->rdh.rcBound.top < (MIN_COORD - cy))
2787 {
2788 return FALSE;
2789 }
2790 }
2791
2792 /* Loop to move the rects */
2793 prcl = prgn->Buffer;
2794 for (i = 0; i < prgn->rdh.nCount; i++)
2795 {
2796 prcl[i].left += cx;
2797 prcl[i].right += cx;
2798 prcl[i].top += cy;
2799 prcl[i].bottom += cy;
2800 }
2801
2802 /* Finally update the bounds rect */
2803 if (prgn->Buffer != &prgn->rdh.rcBound)
2804 {
2805 prgn->rdh.rcBound.left += cx;
2806 prgn->rdh.rcBound.right += cx;
2807 prgn->rdh.rcBound.top += cy;
2808 prgn->rdh.rcBound.bottom += cy;
2809 }
2810
2811 return TRUE;
2812}
2813
2814/***********************************************************************
2815 * REGION_InsertEdgeInET
2816 *
2817 * Insert the given edge into the edge table.
2818 * First we must find the correct bucket in the
2819 * Edge table, then find the right slot in the
2820 * bucket. Finally, we can insert it.
2821 *
2822 */
2823static
2824VOID
2827 EDGE_TABLE *ET,
2828 EDGE_TABLE_ENTRY *ETE,
2829 INT scanline,
2830 SCANLINE_LISTBLOCK **SLLBlock,
2831 INT *iSLLBlock)
2832{
2833 EDGE_TABLE_ENTRY *start, *prev;
2834 SCANLINE_LIST *pSLL, *pPrevSLL;
2835 SCANLINE_LISTBLOCK *tmpSLLBlock;
2836
2837 /* Find the right bucket to put the edge into */
2838 pPrevSLL = &ET->scanlines;
2839 pSLL = pPrevSLL->next;
2840 while (pSLL && (pSLL->scanline < scanline))
2841 {
2842 pPrevSLL = pSLL;
2843 pSLL = pSLL->next;
2844 }
2845
2846 /* Reassign pSLL (pointer to SCANLINE_LIST) if necessary */
2847 if ((!pSLL) || (pSLL->scanline > scanline))
2848 {
2849 if (*iSLLBlock > SLLSPERBLOCK-1)
2850 {
2851 tmpSLLBlock = ExAllocatePoolWithTag(PagedPool,
2852 sizeof(SCANLINE_LISTBLOCK),
2853 TAG_REGION);
2854 if (tmpSLLBlock == NULL)
2855 {
2856 DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2857 /* FIXME: Free resources? */
2858 return;
2859 }
2860
2861 (*SLLBlock)->next = tmpSLLBlock;
2862 tmpSLLBlock->next = (SCANLINE_LISTBLOCK *)NULL;
2863 *SLLBlock = tmpSLLBlock;
2864 *iSLLBlock = 0;
2865 }
2866
2867 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
2868
2869 pSLL->next = pPrevSLL->next;
2870 pSLL->edgelist = (EDGE_TABLE_ENTRY *)NULL;
2871 pPrevSLL->next = pSLL;
2872 }
2873
2874 pSLL->scanline = scanline;
2875
2876 /* Now insert the edge in the right bucket */
2877 prev = (EDGE_TABLE_ENTRY *)NULL;
2878 start = pSLL->edgelist;
2879 while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
2880 {
2881 prev = start;
2882 start = start->next;
2883 }
2884
2885 ETE->next = start;
2886
2887 if (prev)
2888 prev->next = ETE;
2889 else
2890 pSLL->edgelist = ETE;
2891}
2892
2893/***********************************************************************
2894 * REGION_loadAET
2895 *
2896 * This routine moves EDGE_TABLEEntries from the
2897 * EDGE_TABLE into the Active Edge Table,
2898 * leaving them sorted by smaller x coordinate.
2899 *
2900 */
2901static
2902VOID
2905 EDGE_TABLE_ENTRY *AET,
2906 EDGE_TABLE_ENTRY *ETEs)
2907{
2908 EDGE_TABLE_ENTRY *pPrevAET;
2909 EDGE_TABLE_ENTRY *tmp;
2910
2911 pPrevAET = AET;
2912 AET = AET->next;
2913 while (ETEs)
2914 {
2915 while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
2916 {
2917 pPrevAET = AET;
2918 AET = AET->next;
2919 }
2920
2921 tmp = ETEs->next;
2922 ETEs->next = AET;
2923 if (AET)
2924 AET->back = ETEs;
2925
2926 ETEs->back = pPrevAET;
2927 pPrevAET->next = ETEs;
2928 pPrevAET = ETEs;
2929
2930 ETEs = tmp;
2931 }
2932}
2933
2934/***********************************************************************
2935 * REGION_computeWAET
2936 *
2937 * This routine links the AET by the
2938 * nextWETE (winding EDGE_TABLE_ENTRY) link for
2939 * use by the winding number rule. The final
2940 * Active Edge Table (AET) might look something
2941 * like:
2942 *
2943 * AET
2944 * ---------- --------- ---------
2945 * |ymax | |ymax | |ymax |
2946 * | ... | |... | |... |
2947 * |next |->|next |->|next |->...
2948 * |nextWETE| |nextWETE| |nextWETE|
2949 * --------- --------- ^--------
2950 * | | |
2951 * V-------------------> V---> ...
2952 *
2953 */
2954static
2955VOID
2958 EDGE_TABLE_ENTRY *AET)
2959{
2960 register EDGE_TABLE_ENTRY *pWETE;
2961 register INT inside = 1;
2962 register INT isInside = 0;
2963
2964 AET->nextWETE = (EDGE_TABLE_ENTRY *)NULL;
2965 pWETE = AET;
2966 AET = AET->next;
2967 while (AET)
2968 {
2969 if (AET->ClockWise)
2970 isInside++;
2971 else
2972 isInside--;
2973
2974 if ((!inside && !isInside) ||
2975 ( inside && isInside))
2976 {
2977 pWETE->nextWETE = AET;
2978 pWETE = AET;
2979 inside = !inside;
2980 }
2981 AET = AET->next;
2982 }
2983
2984 pWETE->nextWETE = (EDGE_TABLE_ENTRY *)NULL;
2985}
2986
2987/***********************************************************************
2988 * REGION_InsertionSort
2989 *
2990 * Just a simple insertion sort using
2991 * pointers and back pointers to sort the Active
2992 * Edge Table.
2993 *
2994 */
2995static
2996BOOL
2999 EDGE_TABLE_ENTRY *AET)
3000{
3001 EDGE_TABLE_ENTRY *pETEchase;
3002 EDGE_TABLE_ENTRY *pETEinsert;
3003 EDGE_TABLE_ENTRY *pETEchaseBackTMP;
3004 BOOL changed = FALSE;
3005
3006 AET = AET->next;
3007 while (AET)
3008 {
3009 pETEinsert = AET;
3010 pETEchase = AET;
3011 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
3012 pETEchase = pETEchase->back;
3013
3014 AET = AET->next;
3015 if (pETEchase != pETEinsert)
3016 {
3017 pETEchaseBackTMP = pETEchase->back;
3018 pETEinsert->back->next = AET;
3019 if (AET)
3020 AET->back = pETEinsert->back;
3021
3022 pETEinsert->next = pETEchase;
3023 pETEchase->back->next = pETEinsert;
3024 pETEchase->back = pETEinsert;
3025 pETEinsert->back = pETEchaseBackTMP;
3026 changed = TRUE;
3027 }
3028 }
3029
3030 return changed;
3031}
3032
3033/***********************************************************************
3034 * REGION_FreeStorage
3035 *
3036 * Clean up our act.
3037 */
3038static
3039VOID
3042 SCANLINE_LISTBLOCK *pSLLBlock)
3043{
3044 SCANLINE_LISTBLOCK *tmpSLLBlock;
3045
3046 while (pSLLBlock)
3047 {
3048 tmpSLLBlock = pSLLBlock->next;
3049 ExFreePoolWithTag(pSLLBlock, TAG_REGION);
3050 pSLLBlock = tmpSLLBlock;
3051 }
3052}
3053
3054
3055/***********************************************************************
3056 * REGION_PtsToRegion
3057 *
3058 * Create an array of rectangles from a list of points.
3059 */
3060static
3061INT
3064 INT numFullPtBlocks,
3065 INT iCurPtBlock,
3066 POINTBLOCK *FirstPtBlock,
3067 PREGION reg)
3068{
3069 RECTL *rects;
3070 POINT *pts;
3071 POINTBLOCK *CurPtBlock;
3072 INT i;
3073 RECTL *extents, *temp;
3074 INT numRects;
3075
3076 extents = &reg->rdh.rcBound;
3077
3078 numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
3079
3080 /* Make sure, we have at least one rect */
3081 if (numRects == 0)
3082 {
3083 numRects = 1;
3084 }
3085
3086 temp = ExAllocatePoolWithTag(PagedPool, numRects * sizeof(RECT), TAG_REGION);
3087 if (temp == NULL)
3088 {
3089 return 0;
3090 }
3091
3092 if (reg->Buffer != NULL)
3093 {
3094 COPY_RECTS(temp, reg->Buffer, reg->rdh.nCount);
3095 if (reg->Buffer != &reg->rdh.rcBound)
3097 }
3098 reg->Buffer = temp;
3099
3100 reg->rdh.nCount = numRects;
3101 CurPtBlock = FirstPtBlock;
3102 rects = reg->Buffer - 1;
3103 numRects = 0;
3104 extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
3105
3106 for ( ; numFullPtBlocks >= 0; numFullPtBlocks--)
3107 {
3108 /* The loop uses 2 points per iteration */
3109 i = NUMPTSTOBUFFER >> 1;
3110 if (numFullPtBlocks == 0)
3111 i = iCurPtBlock >> 1;
3112
3113 for (pts = CurPtBlock->pts; i--; pts += 2)
3114 {
3115 if (pts->x == pts[1].x)
3116 continue;
3117
3118 if ((numRects && pts->x == rects->left) &&
3119 (pts->y == rects->bottom) &&
3120 (pts[1].x == rects->right) &&
3121 ((numRects == 1) || (rects[-1].top != rects->top)) &&
3122 (i && pts[2].y > pts[1].y))
3123 {
3124 rects->bottom = pts[1].y + 1;
3125 continue;
3126 }
3127
3128 numRects++;
3129 rects++;
3130 rects->left = pts->x;
3131 rects->top = pts->y;
3132 rects->right = pts[1].x;
3133 rects->bottom = pts[1].y + 1;
3134
3135 if (rects->left < extents->left)
3136 extents->left = rects->left;
3137 if (rects->right > extents->right)
3138 extents->right = rects->right;
3139 }
3140
3141 CurPtBlock = CurPtBlock->next;
3142 }
3143
3144 if (numRects)
3145 {
3146 extents->top = reg->Buffer->top;
3147 extents->bottom = rects->bottom;
3148 }
3149 else
3150 {
3151 extents->left = 0;
3152 extents->top = 0;
3153 extents->right = 0;
3154 extents->bottom = 0;
3155 }
3156
3157 reg->rdh.nCount = numRects;
3158
3159 return(TRUE);
3160}
3161
3162/***********************************************************************
3163 * REGION_CreateETandAET
3164 *
3165 * This routine creates the edge table for
3166 * scan converting polygons.
3167 * The Edge Table (ET) looks like:
3168 *
3169 * EDGE_TABLE
3170 * --------
3171 * | ymax | SCANLINE_LISTs
3172 * |scanline|-->------------>-------------->...
3173 * -------- |scanline| |scanline|
3174 * |edgelist| |edgelist|
3175 * --------- ---------
3176 * | |
3177 * | |
3178 * V V
3179 * list of ETEs list of ETEs
3180 *
3181 * where ETE is an EDGE_TABLE_ENTRY data structure,
3182 * and there is one SCANLINE_LIST per scanline at
3183 * which an edge is initially entered.
3184 *
3185 */
3186static
3187VOID
3190 const ULONG *Count,
3191 INT nbpolygons,
3192 const POINT *pts,
3193 EDGE_TABLE *ET,
3194 EDGE_TABLE_ENTRY *AET,
3195 EDGE_TABLE_ENTRY *pETEs,
3196 SCANLINE_LISTBLOCK *pSLLBlock)
3197{
3198 const POINT *top, *bottom;
3199 const POINT *PrevPt, *CurrPt, *EndPt;
3200 INT poly, count;
3201 INT iSLLBlock = 0;
3202 INT dy;
3203
3204 /* Initialize the Active Edge Table */
3205 AET->next = (EDGE_TABLE_ENTRY *)NULL;
3206 AET->back = (EDGE_TABLE_ENTRY *)NULL;
3207 AET->nextWETE = (EDGE_TABLE_ENTRY *)NULL;
3209
3210 /* Initialize the Edge Table. */
3211 ET->scanlines.next = (SCANLINE_LIST *)NULL;
3212 ET->ymax = SMALL_COORDINATE;
3213 ET->ymin = LARGE_COORDINATE;
3214 pSLLBlock->next = (SCANLINE_LISTBLOCK *)NULL;
3215
3216 EndPt = pts - 1;
3217 for (poly = 0; poly < nbpolygons; poly++)
3218 {
3219 count = Count[poly];
3220 EndPt += count;
3221 if (count < 2)
3222 continue;
3223
3224 PrevPt = EndPt;
3225
3226 /* For each vertex in the array of points.
3227 * In this loop we are dealing with two vertices at
3228 * a time -- these make up one edge of the polygon. */
3229 while (count--)
3230 {
3231 CurrPt = pts++;
3232
3233 /* Find out which point is above and which is below. */
3234 if (PrevPt->y > CurrPt->y)
3235 {
3236 bottom = PrevPt, top = CurrPt;
3237 pETEs->ClockWise = 0;
3238 }
3239 else
3240 {
3241 bottom = CurrPt, top = PrevPt;
3242 pETEs->ClockWise = 1;
3243 }
3244
3245 /* Don't add horizontal edges to the Edge table. */
3246 if (bottom->y != top->y)
3247 {
3248 /* -1 so we don't get last scanline */
3249 pETEs->ymax = bottom->y - 1;
3250
3251 /* Initialize integer edge algorithm */
3252 dy = bottom->y - top->y;
3253 BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
3254
3256 pETEs,
3257 top->y,
3258 &pSLLBlock,
3259 &iSLLBlock);
3260
3261 if (PrevPt->y > ET->ymax)
3262 ET->ymax = PrevPt->y;
3263 if (PrevPt->y < ET->ymin)
3264 ET->ymin = PrevPt->y;
3265 pETEs++;
3266 }
3267
3268 PrevPt = CurrPt;
3269 }
3270 }
3271}
3273BOOL
3276 _Inout_ PREGION prgn,
3277 _In_ const POINT *ppt,
3278 _In_ const ULONG *pcPoints,
3279 _In_ ULONG cPolygons,
3280 _In_ INT iMode)
3281{
3282 EDGE_TABLE_ENTRY *pAET; /* Active Edge Table */
3283 INT y; /* Current scanline */
3284 INT iPts = 0; /* Number of pts in buffer */
3285 EDGE_TABLE_ENTRY *pWETE; /* Winding Edge Table Entry */
3286 SCANLINE_LIST *pSLL; /* Current SCANLINE_LIST */
3287 POINT *pts; /* Output buffer */
3288 EDGE_TABLE_ENTRY *pPrevAET; /* Pointer to previous AET */
3289 EDGE_TABLE ET; /* Header node for ET */
3290 EDGE_TABLE_ENTRY AET; /* Header node for AET */
3291 EDGE_TABLE_ENTRY *pETEs; /* EDGE_TABLEEntries pool */
3292 SCANLINE_LISTBLOCK SLLBlock; /* Header for SCANLINE_LIST */
3293 INT fixWAET = FALSE;
3294 POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
3295 POINTBLOCK *tmpPtBlock;
3296 UINT numFullPtBlocks = 0;
3297 UINT poly, total;
3298 BOOL bResult = FALSE;
3299
3300 /* Check if iMode is valid */
3301 if ((iMode != ALTERNATE) && (iMode != WINDING))
3302 {
3303 DPRINT1("Invalid iMode: %lu\n", iMode);
3304 return FALSE;
3305 }
3306
3307 /* Special case a rectangle */
3308 if (((cPolygons == 1) && ((pcPoints[0] == 4) ||
3309 ((pcPoints[0] == 5) && (ppt[4].x == ppt[0].x) && (ppt[4].y == ppt[0].y)))) &&
3310 (((ppt[0].y == ppt[1].y) &&
3311 (ppt[1].x == ppt[2].x) &&
3312 (ppt[2].y == ppt[3].y) &&
3313 (ppt[3].x == ppt[0].x)) ||
3314 ((ppt[0].x == ppt[1].x) &&
3315 (ppt[1].y == ppt[2].y) &&
3316 (ppt[2].x == ppt[3].x) &&
3317 (ppt[3].y == ppt[0].y))))
3318 {
3319 REGION_SetRectRgn(prgn,
3320 min(ppt[0].x, ppt[2].x),
3321 min(ppt[0].y, ppt[2].y),
3322 max(ppt[0].x, ppt[2].x),
3323 max(ppt[0].y, ppt[2].y));
3324 return TRUE;
3325 }
3326
3327 for (poly = total = 0; poly < cPolygons; poly++)
3328 total += pcPoints[poly];
3329
3331 sizeof(EDGE_TABLE_ENTRY) * total,
3332 TAG_REGION);
3333 if (pETEs == NULL)
3334 {
3335 DPRINT1("Failed to allocate %lu edge entries\n", total);
3336 return FALSE;
3337 }
3338
3339 pts = FirstPtBlock.pts;
3340 REGION_CreateETandAET(pcPoints, cPolygons, ppt, &ET, &AET, pETEs, &SLLBlock);
3341 pSLL = ET.scanlines.next;
3342 curPtBlock = &FirstPtBlock;
3343
3344 if (iMode != WINDING)
3345 {
3346 /* For each scanline */
3347 for (y = ET.ymin; y < ET.ymax; y++)
3348 {
3349 /* Add a new edge to the active edge table when we
3350 * get to the next edge. */
3351 if (pSLL != NULL && y == pSLL->scanline)
3352 {
3353 REGION_loadAET(&AET, pSLL->edgelist);
3354 pSLL = pSLL->next;
3355 }
3356 pPrevAET = &AET;
3357 pAET = AET.next;
3358
3359 /* For each active edge */
3360 while (pAET)
3361 {
3362 pts->x = pAET->bres.minor_axis, pts->y = y;
3363 pts++, iPts++;
3364
3365 /* Send out the buffer */
3366 if (iPts == NUMPTSTOBUFFER)
3367 {
3368 tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
3369 sizeof(POINTBLOCK),
3370 TAG_REGION);
3371 if (tmpPtBlock == NULL)
3372 {
3373 DPRINT1("Can't alloc tmpPtBlock\n");
3374 goto Cleanup;
3375 }
3376
3377 curPtBlock->next = tmpPtBlock;
3378 curPtBlock = tmpPtBlock;
3379 pts = curPtBlock->pts;
3380 numFullPtBlocks++;
3381 iPts = 0;
3382 }
3383
3384 EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
3385 }
3386
3388 }
3389 }
3390 else
3391 {
3392 /* For each scanline */
3393 for (y = ET.ymin; y < ET.ymax; y++)
3394 {
3395 /* Add a new edge to the active edge table when we
3396 * get to the next edge. */
3397 if (pSLL != NULL && y == pSLL->scanline)
3398 {
3399 REGION_loadAET(&AET, pSLL->edgelist);
3400 REGION_computeWAET(&AET);
3401 pSLL = pSLL->next;
3402 }
3403
3404 pPrevAET = &AET;
3405 pAET = AET.next;
3406 pWETE = pAET;
3407
3408 /* For each active edge */
3409 while (pAET)
3410 {
3411 /* Add to the buffer only those edges that
3412 * are in the Winding active edge table. */
3413 if (pWETE == pAET)
3414 {
3415 pts->x = pAET->bres.minor_axis;
3416 pts->y = y;
3417 pts++;
3418 iPts++;
3419
3420 /* Send out the buffer */
3421 if (iPts == NUMPTSTOBUFFER)
3422 {
3423 tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
3424 sizeof(POINTBLOCK),
3425 TAG_REGION);
3426 if (tmpPtBlock == NULL)
3427 {
3428 DPRINT1("Can't alloc tPB\n");
3429 goto Cleanup;
3430 }
3431 curPtBlock->next = tmpPtBlock;
3432 curPtBlock = tmpPtBlock;
3433 pts = curPtBlock->pts;
3434 numFullPtBlocks++;
3435 iPts = 0;
3436 }
3437
3438 pWETE = pWETE->nextWETE;
3439 }
3440
3441 EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
3442 }
3443
3444 /* Recompute the winding active edge table if
3445 * we just resorted or have exited an edge. */
3446 if (REGION_InsertionSort(&AET) || fixWAET)
3447 {
3448 REGION_computeWAET(&AET);
3449 fixWAET = FALSE;
3450 }
3451 }
3452 }
3453
3454 REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, prgn);
3455 bResult = TRUE;
3456
3457Cleanup:
3458 REGION_FreeStorage(SLLBlock.next);
3459
3460 for (curPtBlock = FirstPtBlock.next; numFullPtBlocks-- > 0;)
3461 {
3462 tmpPtBlock = curPtBlock->next;
3463 ExFreePoolWithTag(curPtBlock, TAG_REGION);
3464 curPtBlock = tmpPtBlock;
3465 }
3466
3468 return bResult;
3469}
3471HRGN
3472NTAPI
3474 _In_ const POINT *ppt,
3475 _In_ const ULONG *pcPoints,
3476 _In_ ULONG cPolygons,
3477 _In_ INT iMode)
3478{
3479 PREGION prgn;
3480 HRGN hrgn;
3481
3482 /* Allocate a new region */
3484 if (prgn == NULL)
3485 {
3487 return NULL;
3488 }
3489
3490 /* Call the internal function and check for success */
3491 if (REGION_SetPolyPolygonRgn(prgn, ppt, pcPoints, cPolygons, iMode))
3492 {
3493 /* Success, get the handle and unlock the region */
3494 hrgn = prgn->BaseObject.hHmgr;
3495 REGION_UnlockRgn(prgn);
3496 }
3497 else
3498 {
3499 /* Failure, delete the region */
3500 REGION_Delete(prgn);
3501 hrgn = NULL;
3502 }
3503
3504 return hrgn;
3505}
3507BOOL
3510 HRGN hRgn,
3511 LPRECTL rc)
3512{
3513 PREGION Rgn;
3514 BOOL Ret;
3515
3516 Rgn = REGION_LockRgn(hRgn);
3517 if (Rgn == NULL)
3518 {
3519 return ERROR;
3520 }
3521
3522 Ret = REGION_RectInRegion(Rgn, rc);
3523 REGION_UnlockRgn(Rgn);
3524 return Ret;
3525}
3526
3527
3528//
3529// NtGdi Exported Functions
3531INT
3534 IN HRGN hrgnDst,
3535 IN HRGN hrgnSrc1,
3536 IN HRGN hrgnSrc2,
3537 IN INT iMode)
3538{
3539 HRGN ahrgn[3];
3540 PREGION aprgn[3];
3541 INT iResult;
3542
3543 /* Validate the combine mode */
3544 if ((iMode < RGN_AND) || (iMode > RGN_COPY))
3545 {
3546 return ERROR;
3547 }
3548
3549 /* Validate that we have the required regions */
3550 if ((hrgnDst == NULL) ||
3551 (hrgnSrc1 == NULL) ||
3552 ((iMode != RGN_COPY) && (hrgnSrc2 == NULL)))
3553 {
3554 DPRINT1("NtGdiCombineRgn invalid parameters: %p, %p, %p, %d\n",
3555 hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
3557 return ERROR;
3558 }
3559
3560 /* Lock all regions */
3561 ahrgn[0] = hrgnDst;
3562 ahrgn[1] = hrgnSrc1;
3563 ahrgn[2] = iMode != RGN_COPY ? hrgnSrc2 : NULL;
3565 {
3566 DPRINT1("NtGdiCombineRgn failed to lock regions: %p, %p, %p, %d\n",
3567 hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
3568 return ERROR;
3569 }
3570
3571 /* HACK: Sync usermode attributes */
3572 REGION_vSyncRegion(aprgn[0]);
3573 if (aprgn[1] != aprgn[0])
3574 REGION_vSyncRegion(aprgn[1]);
3575 if ((aprgn[2] != NULL) && (aprgn[2] != aprgn[0]) && (aprgn[2] != aprgn[1]))
3576 REGION_vSyncRegion(aprgn[2]);
3577
3578 /* Call the internal function */
3579 iResult = IntGdiCombineRgn(aprgn[0], aprgn[1], aprgn[2], iMode);
3580
3581 /* Unlock and return */
3582 REGION_UnlockRgn(aprgn[0]);
3583 REGION_UnlockRgn(aprgn[1]);
3584 if (aprgn[2] != NULL)
3585 REGION_UnlockRgn(aprgn[2]);
3586
3587 return iResult;
3588}
3590HRGN
3593 INT Left,
3594 INT Top,
3595 INT Right,
3596 INT Bottom)
3597{
3598 return NtGdiCreateRoundRectRgn(Left,
3599 Top,
3600 Right, Bottom,
3601 Right - Left,
3602 Bottom - Top);
3603}
3605HRGN
3608 INT LeftRect,
3609 INT TopRect,
3610 INT RightRect,
3611 INT BottomRect)
3612{
3613 PREGION pRgn;
3614 HRGN hRgn;
3615
3616 /* Allocate region data structure with space for 1 RECTL */
3618 if (pRgn == NULL)
3619 {
3621 return NULL;
3622 }
3623
3624 hRgn = pRgn->BaseObject.hHmgr;
3625
3626 REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
3627 REGION_UnlockRgn(pRgn);
3628
3629 DPRINT("Returning %p.\n", hRgn);
3630
3631 return hRgn;
3632}
3634HRGN
3637 INT left,
3638 INT top,
3639 INT right,
3640 INT bottom,
3641 INT ellipse_width,
3642 INT ellipse_height)
3643{
3644 PREGION obj;
3645 HRGN hrgn;
3646 int a, b, i, x, y;
3647 INT64 asq, bsq, dx, dy, err;
3648 RECT *rects;
3649
3650 /* Make the dimensions sensible */
3651 if (left > right)
3652 {
3653 INT tmp = left;
3654 left = right;
3655 right = tmp;
3656 }
3657
3658 if (top > bottom)
3659 {
3660 INT tmp = top;
3661 top = bottom;
3662 bottom = tmp;
3663 }
3664
3665 /* the region is for the rectangle interior, but only at right and bottom for some reason */
3666 right--;
3667 bottom--;
3668
3669 ellipse_width = min( right - left, abs( ellipse_width ));
3670 ellipse_height = min( bottom - top, abs( ellipse_height ));
3671
3672 /* Check if we can do a normal rectangle instead */
3673
3674 if ((ellipse_width < 2) || (ellipse_height < 2))
3676
3677 obj = REGION_AllocUserRgnWithHandle( ellipse_height );
3678 if (obj == NULL)
3679 return 0;
3680
3681 hrgn = obj->BaseObject.hHmgr;
3682
3683 obj->rdh.rcBound.left = left;
3684 obj->rdh.rcBound.top = top;
3685 obj->rdh.rcBound.right = right;
3686 obj->rdh.rcBound.bottom = bottom;
3687 rects = obj->Buffer;
3688
3689 /* based on an algorithm by Alois Zingl */
3690
3691 a = ellipse_width - 1;
3692 b = ellipse_height - 1;
3693 asq = (INT64)8 * a * a;
3694 bsq = (INT64)8 * b * b;
3695 dx = (INT64)4 * b * b * (1 - a);
3696 dy = (INT64)4 * a * a * (1 + (b % 2));
3697 err = dx + dy + a * a * (b % 2);
3698
3699 x = 0;
3700 y = ellipse_height / 2;
3701
3702 rects[y].left = left;
3703 rects[y].right = right;
3704
3705 while (x <= ellipse_width / 2)
3706 {
3707 INT64 e2 = 2 * err;
3708 if (e2 >= dx)
3709 {
3710 x++;
3711 err += dx += bsq;
3712 }
3713 if (e2 <= dy)
3714 {
3715 y++;
3716 err += dy += asq;
3717 rects[y].left = left + x;
3718 rects[y].right = right - x;
3719 }
3720 }
3721 for (i = 0; i < ellipse_height / 2; i++)
3722 {
3723 rects[i].left = rects[b - i].left;
3724 rects[i].right = rects[b - i].right;
3725 rects[i].top = top + i;
3726 rects[i].bottom = rects[i].top + 1;
3727 }
3728 for (; i < ellipse_height; i++)
3729 {
3730 rects[i].top = bottom - ellipse_height + i;
3731 rects[i].bottom = rects[i].top + 1;
3732 }
3733 rects[ellipse_height / 2].top = top + ellipse_height / 2; /* extend to top of rectangle */
3734
3736 return hrgn;
3737}
3739BOOL
3742 HRGN hSrcRgn1,
3743 HRGN hSrcRgn2)
3744{
3745 HRGN ahrgn[2];
3746 PREGION aprgn[2];
3747 PREGION rgn1, rgn2;
3748 PRECTL tRect1, tRect2;
3749 ULONG i;
3750 BOOL bRet = FALSE;
3751
3752 /* Check if we got 2 regions */
3753 if ((hSrcRgn1 == NULL) || (hSrcRgn2 == NULL))
3754 {
3755 return FALSE;
3756 }
3757
3758 /* Check if these are the same regions */
3759 if (hSrcRgn1 == hSrcRgn2)
3760 {
3761 /* Make sure this region is valid */
3763 GreIsHandleValid(hSrcRgn1))
3764 {
3765 return TRUE;
3766 }
3767 return FALSE;
3768 }
3769
3770 /* Lock both regions */
3771 ahrgn[0] = hSrcRgn1;
3772 ahrgn[1] = hSrcRgn2;
3774 {
3775 DPRINT1("NtGdiEqualRgn failed to lock regions: %p, %p\n",
3776 hSrcRgn1, hSrcRgn2);
3777 return FALSE;
3778 }
3779
3780 REGION_vSyncRegion(aprgn[0]);
3781 REGION_vSyncRegion(aprgn[1]);
3782
3783 rgn1 = aprgn[0];
3784 rgn2 = aprgn[1];
3785
3786 if (rgn1->rdh.nCount != rgn2->rdh.nCount)
3787 goto exit;
3788
3789 if (rgn1->rdh.nCount == 0)
3790 {
3791 bRet = TRUE;
3792 goto exit;
3793 }
3794
3795 if ((rgn1->rdh.rcBound.left != rgn2->rdh.rcBound.left) ||
3796 (rgn1->rdh.rcBound.right != rgn2->rdh.rcBound.right) ||
3797 (rgn1->rdh.rcBound.top != rgn2->rdh.rcBound.top) ||
3798 (rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom))
3799 goto exit;
3800
3801 tRect1 = rgn1->Buffer;
3802 tRect2 = rgn2->Buffer;
3803
3804 if ((tRect1 == NULL) || (tRect2 == NULL))
3805 goto exit;
3806
3807 for (i=0; i < rgn1->rdh.nCount; i++)
3808 {
3809 if ((tRect1[i].left != tRect2[i].left) ||
3810 (tRect1[i].right != tRect2[i].right) ||
3811 (tRect1[i].top != tRect2[i].top) ||
3812 (tRect1[i].bottom != tRect2[i].bottom))
3813 goto exit;
3814 }
3815
3816 bRet = TRUE;
3817
3818exit:
3819 REGION_UnlockRgn(rgn1);
3820 REGION_UnlockRgn(rgn2);
3821 return bRet;
3822}
3824HRGN
3827 OPTIONAL LPXFORM Xform,
3828 DWORD Count,
3829 LPRGNDATA RgnData)
3830{
3831 HRGN hRgn;
3833 DWORD nCount = 0;
3834 DWORD iType = 0;
3835 DWORD dwSize = 0;
3836 UINT i;
3837 RECT* rects;
3839 MATRIX matrix;
3840 XFORMOBJ xo;
3841
3842 DPRINT("NtGdiExtCreateRegion\n");
3843 _SEH2_TRY
3844 {
3845 ProbeForRead(RgnData, Count, 1);
3846 nCount = RgnData->rdh.nCount;
3847 iType = RgnData->rdh.iType;
3848 dwSize = RgnData->rdh.dwSize;
3849 rects = (RECT*)RgnData->Buffer;
3850 }
3852 {
3854 }
3855 _SEH2_END;
3856
3857 if (!NT_SUCCESS(Status))
3858 {
3860 return NULL;
3861 }
3862
3863 /* Check parameters, but don't set last error here */
3864 if ((Count < sizeof(RGNDATAHEADER) + nCount * sizeof(RECT)) ||
3865 (iType != RDH_RECTANGLES) ||
3866 (dwSize != sizeof(RGNDATAHEADER)))
3867 {
3868 return NULL;
3869 }
3870
3872
3873 if (Region == NULL)
3874 {
3876 return FALSE;
3877 }
3878 hRgn = Region->BaseObject.hHmgr;
3879
3880 _SEH2_TRY
3881 {
3882 /* Insert the rectangles one by one */
3883 for(i=0; i<nCount; i++)
3884 {
3885 if ( rects[i].left < rects[i].right && rects[i].top < rects[i].bottom )
3886 {
3887 if (!REGION_UnionRectWithRgn(Region, &rects[i]))
3888 {
3891 hRgn = NULL;
3893 }
3894 }
3895 }
3896
3897 if (Xform != NULL)
3898 {
3899 ULONG ret;
3900
3901 /* Init the XFORMOBJ from the Xform struct */
3903 XFORMOBJ_vInit(&xo, &matrix);
3904 ret = XFORMOBJ_iSetXform(&xo, (XFORML*)Xform);
3905
3906 /* Check for error */
3907 if (ret != DDI_ERROR)
3908 {
3909 /* Apply the coordinate transformation on the rects */
3910 if (XFORMOBJ_bApplyXform(&xo,
3911 XF_LTOL,
3912 Region->rdh.nCount * 2,
3913 Region->Buffer,
3914 Region->Buffer))
3915 {
3917 }
3918 }
3919 }
3920 }
3922 {
3924 }
3925 _SEH2_END;
3926 if (!NT_SUCCESS(Status))
3927 {
3931 return NULL;
3932 }
3933
3935
3936 return hRgn;
3937}
3939INT
3942 HRGN hRgn,
3943 PRECTL pRect)
3944{
3945 PREGION Rgn;
3946 RECTL SafeRect;
3947 DWORD ret;
3949
3950 Rgn = REGION_LockRgn(hRgn);
3951 if (Rgn == NULL)
3952 {
3953 return ERROR;
3954 }
3955
3956 ret = REGION_GetRgnBox(Rgn, &SafeRect);
3957 REGION_UnlockRgn(Rgn);
3958 if (ret == ERROR)
3959 {
3960 return ret;
3961 }
3962
3963 _SEH2_TRY
3964 {
3965 ProbeForWrite(pRect, sizeof(RECT), 1);
3966 *pRect = SafeRect;
3967 }
3969 {
3971 }
3972 _SEH2_END;
3973 if (!NT_SUCCESS(Status))
3974 {
3975 return ERROR;
3976 }
3977
3978 return ret;
3979}
3981INT
3984 _In_ HRGN hrgn,
3985 _In_ INT cx,
3986 _In_ INT cy)
3987{
3988 PREGION prgn;
3989 INT iResult;
3990
3991 DPRINT("NtGdiOffsetRgn: hrgn %p cx %d cy %d\n", hrgn, cx, cy);
3992
3993 /* Lock the region */
3994 prgn = REGION_LockRgn(hrgn);
3995 if (prgn == NULL)
3996 {
3997 DPRINT1("NtGdiOffsetRgn: failed to lock region %p\n", hrgn);
3998 return ERROR;
3999 }
4000
4001 /* Call the internal function */
4002 if (!REGION_bOffsetRgn(prgn, cx, cy))
4003 {
4004 iResult = ERROR;
4005 }
4006 else
4007 {
4008 iResult = REGION_Complexity(prgn);
4009 }
4010
4011 /* Unlock and return the result */
4012 REGION_UnlockRgn(prgn);
4013 return iResult;
4014}
4016BOOL
4019 _In_ HRGN hrgn,
4020 _In_ INT x,
4021 _In_ INT y)
4022{
4023 PREGION prgn;
4024 BOOL bResult;
4025
4026 /* Lock the region */
4027 prgn = REGION_LockRgn(hrgn);
4028 if (prgn == NULL)
4029 {
4030 DPRINT1("NtGdiPtInRegion: hrgn error\n");
4031 return FALSE;
4032 }
4033
4034 /* Call the internal function */
4035 bResult = REGION_PtInRegion(prgn, x, y);
4036
4037 /* Unlock and return the result */
4038 REGION_UnlockRgn(prgn);
4039 return bResult;
4040}
4041
4043BOOL
4046 _In_ HRGN hrgn,
4047 _Inout_ LPRECT prclUnsafe)
4048{
4049 RECTL rcTemp;
4050
4051 /* Probe and copy the rect */
4052 _SEH2_TRY
4053 {
4054 ProbeForRead(prclUnsafe, sizeof(RECT), 1);
4055 rcTemp = *prclUnsafe;
4056 }
4058 {
4059 DPRINT1("NtGdiRectInRegion: Exception accessing the rect\n");
4060 return FALSE;
4061 }
4062 _SEH2_END;
4063
4064 /* Call the internal function */
4065 return IntRectInRegion(hrgn, &rcTemp);
4066}
4068BOOL
4071 _In_ HRGN hrgn,
4072 _In_ INT xLeft,
4073 _In_ INT yTop,
4074 _In_ INT xRight,
4075 _In_ INT yBottom)
4076{
4077 PREGION prgn;
4078
4079 /* Lock the region */
4080 prgn = REGION_LockRgn(hrgn);
4081 if (prgn == NULL)
4082 {
4083 return FALSE;
4084 }
4085
4086 /* Call the internal API */
4087 REGION_SetRectRgn(prgn, xLeft, yTop, xRight, yBottom);
4088
4089 /* Unlock the region and return success */
4090 REGION_UnlockRgn(prgn);
4091 return TRUE;
4092}
4093
4104_Success_(return!=0)
4106ULONG
4108NtGdiGetRegionData(
4109 _In_ HRGN hrgn,
4112{
4113 ULONG cjRects, cjSize;
4114 PREGION prgn;
4115
4116 /* Lock the region */
4117 prgn = REGION_LockRgn(hrgn);
4118 if (prgn == NULL)
4119 {
4121 return 0;
4122 }
4123
4124 /* Calculate the region sizes */
4125 cjRects = prgn->rdh.nCount * sizeof(RECT);
4126 cjSize = cjRects + sizeof(RGNDATAHEADER);
4127
4128 /* Check if region data is requested */
4129 if (lpRgnData)
4130 {
4131 /* Check if the buffer is large enough */
4132 if (cjBuffer >= cjSize)
4133 {
4134 /* Probe the buffer and copy the data */
4135 _SEH2_TRY
4136 {
4137 ProbeForWrite(lpRgnData, cjSize, sizeof(ULONG));
4138 RtlCopyMemory(lpRgnData, &prgn->rdh, sizeof(RGNDATAHEADER));
4139 RtlCopyMemory(lpRgnData->Buffer, prgn->Buffer, cjRects);
4140 lpRgnData->rdh.iType = RDH_RECTANGLES;
4141 lpRgnData->rdh.nRgnSize = cjRects;
4142 }
4144 {
4146 cjSize = 0;
4147 }
4148 _SEH2_END;
4149 }
4150 else
4151 {
4152 /* Buffer is too small */
4154 cjSize = 0;
4155 }
4156 }
4157
4158 /* Unlock the region and return the size */
4159 REGION_UnlockRgn(prgn);
4160 return cjSize;
4161}
4162
4163/* EOF */
static HRGN hrgn
signed long long INT64
#define VOID
Definition: acefi.h:82
struct _RGNDATAHEADER RGNDATAHEADER
LONG NTSTATUS
Definition: precomp.h:26
#define WINDING
Definition: constants.h:279
#define ALTERNATE
Definition: constants.h:278
#define DPRINT1
Definition: precomp.h:8
static LPHIST_ENTRY Bottom
Definition: history.c:54
static LPHIST_ENTRY Top
Definition: history.c:53
return
Definition: dirsup.c:529
HGDIOBJ hHmgr(VOID)
Definition: baseobj.hpp:95
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define APIENTRY
Definition: api.h:79
#define Y(I)
static const WCHAR empty[]
Definition: main.c:47
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
static const WCHAR Cleanup[]
Definition: register.c:80
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
#define ERROR(name)
Definition: error_private.h:53
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
#define abs(i)
Definition: fconv.c:206
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define _SEH2_LEAVE
Definition: filesup.c:20
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
size_t total
#define GDI_HANDLE_GET_TYPE(h)
Definition: gdi.h:31
@ GDILoObjType_LO_REGION_TYPE
Definition: gdi_private.h:38
@ BASEFLAG_LOOKASIDE
Definition: gdiobj.h:58
Status
Definition: gdiplustypes.h:25
VOID NTAPI GdiPoolFree(PGDI_POOL pPool, PVOID pvAlloc)
Definition: gdipool.c:233
PVOID NTAPI GdiPoolAllocate(PGDI_POOL pPool)
Definition: gdipool.c:122
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLenum src
Definition: glext.h:6340
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
GLdouble GLdouble right
Definition: glext.h:10859
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLuint GLenum matrix
Definition: glext.h:9407
GLint left
Definition: glext.h:7726
GLenum GLenum dst
Definition: glext.h:6340
GLint GLint bottom
Definition: glext.h:7726
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
const GLfloat * m
Definition: glext.h:10848
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define DbgPrint
Definition: hal.h:12
static int reg
Definition: i386-dis.c:1290
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
JSAMPARRAY scanlines
Definition: jpeglib.h:1016
#define d
Definition: ke_i.h:81
#define a
Definition: ke_i.h:78
#define b
Definition: ke_i.h:79
GLint dy
Definition: linetemp.h:97
GLint dx
Definition: linetemp.h:97
@ ET
Definition: bidi.c:79
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
#define for
Definition: utility.h:88
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
static DNS_RECORDW r1
Definition: record.c:37
static DNS_RECORDW r2
Definition: record.c:38
static HRGN hRgn
Definition: mapping.c:33
#define min(a, b)
Definition: monoChain.cc:55
#define _Success_(expr)
Definition: ms_sal.h:259
#define _Inout_
Definition: ms_sal.h:378
#define _Out_writes_bytes_to_opt_(size, count)
Definition: ms_sal.h:361
#define _In_
Definition: ms_sal.h:308
unsigned int UINT
Definition: ndis.h:50
int Count
Definition: noreturn.cpp:7
#define BOOL
Definition: nt_native.h:43
#define FASTCALL
Definition: nt_native.h:50
__kernel_entry W32KAPI INT APIENTRY NtGdiCombineRgn(_In_ HRGN hrgnDst, _In_ HRGN hrgnSrc1, _In_opt_ HRGN hrgnSrc2, _In_ INT iMode)
__kernel_entry W32KAPI BOOL APIENTRY NtGdiSetRectRgn(_In_ HRGN hrgn, _In_ INT xLeft, _In_ INT yTop, _In_ INT xRight, _In_ INT yBottom)
Definition: region.c:4067
__kernel_entry W32KAPI BOOL APIENTRY NtGdiRectInRegion(_In_ HRGN hrgn, _Inout_ LPRECT prcl)
Definition: region.c:4042
__kernel_entry W32KAPI BOOL APIENTRY NtGdiPtInRegion(_In_ HRGN hrgn, _In_ INT x, _In_ INT y)
Definition: region.c:4015
__kernel_entry W32KAPI HRGN APIENTRY NtGdiCreateEllipticRgn(_In_ INT xLeft, _In_ INT yTop, _In_ INT xRight, _In_ INT yBottom)
__kernel_entry W32KAPI HRGN APIENTRY NtGdiExtCreateRegion(_In_opt_ LPXFORM px, _In_ DWORD cj, _In_reads_bytes_(cj) LPRGNDATA prgndata)
__kernel_entry W32KAPI HRGN APIENTRY NtGdiCreateRectRgn(_In_ INT xLeft, _In_ INT yTop, _In_ INT xRight, _In_ INT yBottom)
_In_ ULONG cjBuffer
Definition: ntgdi.h:2860
__kernel_entry W32KAPI INT APIENTRY NtGdiOffsetRgn(_In_ HRGN hrgn, _In_ INT cx, _In_ INT cy)
Definition: region.c:3980
#define GDI_OBJ_HMGR_POWNED
Definition: ntgdihdl.h:117
#define ATTR_RGN_VALID
Definition: ntgdihdl.h:195
#define ATTR_RGN_DIRTY
Definition: ntgdihdl.h:196
@ XFORM_SCALE
Definition: ntgdityp.h:106
@ XFORM_UNITY
Definition: ntgdityp.h:107
@ GDIObjType_RGN_TYPE
Definition: ntgdityp.h:124
PVOID NTAPI PsGetCurrentProcessWin32Process(VOID)
Definition: process.c:1183
long LONG
Definition: pedump.c:60
#define INT
Definition: polytest.cpp:20
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
_Out_opt_ int * cx
Definition: commctrl.h:585
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define err(...)
struct _REGION * PREGION
static calc_node_t temp
Definition: rpn_ieee.c:38
#define exit(n)
Definition: config.h:202
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
#define __kernel_entry
Definition: specstrings.h:355
& rect
Definition: startmenu.cpp:1413
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
INT minor_axis
Definition: region.c:246
Definition: matrix.h:44
long bottom
Definition: polytest.cpp:53
long right
Definition: polytest.cpp:53
long top
Definition: polytest.cpp:53
long left
Definition: polytest.cpp:53
Definition: region.c:315
BRESINFO bres
Definition: region.c:317
struct _EDGE_TABLE_ENTRY * nextWETE
Definition: region.c:320
INT ClockWise
Definition: region.c:321
INT ymax
Definition: region.c:316
struct _EDGE_TABLE_ENTRY * back
Definition: region.c:319
struct _EDGE_TABLE_ENTRY * next
Definition: region.c:318
struct _POINTBLOCK * next
Definition: region.c:529
POINT pts[NUMPTSTOBUFFER]
Definition: region.c:528
struct _GDI_POOL * pPoolRgnAttr
Definition: win32.h:293
Definition: windef.h:314
Definition: region.h:8
RGN_ATTR rgnattr
Definition: region.h:13
_Notnull_ PRGN_ATTR prgnattr
Definition: region.h:12
RECTL * Buffer
Definition: region.h:16
RGNDATAHEADER rdh
Definition: region.h:15
BASEOBJECT BaseObject
Definition: region.h:11
RGNDATAHEADER rdh
Definition: axextend.idl:399
char Buffer[1]
Definition: axextend.idl:400
ULONG iComplexity
Definition: ntgdihdl.h:257
RECTL Rect
Definition: ntgdihdl.h:258
ULONG AttrFlags
Definition: ntgdihdl.h:256
struct _SCANLINE_LISTBLOCK * next
Definition: region.c:351
SCANLINE_LIST SLLs[SLLSPERBLOCK]
Definition: region.c:350
struct _SCANLINE_LIST * next
Definition: region.c:329
EDGE_TABLE_ENTRY * edgelist
Definition: region.c:328
INT scanline
Definition: region.c:327
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
#define _PRAGMA_WARNING_SUPPRESS(x)
Definition: suppress.h:28
#define __WARNING_MAYBE_UNINIT_VAR
Definition: suppress.h:598
#define max(a, b)
Definition: svc.c:63
#define MAXULONG
Definition: typedefs.h:251
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
int32_t INT
Definition: typedefs.h:58
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define MAXLONG
Definition: umtypes.h:116
#define MINLONG
Definition: umtypes.h:115
int ret
#define FORCEINLINE
Definition: wdftypes.h:67
VOID FASTCALL SetLastNtError(NTSTATUS Status)
Definition: error.c:37
#define POINT
Definition: precomp.h:30
#define PRECT
Definition: precomp.h:27
#define RECT
Definition: precomp.h:26
#define MAX_COORD
Definition: region.c:12
#define INRECT(r, x, y)
Definition: region.c:14
#define MIN_COORD
Definition: region.c:11
BOOL NTAPI GreSetObjectOwner(HGDIOBJ hobj, ULONG ulOwner)
Definition: gdiobj.c:1255
VOID NTAPI GDIOBJ_vFreeObject(POBJ pobj)
Definition: gdiobj.c:596
HGDIOBJ NTAPI GDIOBJ_hInsertObject(POBJ pobj, ULONG ulOwner)
Definition: gdiobj.c:912
VOID NTAPI GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr)
Definition: gdiobj.c:1096
BOOL NTAPI GreDeleteObject(HGDIOBJ hobj)
Definition: gdiobj.c:1158
BOOL NTAPI GDIOBJ_bLockMultipleObjects(IN ULONG ulCount, IN HGDIOBJ *ahObj, OUT PGDIOBJ *apObj, IN UCHAR objt)
Definition: gdiobj.c:1031
PGDIOBJ NTAPI GDIOBJ_LockObject(HGDIOBJ hobj, UCHAR objt)
Definition: gdiobj.c:826
ULONG NTAPI GreGetObjectOwner(HGDIOBJ hobj)
Definition: gdiobj.c:1192
POBJ NTAPI GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl)
Definition: gdiobj.c:562
BOOL NTAPI GreIsHandleValid(HGDIOBJ hobj)
Definition: gdiobj.c:1146
VOID NTAPI GDIOBJ_vUnlockObject(POBJ pobj)
Definition: gdiobj.c:880
VOID NTAPI GDIOBJ_vDeleteObject(POBJ pobj)
Definition: gdiobj.c:1111
VOID FASTCALL RECTL_vMakeWellOrdered(_Inout_ RECTL *prcl)
Definition: rect.c:81
BOOL FASTCALL RECTL_bUnionRect(_Out_ RECTL *prclDst, _In_ const RECTL *prcl1, _In_ const RECTL *prcl2)
Definition: rect.c:18
FORCEINLINE VOID RECTL_vSetEmptyRect(_Out_ RECTL *prcl)
Definition: rect.h:20
INT FASTCALL REGION_Complexity(PREGION prgn)
Definition: region.c:564
static VOID FASTCALL REGION_CreateETandAET(const ULONG *Count, INT nbpolygons, const POINT *pts, EDGE_TABLE *ET, EDGE_TABLE_ENTRY *AET, EDGE_TABLE_ENTRY *pETEs, SCANLINE_LISTBLOCK *pSLLBlock)
Definition: region.c:3186
HRGN APIENTRY NtGdiCreateRoundRectRgn(INT left, INT top, INT right, INT bottom, INT ellipse_width, INT ellipse_height)
Definition: region.c:3633
PREGION prgnDefault
Definition: region.c:130
static BOOL REGION_bGrowBufferSize(_Inout_ PREGION prgn, _In_ UINT cRects)
Definition: region.c:415
struct _EDGE_TABLE_ENTRY EDGE_TABLE_ENTRY
static INT FASTCALL REGION_PtsToRegion(INT numFullPtBlocks, INT iCurPtBlock, POINTBLOCK *FirstPtBlock, PREGION reg)
Definition: region.c:3060
VOID FASTCALL REGION_Delete(PREGION pRgn)
Definition: region.c:2465
BOOL FASTCALL REGION_UnionRectWithRgn(PREGION rgn, const RECTL *rect)
Definition: region.c:1809
static BOOL REGION_bMakeSimpleFrameRgn(_Inout_ PREGION prgn, _In_ PRECTL prclSrc, _In_ INT cx, _In_ INT cy)
Definition: region.c:1862
BOOL FASTCALL IntRectInRegion(HRGN hRgn, LPRECTL rc)
Definition: region.c:3506
struct _POINTBLOCK POINTBLOCK
#define SMALL_COORDINATE
Definition: region.c:411
PREGION FASTCALL REGION_LockRgn(_In_ HRGN hrgn)
Definition: region.c:2374
#define LARGE_COORDINATE
Definition: region.c:410
#define COPY_RECTS(dest, src, nRects)
Definition: region.c:136
static VOID FASTCALL REGION_FreeStorage(SCANLINE_LISTBLOCK *pSLLBlock)
Definition: region.c:3038
static BOOL FASTCALL REGION_UnionRegion(PREGION newReg, PREGION reg1, PREGION reg2)
Definition: region.c:1475
struct _SCANLINE_LIST SCANLINE_LIST
BOOL FASTCALL REGION_bXformRgn(_Inout_ PREGION prgn, _In_ PMATRIX pmx)
Definition: region.c:2079
BOOL FASTCALL REGION_RectInRegion(PREGION Rgn, const RECTL *rect)
Definition: region.c:2622
static BOOL FASTCALL REGION_UnionO(PREGION pReg, PRECTL r1, PRECTL r1End, PRECTL r2, PRECTL r2End, INT top, INT bottom)
Definition: region.c:1425
static BOOL FASTCALL REGION_XorRegion(PREGION dr, PREGION sra, PREGION srb)
Definition: region.c:1765
BOOL FASTCALL IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
Definition: region.c:2475
#define EXTENTCHECK(r1, r2)
Definition: region.c:167
BOOL FASTCALL REGION_SetPolyPolygonRgn(_Inout_ PREGION prgn, _In_ const POINT *ppt, _In_ const ULONG *pcPoints, _In_ ULONG cPolygons, _In_ INT iMode)
Definition: region.c:3272
BOOL APIENTRY NtGdiEqualRgn(HRGN hSrcRgn1, HRGN hSrcRgn2)
Definition: region.c:3738
static BOOL FASTCALL REGION_SubtractO(PREGION pReg, PRECTL r1, PRECTL r1End, PRECTL r2, PRECTL r2End, INT top, INT bottom)
Definition: region.c:1612
static BOOL FASTCALL REGION_SubtractNonO1(PREGION pReg, PRECTL r, PRECTL rEnd, INT top, INT bottom)
Definition: region.c:1572
static VOID FASTCALL REGION_SetExtents(PREGION pReg)
Definition: region.c:627
BOOL NTAPI REGION_bAllocRgnAttr(PREGION prgn)
Definition: region.c:2276
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
Definition: region.c:390
VOID FASTCALL REGION_SetRectRgn(PREGION rgn, INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
Definition: region.c:2682
INT FASTCALL REGION_CropRegion(PREGION rgnDst, PREGION rgnSrc, const RECTL *rect)
Definition: region.c:675
#define EMPTY_REGION(pReg)
Definition: region.c:149
#define NUMPTSTOBUFFER
Definition: region.c:521
static VOID FASTCALL REGION_loadAET(EDGE_TABLE_ENTRY *AET, EDGE_TABLE_ENTRY *ETEs)
Definition: region.c:2901
INT APIENTRY IntGdiGetRgnBox(HRGN hRgn, PRECTL pRect)
Definition: region.c:2577
BOOL(FASTCALL * nonOverlapProcp)(PREGION, PRECT, PRECT, INT, INT)
Definition: region.c:518
VOID FASTCALL REGION_UnlockRgn(_In_ PREGION prgn)
Definition: region.c:2389
static VOID FASTCALL REGION_InsertEdgeInET(EDGE_TABLE *ET, EDGE_TABLE_ENTRY *ETE, INT scanline, SCANLINE_LISTBLOCK **SLLBlock, INT *iSLLBlock)
Definition: region.c:2823
INT FASTCALL REGION_SubtractRectFromRgn(PREGION prgnDest, PREGION prgnSrc, const RECTL *prcl)
Definition: region.c:1824
struct _SCANLINE_LISTBLOCK SCANLINE_LISTBLOCK
BOOL FASTCALL REGION_PtInRegion(PREGION prgn, INT X, INT Y)
Definition: region.c:2599
HRGN NTAPI GreCreatePolyPolygonRgn(_In_ const POINT *ppt, _In_ const ULONG *pcPoints, _In_ ULONG cPolygons, _In_ INT iMode)
Definition: region.c:3470
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres)
Definition: region.c:253
#define SLLSPERBLOCK
Definition: region.c:346
static BOOL FASTCALL REGION_IntersectO(PREGION pReg, PRECTL r1, PRECTL r1End, PRECTL r2, PRECTL r2End, INT top, INT bottom)
Definition: region.c:1247
static BOOL FASTCALL REGION_IntersectRegion(PREGION newReg, PREGION reg1, PREGION reg2)
Definition: region.c:1303
INT FASTCALL REGION_GetRgnBox(PREGION Rgn, PRECTL pRect)
Definition: region.c:2559
BOOL(FASTCALL * overlapProcp)(PREGION, PRECT, PRECT, PRECT, PRECT, INT, INT)
Definition: region.c:517
static BOOL FASTCALL REGION_RegionOp(PREGION newReg, PREGION reg1, PREGION reg2, overlapProcp overlapFunc, nonOverlapProcp nonOverlap1Func, nonOverlapProcp nonOverlap2Func)
Definition: region.c:957
FORCEINLINE VOID REGION_vAddRect(_Inout_ PREGION prgn, _In_ LONG left, _In_ LONG top, _In_ LONG right, _In_ LONG bottom)
Definition: region.c:481
static VOID FASTCALL REGION_computeWAET(EDGE_TABLE_ENTRY *AET)
Definition: region.c:2954
BOOL FASTCALL REGION_bCopy(PREGION dst, PREGION src)
Definition: region.c:1841
PREGION FASTCALL IntSysCreateRectpRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
Definition: region.c:2423
static __inline BOOL REGION_bAddRect(_Inout_ PREGION prgn, _In_ LONG left, _In_ LONG top, _In_ LONG right, _In_ LONG bottom)
Definition: region.c:501
static VOID REGION_vSyncRegion(_In_ PREGION prgn)
Definition: region.c:2331
static __inline BOOL REGION_bMergeRect(_Inout_ PREGION prgn, _In_ LONG left, _In_ LONG top, _In_ LONG right, _In_ LONG bottom)
Definition: region.c:1382
PREGION FASTCALL REGION_AllocUserRgnWithHandle(INT nRgn)
Definition: region.c:2310
static INT FASTCALL REGION_Coalesce(PREGION pReg, INT prevStart, INT curStart)
Definition: region.c:819
#define REGION_NOT_EMPTY(pReg)
Definition: region.c:156
PREGION FASTCALL REGION_AllocRgnWithHandle(INT nReg)
Definition: region.c:2216
static BOOL FASTCALL REGION_InsertionSort(EDGE_TABLE_ENTRY *AET)
Definition: region.c:2995
static BOOL FASTCALL REGION_UnionNonO(PREGION pReg, PRECTL r, PRECTL rEnd, INT top, INT bottom)
Definition: region.c:1355
HRGN FASTCALL GreCreateFrameRgn(HRGN hrgn, INT cx, INT cy)
Definition: region.c:2038
static __inline BOOL REGION_bEnsureBufferSize(_Inout_ PREGION prgn, _In_ UINT cRects)
Definition: region.c:465
static BOOL FASTCALL REGION_SubtractRegion(PREGION regD, PREGION regM, PREGION regS)
Definition: region.c:1729
BOOL FASTCALL REGION_bOffsetRgn(_Inout_ PREGION prgn, _In_ INT cx, _In_ INT cy)
Definition: region.c:2724
HRGN hrgnDefault
Definition: region.c:131
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
Definition: region.c:367
static BOOL REGION_bMakeFrameRegion(_Inout_ PREGION prgnDest, _Inout_ PREGION prgnSrc, _In_ INT cx, _In_ INT cy)
Definition: region.c:1953
static BOOL FASTCALL REGION_CopyRegion(PREGION dst, PREGION src)
Definition: region.c:584
INT FASTCALL IntGdiCombineRgn(PREGION prgnDest, PREGION prgnSrc1, PREGION prgnSrc2, INT iCombineMode)
Definition: region.c:2503
BOOL FASTCALL REGION_bIntersectRegion(PREGION newReg, PREGION reg1, PREGION reg2)
Definition: region.c:1851
VOID NTAPI REGION_vCleanup(PVOID ObjectBody)
Definition: region.c:2449
INT APIENTRY NtGdiGetRgnBox(HRGN hRgn, PRECTL pRect)
Definition: region.c:3938
#define GDITAG_REGION
Definition: tags.h:158
#define TAG_REGION
Definition: tags.h:22
#define XF_LTOL
Definition: winddi.h:3109
#define DDI_ERROR
Definition: winddi.h:154
_In_ SURFOBJ _In_ CLIPOBJ _In_opt_ XLATEOBJ _In_ RECTL _In_ RECTL * prclSrc
Definition: winddi.h:3418
_In_ ULONG iMode
Definition: winddi.h:3520
_In_ ULONG _In_ CLIPOBJ _In_ RECTL * prcl
Definition: winddi.h:3531
ENGAPI VOID APIENTRY EngSetLastError(_In_ ULONG iError)
Definition: error.c:28
_In_ ULONG iType
Definition: winddi.h:3748
_In_ HANDLE hrgnSrc1
Definition: winddi.h:4295
_In_ ULONG cjSize
Definition: winddi.h:3634
_In_ HANDLE _In_ HANDLE hrgnSrc2
Definition: winddi.h:4296
#define COMPLEXREGION
Definition: wingdi.h:363
#define RGN_DIFF
Definition: wingdi.h:358
#define NULLREGION
Definition: wingdi.h:361
#define RDH_RECTANGLES
Definition: wingdi.h:669
#define RGN_COPY
Definition: wingdi.h:357
#define RGN_AND
Definition: wingdi.h:356
#define SIMPLEREGION
Definition: wingdi.h:362
#define RGN_XOR
Definition: wingdi.h:360
#define RGN_OR
Definition: wingdi.h:359
#define NT_ASSERT
Definition: rtlfuncs.h:3310
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3287
#define XFORMOBJ_iSetXform
Definition: xformobj.h:14
#define XFORMOBJ_vInit
Definition: xformobj.h:12
#define XFORMOBJ_bApplyXform
Definition: xformobj.h:11