xref: /reactos/win32ss/gdi/gdi32/objects/region.c (revision 1ac9e484)
1 #include <precomp.h>
2 
3 #define NDEBUG
4 #include <debug.h>
5 
6 //
7 // "Windows Graphics Programming: Win32 GDI and DirectDraw",
8 //   Chp 9 Areas, Region, Set Operations on Regions, hard copy pg 560.
9 //   universal set's bounding box to be [-(1 << 27), -(1 << 27), (1 << 27) -1, (1 << 27) -1].
10 //
11 #define MIN_COORD (INT_MIN/16) // See also ntgdi/region.c
12 #define MAX_COORD (INT_MAX/16)
13 
14 #define INRECT(r, x, y) \
15       ( ( ((r).right >  x)) && \
16       ( ((r).left <= x)) && \
17       ( ((r).bottom >  y)) && \
18       ( ((r).top <= y)) )
19 
20 static
21 VOID
22 FASTCALL
23 SortRects(PRECT pRect, INT nCount)
24 {
25     INT i, a, b, c, s;
26     RECT sRect;
27 
28     if (nCount > 0)
29     {
30         i = 1; // set index point
31         c = nCount; // set inverse count
32         do
33         {
34             s = i; // set sort count
35             if ( i < nCount )
36             {
37                 a = i - 1; // [0]
38                 b = i;     // [1]
39                 do
40                 {
41                     if ( pRect[a].top != pRect[b].top ) break;
42                     if ( pRect[a].left > pRect[b].left )
43                     {
44                         sRect = pRect[a];
45                         pRect[a] = pRect[b];
46                         pRect[b] = sRect;
47                     }
48                     ++s;
49                     b++;
50                 }
51                 while ( s < nCount );
52             }
53             ++i;
54         }
55         while ( c-- != 1 );
56     }
57 }
58 
59 /*
60  * I thought it was okay to have this in DeleteObject but~ Speed. (jt)
61  */
62 BOOL
63 FASTCALL
64 DeleteRegion(
65     _In_ HRGN hrgn)
66 {
67 #if 0
68     PRGN_ATTR Rgn_Attr = GdiGetRgnAttr(hrgn);
69 
70     if ( Rgn_Attr )
71     {
72         PGDIBSOBJECT pgO;
73 
74         pgO = GdiAllocBatchCommand(NULL, GdiBCDelRgn);
75         if (pgO)
76         {
77             pgO->hgdiobj = hrgn;
78             return TRUE;
79         }
80     }
81 #endif
82     return NtGdiDeleteObjectApp(hrgn);
83 }
84 
85 INT
86 FASTCALL
87 MirrorRgnByWidth(
88     _In_ HRGN hrgn,
89     _In_ INT Width,
90     _In_ HRGN *phrgn)
91 {
92     INT cRgnDSize, Ret = 0;
93     PRGNDATA pRgnData;
94 
95     cRgnDSize = NtGdiGetRegionData(hrgn, 0, NULL);
96 
97     if (cRgnDSize)
98     {
99         pRgnData = HeapAlloc(GetProcessHeap(), 0, cRgnDSize * sizeof(LONG));
100         if (pRgnData)
101         {
102             if ( GetRegionData(hrgn, cRgnDSize, pRgnData) )
103             {
104                 HRGN hRgnex;
105                 UINT i;
106                 INT SaveL = pRgnData->rdh.rcBound.left;
107                 pRgnData->rdh.rcBound.left = Width - pRgnData->rdh.rcBound.right;
108                 pRgnData->rdh.rcBound.right = Width - SaveL;
109                 if (pRgnData->rdh.nCount > 0)
110                 {
111                     PRECT pRect = (PRECT)&pRgnData->Buffer;
112                     for (i = 0; i < pRgnData->rdh.nCount; i++)
113                     {
114                         SaveL = pRect[i].left;
115                         pRect[i].left = Width - pRect[i].right;
116                         pRect[i].right = Width - SaveL;
117                     }
118                 }
119                 SortRects((PRECT)&pRgnData->Buffer, pRgnData->rdh.nCount);
120                 hRgnex = ExtCreateRegion(NULL, cRgnDSize , pRgnData);
121                 if (hRgnex)
122                 {
123                     if (phrgn) phrgn = (HRGN *)hRgnex;
124                     else
125                     {
126                         CombineRgn(hrgn, hRgnex, 0, RGN_COPY);
127                         DeleteObject(hRgnex);
128                     }
129                     Ret = 1;
130                 }
131             }
132             HeapFree( GetProcessHeap(), 0, pRgnData);
133         }
134     }
135     return Ret;
136 }
137 
138 INT
139 WINAPI
140 MirrorRgnDC(
141     _In_ HDC hdc,
142     _In_ HRGN hrgn,
143     _In_ HRGN *phrn)
144 {
145     if (!GdiValidateHandle((HGDIOBJ) hdc) ||
146         (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC))
147         return 0;
148 
149     return MirrorRgnByWidth(hrgn, NtGdiGetDeviceWidth(hdc), phrn);
150 }
151 
152 /* FUNCTIONS *****************************************************************/
153 
154 FORCEINLINE
155 ULONG
156 IntSetNullRgn(
157     _Inout_ PRGN_ATTR prgnattr)
158 {
159     prgnattr->iComplexity = NULLREGION;
160     prgnattr->AttrFlags |= ATTR_RGN_DIRTY;
161     prgnattr->Rect.left = prgnattr->Rect.top = prgnattr->Rect.right = prgnattr->Rect.bottom = 0;
162     return NULLREGION;
163 }
164 
165 FORCEINLINE
166 ULONG
167 IntSetRectRgn(
168     _Inout_ PRGN_ATTR prgnattr,
169     _In_ INT xLeft,
170     _In_ INT yTop,
171     _In_ INT xRight,
172     _In_ INT yBottom)
173 {
174     ASSERT(xLeft <= xRight);
175     ASSERT(yTop <= yBottom);
176 
177     if ((xLeft == xRight) || (yTop == yBottom))
178         return IntSetNullRgn(prgnattr);
179 
180     prgnattr->iComplexity = SIMPLEREGION;
181     prgnattr->Rect.left = xLeft;
182     prgnattr->Rect.top = yTop;
183     prgnattr->Rect.right = xRight;
184     prgnattr->Rect.bottom = yBottom;
185     prgnattr->AttrFlags |= ATTR_RGN_DIRTY;
186     return SIMPLEREGION;
187 }
188 
189 /*
190  * @implemented
191  */
192 INT
193 WINAPI
194 CombineRgn(
195     _In_ HRGN hrgnDest,
196     _In_ HRGN hrgnSrc1,
197     _In_ HRGN hrgnSrc2,
198     _In_ INT  iCombineMode)
199 {
200     PRGN_ATTR prngattrDest = NULL;
201     PRGN_ATTR prngattrSrc1 = NULL;
202     PRGN_ATTR prngattrSrc2 = NULL;
203     RECT rcTemp;
204 
205     /* Get the region attribute for dest and source 1 */
206     prngattrDest = GdiGetRgnAttr(hrgnDest);
207     prngattrSrc1 = GdiGetRgnAttr(hrgnSrc1);
208 
209     /* If that failed or if the source 1 region is complex, go to win32k */
210     if ((prngattrDest == NULL) || (prngattrSrc1 == NULL) ||
211         (prngattrSrc1->iComplexity > SIMPLEREGION))
212     {
213         return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
214     }
215 
216     /* Handle RGN_COPY first, it needs only hrgnSrc1 */
217     if (iCombineMode == RGN_COPY)
218     {
219         /* Check if the source region is a NULLREGION */
220         if (prngattrSrc1->iComplexity == NULLREGION)
221         {
222             /* The dest region is a NULLREGION, too */
223             return IntSetNullRgn(prngattrDest);
224         }
225 
226         /* We already know that the source region cannot be complex, so
227            create a rect region from the bounds of the source rect */
228         return IntSetRectRgn(prngattrDest,
229                              prngattrSrc1->Rect.left,
230                              prngattrSrc1->Rect.top,
231                              prngattrSrc1->Rect.right,
232                              prngattrSrc1->Rect.bottom);
233     }
234 
235     /* For all other operations we need hrgnSrc2 */
236     prngattrSrc2 = GdiGetRgnAttr(hrgnSrc2);
237 
238     /* If we got no attribute or the region is complex, go to win32k */
239     if ((prngattrSrc2 == NULL) || (prngattrSrc2->iComplexity > SIMPLEREGION))
240     {
241         return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
242     }
243 
244     /* Handle RGN_AND */
245     if (iCombineMode == RGN_AND)
246     {
247         /* Check if either of the regions is a NULLREGION */
248         if ((prngattrSrc1->iComplexity == NULLREGION) ||
249             (prngattrSrc2->iComplexity == NULLREGION))
250         {
251             /* Result is also a NULLREGION */
252             return IntSetNullRgn(prngattrDest);
253         }
254 
255         /* Get the intersection of the 2 rects */
256         if (!IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect))
257         {
258             /* The rects do not intersect, result is a NULLREGION */
259             return IntSetNullRgn(prngattrDest);
260         }
261 
262         /* Use the intersection of the rects */
263         return IntSetRectRgn(prngattrDest,
264                              rcTemp.left,
265                              rcTemp.top,
266                              rcTemp.right,
267                              rcTemp.bottom);
268     }
269 
270     /* Handle RGN_DIFF */
271     if (iCombineMode == RGN_DIFF)
272     {
273         /* Check if source 1 is a NULLREGION */
274         if (prngattrSrc1->iComplexity == NULLREGION)
275         {
276             /* The result is a NULLREGION as well */
277             return IntSetNullRgn(prngattrDest);
278         }
279 
280         /* Get the intersection of the 2 rects */
281         if ((prngattrSrc2->iComplexity == NULLREGION) ||
282             !IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect))
283         {
284             /* The rects do not intersect, dest equals source 1 */
285             return IntSetRectRgn(prngattrDest,
286                                  prngattrSrc1->Rect.left,
287                                  prngattrSrc1->Rect.top,
288                                  prngattrSrc1->Rect.right,
289                                  prngattrSrc1->Rect.bottom);
290         }
291 
292         /* We need to check is whether we can subtract the rects. For that
293            we call SubtractRect, which will give us the bounding box of the
294            subtraction. The function returns FALSE if the resulting rect is
295            empty */
296         if (!SubtractRect(&rcTemp, &prngattrSrc1->Rect, &rcTemp))
297         {
298             /* The result is a NULLREGION */
299             return IntSetNullRgn(prngattrDest);
300         }
301 
302         /* Now check if the result of SubtractRect matches the source 1 rect.
303            Since we already know that the rects intersect, the result can
304            only match the source 1 rect, if it could not be "cut" on either
305            side, but the overlapping was on a corner, so the new bounding box
306            equals the previous rect */
307         if (!EqualRect(&rcTemp, &prngattrSrc1->Rect))
308         {
309             /* We got a properly subtracted rect, so use it. */
310             return IntSetRectRgn(prngattrDest,
311                                  rcTemp.left,
312                                  rcTemp.top,
313                                  rcTemp.right,
314                                  rcTemp.bottom);
315         }
316 
317         /* The result would be a complex region, go to win32k */
318         return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
319     }
320 
321     /* Handle OR and XOR */
322     if ((iCombineMode == RGN_OR) || (iCombineMode == RGN_XOR))
323     {
324         /* Check if source 1 is a NULLREGION */
325         if (prngattrSrc1->iComplexity == NULLREGION)
326         {
327             /* Check if source 2 is also a NULLREGION */
328             if (prngattrSrc2->iComplexity == NULLREGION)
329             {
330                 /* Both are NULLREGIONs, result is also a NULLREGION */
331                 return IntSetNullRgn(prngattrDest);
332             }
333 
334             /* The result is equal to source 2 */
335             return IntSetRectRgn(prngattrDest,
336                                  prngattrSrc2->Rect.left,
337                                  prngattrSrc2->Rect.top,
338                                  prngattrSrc2->Rect.right,
339                                  prngattrSrc2->Rect.bottom );
340         }
341 
342         /* Check if only source 2 is a NULLREGION */
343         if (prngattrSrc2->iComplexity == NULLREGION)
344         {
345             /* The result is equal to source 1 */
346             return IntSetRectRgn(prngattrDest,
347                                  prngattrSrc1->Rect.left,
348                                  prngattrSrc1->Rect.top,
349                                  prngattrSrc1->Rect.right,
350                                  prngattrSrc1->Rect.bottom);
351         }
352 
353         /* Do the rects have the same x extent */
354         if ((prngattrSrc1->Rect.left == prngattrSrc2->Rect.left) &&
355             (prngattrSrc1->Rect.right == prngattrSrc2->Rect.right))
356         {
357             /* Do the rects also have the same y extent */
358             if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) &&
359                 (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom))
360             {
361                 /* Rects are equal, if this is RGN_OR, the result is source 1 */
362                 if (iCombineMode == RGN_OR)
363                 {
364                     /* The result is equal to source 1 */
365                     return IntSetRectRgn(prngattrDest,
366                                          prngattrSrc1->Rect.left,
367                                          prngattrSrc1->Rect.top,
368                                          prngattrSrc1->Rect.right,
369                                          prngattrSrc1->Rect.bottom );
370                 }
371                 else
372                 {
373                     /* XORing with itself yields an empty region */
374                     return IntSetNullRgn(prngattrDest);
375                 }
376             }
377 
378             /* Check if the rects are disjoint */
379             if ((prngattrSrc2->Rect.bottom < prngattrSrc1->Rect.top) ||
380                 (prngattrSrc2->Rect.top > prngattrSrc1->Rect.bottom))
381             {
382                 /* The result would be a complex region, go to win32k */
383                 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
384             }
385 
386             /* Check if this is OR */
387             if (iCombineMode == RGN_OR)
388             {
389                 /* Use the maximum extent of both rects combined */
390                 return IntSetRectRgn(prngattrDest,
391                                      prngattrSrc1->Rect.left,
392                                      min(prngattrSrc1->Rect.top, prngattrSrc2->Rect.top),
393                                      prngattrSrc1->Rect.right,
394                                      max(prngattrSrc1->Rect.bottom, prngattrSrc2->Rect.bottom));
395             }
396 
397             /* Check if the rects are adjacent */
398             if (prngattrSrc2->Rect.bottom == prngattrSrc1->Rect.top)
399             {
400                 /* The result is the combined rects */
401                 return IntSetRectRgn(prngattrDest,
402                                      prngattrSrc1->Rect.left,
403                                      prngattrSrc2->Rect.top,
404                                      prngattrSrc1->Rect.right,
405                                      prngattrSrc1->Rect.bottom );
406             }
407             else if (prngattrSrc2->Rect.top == prngattrSrc1->Rect.bottom)
408             {
409                 /* The result is the combined rects */
410                 return IntSetRectRgn(prngattrDest,
411                                      prngattrSrc1->Rect.left,
412                                      prngattrSrc1->Rect.top,
413                                      prngattrSrc1->Rect.right,
414                                      prngattrSrc2->Rect.bottom );
415             }
416 
417             /* When we are here, this is RGN_XOR and the rects overlap */
418             return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
419         }
420 
421         /* Do the rects have the same y extent */
422         if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) &&
423             (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom))
424         {
425             /* Check if the rects are disjoint */
426             if ((prngattrSrc2->Rect.right < prngattrSrc1->Rect.left) ||
427                 (prngattrSrc2->Rect.left > prngattrSrc1->Rect.right))
428             {
429                 /* The result would be a complex region, go to win32k */
430                 return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
431             }
432 
433             /* Check if this is OR */
434             if (iCombineMode == RGN_OR)
435             {
436                 /* Use the maximum extent of both rects combined */
437                 return IntSetRectRgn(prngattrDest,
438                                      min(prngattrSrc1->Rect.left, prngattrSrc2->Rect.left),
439                                      prngattrSrc1->Rect.top,
440                                      max(prngattrSrc1->Rect.right, prngattrSrc2->Rect.right),
441                                      prngattrSrc1->Rect.bottom);
442             }
443 
444             /* Check if the rects are adjacent */
445             if (prngattrSrc2->Rect.right == prngattrSrc1->Rect.left)
446             {
447                 /* The result is the combined rects */
448                 return IntSetRectRgn(prngattrDest,
449                                      prngattrSrc2->Rect.left,
450                                      prngattrSrc1->Rect.top,
451                                      prngattrSrc1->Rect.right,
452                                      prngattrSrc1->Rect.bottom );
453             }
454             else if (prngattrSrc2->Rect.left == prngattrSrc1->Rect.right)
455             {
456                 /* The result is the combined rects */
457                 return IntSetRectRgn(prngattrDest,
458                                      prngattrSrc1->Rect.left,
459                                      prngattrSrc1->Rect.top,
460                                      prngattrSrc2->Rect.right,
461                                      prngattrSrc1->Rect.bottom );
462             }
463 
464             /* When we are here, this is RGN_XOR and the rects overlap */
465             return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
466         }
467 
468         /* Last case: RGN_OR and one rect is completely within the other */
469         if (iCombineMode == RGN_OR)
470         {
471             /* Check if rect 1 can contain rect 2 */
472             if (prngattrSrc1->Rect.left <= prngattrSrc2->Rect.left)
473             {
474                 /* rect 1 might be the outer one, check of that is true */
475                 if ((prngattrSrc1->Rect.right >= prngattrSrc2->Rect.right) &&
476                     (prngattrSrc1->Rect.top <= prngattrSrc2->Rect.top) &&
477                     (prngattrSrc1->Rect.bottom >= prngattrSrc2->Rect.bottom))
478                 {
479                     /* Rect 1 contains rect 2, use it */
480                     return IntSetRectRgn(prngattrDest,
481                                          prngattrSrc1->Rect.left,
482                                          prngattrSrc1->Rect.top,
483                                          prngattrSrc1->Rect.right,
484                                          prngattrSrc1->Rect.bottom );
485                 }
486             }
487             else
488             {
489                 /* rect 2 might be the outer one, check of that is true */
490                 if ((prngattrSrc2->Rect.right >= prngattrSrc1->Rect.right) &&
491                     (prngattrSrc2->Rect.top <= prngattrSrc1->Rect.top) &&
492                     (prngattrSrc2->Rect.bottom >= prngattrSrc1->Rect.bottom))
493                 {
494                     /* Rect 2 contains rect 1, use it */
495                     return IntSetRectRgn(prngattrDest,
496                                          prngattrSrc2->Rect.left,
497                                          prngattrSrc2->Rect.top,
498                                          prngattrSrc2->Rect.right,
499                                          prngattrSrc2->Rect.bottom );
500                 }
501             }
502         }
503 
504         /* We couldn't handle the operation, go to win32k */
505         return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
506     }
507 
508     DPRINT1("Invalid iCombineMode %d\n", iCombineMode);
509     SetLastError(ERROR_INVALID_PARAMETER);
510     return ERROR;
511 }
512 
513 
514 /*
515  * @implemented
516  */
517 HRGN
518 WINAPI
519 CreateEllipticRgnIndirect(
520     const RECT *prc
521 )
522 {
523     /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
524     return NtGdiCreateEllipticRgn(prc->left, prc->top, prc->right, prc->bottom);
525 
526 }
527 
528 /*
529  * @implemented
530  */
531 HRGN
532 WINAPI
533 CreatePolygonRgn( const POINT * lppt, int cPoints, int fnPolyFillMode)
534 {
535     return (HRGN) NtGdiPolyPolyDraw( (HDC)UlongToHandle(fnPolyFillMode), (PPOINT) lppt, (PULONG) &cPoints, 1, GdiPolyPolyRgn);
536 }
537 
538 /*
539  * @implemented
540  */
541 HRGN
542 WINAPI
543 CreatePolyPolygonRgn( const POINT* lppt,
544                       const INT* lpPolyCounts,
545                       int nCount,
546                       int fnPolyFillMode)
547 {
548     return (HRGN) NtGdiPolyPolyDraw(  (HDC)UlongToHandle(fnPolyFillMode), (PPOINT) lppt, (PULONG) lpPolyCounts, (ULONG) nCount, GdiPolyPolyRgn );
549 }
550 
551 /*
552  * @implemented
553  */
554 HRGN
555 WINAPI
556 CreateRectRgn(int x1, int y1, int x2, int y2)
557 {
558     PRGN_ATTR pRgn_Attr;
559     HRGN hrgn = NULL;
560     int tmp;
561 
562     /* Normalize points, REGION_SetRectRgn does this too. */
563     if ( x1 > x2 )
564     {
565         tmp = x1;
566         x1 = x2;
567         x2 = tmp;
568     }
569 
570     if ( y1 > y2 )
571     {
572         tmp = y1;
573         y1 = y2;
574         y2 = tmp;
575     }
576     /* Check outside 28 bit limit for universal set bound box. REGION_SetRectRgn doesn't do this! */
577     if ( x1 < MIN_COORD ||
578          y1 < MIN_COORD ||
579          x2 > MAX_COORD ||
580          y2 > MAX_COORD  )
581     {
582         SetLastError(ERROR_INVALID_PARAMETER);
583         return NULL;
584     }
585 
586     hrgn = hGetPEBHandle(hctRegionHandle, 0);
587     if (hrgn)
588     {
589        DPRINT1("PEB Handle Cache Test return hrgn %p, should be NULL!\n",hrgn);
590        hrgn = NULL;
591     }
592 
593     if (!hrgn)
594         hrgn = NtGdiCreateRectRgn(0, 0, 1, 1);
595 
596     if (!hrgn)
597         return hrgn;
598 
599     if (!(pRgn_Attr = GdiGetRgnAttr(hrgn)) )
600     {
601         DPRINT1("No Attr for Region handle!!!\n");
602         DeleteRegion(hrgn);
603         return NULL;
604     }
605 
606     pRgn_Attr->AttrFlags = ATTR_RGN_VALID;
607 
608     IntSetRectRgn( pRgn_Attr, x1, y1, x2, y2 );
609 
610     return hrgn;
611 }
612 
613 /*
614  * @implemented
615  */
616 HRGN
617 WINAPI
618 CreateRectRgnIndirect(
619     const RECT *prc
620 )
621 {
622     /* Notes if prc is NULL it will crash on All Windows NT I checked 2000/XP/VISTA */
623     return CreateRectRgn(prc->left, prc->top, prc->right, prc->bottom);
624 
625 }
626 
627 /*
628  * @implemented
629  */
630 INT
631 WINAPI
632 ExcludeClipRect(
633     _In_ HDC hdc,
634     _In_ INT xLeft,
635     _In_ INT yTop,
636     _In_ INT xRight,
637     _In_ INT yBottom)
638 {
639     HANDLE_METADC(INT, ExcludeClipRect, ERROR, hdc, xLeft, yTop, xRight, yBottom);
640 
641     return NtGdiExcludeClipRect(hdc, xLeft, yTop, xRight, yBottom);
642 }
643 
644 /*
645  * @implemented
646  */
647 HRGN
648 WINAPI
649 ExtCreateRegion(
650     CONST XFORM *	lpXform,
651     DWORD		nCount,
652     CONST RGNDATA *	lpRgnData
653 )
654 {
655     if (lpRgnData)
656     {
657         if ((!lpXform) && (lpRgnData->rdh.nCount == 1))
658         {
659             PRECT pRect = (PRECT)&lpRgnData->Buffer[0];
660             return CreateRectRgn(pRect->left, pRect->top, pRect->right, pRect->bottom);
661         }
662         return NtGdiExtCreateRegion((LPXFORM) lpXform, nCount,(LPRGNDATA) lpRgnData);
663     }
664     SetLastError(ERROR_INVALID_PARAMETER);
665     return NULL;
666 }
667 
668 /*
669  * @implemented
670  */
671 INT
672 WINAPI
673 ExtSelectClipRgn(
674     _In_ HDC hdc,
675     _In_ HRGN hrgn,
676     _In_ INT iMode)
677 {
678     INT Ret;
679     HRGN NewRgn = NULL;
680 
681     HANDLE_METADC(INT, ExtSelectClipRgn, 0, hdc, hrgn, iMode);
682 
683 #if 0
684     if ( hrgn )
685     {
686         if ( GetLayout(hdc) & LAYOUT_RTL )
687         {
688             if ( MirrorRgnDC(hdc, hrgn, &NewRgn) )
689             {
690                 if ( NewRgn ) hrgn = NewRgn;
691             }
692         }
693     }
694 #endif
695     /* Batch handles RGN_COPY only! */
696     if (iMode == RGN_COPY)
697     {
698         PDC_ATTR pdcattr;
699         PRGN_ATTR pRgn_Attr = NULL;
700 
701         /* Get the DC attribute */
702         pdcattr = GdiGetDcAttr(hdc);
703         if ( pdcattr )
704         {
705             PGDI_TABLE_ENTRY pEntry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hdc);
706 
707             /* hrgn can be NULL unless the RGN_COPY mode is specified. */
708             if (hrgn) pRgn_Attr = GdiGetRgnAttr(hrgn);
709 
710             if ( !(pdcattr->ulDirty_ & DC_DIBSECTION) &&
711                  !(pEntry->Flags & GDI_ENTRY_VALIDATE_VIS) )
712             {
713                 if (!hrgn || (hrgn && pRgn_Attr && pRgn_Attr->iComplexity <= SIMPLEREGION) )
714                 {
715                     PGDIBSEXTSELCLPRGN pgO = GdiAllocBatchCommand(hdc, GdiBCExtSelClipRgn);
716                     if (pgO)
717                     {
718                         pgO->fnMode = iMode;
719 
720                         if ( hrgn && pRgn_Attr )
721                         {
722                             Ret = pRgn_Attr->iComplexity;
723                             // Note from ntgdi/dcstate.c : "The VisRectRegion field needs to be set to a valid state."
724                             if ( pdcattr->VisRectRegion.Rect.left   >= pRgn_Attr->Rect.right  ||
725                                  pdcattr->VisRectRegion.Rect.top    >= pRgn_Attr->Rect.bottom ||
726                                  pdcattr->VisRectRegion.Rect.right  <= pRgn_Attr->Rect.left   ||
727                                  pdcattr->VisRectRegion.Rect.bottom <= pRgn_Attr->Rect.top )
728                                 Ret = NULLREGION;
729 
730                             // Pass the rect since this region will go away.
731                             pgO->rcl = pRgn_Attr->Rect;
732                         }
733                         else
734                         {
735                             Ret = pdcattr->VisRectRegion.iComplexity;
736                             pgO->fnMode |= GDIBS_NORECT; // Set no hrgn mode.
737                         }
738                         if ( NewRgn ) DeleteObject(NewRgn);
739                         return Ret;
740                     }
741                 }
742             }
743         }
744     }
745     Ret = NtGdiExtSelectClipRgn(hdc, hrgn, iMode);
746 
747     if ( NewRgn ) DeleteObject(NewRgn);
748 
749     return Ret;
750 }
751 
752 /*
753  * @implemented
754  */
755 int
756 WINAPI
757 GetClipRgn(
758     HDC     hdc,
759     HRGN    hrgn
760 )
761 {
762     INT Ret;
763 
764     /* Check if DC handle is valid */
765     if (!GdiGetDcAttr(hdc))
766     {
767         /* Last error code differs from what NtGdiGetRandomRgn returns */
768         SetLastError(ERROR_INVALID_PARAMETER);
769         return -1;
770     }
771 
772     Ret = NtGdiGetRandomRgn(hdc, hrgn, CLIPRGN);
773 
774 //  if (Ret)
775 //  {
776 //     if(GetLayout(hdc) & LAYOUT_RTL) MirrorRgnDC(hdc,(HRGN)Ret, NULL);
777 //  }
778     return Ret;
779 }
780 
781 /*
782  * @implemented
783  */
784 int
785 WINAPI
786 GetMetaRgn(HDC hdc,
787            HRGN hrgn)
788 {
789     return NtGdiGetRandomRgn(hdc, hrgn, METARGN);
790 }
791 
792 /*
793  * @implemented
794  *
795  */
796 DWORD
797 WINAPI
798 GetRegionData(HRGN hrgn,
799               DWORD nCount,
800               LPRGNDATA lpRgnData)
801 {
802     if (!lpRgnData)
803     {
804         nCount = 0;
805     }
806 
807     return NtGdiGetRegionData(hrgn,nCount,lpRgnData);
808 }
809 
810 /*
811  * @implemented
812  *
813  */
814 INT
815 WINAPI
816 GetRgnBox(HRGN hrgn,
817           LPRECT prcOut)
818 {
819     PRGN_ATTR Rgn_Attr;
820 
821     if (!(Rgn_Attr = GdiGetRgnAttr(hrgn)))
822         return NtGdiGetRgnBox(hrgn, prcOut);
823 
824     if (Rgn_Attr->iComplexity == NULLREGION)
825     {
826         prcOut->left   = 0;
827         prcOut->top    = 0;
828         prcOut->right  = 0;
829         prcOut->bottom = 0;
830     }
831     else
832     {
833         if (Rgn_Attr->iComplexity != SIMPLEREGION)
834             return NtGdiGetRgnBox(hrgn, prcOut);
835         /* WARNING! prcOut is never checked newbies! */
836         RtlCopyMemory( prcOut, &Rgn_Attr->Rect, sizeof(RECT));
837     }
838     return Rgn_Attr->iComplexity;
839 }
840 
841 /*
842  * @implemented
843  */
844 INT
845 WINAPI
846 IntersectClipRect(
847     _In_ HDC hdc,
848     _In_ INT nLeft,
849     _In_ INT nTop,
850     _In_ INT nRight,
851     _In_ INT nBottom)
852 {
853     HANDLE_METADC(INT, IntersectClipRect, ERROR, hdc, nLeft, nTop, nRight, nBottom);
854     return NtGdiIntersectClipRect(hdc, nLeft, nTop, nRight, nBottom);
855 }
856 
857 /*
858  * @implemented
859  */
860 BOOL
861 WINAPI
862 MirrorRgn(HWND hwnd, HRGN hrgn)
863 {
864     INT l;
865     RECT Rect;
866     GetWindowRect(hwnd, &Rect);
867     l = Rect.right - Rect.left;
868     Rect.right -= Rect.left;
869     return MirrorRgnByWidth(hrgn, l, NULL);
870 }
871 
872 /*
873  * @implemented
874  */
875 INT
876 WINAPI
877 OffsetClipRgn(
878     HDC hdc,
879     INT nXOffset,
880     INT nYOffset)
881 {
882     HANDLE_METADC(INT, OffsetClipRgn, ERROR, hdc, nXOffset, nYOffset);
883     return NtGdiOffsetClipRgn(hdc, nXOffset, nYOffset);
884 }
885 
886 /*
887  * @implemented
888  *
889  */
890 INT
891 WINAPI
892 OffsetRgn( HRGN hrgn,
893            int nXOffset,
894            int nYOffset)
895 {
896     PRGN_ATTR pRgn_Attr;
897     RECTL rc;
898 
899     if (!(pRgn_Attr = GdiGetRgnAttr(hrgn)))
900         return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
901 
902     if ( pRgn_Attr->iComplexity == NULLREGION)
903         return pRgn_Attr->iComplexity;
904 
905     if ( pRgn_Attr->iComplexity != SIMPLEREGION)
906         return NtGdiOffsetRgn(hrgn,nXOffset,nYOffset);
907 
908     rc = pRgn_Attr->Rect;
909 
910     if (rc.left < rc.right)
911     {
912         if (rc.top < rc.bottom)
913         {
914             rc.left   += nXOffset;
915             rc.top    += nYOffset;
916             rc.right  += nXOffset;
917             rc.bottom += nYOffset;
918 
919             /* Make sure the offset is within the legal range */
920             if ( (rc.left   & MIN_COORD && ((rc.left   & MIN_COORD) != MIN_COORD)) ||
921                  (rc.top    & MIN_COORD && ((rc.top    & MIN_COORD) != MIN_COORD)) ||
922                  (rc.right  & MIN_COORD && ((rc.right  & MIN_COORD) != MIN_COORD)) ||
923                  (rc.bottom & MIN_COORD && ((rc.bottom & MIN_COORD) != MIN_COORD))  )
924             {
925                 DPRINT("OffsetRgn ERROR\n");
926                 return ERROR;
927             }
928 
929             pRgn_Attr->Rect = rc;
930             pRgn_Attr->AttrFlags |= ATTR_RGN_DIRTY;
931         }
932     }
933     return pRgn_Attr->iComplexity;
934 }
935 
936 /*
937  * @implemented
938  */
939 BOOL
940 WINAPI
941 PtInRegion(IN HRGN hrgn,
942            int x,
943            int y)
944 {
945     PRGN_ATTR pRgn_Attr;
946 
947     if (!(pRgn_Attr = GdiGetRgnAttr(hrgn)))
948         return NtGdiPtInRegion(hrgn,x,y);
949 
950     if ( pRgn_Attr->iComplexity == NULLREGION)
951         return FALSE;
952 
953     if ( pRgn_Attr->iComplexity != SIMPLEREGION)
954         return NtGdiPtInRegion(hrgn,x,y);
955 
956     return INRECT( pRgn_Attr->Rect, x, y);
957 }
958 
959 /*
960  * @implemented
961  */
962 BOOL
963 WINAPI
964 RectInRegion(HRGN hrgn,
965              LPCRECT prcl)
966 {
967     PRGN_ATTR pRgn_Attr;
968     RECTL rc;
969 
970     if (!(pRgn_Attr = GdiGetRgnAttr(hrgn)))
971         return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
972 
973     if ( pRgn_Attr->iComplexity == NULLREGION)
974         return FALSE;
975 
976     if ( pRgn_Attr->iComplexity != SIMPLEREGION)
977         return NtGdiRectInRegion(hrgn, (LPRECT) prcl);
978 
979     /* swap the coordinates to make right >= left and bottom >= top */
980     /* (region building rectangles are normalized the same way) */
981     if ( prcl->top > prcl->bottom)
982     {
983         rc.top = prcl->bottom;
984         rc.bottom = prcl->top;
985     }
986     else
987     {
988         rc.top = prcl->top;
989         rc.bottom = prcl->bottom;
990     }
991     if ( prcl->right < prcl->left)
992     {
993         rc.right = prcl->left;
994         rc.left = prcl->right;
995     }
996     else
997     {
998         rc.right = prcl->right;
999         rc.left = prcl->left;
1000     }
1001 
1002     if ( ( pRgn_Attr->Rect.left   >= rc.right )  ||
1003          ( pRgn_Attr->Rect.right  <= rc.left )   ||
1004          ( pRgn_Attr->Rect.top    >= rc.bottom ) ||
1005          ( pRgn_Attr->Rect.bottom <= rc.top ) )
1006     {
1007         return FALSE;
1008     }
1009 
1010     return TRUE;
1011 }
1012 
1013 /*
1014  * @implemented
1015  */
1016 int
1017 WINAPI
1018 SelectClipRgn(
1019     _In_ HDC hdc,
1020     _In_ HRGN hrgn)
1021 {
1022     return ExtSelectClipRgn(hdc, hrgn, RGN_COPY);
1023 }
1024 
1025 /*
1026  * @implemented
1027  */
1028 BOOL
1029 WINAPI
1030 SetRectRgn(
1031     _In_ HRGN hrgn,
1032     _In_ INT xLeft,
1033     _In_ INT yTop,
1034     _In_ INT xRight,
1035     _In_ INT yBottom)
1036 {
1037     PRGN_ATTR prngattr;
1038 
1039     /* Try to get the region attribute */
1040     prngattr = GdiGetRgnAttr(hrgn);
1041     if (prngattr == NULL)
1042     {
1043         return NtGdiSetRectRgn(hrgn, xLeft, yTop, xRight, yBottom);
1044     }
1045 
1046     /* check for NULL region */
1047     if ((xLeft == xRight) || (yTop == yBottom))
1048     {
1049         IntSetNullRgn(prngattr);
1050         return TRUE;
1051     }
1052 
1053     if (xLeft > xRight)
1054     {
1055         prngattr->Rect.left   = xRight;
1056         prngattr->Rect.right  = xLeft;
1057     }
1058     else
1059     {
1060         prngattr->Rect.left   = xLeft;
1061         prngattr->Rect.right  = xRight;
1062     }
1063 
1064     if (yTop > yBottom)
1065     {
1066         prngattr->Rect.top    = yBottom;
1067         prngattr->Rect.bottom = yTop;
1068     }
1069     else
1070     {
1071         prngattr->Rect.top    = yTop;
1072         prngattr->Rect.bottom = yBottom;
1073     }
1074 
1075     prngattr->AttrFlags |= ATTR_RGN_DIRTY ;
1076     prngattr->iComplexity = SIMPLEREGION;
1077 
1078     return TRUE;
1079 }
1080 
1081 /*
1082  * @implemented
1083  */
1084 int
1085 WINAPI
1086 SetMetaRgn(HDC hDC)
1087 {
1088     if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
1089         return NtGdiSetMetaRgn(hDC);
1090 #if 0
1091     PLDC pLDC = GdiGetLDC(hDC);
1092     if ( pLDC && GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC )
1093     {
1094         if (pLDC->iType == LDC_EMFLDC || EMFDRV_SetMetaRgn(hDC))
1095         {
1096             return NtGdiSetMetaRgn(hDC);
1097         }
1098         else
1099             SetLastError(ERROR_INVALID_HANDLE);
1100     }
1101 #endif
1102     return ERROR;
1103 }
1104 
1105