ReactOS  0.4.13-dev-73-gcfe54aa
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, j, 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  for (j = i; i < prgn->rdh.nCount; i++)
2153  {
2154  NT_ASSERT(prgn->Buffer[i].top < prgn->Buffer[i].bottom);
2155  NT_ASSERT(prgn->Buffer[j].top >= prgn->Buffer[i].top);
2156  }
2157  }
2158 
2159  return TRUE;
2160  }
2161  }
2162  else
2163  {
2164  /* Allocate a buffer for the polygons */
2165  cjSize = prgn->rdh.nCount * (4 * sizeof(POINT) + sizeof(ULONG));
2167  if (ppt == NULL)
2168  {
2169  return FALSE;
2170  }
2171 
2172  /* Fill the buffer with the rects */
2173  pcPoints = (PULONG)&ppt[4 * prgn->rdh.nCount];
2174  for (i = 0; i < prgn->rdh.nCount; i++)
2175  {
2176  /* Make sure the rect is within the legal range */
2177  pcPoints[i] = 4;
2178  ppt[4 * i + 0].x = prgn->Buffer[i].left;
2179  ppt[4 * i + 0].y = prgn->Buffer[i].top;
2180  ppt[4 * i + 1].x = prgn->Buffer[i].right;
2181  ppt[4 * i + 1].y = prgn->Buffer[i].top;
2182  ppt[4 * i + 2].x = prgn->Buffer[i].right;
2183  ppt[4 * i + 2].y = prgn->Buffer[i].bottom;
2184  ppt[4 * i + 3].x = prgn->Buffer[i].left;
2185  ppt[4 * i + 3].y = prgn->Buffer[i].bottom;
2186  }
2187 
2188  /* Initialize the xform object */
2189  XFORMOBJ_vInit(&xo, pmx);
2190 
2191  /* Apply the xform to the rects in the buffer */
2192  if (!XFORMOBJ_bApplyXform(&xo,
2193  XF_LTOL,
2194  prgn->rdh.nCount * 2,
2195  ppt,
2196  ppt))
2197  {
2198  /* This means, there were coordinates that would go outside of
2199  the coordinate space after the transformation */
2201  return FALSE;
2202  }
2203 
2204  /* Now use the polygons to create a polygon region */
2205  bResult = REGION_SetPolyPolygonRgn(prgn,
2206  ppt,
2207  pcPoints,
2208  prgn->rdh.nCount,
2209  WINDING);
2210 
2211  /* Free the polygon buffer */
2213 
2214  return bResult;
2215  }
2216 
2217 }
2218 
2219 
2220 PREGION
2221 FASTCALL
2223  INT nReg)
2224 {
2225  //HRGN hReg;
2226  PREGION pReg;
2227 
2229  sizeof(REGION),
2231  if (pReg == NULL)
2232  {
2233  DPRINT1("Could not allocate a palette.\n");
2234  return NULL;
2235  }
2236 
2237  //hReg = pReg->BaseObject.hHmgr;
2238 
2239  if ((nReg == 0) || (nReg == 1))
2240  {
2241  /* Testing shows that > 95% of all regions have only 1 rect.
2242  Including that here saves us from having to do another allocation */
2243  pReg->Buffer = &pReg->rdh.rcBound;
2244  }
2245  else
2246  {
2248  nReg * sizeof(RECT),
2249  TAG_REGION);
2250  if (pReg->Buffer == NULL)
2251  {
2252  DPRINT1("Could not allocate region buffer\n");
2254  return NULL;
2255  }
2256  }
2257 
2258  EMPTY_REGION(pReg);
2259  pReg->rdh.dwSize = sizeof(RGNDATAHEADER);
2260  pReg->rdh.nCount = nReg;
2261  pReg->rdh.nRgnSize = nReg * sizeof(RECT);
2262  pReg->prgnattr = &pReg->rgnattr;
2263 
2264  /* Initialize the region attribute */
2265  pReg->rgnattr.AttrFlags = 0;
2267  pReg->rgnattr.Rect = pReg->rdh.rcBound;
2268 
2269  /* Finally insert the region into the handle table */
2271  {
2272  DPRINT1("Could not insert palette into handle table.\n");
2274  return NULL;
2275  }
2276 
2277  return pReg;
2278 }
2279 
2280 BOOL
2281 NTAPI
2283  PREGION prgn)
2284 {
2285  PPROCESSINFO ppi;
2286  PRGN_ATTR prgnattr;
2287 
2288  NT_ASSERT(prgn->prgnattr == &prgn->rgnattr);
2289 
2291  ASSERT(ppi);
2292 
2293  prgnattr = GdiPoolAllocate(ppi->pPoolRgnAttr);
2294  if (prgnattr == NULL)
2295  {
2296  DPRINT1("Could not allocate RGN attr\n");
2297  return FALSE;
2298  }
2299 
2300  /* Copy the current region attribute */
2301  *prgnattr = prgn->rgnattr;
2302 
2303  /* Set the object attribute in the handle table */
2304  prgn->prgnattr = prgnattr;
2305  GDIOBJ_vSetObjectAttr(&prgn->BaseObject, prgnattr);
2306 
2307  return TRUE;
2308 }
2309 
2310 
2311 //
2312 // Allocate User Space Region Handle.
2313 //
2314 PREGION
2315 FASTCALL
2317  INT nRgn)
2318 {
2319  PREGION prgn;
2320 
2321  prgn = REGION_AllocRgnWithHandle(nRgn);
2322  if (prgn == NULL)
2323  {
2324  return NULL;
2325  }
2326 
2327  if (!REGION_bAllocRgnAttr(prgn))
2328  {
2329  ASSERT(FALSE);
2330  }
2331 
2332  return prgn;
2333 }
2334 
2335 static
2336 VOID
2338  _In_ PREGION prgn)
2339 {
2340  PRGN_ATTR prgnattr;
2341 
2342  NT_ASSERT(prgn != NULL);
2343  NT_ASSERT(prgn->prgnattr != NULL);
2344  NT_ASSERT((prgn->prgnattr == &prgn->rgnattr) ||
2345  (prgn->prgnattr->AttrFlags & ATTR_RGN_VALID));
2346 
2347  /* Get the region attribute and check if it's dirty (modified) */
2348  prgnattr = prgn->prgnattr;
2349  if (prgnattr->AttrFlags & ATTR_RGN_DIRTY)
2350  {
2351  NT_ASSERT(GreGetObjectOwner(prgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED);
2352  NT_ASSERT(prgnattr != &prgn->rgnattr);
2353 
2354  if (prgnattr->iComplexity == NULLREGION)
2355  {
2356  EMPTY_REGION(prgn);
2357  }
2358  else if (prgnattr->iComplexity == SIMPLEREGION)
2359  {
2360  REGION_SetRectRgn(prgn,
2361  prgnattr->Rect.left,
2362  prgnattr->Rect.top,
2363  prgnattr->Rect.right,
2364  prgnattr->Rect.bottom);
2365  }
2366  else
2367  {
2368  /* Should not happen, region attribute is corrupted! */
2369  DPRINT1("Region attribute is corrupted, ignoring\n");
2370  NT_ASSERT(FALSE);
2371  }
2372  }
2373 
2374  /* Reset the flags */
2375  prgnattr->AttrFlags &= ~(ATTR_RGN_DIRTY | ATTR_RGN_VALID);
2376 }
2377 
2378 PREGION
2379 FASTCALL
2381  _In_ HRGN hrgn)
2382 {
2383  PREGION prgn;
2384 
2386  if (prgn == NULL)
2387  return NULL;
2388 
2389  REGION_vSyncRegion(prgn);
2390  return prgn;
2391 }
2392 
2393 VOID
2394 FASTCALL
2396  _In_ PREGION prgn)
2397 {
2398  PRGN_ATTR prgnattr;
2399 
2400  NT_ASSERT(prgn != NULL);
2401  NT_ASSERT(prgn->prgnattr != NULL);
2402 
2403  /* Get the region attribute and check if it's user mode */
2404  prgnattr = prgn->prgnattr;
2405  if (prgnattr != &prgn->rgnattr)
2406  {
2407  NT_ASSERT(GreGetObjectOwner(prgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED);
2408  prgnattr->iComplexity = REGION_Complexity(prgn);
2409  prgnattr->Rect.left = prgn->rdh.rcBound.left;
2410  prgnattr->Rect.top = prgn->rdh.rcBound.top;
2411  prgnattr->Rect.right = prgn->rdh.rcBound.right;
2412  prgnattr->Rect.bottom = prgn->rdh.rcBound.bottom;
2413  prgnattr->AttrFlags |= ATTR_RGN_VALID;
2414  }
2415 
2416  GDIOBJ_vUnlockObject(&prgn->BaseObject);
2417 }
2418 
2419 /*
2420  System Regions:
2421  These regions do not use attribute sections and when allocated, use gdiobj
2422  level functions.
2423 */
2424 //
2425 // System Region Functions
2426 //
2427 PREGION
2428 FASTCALL
2430  INT LeftRect,
2431  INT TopRect,
2432  INT RightRect,
2433  INT BottomRect)
2434 {
2435  PREGION prgn;
2436 
2437  /* Allocate a region, without a handle */
2439  if (prgn == NULL)
2440  {
2441  return NULL;
2442  }
2443 
2444  /* Initialize it */
2445  prgn->Buffer = &prgn->rdh.rcBound;
2446  prgn->prgnattr = &prgn->rgnattr;
2448  REGION_SetRectRgn(prgn, LeftRect, TopRect, RightRect, BottomRect);
2449 
2450  return prgn;
2451 }
2452 
2453 VOID
2454 NTAPI
2456 {
2457  PREGION pRgn = (PREGION)ObjectBody;
2459  ASSERT(ppi);
2460 
2461  ASSERT(pRgn->prgnattr);
2462  if (pRgn->prgnattr != &pRgn->rgnattr)
2463  GdiPoolFree(ppi->pPoolRgnAttr, pRgn->prgnattr);
2464 
2465  if (pRgn->Buffer && pRgn->Buffer != &pRgn->rdh.rcBound)
2467 }
2468 
2469 VOID
2470 FASTCALL
2472 {
2473  if (pRgn == prgnDefault)
2474  return;
2475 
2477 }
2478 
2479 BOOL
2480 FASTCALL
2482 {
2483  PREGION prgn;
2484  PRGN_ATTR prgnattr;
2485  PPROCESSINFO ppi;
2486 
2487  prgn = REGION_LockRgn(hRgn);
2488  if (prgn == NULL)
2489  {
2490  return FALSE;
2491  }
2492 
2493  prgnattr = prgn->prgnattr;
2494  if (prgnattr != &prgn->rgnattr)
2495  {
2497  prgn->prgnattr = &prgn->rgnattr;
2499  GdiPoolFree(ppi->pPoolRgnAttr, prgnattr);
2500  }
2501 
2502  REGION_UnlockRgn(prgn);
2503 
2504  return GreSetObjectOwner(hRgn, OwnerMask);
2505 }
2506 
2507 INT
2508 FASTCALL
2510  PREGION prgnDest,
2511  PREGION prgnSrc1,
2512  PREGION prgnSrc2,
2513  INT iCombineMode)
2514 {
2515  BOOL Ret = TRUE;
2516 
2517  if (prgnDest == NULL)
2518  {
2519  DPRINT("IntGdiCombineRgn: hDest unavailable\n");
2520  return ERROR;
2521  }
2522 
2523  if (prgnSrc1 == NULL)
2524  {
2525  DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
2526  return ERROR;
2527  }
2528 
2529  if (iCombineMode == RGN_COPY)
2530  {
2531  if (!REGION_CopyRegion(prgnDest, prgnSrc1))
2532  return ERROR;
2533 
2534  return REGION_Complexity(prgnDest);
2535  }
2536 
2537  if (prgnSrc2 == NULL)
2538  {
2539  DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", iCombineMode);
2540  ASSERT(FALSE);
2541  return ERROR;
2542  }
2543 
2544  switch (iCombineMode)
2545  {
2546  case RGN_AND:
2547  Ret = REGION_IntersectRegion(prgnDest, prgnSrc1, prgnSrc2);
2548  break;
2549  case RGN_OR:
2550  Ret = REGION_UnionRegion(prgnDest, prgnSrc1, prgnSrc2);
2551  break;
2552  case RGN_XOR:
2553  Ret = REGION_XorRegion(prgnDest, prgnSrc1, prgnSrc2);
2554  break;
2555  case RGN_DIFF:
2556  Ret = REGION_SubtractRegion(prgnDest, prgnSrc1, prgnSrc2);
2557  break;
2558  }
2559 
2560  return Ret ? REGION_Complexity(prgnDest) : ERROR;
2561 }
2562 
2563 INT
2564 FASTCALL
2566  PREGION Rgn,
2567  PRECTL pRect)
2568 {
2569  DWORD ret;
2570 
2571  if (Rgn != NULL)
2572  {
2573  *pRect = Rgn->rdh.rcBound;
2574  ret = REGION_Complexity(Rgn);
2575 
2576  return ret;
2577  }
2578  return 0; // If invalid region return zero
2579 }
2580 
2581 INT
2582 APIENTRY
2584  HRGN hRgn,
2585  PRECTL pRect)
2586 {
2587  PREGION Rgn;
2588  DWORD ret;
2589 
2590  Rgn = REGION_LockRgn(hRgn);
2591  if (Rgn == NULL)
2592  {
2593  return ERROR;
2594  }
2595 
2596  ret = REGION_GetRgnBox(Rgn, pRect);
2597  REGION_UnlockRgn(Rgn);
2598 
2599  return ret;
2600 }
2601 
2602 
2603 BOOL
2604 FASTCALL
2606  PREGION prgn,
2607  INT X,
2608  INT Y)
2609 {
2610  ULONG i;
2611  PRECT r;
2612 
2613  if (prgn->rdh.nCount > 0 && INRECT(prgn->rdh.rcBound, X, Y))
2614  {
2615  r = prgn->Buffer;
2616  for (i = 0; i < prgn->rdh.nCount; i++)
2617  {
2618  if (INRECT(r[i], X, Y))
2619  return TRUE;
2620  }
2621  }
2622 
2623  return FALSE;
2624 }
2625 
2626 BOOL
2627 FASTCALL
2629  PREGION Rgn,
2630  const RECTL *rect)
2631 {
2632  PRECTL pCurRect, pRectEnd;
2633  RECT rc;
2634 
2635  /* Swap the coordinates to make right >= left and bottom >= top */
2636  /* (region building rectangles are normalized the same way) */
2637  if (rect->top > rect->bottom)
2638  {
2639  rc.top = rect->bottom;
2640  rc.bottom = rect->top;
2641  }
2642  else
2643  {
2644  rc.top = rect->top;
2645  rc.bottom = rect->bottom;
2646  }
2647 
2648  if (rect->right < rect->left)
2649  {
2650  rc.right = rect->left;
2651  rc.left = rect->right;
2652  }
2653  else
2654  {
2655  rc.right = rect->right;
2656  rc.left = rect->left;
2657  }
2658 
2659  /* This is (just) a useful optimization */
2660  if ((Rgn->rdh.nCount > 0) && EXTENTCHECK(&Rgn->rdh.rcBound, &rc))
2661  {
2662  for (pCurRect = Rgn->Buffer, pRectEnd = pCurRect +
2663  Rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
2664  {
2665  if (pCurRect->bottom <= rc.top)
2666  continue; /* Not far enough down yet */
2667 
2668  if (pCurRect->top >= rc.bottom)
2669  break; /* Too far down */
2670 
2671  if (pCurRect->right <= rc.left)
2672  continue; /* Not far enough over yet */
2673 
2674  if (pCurRect->left >= rc.right)
2675  {
2676  continue;
2677  }
2678 
2679  return TRUE;
2680  }
2681  }
2682 
2683  return FALSE;
2684 }
2685 
2686 VOID
2687 FASTCALL
2689  PREGION rgn,
2690  INT LeftRect,
2691  INT TopRect,
2692  INT RightRect,
2693  INT BottomRect)
2694 {
2695  PRECTL firstRect;
2696 
2697  if (LeftRect > RightRect)
2698  {
2699  INT tmp = LeftRect;
2700  LeftRect = RightRect;
2701  RightRect = tmp;
2702  }
2703 
2704  if (TopRect > BottomRect)
2705  {
2706  INT tmp = TopRect;
2707  TopRect = BottomRect;
2708  BottomRect = tmp;
2709  }
2710 
2711  if ((LeftRect != RightRect) && (TopRect != BottomRect))
2712  {
2713  firstRect = rgn->Buffer;
2714  ASSERT(firstRect);
2715  firstRect->left = rgn->rdh.rcBound.left = LeftRect;
2716  firstRect->top = rgn->rdh.rcBound.top = TopRect;
2717  firstRect->right = rgn->rdh.rcBound.right = RightRect;
2718  firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
2719  rgn->rdh.nCount = 1;
2720  rgn->rdh.iType = RDH_RECTANGLES;
2721  }
2722  else
2723  {
2724  EMPTY_REGION(rgn);
2725  }
2726 }
2727 
2728 BOOL
2729 FASTCALL
2731  _Inout_ PREGION prgn,
2732  _In_ INT cx,
2733  _In_ INT cy)
2734 {
2735  PRECTL prcl;
2736  UINT i;
2737 
2738  NT_ASSERT(prgn != NULL);
2739 
2740  /* Check for trivial case */
2741  if ((cx == 0) && (cy == 0))
2742  {
2743  return TRUE;
2744  }
2745 
2746  /* Check for empty regions, we ignore the offset values here */
2747  if (prgn->rdh.nCount == 0)
2748  {
2749  return TRUE;
2750  }
2751 
2752  /* Make sure the offset is within the legal range */
2753  if ((cx > MAX_COORD) || (cx < MIN_COORD) ||
2754  (cy > MAX_COORD) || (cy < MIN_COORD))
2755  {
2756  return FALSE;
2757  }
2758 
2759  /* Are we moving right? */
2760  if (cx > 0)
2761  {
2762  /* Check if we stay inside the bounds on the right side */
2763  if (prgn->rdh.rcBound.right > (MAX_COORD - cx))
2764  {
2765  return FALSE;
2766  }
2767  }
2768  else
2769  {
2770  /* Check if we stay inside the bounds on the left side */
2771  if (prgn->rdh.rcBound.left < (MIN_COORD - cx))
2772  {
2773  return FALSE;
2774  }
2775  }
2776 
2777  /* Are we moving down? */
2778  if (cy > 0)
2779  {
2780  /* Check if we stay inside the bounds on the right side */
2781  if (prgn->rdh.rcBound.bottom > (MAX_COORD - cy))
2782  {
2783  return FALSE;
2784  }
2785  }
2786  else
2787  {
2788  /* Check if we stay inside the bounds on the left side */
2789  if (prgn->rdh.rcBound.top < (MIN_COORD - cy))
2790  {
2791  return FALSE;
2792  }
2793  }
2794 
2795  /* Loop to move the rects */
2796  prcl = prgn->Buffer;
2797  for (i = 0; i < prgn->rdh.nCount; i++)
2798  {
2799  prcl[i].left += cx;
2800  prcl[i].right += cx;
2801  prcl[i].top += cy;
2802  prcl[i].bottom += cy;
2803  }
2804 
2805  /* Finally update the bounds rect */
2806  if (prgn->Buffer != &prgn->rdh.rcBound)
2807  {
2808  prgn->rdh.rcBound.left += cx;
2809  prgn->rdh.rcBound.right += cx;
2810  prgn->rdh.rcBound.top += cy;
2811  prgn->rdh.rcBound.bottom += cy;
2812  }
2813 
2814  return TRUE;
2815 }
2816 
2817 /***********************************************************************
2818  * REGION_InsertEdgeInET
2819  *
2820  * Insert the given edge into the edge table.
2821  * First we must find the correct bucket in the
2822  * Edge table, then find the right slot in the
2823  * bucket. Finally, we can insert it.
2824  *
2825  */
2826 static
2827 VOID
2828 FASTCALL
2830  EDGE_TABLE *ET,
2831  EDGE_TABLE_ENTRY *ETE,
2832  INT scanline,
2833  SCANLINE_LISTBLOCK **SLLBlock,
2834  INT *iSLLBlock)
2835 {
2836  EDGE_TABLE_ENTRY *start, *prev;
2837  SCANLINE_LIST *pSLL, *pPrevSLL;
2838  SCANLINE_LISTBLOCK *tmpSLLBlock;
2839 
2840  /* Find the right bucket to put the edge into */
2841  pPrevSLL = &ET->scanlines;
2842  pSLL = pPrevSLL->next;
2843  while (pSLL && (pSLL->scanline < scanline))
2844  {
2845  pPrevSLL = pSLL;
2846  pSLL = pSLL->next;
2847  }
2848 
2849  /* Reassign pSLL (pointer to SCANLINE_LIST) if necessary */
2850  if ((!pSLL) || (pSLL->scanline > scanline))
2851  {
2852  if (*iSLLBlock > SLLSPERBLOCK-1)
2853  {
2854  tmpSLLBlock = ExAllocatePoolWithTag(PagedPool,
2855  sizeof(SCANLINE_LISTBLOCK),
2856  TAG_REGION);
2857  if (tmpSLLBlock == NULL)
2858  {
2859  DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
2860  /* FIXME: Free resources? */
2861  return;
2862  }
2863 
2864  (*SLLBlock)->next = tmpSLLBlock;
2865  tmpSLLBlock->next = (SCANLINE_LISTBLOCK *)NULL;
2866  *SLLBlock = tmpSLLBlock;
2867  *iSLLBlock = 0;
2868  }
2869 
2870  pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
2871 
2872  pSLL->next = pPrevSLL->next;
2873  pSLL->edgelist = (EDGE_TABLE_ENTRY *)NULL;
2874  pPrevSLL->next = pSLL;
2875  }
2876 
2877  pSLL->scanline = scanline;
2878 
2879  /* Now insert the edge in the right bucket */
2880  prev = (EDGE_TABLE_ENTRY *)NULL;
2881  start = pSLL->edgelist;
2882  while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
2883  {
2884  prev = start;
2885  start = start->next;
2886  }
2887 
2888  ETE->next = start;
2889 
2890  if (prev)
2891  prev->next = ETE;
2892  else
2893  pSLL->edgelist = ETE;
2894 }
2895 
2896 /***********************************************************************
2897  * REGION_loadAET
2898  *
2899  * This routine moves EDGE_TABLEEntries from the
2900  * EDGE_TABLE into the Active Edge Table,
2901  * leaving them sorted by smaller x coordinate.
2902  *
2903  */
2904 static
2905 VOID
2906 FASTCALL
2908  EDGE_TABLE_ENTRY *AET,
2909  EDGE_TABLE_ENTRY *ETEs)
2910 {
2911  EDGE_TABLE_ENTRY *pPrevAET;
2912  EDGE_TABLE_ENTRY *tmp;
2913 
2914  pPrevAET = AET;
2915  AET = AET->next;
2916  while (ETEs)
2917  {
2918  while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
2919  {
2920  pPrevAET = AET;
2921  AET = AET->next;
2922  }
2923 
2924  tmp = ETEs->next;
2925  ETEs->next = AET;
2926  if (AET)
2927  AET->back = ETEs;
2928 
2929  ETEs->back = pPrevAET;
2930  pPrevAET->next = ETEs;
2931  pPrevAET = ETEs;
2932 
2933  ETEs = tmp;
2934  }
2935 }
2936 
2937 /***********************************************************************
2938  * REGION_computeWAET
2939  *
2940  * This routine links the AET by the
2941  * nextWETE (winding EDGE_TABLE_ENTRY) link for
2942  * use by the winding number rule. The final
2943  * Active Edge Table (AET) might look something
2944  * like:
2945  *
2946  * AET
2947  * ---------- --------- ---------
2948  * |ymax | |ymax | |ymax |
2949  * | ... | |... | |... |
2950  * |next |->|next |->|next |->...
2951  * |nextWETE| |nextWETE| |nextWETE|
2952  * --------- --------- ^--------
2953  * | | |
2954  * V-------------------> V---> ...
2955  *
2956  */
2957 static
2958 VOID
2959 FASTCALL
2961  EDGE_TABLE_ENTRY *AET)
2962 {
2963  register EDGE_TABLE_ENTRY *pWETE;
2964  register INT inside = 1;
2965  register INT isInside = 0;
2966 
2967  AET->nextWETE = (EDGE_TABLE_ENTRY *)NULL;
2968  pWETE = AET;
2969  AET = AET->next;
2970  while (AET)
2971  {
2972  if (AET->ClockWise)
2973  isInside++;
2974  else
2975  isInside--;
2976 
2977  if ((!inside && !isInside) ||
2978  ( inside && isInside))
2979  {
2980  pWETE->nextWETE = AET;
2981  pWETE = AET;
2982  inside = !inside;
2983  }
2984  AET = AET->next;
2985  }
2986 
2987  pWETE->nextWETE = (EDGE_TABLE_ENTRY *)NULL;
2988 }
2989 
2990 /***********************************************************************
2991  * REGION_InsertionSort
2992  *
2993  * Just a simple insertion sort using
2994  * pointers and back pointers to sort the Active
2995  * Edge Table.
2996  *
2997  */
2998 static
2999 BOOL
3000 FASTCALL
3002  EDGE_TABLE_ENTRY *AET)
3003 {
3004  EDGE_TABLE_ENTRY *pETEchase;
3005  EDGE_TABLE_ENTRY *pETEinsert;
3006  EDGE_TABLE_ENTRY *pETEchaseBackTMP;
3007  BOOL changed = FALSE;
3008 
3009  AET = AET->next;
3010  while (AET)
3011  {
3012  pETEinsert = AET;
3013  pETEchase = AET;
3014  while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
3015  pETEchase = pETEchase->back;
3016 
3017  AET = AET->next;
3018  if (pETEchase != pETEinsert)
3019  {
3020  pETEchaseBackTMP = pETEchase->back;
3021  pETEinsert->back->next = AET;
3022  if (AET)
3023  AET->back = pETEinsert->back;
3024 
3025  pETEinsert->next = pETEchase;
3026  pETEchase->back->next = pETEinsert;
3027  pETEchase->back = pETEinsert;
3028  pETEinsert->back = pETEchaseBackTMP;
3029  changed = TRUE;
3030  }
3031  }
3032 
3033  return changed;
3034 }
3035 
3036 /***********************************************************************
3037  * REGION_FreeStorage
3038  *
3039  * Clean up our act.
3040  */
3041 static
3042 VOID
3043 FASTCALL
3045  SCANLINE_LISTBLOCK *pSLLBlock)
3046 {
3047  SCANLINE_LISTBLOCK *tmpSLLBlock;
3048 
3049  while (pSLLBlock)
3050  {
3051  tmpSLLBlock = pSLLBlock->next;
3052  ExFreePoolWithTag(pSLLBlock, TAG_REGION);
3053  pSLLBlock = tmpSLLBlock;
3054  }
3055 }
3056 
3057 
3058 /***********************************************************************
3059  * REGION_PtsToRegion
3060  *
3061  * Create an array of rectangles from a list of points.
3062  */
3063 static
3064 INT
3065 FASTCALL
3067  INT numFullPtBlocks,
3068  INT iCurPtBlock,
3069  POINTBLOCK *FirstPtBlock,
3070  PREGION reg)
3071 {
3072  RECTL *rects;
3073  POINT *pts;
3074  POINTBLOCK *CurPtBlock;
3075  INT i;
3076  RECTL *extents, *temp;
3077  INT numRects;
3078 
3079  extents = &reg->rdh.rcBound;
3080 
3081  numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
3082 
3083  /* Make sure, we have at least one rect */
3084  if (numRects == 0)
3085  {
3086  numRects = 1;
3087  }
3088 
3089  temp = ExAllocatePoolWithTag(PagedPool, numRects * sizeof(RECT), TAG_REGION);
3090  if (temp == NULL)
3091  {
3092  return 0;
3093  }
3094 
3095  if (reg->Buffer != NULL)
3096  {
3097  COPY_RECTS(temp, reg->Buffer, reg->rdh.nCount);
3098  if (reg->Buffer != &reg->rdh.rcBound)
3099  ExFreePoolWithTag(reg->Buffer, TAG_REGION);
3100  }
3101  reg->Buffer = temp;
3102 
3103  reg->rdh.nCount = numRects;
3104  CurPtBlock = FirstPtBlock;
3105  rects = reg->Buffer - 1;
3106  numRects = 0;
3107  extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
3108 
3109  for ( ; numFullPtBlocks >= 0; numFullPtBlocks--)
3110  {
3111  /* The loop uses 2 points per iteration */
3112  i = NUMPTSTOBUFFER >> 1;
3113  if (numFullPtBlocks == 0)
3114  i = iCurPtBlock >> 1;
3115 
3116  for (pts = CurPtBlock->pts; i--; pts += 2)
3117  {
3118  if (pts->x == pts[1].x)
3119  continue;
3120 
3121  if ((numRects && pts->x == rects->left) &&
3122  (pts->y == rects->bottom) &&
3123  (pts[1].x == rects->right) &&
3124  ((numRects == 1) || (rects[-1].top != rects->top)) &&
3125  (i && pts[2].y > pts[1].y))
3126  {
3127  rects->bottom = pts[1].y + 1;
3128  continue;
3129  }
3130 
3131  numRects++;
3132  rects++;
3133  rects->left = pts->x;
3134  rects->top = pts->y;
3135  rects->right = pts[1].x;
3136  rects->bottom = pts[1].y + 1;
3137 
3138  if (rects->left < extents->left)
3139  extents->left = rects->left;
3140  if (rects->right > extents->right)
3141  extents->right = rects->right;
3142  }
3143 
3144  CurPtBlock = CurPtBlock->next;
3145  }
3146 
3147  if (numRects)
3148  {
3149  extents->top = reg->Buffer->top;
3150  extents->bottom = rects->bottom;
3151  }
3152  else
3153  {
3154  extents->left = 0;
3155  extents->top = 0;
3156  extents->right = 0;
3157  extents->bottom = 0;
3158  }
3159 
3160  reg->rdh.nCount = numRects;
3161 
3162  return(TRUE);
3163 }
3164 
3165 /***********************************************************************
3166  * REGION_CreateETandAET
3167  *
3168  * This routine creates the edge table for
3169  * scan converting polygons.
3170  * The Edge Table (ET) looks like:
3171  *
3172  * EDGE_TABLE
3173  * --------
3174  * | ymax | SCANLINE_LISTs
3175  * |scanline|-->------------>-------------->...
3176  * -------- |scanline| |scanline|
3177  * |edgelist| |edgelist|
3178  * --------- ---------
3179  * | |
3180  * | |
3181  * V V
3182  * list of ETEs list of ETEs
3183  *
3184  * where ETE is an EDGE_TABLE_ENTRY data structure,
3185  * and there is one SCANLINE_LIST per scanline at
3186  * which an edge is initially entered.
3187  *
3188  */
3189 static
3190 VOID
3191 FASTCALL
3193  const ULONG *Count,
3194  INT nbpolygons,
3195  const POINT *pts,
3196  EDGE_TABLE *ET,
3197  EDGE_TABLE_ENTRY *AET,
3198  EDGE_TABLE_ENTRY *pETEs,
3199  SCANLINE_LISTBLOCK *pSLLBlock)
3200 {
3201  const POINT *top, *bottom;
3202  const POINT *PrevPt, *CurrPt, *EndPt;
3203  INT poly, count;
3204  INT iSLLBlock = 0;
3205  INT dy;
3206 
3207  /* Initialize the Active Edge Table */
3208  AET->next = (EDGE_TABLE_ENTRY *)NULL;
3209  AET->back = (EDGE_TABLE_ENTRY *)NULL;
3210  AET->nextWETE = (EDGE_TABLE_ENTRY *)NULL;
3212 
3213  /* Initialize the Edge Table. */
3214  ET->scanlines.next = (SCANLINE_LIST *)NULL;
3215  ET->ymax = SMALL_COORDINATE;
3216  ET->ymin = LARGE_COORDINATE;
3217  pSLLBlock->next = (SCANLINE_LISTBLOCK *)NULL;
3218 
3219  EndPt = pts - 1;
3220  for (poly = 0; poly < nbpolygons; poly++)
3221  {
3222  count = Count[poly];
3223  EndPt += count;
3224  if (count < 2)
3225  continue;
3226 
3227  PrevPt = EndPt;
3228 
3229  /* For each vertex in the array of points.
3230  * In this loop we are dealing with two vertices at
3231  * a time -- these make up one edge of the polygon. */
3232  while (count--)
3233  {
3234  CurrPt = pts++;
3235 
3236  /* Find out which point is above and which is below. */
3237  if (PrevPt->y > CurrPt->y)
3238  {
3239  bottom = PrevPt, top = CurrPt;
3240  pETEs->ClockWise = 0;
3241  }
3242  else
3243  {
3244  bottom = CurrPt, top = PrevPt;
3245  pETEs->ClockWise = 1;
3246  }
3247 
3248  /* Don't add horizontal edges to the Edge table. */
3249  if (bottom->y != top->y)
3250  {
3251  /* -1 so we don't get last scanline */
3252  pETEs->ymax = bottom->y - 1;
3253 
3254  /* Initialize integer edge algorithm */
3255  dy = bottom->y - top->y;
3256  BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
3257 
3259  pETEs,
3260  top->y,
3261  &pSLLBlock,
3262  &iSLLBlock);
3263 
3264  if (PrevPt->y > ET->ymax)
3265  ET->ymax = PrevPt->y;
3266  if (PrevPt->y < ET->ymin)
3267  ET->ymin = PrevPt->y;
3268  pETEs++;
3269  }
3270 
3271  PrevPt = CurrPt;
3272  }
3273  }
3274 }
3275 
3276 BOOL
3277 FASTCALL
3279  _Inout_ PREGION prgn,
3280  _In_ const POINT *ppt,
3281  _In_ const ULONG *pcPoints,
3282  _In_ ULONG cPolygons,
3283  _In_ INT iMode)
3284 {
3285  EDGE_TABLE_ENTRY *pAET; /* Active Edge Table */
3286  INT y; /* Current scanline */
3287  INT iPts = 0; /* Number of pts in buffer */
3288  EDGE_TABLE_ENTRY *pWETE; /* Winding Edge Table Entry */
3289  SCANLINE_LIST *pSLL; /* Current SCANLINE_LIST */
3290  POINT *pts; /* Output buffer */
3291  EDGE_TABLE_ENTRY *pPrevAET; /* Pointer to previous AET */
3292  EDGE_TABLE ET; /* Header node for ET */
3293  EDGE_TABLE_ENTRY AET; /* Header node for AET */
3294  EDGE_TABLE_ENTRY *pETEs; /* EDGE_TABLEEntries pool */
3295  SCANLINE_LISTBLOCK SLLBlock; /* Header for SCANLINE_LIST */
3296  INT fixWAET = FALSE;
3297  POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
3298  POINTBLOCK *tmpPtBlock;
3299  UINT numFullPtBlocks = 0;
3300  UINT poly, total;
3301 
3302  /* Check if iMode is valid */
3303  if ((iMode != ALTERNATE) && (iMode != WINDING))
3304  {
3305  DPRINT1("Invalid iMode: %lu\n", iMode);
3306  return FALSE;
3307  }
3308 
3309  /* Special case a rectangle */
3310  if (((cPolygons == 1) && ((pcPoints[0] == 4) ||
3311  ((pcPoints[0] == 5) && (ppt[4].x == ppt[0].x) && (ppt[4].y == ppt[0].y)))) &&
3312  (((ppt[0].y == ppt[1].y) &&
3313  (ppt[1].x == ppt[2].x) &&
3314  (ppt[2].y == ppt[3].y) &&
3315  (ppt[3].x == ppt[0].x)) ||
3316  ((ppt[0].x == ppt[1].x) &&
3317  (ppt[1].y == ppt[2].y) &&
3318  (ppt[2].x == ppt[3].x) &&
3319  (ppt[3].y == ppt[0].y))))
3320  {
3321  REGION_SetRectRgn(prgn,
3322  min(ppt[0].x, ppt[2].x),
3323  min(ppt[0].y, ppt[2].y),
3324  max(ppt[0].x, ppt[2].x),
3325  max(ppt[0].y, ppt[2].y));
3326  return TRUE;
3327  }
3328 
3329  for (poly = total = 0; poly < cPolygons; poly++)
3330  total += pcPoints[poly];
3331 
3333  sizeof(EDGE_TABLE_ENTRY) * total,
3334  TAG_REGION);
3335  if (pETEs == NULL)
3336  {
3337  DPRINT1("Failed to allocate %lu edge entries\n", total);
3338  return FALSE;
3339  }
3340 
3341  pts = FirstPtBlock.pts;
3342  REGION_CreateETandAET(pcPoints, cPolygons, ppt, &ET, &AET, pETEs, &SLLBlock);
3343  pSLL = ET.scanlines.next;
3344  curPtBlock = &FirstPtBlock;
3345 
3346  if (iMode != WINDING)
3347  {
3348  /* For each scanline */
3349  for (y = ET.ymin; y < ET.ymax; y++)
3350  {
3351  /* Add a new edge to the active edge table when we
3352  * get to the next edge. */
3353  if (pSLL != NULL && y == pSLL->scanline)
3354  {
3355  REGION_loadAET(&AET, pSLL->edgelist);
3356  pSLL = pSLL->next;
3357  }
3358  pPrevAET = &AET;
3359  pAET = AET.next;
3360 
3361  /* For each active edge */
3362  while (pAET)
3363  {
3364  pts->x = pAET->bres.minor_axis, pts->y = y;
3365  pts++, iPts++;
3366 
3367  /* Send out the buffer */
3368  if (iPts == NUMPTSTOBUFFER)
3369  {
3370  tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
3371  sizeof(POINTBLOCK),
3372  TAG_REGION);
3373  if (tmpPtBlock == NULL)
3374  {
3375  DPRINT1("Can't alloc tmpPtBlock\n");
3376  ExFreePoolWithTag(pETEs, TAG_REGION);
3377  return FALSE;
3378  }
3379 
3380  curPtBlock->next = tmpPtBlock;
3381  curPtBlock = tmpPtBlock;
3382  pts = curPtBlock->pts;
3383  numFullPtBlocks++;
3384  iPts = 0;
3385  }
3386 
3387  EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
3388  }
3389 
3390  REGION_InsertionSort(&AET);
3391  }
3392  }
3393  else
3394  {
3395  /* For each scanline */
3396  for (y = ET.ymin; y < ET.ymax; y++)
3397  {
3398  /* Add a new edge to the active edge table when we
3399  * get to the next edge. */
3400  if (pSLL != NULL && y == pSLL->scanline)
3401  {
3402  REGION_loadAET(&AET, pSLL->edgelist);
3403  REGION_computeWAET(&AET);
3404  pSLL = pSLL->next;
3405  }
3406 
3407  pPrevAET = &AET;
3408  pAET = AET.next;
3409  pWETE = pAET;
3410 
3411  /* For each active edge */
3412  while (pAET)
3413  {
3414  /* Add to the buffer only those edges that
3415  * are in the Winding active edge table. */
3416  if (pWETE == pAET)
3417  {
3418  pts->x = pAET->bres.minor_axis;
3419  pts->y = y;
3420  pts++;
3421  iPts++;
3422 
3423  /* Send out the buffer */
3424  if (iPts == NUMPTSTOBUFFER)
3425  {
3426  tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
3427  sizeof(POINTBLOCK),
3428  TAG_REGION);
3429  if (tmpPtBlock == NULL)
3430  {
3431  DPRINT1("Can't alloc tPB\n");
3432  ExFreePoolWithTag(pETEs, TAG_REGION);
3433  return FALSE;
3434  }
3435  curPtBlock->next = tmpPtBlock;
3436  curPtBlock = tmpPtBlock;
3437  pts = curPtBlock->pts;
3438  numFullPtBlocks++;
3439  iPts = 0;
3440  }
3441 
3442  pWETE = pWETE->nextWETE;
3443  }
3444 
3445  EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
3446  }
3447 
3448  /* Recompute the winding active edge table if
3449  * we just resorted or have exited an edge. */
3450  if (REGION_InsertionSort(&AET) || fixWAET)
3451  {
3452  REGION_computeWAET(&AET);
3453  fixWAET = FALSE;
3454  }
3455  }
3456  }
3457 
3458  REGION_FreeStorage(SLLBlock.next);
3459  REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, prgn);
3460 
3461  for (curPtBlock = FirstPtBlock.next; numFullPtBlocks-- > 0;)
3462  {
3463  tmpPtBlock = curPtBlock->next;
3464  ExFreePoolWithTag(curPtBlock, TAG_REGION);
3465  curPtBlock = tmpPtBlock;
3466  }
3467 
3468  ExFreePoolWithTag(pETEs, TAG_REGION);
3469  return TRUE;
3470 }
3471 
3472 HRGN
3473 NTAPI
3475  _In_ const POINT *ppt,
3476  _In_ const ULONG *pcPoints,
3477  _In_ ULONG cPolygons,
3478  _In_ INT iMode)
3479 {
3480  PREGION prgn;
3481  HRGN hrgn;
3482 
3483  /* Allocate a new region */
3485  if (prgn == NULL)
3486  {
3488  return NULL;
3489  }
3490 
3491  /* Call the internal function and check for success */
3492  if (REGION_SetPolyPolygonRgn(prgn, ppt, pcPoints, cPolygons, iMode))
3493  {
3494  /* Success, get the handle and unlock the region */
3495  hrgn = prgn->BaseObject.hHmgr;
3496  REGION_UnlockRgn(prgn);
3497  }
3498  else
3499  {
3500  /* Failure, delete the region */
3501  REGION_Delete(prgn);
3502  hrgn = NULL;
3503  }
3504 
3505  return hrgn;
3506 }
3507 
3508 BOOL
3509 FASTCALL
3511  HRGN hRgn,
3512  LPRECTL rc)
3513 {
3514  PREGION Rgn;
3515  BOOL Ret;
3516 
3517  Rgn = REGION_LockRgn(hRgn);
3518  if (Rgn == NULL)
3519  {
3520  return ERROR;
3521  }
3522 
3523  Ret = REGION_RectInRegion(Rgn, rc);
3524  REGION_UnlockRgn(Rgn);
3525  return Ret;
3526 }
3527 
3528 
3529 //
3530 // NtGdi Exported Functions
3531 //
3532 INT
3533 APIENTRY
3535  IN HRGN hrgnDst,
3536  IN HRGN hrgnSrc1,
3537  IN HRGN hrgnSrc2,
3538  IN INT iMode)
3539 {
3540  HRGN ahrgn[3];
3541  PREGION aprgn[3];
3542  INT iResult;
3543 
3544  /* Validate the combine mode */
3545  if ((iMode < RGN_AND) || (iMode > RGN_COPY))
3546  {
3547  return ERROR;
3548  }
3549 
3550  /* Validate that we have the required regions */
3551  if ((hrgnDst == NULL) ||
3552  (hrgnSrc1 == NULL) ||
3553  ((iMode != RGN_COPY) && (hrgnSrc2 == NULL)))
3554  {
3555  DPRINT1("NtGdiCombineRgn invalid parameters: %p, %p, %p, %d\n",
3556  hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
3558  return ERROR;
3559  }
3560 
3561  /* Lock all regions */
3562  ahrgn[0] = hrgnDst;
3563  ahrgn[1] = hrgnSrc1;
3564  ahrgn[2] = iMode != RGN_COPY ? hrgnSrc2 : NULL;
3565  if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahrgn, (PVOID*)aprgn, GDIObjType_RGN_TYPE))
3566  {
3567  DPRINT1("NtGdiCombineRgn failed to lock regions: %p, %p, %p, %d\n",
3568  hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
3569  return ERROR;
3570  }
3571 
3572  /* HACK: Sync usermode attributes */
3573  REGION_vSyncRegion(aprgn[0]);
3574  if (aprgn[1] != aprgn[0])
3575  REGION_vSyncRegion(aprgn[1]);
3576  if ((aprgn[2] != NULL) && (aprgn[2] != aprgn[0]) && (aprgn[2] != aprgn[1]))
3577  REGION_vSyncRegion(aprgn[2]);
3578 
3579  /* Call the internal function */
3580  iResult = IntGdiCombineRgn(aprgn[0], aprgn[1], aprgn[2], iMode);
3581 
3582  /* Unlock and return */
3583  REGION_UnlockRgn(aprgn[0]);
3584  REGION_UnlockRgn(aprgn[1]);
3585  if (aprgn[2] != NULL)
3586  REGION_UnlockRgn(aprgn[2]);
3587 
3588  return iResult;
3589 }
3590 
3591 HRGN
3592 APIENTRY
3594  INT Left,
3595  INT Top,
3596  INT Right,
3597  INT Bottom)
3598 {
3599  return NtGdiCreateRoundRectRgn(Left,
3600  Top,
3601  Right, Bottom,
3602  Right - Left,
3603  Bottom - Top);
3604 }
3605 
3606 HRGN
3607 APIENTRY
3609  INT LeftRect,
3610  INT TopRect,
3611  INT RightRect,
3612  INT BottomRect)
3613 {
3614  PREGION pRgn;
3615  HRGN hRgn;
3616 
3617  /* Allocate region data structure with space for 1 RECTL */
3619  if (pRgn == NULL)
3620  {
3622  return NULL;
3623  }
3624 
3625  hRgn = pRgn->BaseObject.hHmgr;
3626 
3627  REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
3628  REGION_UnlockRgn(pRgn);
3629 
3630  DPRINT("Returning %p.\n", hRgn);
3631 
3632  return hRgn;
3633 }
3634 
3635 HRGN
3636 APIENTRY
3638  INT left,
3639  INT top,
3640  INT right,
3641  INT bottom,
3642  INT ellipse_width,
3643  INT ellipse_height)
3644 {
3645  PREGION obj;
3646  HRGN hrgn;
3647  int a, b, i, x, y;
3648  INT64 asq, bsq, dx, dy, err;
3649  RECT *rects;
3650 
3651  /* Make the dimensions sensible */
3652  if (left > right)
3653  {
3654  INT tmp = left;
3655  left = right;
3656  right = tmp;
3657  }
3658 
3659  if (top > bottom)
3660  {
3661  INT tmp = top;
3662  top = bottom;
3663  bottom = tmp;
3664  }
3665 
3666  /* the region is for the rectangle interior, but only at right and bottom for some reason */
3667  right--;
3668  bottom--;
3669 
3670  ellipse_width = min( right - left, abs( ellipse_width ));
3671  ellipse_height = min( bottom - top, abs( ellipse_height ));
3672 
3673  /* Check if we can do a normal rectangle instead */
3674 
3675  if ((ellipse_width < 2) || (ellipse_height < 2))
3676  return NtGdiCreateRectRgn(left, top, right, bottom);
3677 
3678  obj = REGION_AllocUserRgnWithHandle( ellipse_height );
3679  if (obj == NULL)
3680  return 0;
3681 
3682  hrgn = obj->BaseObject.hHmgr;
3683 
3684  obj->rdh.rcBound.left = left;
3685  obj->rdh.rcBound.top = top;
3686  obj->rdh.rcBound.right = right;
3687  obj->rdh.rcBound.bottom = bottom;
3688  rects = obj->Buffer;
3689 
3690  /* based on an algorithm by Alois Zingl */
3691 
3692  a = ellipse_width - 1;
3693  b = ellipse_height - 1;
3694  asq = (INT64)8 * a * a;
3695  bsq = (INT64)8 * b * b;
3696  dx = (INT64)4 * b * b * (1 - a);
3697  dy = (INT64)4 * a * a * (1 + (b % 2));
3698  err = dx + dy + a * a * (b % 2);
3699 
3700  x = 0;
3701  y = ellipse_height / 2;
3702 
3703  rects[y].left = left;
3704  rects[y].right = right;
3705 
3706  while (x <= ellipse_width / 2)
3707  {
3708  INT64 e2 = 2 * err;
3709  if (e2 >= dx)
3710  {
3711  x++;
3712  err += dx += bsq;
3713  }
3714  if (e2 <= dy)
3715  {
3716  y++;
3717  err += dy += asq;
3718  rects[y].left = left + x;
3719  rects[y].right = right - x;
3720  }
3721  }
3722  for (i = 0; i < ellipse_height / 2; i++)
3723  {
3724  rects[i].left = rects[b - i].left;
3725  rects[i].right = rects[b - i].right;
3726  rects[i].top = top + i;
3727  rects[i].bottom = rects[i].top + 1;
3728  }
3729  for (; i < ellipse_height; i++)
3730  {
3731  rects[i].top = bottom - ellipse_height + i;
3732  rects[i].bottom = rects[i].top + 1;
3733  }
3734  rects[ellipse_height / 2].top = top + ellipse_height / 2; /* extend to top of rectangle */
3735 
3737  return hrgn;
3738 }
3739 
3740 BOOL
3741 APIENTRY
3743  HRGN hSrcRgn1,
3744  HRGN hSrcRgn2)
3745 {
3746  HRGN ahrgn[2];
3747  PREGION aprgn[2];
3748  PREGION rgn1, rgn2;
3749  PRECTL tRect1, tRect2;
3750  ULONG i;
3751  BOOL bRet = FALSE;
3752 
3753  /* Check if we got 2 regions */
3754  if ((hSrcRgn1 == NULL) || (hSrcRgn2 == NULL))
3755  {
3756  return FALSE;
3757  }
3758 
3759  /* Check if these are the same regions */
3760  if (hSrcRgn1 == hSrcRgn2)
3761  {
3762  /* Make sure this region is valid */
3763  if ((GDI_HANDLE_GET_TYPE(hSrcRgn1) == GDILoObjType_LO_REGION_TYPE) &&
3764  GreIsHandleValid(hSrcRgn1))
3765  {
3766  return TRUE;
3767  }
3768  return FALSE;
3769  }
3770 
3771  /* Lock both regions */
3772  ahrgn[0] = hSrcRgn1;
3773  ahrgn[1] = hSrcRgn2;
3774  if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahrgn, (PVOID*)aprgn, GDIObjType_RGN_TYPE))
3775  {
3776  DPRINT1("NtGdiEqualRgn failed to lock regions: %p, %p\n",
3777  hSrcRgn1, hSrcRgn2);
3778  return FALSE;
3779  }
3780 
3781  REGION_vSyncRegion(aprgn[0]);
3782  REGION_vSyncRegion(aprgn[1]);
3783 
3784  rgn1 = aprgn[0];
3785  rgn2 = aprgn[1];
3786 
3787  if (rgn1->rdh.nCount != rgn2->rdh.nCount)
3788  goto exit;
3789 
3790  if (rgn1->rdh.nCount == 0)
3791  {
3792  bRet = TRUE;
3793  goto exit;
3794  }
3795 
3796  if ((rgn1->rdh.rcBound.left != rgn2->rdh.rcBound.left) ||
3797  (rgn1->rdh.rcBound.right != rgn2->rdh.rcBound.right) ||
3798  (rgn1->rdh.rcBound.top != rgn2->rdh.rcBound.top) ||
3799  (rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom))
3800  goto exit;
3801 
3802  tRect1 = rgn1->Buffer;
3803  tRect2 = rgn2->Buffer;
3804 
3805  if ((tRect1 == NULL) || (tRect2 == NULL))
3806  goto exit;
3807 
3808  for (i=0; i < rgn1->rdh.nCount; i++)
3809  {
3810  if ((tRect1[i].left != tRect2[i].left) ||
3811  (tRect1[i].right != tRect2[i].right) ||
3812  (tRect1[i].top != tRect2[i].top) ||
3813  (tRect1[i].bottom != tRect2[i].bottom))
3814  goto exit;
3815  }
3816 
3817  bRet = TRUE;
3818 
3819 exit:
3820  REGION_UnlockRgn(rgn1);
3821  REGION_UnlockRgn(rgn2);
3822  return bRet;
3823 }
3824 
3825 HRGN
3826 APIENTRY
3828  OPTIONAL LPXFORM Xform,
3829  DWORD Count,
3830  LPRGNDATA RgnData)
3831 {
3832  HRGN hRgn;
3833  PREGION Region;
3834  DWORD nCount = 0;
3835  DWORD iType = 0;
3836  DWORD dwSize = 0;
3837  UINT i;
3838  RECT* rects;
3840  MATRIX matrix;
3841  XFORMOBJ xo;
3842 
3843  DPRINT("NtGdiExtCreateRegion\n");
3844  _SEH2_TRY
3845  {
3846  ProbeForRead(RgnData, Count, 1);
3847  nCount = RgnData->rdh.nCount;
3848  iType = RgnData->rdh.iType;
3849  dwSize = RgnData->rdh.dwSize;
3850  rects = (RECT*)RgnData->Buffer;
3851  }
3853  {
3855  }
3856  _SEH2_END;
3857 
3858  if (!NT_SUCCESS(Status))
3859  {
3861  return NULL;
3862  }
3863 
3864  /* Check parameters, but don't set last error here */
3865  if ((Count < sizeof(RGNDATAHEADER) + nCount * sizeof(RECT)) ||
3866  (iType != RDH_RECTANGLES) ||
3867  (dwSize != sizeof(RGNDATAHEADER)))
3868  {
3869  return NULL;
3870  }
3871 
3873 
3874  if (Region == NULL)
3875  {
3877  return FALSE;
3878  }
3879  hRgn = Region->BaseObject.hHmgr;
3880 
3881  _SEH2_TRY
3882  {
3883  /* Insert the rectangles one by one */
3884  for(i=0; i<nCount; i++)
3885  {
3886  if ( rects[i].left < rects[i].right && rects[i].top < rects[i].bottom )
3887  {
3888  if (!REGION_UnionRectWithRgn(Region, &rects[i]))
3889  {
3892  hRgn = NULL;
3893  _SEH2_LEAVE;
3894  }
3895  }
3896  }
3897 
3898  if (Xform != NULL)
3899  {
3900  ULONG ret;
3901 
3902  /* Init the XFORMOBJ from the Xform struct */
3904  XFORMOBJ_vInit(&xo, &matrix);
3905  ret = XFORMOBJ_iSetXform(&xo, (XFORML*)Xform);
3906 
3907  /* Check for error */
3908  if (ret != DDI_ERROR)
3909  {
3910  /* Apply the coordinate transformation on the rects */
3911  if (XFORMOBJ_bApplyXform(&xo,
3912  XF_LTOL,
3913  Region->rdh.nCount * 2,
3914  Region->Buffer,
3915  Region->Buffer))
3916  {
3918  }
3919  }
3920  }
3921  }
3923  {
3925  }
3926  _SEH2_END;
3927  if (!NT_SUCCESS(Status))
3928  {
3932  return NULL;
3933  }
3934 
3936 
3937  return hRgn;
3938 }
3939 
3940 INT
3941 APIENTRY
3943  HRGN hRgn,
3944  PRECTL pRect)
3945 {
3946  PREGION Rgn;
3947  RECTL SafeRect;
3948  DWORD ret;
3950 
3951  Rgn = REGION_LockRgn(hRgn);
3952  if (Rgn == NULL)
3953  {
3954  return ERROR;
3955  }
3956 
3957  ret = REGION_GetRgnBox(Rgn, &SafeRect);
3958  REGION_UnlockRgn(Rgn);
3959  if (ret == ERROR)
3960  {
3961  return ret;
3962  }
3963 
3964  _SEH2_TRY
3965  {
3966  ProbeForWrite(pRect, sizeof(RECT), 1);
3967  *pRect = SafeRect;
3968  }
3970  {
3972  }
3973  _SEH2_END;
3974  if (!NT_SUCCESS(Status))
3975  {
3976  return ERROR;
3977  }
3978 
3979  return ret;
3980 }
3981 
3982 INT
3983 APIENTRY
3985  _In_ HRGN hrgn,
3986  _In_ INT cx,
3987  _In_ INT cy)
3988 {
3989  PREGION prgn;
3990  INT iResult;
3991 
3992  DPRINT("NtGdiOffsetRgn: hrgn %p cx %d cy %d\n", hrgn, cx, cy);
3993 
3994  /* Lock the region */
3995  prgn = REGION_LockRgn(hrgn);
3996  if (prgn == NULL)
3997  {
3998  DPRINT1("NtGdiOffsetRgn: failed to lock region %p\n", hrgn);
3999  return ERROR;
4000  }
4001 
4002  /* Call the internal function */
4003  if (!REGION_bOffsetRgn(prgn, cx, cy))
4004  {
4005  iResult = ERROR;
4006  }
4007  else
4008  {
4009  iResult = REGION_Complexity(prgn);
4010  }
4011 
4012  /* Unlock and return the result */
4013  REGION_UnlockRgn(prgn);
4014  return iResult;
4015 }
4016 
4017 BOOL
4018 APIENTRY
4020  _In_ HRGN hrgn,
4021  _In_ INT x,
4022  _In_ INT y)
4023 {
4024  PREGION prgn;
4025  BOOL bResult;
4026 
4027  /* Lock the region */
4028  prgn = REGION_LockRgn(hrgn);
4029  if (prgn == NULL)
4030  {
4031  DPRINT1("NtGdiPtInRegion: hrgn error\n");
4032  return FALSE;
4033  }
4034 
4035  /* Call the internal function */
4036  bResult = REGION_PtInRegion(prgn, x, y);
4037 
4038  /* Unlock and return the result */
4039  REGION_UnlockRgn(prgn);
4040  return bResult;
4041 }
4042 
4044 BOOL
4045 APIENTRY
4047  _In_ HRGN hrgn,
4048  _Inout_ LPRECT prclUnsafe)
4049 {
4050  RECTL rcTemp;
4051 
4052  /* Probe and copy the rect */
4053  _SEH2_TRY
4054  {
4055  ProbeForRead(prclUnsafe, sizeof(RECT), 1);
4056  rcTemp = *prclUnsafe;
4057  }
4059  {
4060  DPRINT1("NtGdiRectInRegion: Exception accessing the rect\n");
4061  return FALSE;
4062  }
4063  _SEH2_END;
4064 
4065  /* Call the internal function */
4066  return IntRectInRegion(hrgn, &rcTemp);
4067 }
4068 
4069 BOOL
4070 APIENTRY
4072  _In_ HRGN hrgn,
4073  _In_ INT xLeft,
4074  _In_ INT yTop,
4075  _In_ INT xRight,
4076  _In_ INT yBottom)
4077 {
4078  PREGION prgn;
4079 
4080  /* Lock the region */
4081  prgn = REGION_LockRgn(hrgn);
4082  if (prgn == NULL)
4083  {
4084  return FALSE;
4085  }
4086 
4087  /* Call the internal API */
4088  REGION_SetRectRgn(prgn, xLeft, yTop, xRight, yBottom);
4089 
4090  /* Unlock the region and return success */
4091  REGION_UnlockRgn(prgn);
4092  return TRUE;
4093 }
4094 
4105 _Success_(return!=0)
4107 ULONG
4108 APIENTRY
4109 NtGdiGetRegionData(
4110  _In_ HRGN hrgn,
4113 {
4114  ULONG cjRects, cjSize;
4115  PREGION prgn;
4116 
4117  /* Lock the region */
4118  prgn = REGION_LockRgn(hrgn);
4119  if (prgn == NULL)
4120  {
4122  return 0;
4123  }
4124 
4125  /* Calculate the region sizes */
4126  cjRects = prgn->rdh.nCount * sizeof(RECT);
4127  cjSize = cjRects + sizeof(RGNDATAHEADER);
4128 
4129  /* Check if region data is requested */
4130  if (lpRgnData)
4131  {
4132  /* Check if the buffer is large enough */
4133  if (cjBuffer >= cjSize)
4134  {
4135  /* Probe the buffer and copy the data */
4136  _SEH2_TRY
4137  {
4138  ProbeForWrite(lpRgnData, cjSize, sizeof(ULONG));
4139  RtlCopyMemory(lpRgnData, &prgn->rdh, sizeof(RGNDATAHEADER));
4140  RtlCopyMemory(lpRgnData->Buffer, prgn->Buffer, cjRects);
4141  lpRgnData->rdh.iType = RDH_RECTANGLES;
4142  lpRgnData->rdh.nRgnSize = cjRects;
4143  }
4145  {
4147  cjSize = 0;
4148  }
4149  _SEH2_END;
4150  }
4151  else
4152  {
4153  /* Buffer is too small */
4155  cjSize = 0;
4156  }
4157  }
4158 
4159  /* Unlock the region and return the size */
4160  REGION_UnlockRgn(prgn);
4161  return cjSize;
4162 }
4163 
4164 /* 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:821
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:1250
#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:1153
#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:1141
static VOID FASTCALL REGION_loadAET(EDGE_TABLE_ENTRY *AET, EDGE_TABLE_ENTRY *ETEs)
Definition: region.c:2907
BOOL FASTCALL REGION_SetPolyPolygonRgn(_Inout_ PREGION prgn, _In_ const POINT *ppt, _In_ const ULONG *pcPoints, _In_ ULONG cPolygons, _In_ INT iMode)
Definition: region.c:3278
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:2730
ULONG NTAPI GreGetObjectOwner(HGDIOBJ hobj)
Definition: gdiobj.c:1187
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:4046
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:3608
PREGION FASTCALL REGION_LockRgn(_In_ HRGN hrgn)
Definition: region.c:2380
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:3827
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:206
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:3066
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:3742
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:2429
#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:2628
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:3510
ULONG AttrFlags
Definition: ntgdihdl.h:265
BOOL NTAPI GDIOBJ_bLockMultipleObjects(IN ULONG ulCount, IN HGDIOBJ *ahObj, OUT PGDIOBJ *apObj, IN UCHAR objt)
Definition: gdiobj.c:1026
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:2509
#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:3942
#define EXTENTCHECK(r1, r2)
Definition: region.c:167
VOID NTAPI GDIOBJ_vDeleteObject(POBJ pobj)
Definition: gdiobj.c:1106
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:2481
_Success_(return!=0)
Definition: region.c:4105
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:3192
#define _Inout_
Definition: no_sal2.h:244
INT APIENTRY IntGdiGetRgnBox(HRGN hRgn, PRECTL pRect)
Definition: region.c:2583
#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:3637
static VOID FASTCALL REGION_computeWAET(EDGE_TABLE_ENTRY *AET)
Definition: region.c:2960
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:1091
#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:875
#define ATTR_RGN_DIRTY
Definition: ntgdihdl.h:207
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:3001
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:2455
BOOL APIENTRY NtGdiSetRectRgn(_In_ HRGN hrgn, _In_ INT xLeft, _In_ INT yTop, _In_ INT xRight, _In_ INT yBottom)
Definition: region.c:4071
#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:266
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:2282
static VOID FASTCALL REGION_FreeStorage(SCANLINE_LISTBLOCK *pSLLBlock)
Definition: region.c:3044
#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:3534
INT APIENTRY NtGdiOffsetRgn(_In_ HRGN hrgn, _In_ INT cx, _In_ INT cy)
Definition: region.c:3984
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:2222
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:267
_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:2395
_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:3474
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:2829
#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:2565
VOID FASTCALL REGION_SetRectRgn(PREGION rgn, INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
Definition: region.c:2688
PREGION FASTCALL REGION_AllocUserRgnWithHandle(INT nRgn)
Definition: region.c:2316
return STATUS_SUCCESS
Definition: btrfs.c:2725
VOID FASTCALL REGION_Delete(PREGION pRgn)
Definition: region.c:2471
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:2337
#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:557
#define APIENTRY
Definition: api.h:79
VOID NTAPI GDIOBJ_vFreeObject(POBJ pobj)
Definition: gdiobj.c:591
#define _PRAGMA_WARNING_SUPPRESS(x)
Definition: suppress.h:28
BOOL FASTCALL REGION_PtInRegion(PREGION prgn, INT X, INT Y)
Definition: region.c:2605
HRGN APIENTRY NtGdiCreateEllipticRgn(INT Left, INT Top, INT Right, INT Bottom)
Definition: region.c:3593
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:907
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
BOOL APIENTRY NtGdiPtInRegion(_In_ HRGN hrgn, _In_ INT x, _In_ INT y)
Definition: region.c:4019