ReactOS  0.4.14-dev-52-g6116262
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 
45 Copyright (c) 1987, 1988 X Consortium
46 
47 Permission is hereby granted, free of charge, to any person obtaining a copy
48 of this software and associated documentation files (the "Software"), to deal
49 in the Software without restriction, including without limitation the rights
50 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51 copies of the Software, and to permit persons to whom the Software is
52 furnished to do so, subject to the following conditions:
53 
54 The above copyright notice and this permission notice shall be included in
55 all copies or substantial portions of the Software.
56 
57 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
61 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
62 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
63 
64 Except as contained in this notice, the name of the X Consortium shall not be
65 used in advertising or otherwise to promote the sale, use or other dealings
66 in this Software without prior written authorization from the X Consortium.
67 
68 
69 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
70 
71  All Rights Reserved
72 
73 Permission to use, copy, modify, and distribute this software and its
74 documentation for any purpose and without fee is hereby granted,
75 provided that the above copyright notice appear in all copies and that
76 both that copyright notice and this permission notice appear in
77 supporting documentation, and that the name of Digital not be
78 used in advertising or publicity pertaining to distribution of the
79 software without specific, written prior permission.
80 
81 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
82 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
83 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
84 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
85 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
86 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
87 SOFTWARE.
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  */
247 typedef struct
248 {
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 */
253 } BRESINFO;
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 
311 /*
312  * For the winding number rule
313  */
314 #define CLOCKWISE 1
315 #define COUNTERCLOCKWISE -1
316 
317 typedef struct _EDGE_TABLE_ENTRY
318 {
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 
327 
328 typedef struct _SCANLINE_LIST
329 {
330  INT scanline; /* The scanline represented */
331  EDGE_TABLE_ENTRY *edgelist; /* Header node */
332  struct _SCANLINE_LIST *next; /* Next in the list */
333 } SCANLINE_LIST;
334 
335 
336 typedef struct
337 {
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
350 
351 typedef struct _SCANLINE_LISTBLOCK
352 {
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
410  *
411  *************************************************************************/
412 
413 #define LARGE_COORDINATE INT_MAX
414 #define SMALL_COORDINATE INT_MIN
415 
416 static
417 BOOL
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 }
465 
466 static __inline
467 BOOL
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 }
481 
483 VOID
485  _Inout_ PREGION prgn,
486  _In_ LONG left,
487  _In_ LONG top,
488  _In_ LONG right,
489  _In_ LONG bottom)
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 }
501 
502 static __inline
503 BOOL
505  _Inout_ PREGION prgn,
506  _In_ LONG left,
507  _In_ LONG top,
508  _In_ LONG right,
509  _In_ LONG bottom)
510 {
511  if (!REGION_bEnsureBufferSize(prgn, prgn->rdh.nCount + 1))
512  {
513  return FALSE;
514  }
515 
516  REGION_vAddRect(prgn, left, top, right, bottom);
517  return TRUE;
518 }
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
529 typedef struct _POINTBLOCK
530 {
532  struct _POINTBLOCK *next;
533 } POINTBLOCK;
534 
535 #ifndef NDEBUG
536 /*
537  * This function is left there for debugging purposes.
538  */
539 VOID
540 FASTCALL
541 IntDumpRegion(HRGN hRgn)
542 {
543  PREGION Data;
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 
564 
565 INT
566 FASTCALL
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 
584 static
585 BOOL
586 FASTCALL
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))
608  ExFreePoolWithTag(dst->Buffer, TAG_REGION);
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 
627 static
628 VOID
629 FASTCALL
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  */
676 INT
677 FASTCALL
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;
688  INT bottom = MINLONG;
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 
794 empty:
795  if (rgnDst->Buffer == NULL)
796  {
797  rgnDst->Buffer = &rgnDst->rdh.rcBound;
798  }
799 
800  EMPTY_REGION(rgnDst);
801  return NULLREGION;
802 }
803 
804 
819 static
820 INT
821 FASTCALL
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 
957 static
958 BOOL
959 FASTCALL
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 
1247 static
1248 BOOL
1249 FASTCALL
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  */
1303 static
1304 BOOL
1305 FASTCALL
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 
1355 static
1356 BOOL
1357 FASTCALL
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 }
1382 
1383 static __inline
1384 BOOL
1386  _Inout_ PREGION prgn,
1387  _In_ LONG left,
1388  _In_ LONG top,
1389  _In_ LONG right,
1390  _In_ LONG bottom)
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 
1425 static
1426 BOOL
1427 FASTCALL
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  */
1475 static
1476 BOOL
1477 FASTCALL
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,
1545  REGION_UnionO,
1547  REGION_UnionNonO)))
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 
1572 static
1573 BOOL
1574 FASTCALL
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 
1612 static
1613 BOOL
1614 FASTCALL
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 
1729 static
1730 BOOL
1731 FASTCALL
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  */
1765 static
1766 BOOL
1767 FASTCALL
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 
1810 BOOL
1811 FASTCALL
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 }
1824 
1825 INT
1826 FASTCALL
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 }
1841 
1842 BOOL
1843 FASTCALL
1845  PREGION dst,
1846  PREGION src)
1847 {
1848  if ( !dst || !src ) return FALSE;
1849  return REGION_CopyRegion( dst, src);
1850 }
1851 
1852 BOOL
1853 FASTCALL
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 }
1862 
1863 static
1864 BOOL
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 }
1953 
1954 static
1955 BOOL
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 }
2038 
2039 HRGN
2040 FASTCALL
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 }
2079 
2080 BOOL
2081 FASTCALL
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! */
2127  NT_ASSERT(FALSE);
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 
2216 
2217 PREGION
2218 FASTCALL
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 }
2276 
2277 BOOL
2278 NTAPI
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.
2310 //
2311 PREGION
2312 FASTCALL
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 }
2331 
2332 static
2333 VOID
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");
2367  NT_ASSERT(FALSE);
2368  }
2369  }
2370 
2371  /* Reset the flags */
2372  prgnattr->AttrFlags &= ~(ATTR_RGN_DIRTY | ATTR_RGN_VALID);
2373 }
2374 
2375 PREGION
2376 FASTCALL
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 }
2389 
2390 VOID
2391 FASTCALL
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
2423 //
2424 PREGION
2425 FASTCALL
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 }
2449 
2450 VOID
2451 NTAPI
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 }
2465 
2466 VOID
2467 FASTCALL
2469 {
2470  if (pRgn == prgnDefault)
2471  return;
2472 
2474 }
2475 
2476 BOOL
2477 FASTCALL
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 }
2503 
2504 INT
2505 FASTCALL
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 }
2559 
2560 INT
2561 FASTCALL
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 }
2577 
2578 INT
2579 APIENTRY
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 
2599 
2600 BOOL
2601 FASTCALL
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 }
2622 
2623 BOOL
2624 FASTCALL
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 }
2682 
2683 VOID
2684 FASTCALL
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 }
2724 
2725 BOOL
2726 FASTCALL
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  */
2823 static
2824 VOID
2825 FASTCALL
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  */
2901 static
2902 VOID
2903 FASTCALL
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  */
2954 static
2955 VOID
2956 FASTCALL
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  */
2995 static
2996 BOOL
2997 FASTCALL
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  */
3038 static
3039 VOID
3040 FASTCALL
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  */
3060 static
3061 INT
3062 FASTCALL
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)
3096  ExFreePoolWithTag(reg->Buffer, TAG_REGION);
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  */
3186 static
3187 VOID
3188 FASTCALL
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 }
3272 
3273 BOOL
3274 FASTCALL
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 
3299  /* Check if iMode is valid */
3300  if ((iMode != ALTERNATE) && (iMode != WINDING))
3301  {
3302  DPRINT1("Invalid iMode: %lu\n", iMode);
3303  return FALSE;
3304  }
3305 
3306  /* Special case a rectangle */
3307  if (((cPolygons == 1) && ((pcPoints[0] == 4) ||
3308  ((pcPoints[0] == 5) && (ppt[4].x == ppt[0].x) && (ppt[4].y == ppt[0].y)))) &&
3309  (((ppt[0].y == ppt[1].y) &&
3310  (ppt[1].x == ppt[2].x) &&
3311  (ppt[2].y == ppt[3].y) &&
3312  (ppt[3].x == ppt[0].x)) ||
3313  ((ppt[0].x == ppt[1].x) &&
3314  (ppt[1].y == ppt[2].y) &&
3315  (ppt[2].x == ppt[3].x) &&
3316  (ppt[3].y == ppt[0].y))))
3317  {
3318  REGION_SetRectRgn(prgn,
3319  min(ppt[0].x, ppt[2].x),
3320  min(ppt[0].y, ppt[2].y),
3321  max(ppt[0].x, ppt[2].x),
3322  max(ppt[0].y, ppt[2].y));
3323  return TRUE;
3324  }
3325 
3326  for (poly = total = 0; poly < cPolygons; poly++)
3327  total += pcPoints[poly];
3328 
3330  sizeof(EDGE_TABLE_ENTRY) * total,
3331  TAG_REGION);
3332  if (pETEs == NULL)
3333  {
3334  DPRINT1("Failed to allocate %lu edge entries\n", total);
3335  return FALSE;
3336  }
3337 
3338  pts = FirstPtBlock.pts;
3339  REGION_CreateETandAET(pcPoints, cPolygons, ppt, &ET, &AET, pETEs, &SLLBlock);
3340  pSLL = ET.scanlines.next;
3341  curPtBlock = &FirstPtBlock;
3342 
3343  if (iMode != WINDING)
3344  {
3345  /* For each scanline */
3346  for (y = ET.ymin; y < ET.ymax; y++)
3347  {
3348  /* Add a new edge to the active edge table when we
3349  * get to the next edge. */
3350  if (pSLL != NULL && y == pSLL->scanline)
3351  {
3352  REGION_loadAET(&AET, pSLL->edgelist);
3353  pSLL = pSLL->next;
3354  }
3355  pPrevAET = &AET;
3356  pAET = AET.next;
3357 
3358  /* For each active edge */
3359  while (pAET)
3360  {
3361  pts->x = pAET->bres.minor_axis, pts->y = y;
3362  pts++, iPts++;
3363 
3364  /* Send out the buffer */
3365  if (iPts == NUMPTSTOBUFFER)
3366  {
3367  tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
3368  sizeof(POINTBLOCK),
3369  TAG_REGION);
3370  if (tmpPtBlock == NULL)
3371  {
3372  DPRINT1("Can't alloc tmpPtBlock\n");
3373  ExFreePoolWithTag(pETEs, TAG_REGION);
3374  return FALSE;
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 
3387  REGION_InsertionSort(&AET);
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  ExFreePoolWithTag(pETEs, TAG_REGION);
3430  return FALSE;
3431  }
3432  curPtBlock->next = tmpPtBlock;
3433  curPtBlock = tmpPtBlock;
3434  pts = curPtBlock->pts;
3435  numFullPtBlocks++;
3436  iPts = 0;
3437  }
3438 
3439  pWETE = pWETE->nextWETE;
3440  }
3441 
3442  EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
3443  }
3444 
3445  /* Recompute the winding active edge table if
3446  * we just resorted or have exited an edge. */
3447  if (REGION_InsertionSort(&AET) || fixWAET)
3448  {
3449  REGION_computeWAET(&AET);
3450  fixWAET = FALSE;
3451  }
3452  }
3453  }
3454 
3455  REGION_FreeStorage(SLLBlock.next);
3456  REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, prgn);
3457 
3458  for (curPtBlock = FirstPtBlock.next; numFullPtBlocks-- > 0;)
3459  {
3460  tmpPtBlock = curPtBlock->next;
3461  ExFreePoolWithTag(curPtBlock, TAG_REGION);
3462  curPtBlock = tmpPtBlock;
3463  }
3464 
3465  ExFreePoolWithTag(pETEs, TAG_REGION);
3466  return TRUE;
3467 }
3468 
3469 HRGN
3470 NTAPI
3472  _In_ const POINT *ppt,
3473  _In_ const ULONG *pcPoints,
3474  _In_ ULONG cPolygons,
3475  _In_ INT iMode)
3476 {
3477  PREGION prgn;
3478  HRGN hrgn;
3479 
3480  /* Allocate a new region */
3482  if (prgn == NULL)
3483  {
3485  return NULL;
3486  }
3487 
3488  /* Call the internal function and check for success */
3489  if (REGION_SetPolyPolygonRgn(prgn, ppt, pcPoints, cPolygons, iMode))
3490  {
3491  /* Success, get the handle and unlock the region */
3492  hrgn = prgn->BaseObject.hHmgr;
3493  REGION_UnlockRgn(prgn);
3494  }
3495  else
3496  {
3497  /* Failure, delete the region */
3498  REGION_Delete(prgn);
3499  hrgn = NULL;
3500  }
3501 
3502  return hrgn;
3503 }
3504 
3505 BOOL
3506 FASTCALL
3508  HRGN hRgn,
3509  LPRECTL rc)
3510 {
3511  PREGION Rgn;
3512  BOOL Ret;
3513 
3514  Rgn = REGION_LockRgn(hRgn);
3515  if (Rgn == NULL)
3516  {
3517  return ERROR;
3518  }
3519 
3520  Ret = REGION_RectInRegion(Rgn, rc);
3521  REGION_UnlockRgn(Rgn);
3522  return Ret;
3523 }
3524 
3525 
3526 //
3527 // NtGdi Exported Functions
3528 //
3529 INT
3530 APIENTRY
3532  IN HRGN hrgnDst,
3533  IN HRGN hrgnSrc1,
3534  IN HRGN hrgnSrc2,
3535  IN INT iMode)
3536 {
3537  HRGN ahrgn[3];
3538  PREGION aprgn[3];
3539  INT iResult;
3540 
3541  /* Validate the combine mode */
3542  if ((iMode < RGN_AND) || (iMode > RGN_COPY))
3543  {
3544  return ERROR;
3545  }
3546 
3547  /* Validate that we have the required regions */
3548  if ((hrgnDst == NULL) ||
3549  (hrgnSrc1 == NULL) ||
3550  ((iMode != RGN_COPY) && (hrgnSrc2 == NULL)))
3551  {
3552  DPRINT1("NtGdiCombineRgn invalid parameters: %p, %p, %p, %d\n",
3553  hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
3555  return ERROR;
3556  }
3557 
3558  /* Lock all regions */
3559  ahrgn[0] = hrgnDst;
3560  ahrgn[1] = hrgnSrc1;
3561  ahrgn[2] = iMode != RGN_COPY ? hrgnSrc2 : NULL;
3562  if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahrgn, (PVOID*)aprgn, GDIObjType_RGN_TYPE))
3563  {
3564  DPRINT1("NtGdiCombineRgn failed to lock regions: %p, %p, %p, %d\n",
3565  hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
3566  return ERROR;
3567  }
3568 
3569  /* HACK: Sync usermode attributes */
3570  REGION_vSyncRegion(aprgn[0]);
3571  if (aprgn[1] != aprgn[0])
3572  REGION_vSyncRegion(aprgn[1]);
3573  if ((aprgn[2] != NULL) && (aprgn[2] != aprgn[0]) && (aprgn[2] != aprgn[1]))
3574  REGION_vSyncRegion(aprgn[2]);
3575 
3576  /* Call the internal function */
3577  iResult = IntGdiCombineRgn(aprgn[0], aprgn[1], aprgn[2], iMode);
3578 
3579  /* Unlock and return */
3580  REGION_UnlockRgn(aprgn[0]);
3581  REGION_UnlockRgn(aprgn[1]);
3582  if (aprgn[2] != NULL)
3583  REGION_UnlockRgn(aprgn[2]);
3584 
3585  return iResult;
3586 }
3587 
3588 HRGN
3589 APIENTRY
3591  INT Left,
3592  INT Top,
3593  INT Right,
3594  INT Bottom)
3595 {
3596  return NtGdiCreateRoundRectRgn(Left,
3597  Top,
3598  Right, Bottom,
3599  Right - Left,
3600  Bottom - Top);
3601 }
3602 
3603 HRGN
3604 APIENTRY
3606  INT LeftRect,
3607  INT TopRect,
3608  INT RightRect,
3609  INT BottomRect)
3610 {
3611  PREGION pRgn;
3612  HRGN hRgn;
3613 
3614  /* Allocate region data structure with space for 1 RECTL */
3616  if (pRgn == NULL)
3617  {
3619  return NULL;
3620  }
3621 
3622  hRgn = pRgn->BaseObject.hHmgr;
3623 
3624  REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
3625  REGION_UnlockRgn(pRgn);
3626 
3627  DPRINT("Returning %p.\n", hRgn);
3628 
3629  return hRgn;
3630 }
3631 
3632 HRGN
3633 APIENTRY
3635  INT left,
3636  INT top,
3637  INT right,
3638  INT bottom,
3639  INT ellipse_width,
3640  INT ellipse_height)
3641 {
3642  PREGION obj;
3643  HRGN hrgn;
3644  int a, b, i, x, y;
3645  INT64 asq, bsq, dx, dy, err;
3646  RECT *rects;
3647 
3648  /* Make the dimensions sensible */
3649  if (left > right)
3650  {
3651  INT tmp = left;
3652  left = right;
3653  right = tmp;
3654  }
3655 
3656  if (top > bottom)
3657  {
3658  INT tmp = top;
3659  top = bottom;
3660  bottom = tmp;
3661  }
3662 
3663  /* the region is for the rectangle interior, but only at right and bottom for some reason */
3664  right--;
3665  bottom--;
3666 
3667  ellipse_width = min( right - left, abs( ellipse_width ));
3668  ellipse_height = min( bottom - top, abs( ellipse_height ));
3669 
3670  /* Check if we can do a normal rectangle instead */
3671 
3672  if ((ellipse_width < 2) || (ellipse_height < 2))
3673  return NtGdiCreateRectRgn(left, top, right, bottom);
3674 
3675  obj = REGION_AllocUserRgnWithHandle( ellipse_height );
3676  if (obj == NULL)
3677  return 0;
3678 
3679  hrgn = obj->BaseObject.hHmgr;
3680 
3681  obj->rdh.rcBound.left = left;
3682  obj->rdh.rcBound.top = top;
3683  obj->rdh.rcBound.right = right;
3684  obj->rdh.rcBound.bottom = bottom;
3685  rects = obj->Buffer;
3686 
3687  /* based on an algorithm by Alois Zingl */
3688 
3689  a = ellipse_width - 1;
3690  b = ellipse_height - 1;
3691  asq = (INT64)8 * a * a;
3692  bsq = (INT64)8 * b * b;
3693  dx = (INT64)4 * b * b * (1 - a);
3694  dy = (INT64)4 * a * a * (1 + (b % 2));
3695  err = dx + dy + a * a * (b % 2);
3696 
3697  x = 0;
3698  y = ellipse_height / 2;
3699 
3700  rects[y].left = left;
3701  rects[y].right = right;
3702 
3703  while (x <= ellipse_width / 2)
3704  {
3705  INT64 e2 = 2 * err;
3706  if (e2 >= dx)
3707  {
3708  x++;
3709  err += dx += bsq;
3710  }
3711  if (e2 <= dy)
3712  {
3713  y++;
3714  err += dy += asq;
3715  rects[y].left = left + x;
3716  rects[y].right = right - x;
3717  }
3718  }
3719  for (i = 0; i < ellipse_height / 2; i++)
3720  {
3721  rects[i].left = rects[b - i].left;
3722  rects[i].right = rects[b - i].right;
3723  rects[i].top = top + i;
3724  rects[i].bottom = rects[i].top + 1;
3725  }
3726  for (; i < ellipse_height; i++)
3727  {
3728  rects[i].top = bottom - ellipse_height + i;
3729  rects[i].bottom = rects[i].top + 1;
3730  }
3731  rects[ellipse_height / 2].top = top + ellipse_height / 2; /* extend to top of rectangle */
3732 
3734  return hrgn;
3735 }
3736 
3737 BOOL
3738 APIENTRY
3740  HRGN hSrcRgn1,
3741  HRGN hSrcRgn2)
3742 {
3743  HRGN ahrgn[2];
3744  PREGION aprgn[2];
3745  PREGION rgn1, rgn2;
3746  PRECTL tRect1, tRect2;
3747  ULONG i;
3748  BOOL bRet = FALSE;
3749 
3750  /* Check if we got 2 regions */
3751  if ((hSrcRgn1 == NULL) || (hSrcRgn2 == NULL))
3752  {
3753  return FALSE;
3754  }
3755 
3756  /* Check if these are the same regions */
3757  if (hSrcRgn1 == hSrcRgn2)
3758  {
3759  /* Make sure this region is valid */
3760  if ((GDI_HANDLE_GET_TYPE(hSrcRgn1) == GDILoObjType_LO_REGION_TYPE) &&
3761  GreIsHandleValid(hSrcRgn1))
3762  {
3763  return TRUE;
3764  }
3765  return FALSE;
3766  }
3767 
3768  /* Lock both regions */
3769  ahrgn[0] = hSrcRgn1;
3770  ahrgn[1] = hSrcRgn2;
3771  if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahrgn, (PVOID*)aprgn, GDIObjType_RGN_TYPE))
3772  {
3773  DPRINT1("NtGdiEqualRgn failed to lock regions: %p, %p\n",
3774  hSrcRgn1, hSrcRgn2);
3775  return FALSE;
3776  }
3777 
3778  REGION_vSyncRegion(aprgn[0]);
3779  REGION_vSyncRegion(aprgn[1]);
3780 
3781  rgn1 = aprgn[0];
3782  rgn2 = aprgn[1];
3783 
3784  if (rgn1->rdh.nCount != rgn2->rdh.nCount)
3785  goto exit;
3786 
3787  if (rgn1->rdh.nCount == 0)
3788  {
3789  bRet = TRUE;
3790  goto exit;
3791  }
3792 
3793  if ((rgn1->rdh.rcBound.left != rgn2->rdh.rcBound.left) ||
3794  (rgn1->rdh.rcBound.right != rgn2->rdh.rcBound.right) ||
3795  (rgn1->rdh.rcBound.top != rgn2->rdh.rcBound.top) ||
3796  (rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom))
3797  goto exit;
3798 
3799  tRect1 = rgn1->Buffer;
3800  tRect2 = rgn2->Buffer;
3801 
3802  if ((tRect1 == NULL) || (tRect2 == NULL))
3803  goto exit;
3804 
3805  for (i=0; i < rgn1->rdh.nCount; i++)
3806  {
3807  if ((tRect1[i].left != tRect2[i].left) ||
3808  (tRect1[i].right != tRect2[i].right) ||
3809  (tRect1[i].top != tRect2[i].top) ||
3810  (tRect1[i].bottom != tRect2[i].bottom))
3811  goto exit;
3812  }
3813 
3814  bRet = TRUE;
3815 
3816 exit:
3817  REGION_UnlockRgn(rgn1);
3818  REGION_UnlockRgn(rgn2);
3819  return bRet;
3820 }
3821 
3822 HRGN
3823 APIENTRY
3825  OPTIONAL LPXFORM Xform,
3826  DWORD Count,
3827  LPRGNDATA RgnData)
3828 {
3829  HRGN hRgn;
3830  PREGION Region;
3831  DWORD nCount = 0;
3832  DWORD iType = 0;
3833  DWORD dwSize = 0;
3834  UINT i;
3835  RECT* rects;
3837  MATRIX matrix;
3838  XFORMOBJ xo;
3839 
3840  DPRINT("NtGdiExtCreateRegion\n");
3841  _SEH2_TRY
3842  {
3843  ProbeForRead(RgnData, Count, 1);
3844  nCount = RgnData->rdh.nCount;
3845  iType = RgnData->rdh.iType;
3846  dwSize = RgnData->rdh.dwSize;
3847  rects = (RECT*)RgnData->Buffer;
3848  }
3850  {
3852  }
3853  _SEH2_END;
3854 
3855  if (!NT_SUCCESS(Status))
3856  {
3858  return NULL;
3859  }
3860 
3861  /* Check parameters, but don't set last error here */
3862  if ((Count < sizeof(RGNDATAHEADER) + nCount * sizeof(RECT)) ||
3863  (iType != RDH_RECTANGLES) ||
3864  (dwSize != sizeof(RGNDATAHEADER)))
3865  {
3866  return NULL;
3867  }
3868 
3870 
3871  if (Region == NULL)
3872  {
3874  return FALSE;
3875  }
3876  hRgn = Region->BaseObject.hHmgr;
3877 
3878  _SEH2_TRY
3879  {
3880  /* Insert the rectangles one by one */
3881  for(i=0; i<nCount; i++)
3882  {
3883  if ( rects[i].left < rects[i].right && rects[i].top < rects[i].bottom )
3884  {
3885  if (!REGION_UnionRectWithRgn(Region, &rects[i]))
3886  {
3889  hRgn = NULL;
3890  _SEH2_LEAVE;
3891  }
3892  }
3893  }
3894 
3895  if (Xform != NULL)
3896  {
3897  ULONG ret;
3898 
3899  /* Init the XFORMOBJ from the Xform struct */
3901  XFORMOBJ_vInit(&xo, &matrix);
3902  ret = XFORMOBJ_iSetXform(&xo, (XFORML*)Xform);
3903 
3904  /* Check for error */
3905  if (ret != DDI_ERROR)
3906  {
3907  /* Apply the coordinate transformation on the rects */
3908  if (XFORMOBJ_bApplyXform(&xo,
3909  XF_LTOL,
3910  Region->rdh.nCount * 2,
3911  Region->Buffer,
3912  Region->Buffer))
3913  {
3915  }
3916  }
3917  }
3918  }
3920  {
3922  }
3923  _SEH2_END;
3924  if (!NT_SUCCESS(Status))
3925  {
3929  return NULL;
3930  }
3931 
3933 
3934  return hRgn;
3935 }
3936 
3937 INT
3938 APIENTRY
3940  HRGN hRgn,
3941  PRECTL pRect)
3942 {
3943  PREGION Rgn;
3944  RECTL SafeRect;
3945  DWORD ret;
3947 
3948  Rgn = REGION_LockRgn(hRgn);
3949  if (Rgn == NULL)
3950  {
3951  return ERROR;
3952  }
3953 
3954  ret = REGION_GetRgnBox(Rgn, &SafeRect);
3955  REGION_UnlockRgn(Rgn);
3956  if (ret == ERROR)
3957  {
3958  return ret;
3959  }
3960 
3961  _SEH2_TRY
3962  {
3963  ProbeForWrite(pRect, sizeof(RECT), 1);
3964  *pRect = SafeRect;
3965  }
3967  {
3969  }
3970  _SEH2_END;
3971  if (!NT_SUCCESS(Status))
3972  {
3973  return ERROR;
3974  }
3975 
3976  return ret;
3977 }
3978 
3979 INT
3980 APIENTRY
3982  _In_ HRGN hrgn,
3983  _In_ INT cx,
3984  _In_ INT cy)
3985 {
3986  PREGION prgn;
3987  INT iResult;
3988 
3989  DPRINT("NtGdiOffsetRgn: hrgn %p cx %d cy %d\n", hrgn, cx, cy);
3990 
3991  /* Lock the region */
3992  prgn = REGION_LockRgn(hrgn);
3993  if (prgn == NULL)
3994  {
3995  DPRINT1("NtGdiOffsetRgn: failed to lock region %p\n", hrgn);
3996  return ERROR;
3997  }
3998 
3999  /* Call the internal function */
4000  if (!REGION_bOffsetRgn(prgn, cx, cy))
4001  {
4002  iResult = ERROR;
4003  }
4004  else
4005  {
4006  iResult = REGION_Complexity(prgn);
4007  }
4008 
4009  /* Unlock and return the result */
4010  REGION_UnlockRgn(prgn);
4011  return iResult;
4012 }
4013 
4014 BOOL
4015 APIENTRY
4017  _In_ HRGN hrgn,
4018  _In_ INT x,
4019  _In_ INT y)
4020 {
4021  PREGION prgn;
4022  BOOL bResult;
4023 
4024  /* Lock the region */
4025  prgn = REGION_LockRgn(hrgn);
4026  if (prgn == NULL)
4027  {
4028  DPRINT1("NtGdiPtInRegion: hrgn error\n");
4029  return FALSE;
4030  }
4031 
4032  /* Call the internal function */
4033  bResult = REGION_PtInRegion(prgn, x, y);
4034 
4035  /* Unlock and return the result */
4036  REGION_UnlockRgn(prgn);
4037  return bResult;
4038 }
4039 
4041 BOOL
4042 APIENTRY
4044  _In_ HRGN hrgn,
4045  _Inout_ LPRECT prclUnsafe)
4046 {
4047  RECTL rcTemp;
4048 
4049  /* Probe and copy the rect */
4050  _SEH2_TRY
4051  {
4052  ProbeForRead(prclUnsafe, sizeof(RECT), 1);
4053  rcTemp = *prclUnsafe;
4054  }
4056  {
4057  DPRINT1("NtGdiRectInRegion: Exception accessing the rect\n");
4058  return FALSE;
4059  }
4060  _SEH2_END;
4061 
4062  /* Call the internal function */
4063  return IntRectInRegion(hrgn, &rcTemp);
4064 }
4065 
4066 BOOL
4067 APIENTRY
4069  _In_ HRGN hrgn,
4070  _In_ INT xLeft,
4071  _In_ INT yTop,
4072  _In_ INT xRight,
4073  _In_ INT yBottom)
4074 {
4075  PREGION prgn;
4076 
4077  /* Lock the region */
4078  prgn = REGION_LockRgn(hrgn);
4079  if (prgn == NULL)
4080  {
4081  return FALSE;
4082  }
4083 
4084  /* Call the internal API */
4085  REGION_SetRectRgn(prgn, xLeft, yTop, xRight, yBottom);
4086 
4087  /* Unlock the region and return success */
4088  REGION_UnlockRgn(prgn);
4089  return TRUE;
4090 }
4091 
4102 _Success_(return!=0)
4104 ULONG
4105 APIENTRY
4106 NtGdiGetRegionData(
4107  _In_ HRGN hrgn,
4110 {
4111  ULONG cjRects, cjSize;
4112  PREGION prgn;
4113 
4114  /* Lock the region */
4115  prgn = REGION_LockRgn(hrgn);
4116  if (prgn == NULL)
4117  {
4119  return 0;
4120  }
4121 
4122  /* Calculate the region sizes */
4123  cjRects = prgn->rdh.nCount * sizeof(RECT);
4124  cjSize = cjRects + sizeof(RGNDATAHEADER);
4125 
4126  /* Check if region data is requested */
4127  if (lpRgnData)
4128  {
4129  /* Check if the buffer is large enough */
4130  if (cjBuffer >= cjSize)
4131  {
4132  /* Probe the buffer and copy the data */
4133  _SEH2_TRY
4134  {
4135  ProbeForWrite(lpRgnData, cjSize, sizeof(ULONG));
4136  RtlCopyMemory(lpRgnData, &prgn->rdh, sizeof(RGNDATAHEADER));
4137  RtlCopyMemory(lpRgnData->Buffer, prgn->Buffer, cjRects);
4138  lpRgnData->rdh.iType = RDH_RECTANGLES;
4139  lpRgnData->rdh.nRgnSize = cjRects;
4140  }
4142  {
4144  cjSize = 0;
4145  }
4146  _SEH2_END;
4147  }
4148  else
4149  {
4150  /* Buffer is too small */
4152  cjSize = 0;
4153  }
4154  }
4155 
4156  /* Unlock the region and return the size */
4157  REGION_UnlockRgn(prgn);
4158  return cjSize;
4159 }
4160 
4161 /* EOF */
static VOID FASTCALL REGION_SetExtents(PREGION pReg)
Definition: region.c:630
static BOOL FASTCALL REGION_CopyRegion(PREGION dst, PREGION src)
Definition: region.c:587
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
BASEOBJECT BaseObject
Definition: region.h:11
#define abs(i)
Definition: fconv.c:206
struct _RGNDATAHEADER RGNDATAHEADER
#define IN
Definition: typedefs.h:38
PGDIOBJ NTAPI GDIOBJ_LockObject(HGDIOBJ hobj, UCHAR objt)
Definition: gdiobj.c:823
return
Definition: dirsup.c:529
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres)
Definition: region.c:256
BOOL NTAPI GreSetObjectOwner(HGDIOBJ hobj, ULONG ulOwner)
Definition: gdiobj.c:1252
#define max(a, b)
Definition: svc.c:63
static BOOL FASTCALL REGION_RegionOp(PREGION newReg, PREGION reg1, PREGION reg2, overlapProcp overlapFunc, nonOverlapProcp nonOverlap1Func, nonOverlapProcp nonOverlap2Func)
Definition: region.c:960
static BOOL FASTCALL REGION_IntersectO(PREGION pReg, PRECTL r1, PRECTL r1End, PRECTL r2, PRECTL r2End, INT top, INT bottom)
Definition: region.c:1250
#define WINDING
Definition: constants.h:279
INT ymax
Definition: region.c:319
BOOL NTAPI GreDeleteObject(HGDIOBJ hobj)
Definition: gdiobj.c:1155
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
BOOL NTAPI GreIsHandleValid(HGDIOBJ hobj)
Definition: gdiobj.c:1143
static VOID FASTCALL REGION_loadAET(EDGE_TABLE_ENTRY *AET, EDGE_TABLE_ENTRY *ETEs)
Definition: region.c:2904
BOOL FASTCALL REGION_SetPolyPolygonRgn(_Inout_ PREGION prgn, _In_ const POINT *ppt, _In_ const ULONG *pcPoints, _In_ ULONG cPolygons, _In_ INT iMode)
Definition: region.c:3275
long y
Definition: polytest.cpp:48
FORCEINLINE VOID RECTL_vSetEmptyRect(_Out_ RECTL *prcl)
Definition: rect.h:20
#define Y(I)
_In_ ULONG iMode
Definition: winddi.h:3520
#define XFORMOBJ_bApplyXform
Definition: xformobj.h:11
#define DbgPrint
Definition: loader.c:25
#define MAXLONG
Definition: umtypes.h:116
struct _POINTBLOCK POINTBLOCK
long x
Definition: polytest.cpp:48
#define _Out_writes_bytes_to_opt_(size, count)
Definition: no_sal2.h:375
VOID NTAPI GdiPoolFree(PGDI_POOL pPool, PVOID pvAlloc)
Definition: gdipool.c:233
INT FASTCALL REGION_SubtractRectFromRgn(PREGION prgnDest, PREGION prgnSrc, const RECTL *prcl)
Definition: region.c:1827
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
GLuint GLenum matrix
Definition: glext.h:9407
_In_ ULONG iType
Definition: winddi.h:3748
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
static BOOL FASTCALL REGION_SubtractO(PREGION pReg, PRECTL r1, PRECTL r1End, PRECTL r2, PRECTL r2End, INT top, INT bottom)
Definition: region.c:1615
#define ERROR(name)
Definition: error_private.h:53
static const WCHAR empty[]
Definition: main.c:49
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint dy
Definition: linetemp.h:97
static BOOL FASTCALL REGION_UnionNonO(PREGION pReg, PRECTL r, PRECTL rEnd, INT top, INT bottom)
Definition: region.c:1358
EDGE_TABLE_ENTRY * edgelist
Definition: region.c:331
_In_ HANDLE _In_ HANDLE hrgnSrc2
Definition: winddi.h:4295
#define ERROR_INVALID_HANDLE
Definition: compat.h:88
LONG NTSTATUS
Definition: precomp.h:26
#define TAG_REGION
Definition: tags.h:22
#define INT
Definition: polytest.cpp:20
static DNS_RECORDW r1
Definition: record.c:37
#define REGION_NOT_EMPTY(pReg)
Definition: region.c:156
#define COMPLEXREGION
Definition: wingdi.h:362
#define NULLREGION
Definition: wingdi.h:360
static BOOL FASTCALL REGION_SubtractNonO1(PREGION pReg, PRECTL r, PRECTL rEnd, INT top, INT bottom)
Definition: region.c:1575
LONG top
Definition: windef.h:292
long bottom
Definition: polytest.cpp:53
char Buffer[1]
Definition: axextend.idl:395
static HRGN hRgn
Definition: mapping.c:33
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
static BOOL REGION_bGrowBufferSize(_Inout_ PREGION prgn, _In_ UINT cRects)
Definition: region.c:418
#define XFORMOBJ_iSetXform
Definition: xformobj.h:14
BOOL FASTCALL REGION_bOffsetRgn(_Inout_ PREGION prgn, _In_ INT cx, _In_ INT cy)
Definition: region.c:2727
ULONG NTAPI GreGetObjectOwner(HGDIOBJ hobj)
Definition: gdiobj.c:1189
LONG left
Definition: windef.h:291
#define NT_VERIFY(exp)
Definition: rtlfuncs.h:3289
FORCEINLINE VOID XFORMOBJ_vInit(OUT XFORMOBJ *pxo, IN MATRIX *pmx)
Definition: xformobj.h:21
__kernel_entry BOOL APIENTRY NtGdiRectInRegion(_In_ HRGN hrgn, _Inout_ LPRECT prclUnsafe)
Definition: region.c:4043
struct _SCANLINE_LIST * next
Definition: region.c:332
LONG right
Definition: windef.h:293
HRGN APIENTRY NtGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
Definition: region.c:3605
PREGION FASTCALL REGION_LockRgn(_In_ HRGN hrgn)
Definition: region.c:2377
Definition: bidi.c:79
#define BOOL
Definition: nt_native.h:43
#define FASTCALL
Definition: nt_native.h:50
int32_t INT
Definition: typedefs.h:56
HRGN APIENTRY NtGdiExtCreateRegion(OPTIONAL LPXFORM Xform, DWORD Count, LPRGNDATA RgnData)
Definition: region.c:3824
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
& rect
Definition: startmenu.cpp:1413
INT ClockWise
Definition: region.c:324
const GLfloat * m
Definition: glext.h:10848
static BOOL FASTCALL REGION_XorRegion(PREGION dr, PREGION sra, PREGION srb)
Definition: region.c:1768
#define GDITAG_REGION
Definition: tags.h:157
#define MAX_COORD
Definition: region.c:12
HRGN hrgnDefault
Definition: region.c:131
_SEH2_TRY
Definition: create.c:4250
GLsizei GLsizei GLuint * obj
Definition: glext.h:6042
struct _POINTBLOCK * next
Definition: region.c:532
struct tagRECT RECT
#define ATTR_RGN_VALID
Definition: ntgdihdl.h:210
static __inline BOOL REGION_bMergeRect(_Inout_ PREGION prgn, _In_ LONG left, _In_ LONG top, _In_ LONG right, _In_ LONG bottom)
Definition: region.c:1385
#define RGN_AND
Definition: wingdi.h:355
static INT FASTCALL REGION_PtsToRegion(INT numFullPtBlocks, INT iCurPtBlock, POINTBLOCK *FirstPtBlock, PREGION reg)
Definition: region.c:3063
struct _EDGE_TABLE_ENTRY * nextWETE
Definition: region.c:323
INT ymax
Definition: region.c:338
BOOL APIENTRY NtGdiEqualRgn(HRGN hSrcRgn1, HRGN hSrcRgn2)
Definition: region.c:3739
long right
Definition: polytest.cpp:53
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
static INT FASTCALL REGION_Coalesce(PREGION pReg, INT prevStart, INT curStart)
Definition: region.c:822
PREGION FASTCALL IntSysCreateRectpRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
Definition: region.c:2426
#define ALTERNATE
Definition: constants.h:278
_Notnull_ PRGN_ATTR prgnattr
Definition: region.h:12
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
static __inline BOOL REGION_bAddRect(_Inout_ PREGION prgn, _In_ LONG left, _In_ LONG top, _In_ LONG right, _In_ LONG bottom)
Definition: region.c:504
#define SMALL_COORDINATE
Definition: region.c:414
unsigned int BOOL
Definition: ntddk_ex.h:94
#define INRECT(r, x, y)
Definition: region.c:158
long LONG
Definition: pedump.c:60
struct _SCANLINE_LIST SCANLINE_LIST
#define RGN_XOR
Definition: wingdi.h:359
_In_ HANDLE hrgnSrc1
Definition: winddi.h:4295
#define a
Definition: ke_i.h:78
long top
Definition: polytest.cpp:53
RECTL * Buffer
Definition: region.h:16
BOOL FASTCALL REGION_bCopy(PREGION dst, PREGION src)
Definition: region.c:1844
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:570
HGDIOBJ hHmgr(VOID)
Definition: baseobj.hpp:95
smooth NULL
Definition: ftsmooth.c:416
#define RGN_OR
Definition: wingdi.h:358
#define FORCEINLINE
Definition: ntbasedef.h:221
#define DDI_ERROR
Definition: winddi.h:154
_In_ LPGUID _In_ PVOID Data
Definition: classpnp.h:778
BOOL FASTCALL REGION_RectInRegion(PREGION Rgn, const RECTL *rect)
Definition: region.c:2625
void DPRINT(...)
Definition: polytest.cpp:61
GLint GLint bottom
Definition: glext.h:7726
Definition: region.c:317
INT minor_axis
Definition: region.c:249
BOOL(FASTCALL * overlapProcp)(PREGION, PRECT, PRECT, PRECT, PRECT, INT, INT)
Definition: region.c:520
Definition: region.h:7
PVOID NTAPI GdiPoolAllocate(PGDI_POOL pPool)
Definition: gdipool.c:122
BOOL FASTCALL IntRectInRegion(HRGN hRgn, LPRECTL rc)
Definition: region.c:3507
ULONG AttrFlags
Definition: ntgdihdl.h:269
BOOL NTAPI GDIOBJ_bLockMultipleObjects(IN ULONG ulCount, IN HGDIOBJ *ahObj, OUT PGDIOBJ *apObj, IN UCHAR objt)
Definition: gdiobj.c:1028
long left
Definition: polytest.cpp:53
static BOOL REGION_bMakeFrameRegion(_Inout_ PREGION prgnDest, _Inout_ PREGION prgnSrc, _In_ INT cx, _In_ INT cy)
Definition: region.c:1956
INT FASTCALL IntGdiCombineRgn(PREGION prgnDest, PREGION prgnSrc1, PREGION prgnSrc2, INT iCombineMode)
Definition: region.c:2506
#define b
Definition: ke_i.h:79
#define POINT
Definition: precomp.h:30
#define GDI_HANDLE_GET_TYPE(h)
Definition: gdi.h:31
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 XF_LTOL
Definition: winddi.h:3109
POINT pts[NUMPTSTOBUFFER]
Definition: region.c:531
_In_ SURFOBJ _In_ CLIPOBJ _In_opt_ XLATEOBJ _In_ RECTL _In_ RECTL * prclSrc
Definition: winddi.h:3414
static __inline BOOL REGION_bEnsureBufferSize(_Inout_ PREGION prgn, _In_ UINT cRects)
Definition: region.c:468
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
INT APIENTRY NtGdiGetRgnBox(HRGN hRgn, PRECTL pRect)
Definition: region.c:3939
#define EXTENTCHECK(r1, r2)
Definition: region.c:167
VOID NTAPI GDIOBJ_vDeleteObject(POBJ pobj)
Definition: gdiobj.c:1108
HRGN FASTCALL GreCreateFrameRgn(HRGN hrgn, INT cx, INT cy)
Definition: region.c:2041
PREGION prgnDefault
Definition: region.c:130
#define __kernel_entry
Definition: specstrings.h:50
BOOL FASTCALL REGION_UnionRectWithRgn(PREGION rgn, const RECTL *rect)
Definition: region.c:1812
#define RDH_RECTANGLES
Definition: wingdi.h:668
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
Definition: matrix.h:43
static BOOL FASTCALL REGION_UnionRegion(PREGION newReg, PREGION reg1, PREGION reg2)
Definition: region.c:1478
BOOL FASTCALL IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
Definition: region.c:2478
_Success_(return!=0)
Definition: region.c:4102
INT d
Definition: region.c:250
static DNS_RECORDW r2
Definition: record.c:38
BOOL FASTCALL RECTL_bUnionRect(_Out_ RECTL *prclDst, _In_ const RECTL *prcl1, _In_ const RECTL *prcl2)
Definition: rect.c:18
RGN_ATTR rgnattr
Definition: region.h:13
#define for
Definition: utility.h:88
unsigned long DWORD
Definition: ntddk_ex.h:95
BOOL FASTCALL REGION_bXformRgn(_Inout_ PREGION prgn, _In_ PMATRIX pmx)
Definition: region.c:2082
GLint left
Definition: glext.h:7726
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:3189
#define _Inout_
Definition: no_sal2.h:244
INT APIENTRY IntGdiGetRgnBox(HRGN hRgn, PRECTL pRect)
Definition: region.c:2580
#define COPY_RECTS(dest, src, nRects)
Definition: region.c:136
struct _SCANLINE_LISTBLOCK * next
Definition: region.c:354
HRGN APIENTRY NtGdiCreateRoundRectRgn(INT left, INT top, INT right, INT bottom, INT ellipse_width, INT ellipse_height)
Definition: region.c:3634
static VOID FASTCALL REGION_computeWAET(EDGE_TABLE_ENTRY *AET)
Definition: region.c:2957
GLdouble GLdouble right
Definition: glext.h:10859
static BOOL FASTCALL REGION_SubtractRegion(PREGION regD, PREGION regM, PREGION regS)
Definition: region.c:1732
VOID NTAPI GDIOBJ_vSetObjectAttr(POBJ pobj, PVOID pvObjAttr)
Definition: gdiobj.c:1093
#define LARGE_COORDINATE
Definition: region.c:413
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define __WARNING_MAYBE_UNINIT_VAR
Definition: suppress.h:598
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
VOID NTAPI GDIOBJ_vUnlockObject(POBJ pobj)
Definition: gdiobj.c:877
#define ATTR_RGN_DIRTY
Definition: ntgdihdl.h:211
static BOOL REGION_bMakeSimpleFrameRgn(_Inout_ PREGION prgn, _In_ PRECTL prclSrc, _In_ INT cx, _In_ INT cy)
Definition: region.c:1865
int ret
SCANLINE_LIST SLLs[SLLSPERBLOCK]
Definition: region.c:353
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
static BOOL FASTCALL REGION_InsertionSort(EDGE_TABLE_ENTRY *AET)
Definition: region.c:2998
FORCEINLINE VOID REGION_vAddRect(_Inout_ PREGION prgn, _In_ LONG left, _In_ LONG top, _In_ LONG right, _In_ LONG bottom)
Definition: region.c:484
#define NUMPTSTOBUFFER
Definition: region.c:524
static HRGN hrgn
Definition: win.c:55
#define MINLONG
Definition: umtypes.h:115
VOID NTAPI REGION_vCleanup(PVOID ObjectBody)
Definition: region.c:2452
BOOL APIENTRY NtGdiSetRectRgn(_In_ HRGN hrgn, _In_ INT xLeft, _In_ INT yTop, _In_ INT xRight, _In_ INT yBottom)
Definition: region.c:4068
#define VOID
Definition: acefi.h:82
signed long long INT64
struct _EDGE_TABLE_ENTRY EDGE_TABLE_ENTRY
#define GDI_OBJ_HMGR_POWNED
Definition: ntgdihdl.h:117
ULONG iComplexity
Definition: ntgdihdl.h:270
GLenum src
Definition: glext.h:6340
#define err(...)
VOID FASTCALL SetLastNtError(NTSTATUS Status)
Definition: error.c:36
Status
Definition: gdiplustypes.h:24
#define RGN_COPY
Definition: wingdi.h:356
RGNDATAHEADER rdh
Definition: region.h:15
#define SIMPLEREGION
Definition: wingdi.h:361
#define MAXULONG
Definition: typedefs.h:250
#define _In_
Definition: no_sal2.h:204
struct _EDGE_TABLE_ENTRY * back
Definition: region.c:322
struct _GDI_POOL * pPoolRgnAttr
Definition: win32.h:284
_SEH2_END
Definition: create.c:4424
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
Definition: region.c:393
static LPHIST_ENTRY Bottom
Definition: history.c:54
#define EMPTY_REGION(pReg)
Definition: region.c:149
BOOL NTAPI REGION_bAllocRgnAttr(PREGION prgn)
Definition: region.c:2279
static VOID FASTCALL REGION_FreeStorage(SCANLINE_LISTBLOCK *pSLLBlock)
Definition: region.c:3041
#define RGN_DIFF
Definition: wingdi.h:357
BRESINFO bres
Definition: region.c:320
static calc_node_t temp
Definition: rpn_ieee.c:38
GLuint start
Definition: gl.h:1545
INT APIENTRY NtGdiCombineRgn(IN HRGN hrgnDst, IN HRGN hrgnSrc1, IN HRGN hrgnSrc2, IN INT iMode)
Definition: region.c:3531
INT APIENTRY NtGdiOffsetRgn(_In_ HRGN hrgn, _In_ INT cx, _In_ INT cy)
Definition: region.c:3981
GLenum GLenum dst
Definition: glext.h:6340
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
PVOID NTAPI PsGetCurrentProcessWin32Process(VOID)
Definition: process.c:1183
PREGION FASTCALL REGION_AllocRgnWithHandle(INT nReg)
Definition: region.c:2219
static int reg
Definition: i386-dis.c:1275
RGNDATAHEADER rdh
Definition: axextend.idl:394
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLint dx
Definition: linetemp.h:97
#define DPRINT1
Definition: precomp.h:8
RECTL Rect
Definition: ntgdihdl.h:271
_In_ ULONG _In_ CLIPOBJ _In_ RECTL * prcl
Definition: winddi.h:3529
INT scanline
Definition: region.c:330
BOOL FASTCALL REGION_bIntersectRegion(PREGION newReg, PREGION reg1, PREGION reg2)
Definition: region.c:1854
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
Definition: region.c:370
struct _EDGE_TABLE_ENTRY * next
Definition: region.c:321
struct _SCANLINE_LISTBLOCK SCANLINE_LISTBLOCK
static BOOL FASTCALL REGION_UnionO(PREGION pReg, PRECTL r1, PRECTL r1End, PRECTL r2, PRECTL r2End, INT top, INT bottom)
Definition: region.c:1428
VOID FASTCALL REGION_UnlockRgn(_In_ PREGION prgn)
Definition: region.c:2392
_Out_opt_ int * cx
Definition: commctrl.h:570
INT ymin
Definition: region.c:339
HRGN NTAPI GreCreatePolyPolygonRgn(_In_ const POINT *ppt, _In_ const ULONG *pcPoints, _In_ ULONG cPolygons, _In_ INT iMode)
Definition: region.c:3471
unsigned int ULONG
Definition: retypes.h:1
_In_ ULONG cjSize
Definition: winddi.h:3634
INT incr2
Definition: region.c:252
_In_ ULONG cjBuffer
Definition: ntgdi.h:2860
Definition: windef.h:299
LONG bottom
Definition: windef.h:294
struct _REGION * PREGION
INT FASTCALL REGION_CropRegion(PREGION rgnDst, PREGION rgnSrc, const RECTL *rect)
Definition: region.c:678
struct tagRECT * PRECT
struct RECTL RECTL
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
INT FASTCALL REGION_Complexity(PREGION prgn)
Definition: region.c:567
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
static BOOL FASTCALL REGION_IntersectRegion(PREGION newReg, PREGION reg1, PREGION reg2)
Definition: region.c:1306
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
static VOID FASTCALL REGION_InsertEdgeInET(EDGE_TABLE *ET, EDGE_TABLE_ENTRY *ETE, INT scanline, SCANLINE_LISTBLOCK **SLLBlock, INT *iSLLBlock)
Definition: region.c:2826
#define _SEH2_LEAVE
Definition: filesup.c:20
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
void exit(int exitcode)
Definition: _exit.c:33
INT FASTCALL REGION_GetRgnBox(PREGION Rgn, PRECTL pRect)
Definition: region.c:2562
VOID FASTCALL REGION_SetRectRgn(PREGION rgn, INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
Definition: region.c:2685
PREGION FASTCALL REGION_AllocUserRgnWithHandle(INT nRgn)
Definition: region.c:2313
return STATUS_SUCCESS
Definition: btrfs.c:2966
VOID FASTCALL REGION_Delete(PREGION pRgn)
Definition: region.c:2468
SCANLINE_LIST scanlines
Definition: region.c:340
INT m1
Definition: region.c:251
static LPHIST_ENTRY Top
Definition: history.c:53
static VOID REGION_vSyncRegion(_In_ PREGION prgn)
Definition: region.c:2334
#define SLLSPERBLOCK
Definition: region.c:349
VOID FASTCALL RECTL_vMakeWellOrdered(_Inout_ RECTL *prcl)
Definition: rect.c:81
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:54
ENGAPI VOID APIENTRY EngSetLastError(_In_ ULONG iError)
Definition: error.c:27
#define MIN_COORD
Definition: region.c:11
POBJ NTAPI GDIOBJ_AllocateObject(UCHAR objt, ULONG cjSize, FLONG fl)
Definition: gdiobj.c:559
#define APIENTRY
Definition: api.h:79
VOID NTAPI GDIOBJ_vFreeObject(POBJ pobj)
Definition: gdiobj.c:593
#define _PRAGMA_WARNING_SUPPRESS(x)
Definition: suppress.h:28
BOOL FASTCALL REGION_PtInRegion(PREGION prgn, INT X, INT Y)
Definition: region.c:2602
HRGN APIENTRY NtGdiCreateEllipticRgn(INT Left, INT Top, INT Right, INT Bottom)
Definition: region.c:3590
BOOL(FASTCALL * nonOverlapProcp)(PREGION, PRECT, PRECT, INT, INT)
Definition: region.c:521
#define NT_ASSERT
Definition: rtlfuncs.h:3312
HGDIOBJ NTAPI GDIOBJ_hInsertObject(POBJ pobj, ULONG ulOwner)
Definition: gdiobj.c:909
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
BOOL APIENTRY NtGdiPtInRegion(_In_ HRGN hrgn, _In_ INT x, _In_ INT y)
Definition: region.c:4016