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