xref: /reactos/win32ss/gdi/ntgdi/cliprgn.c (revision 9414fb6b)
1 /*
2  * COPYRIGHT:        GNU GPL, See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Clip region functions
5  * FILE:             win32ss/gdi/ntgdi/cliprgn.c
6  * PROGRAMER:        Unknown
7  */
8 
9 #include <win32k.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 DBG_DEFAULT_CHANNEL(GdiClipRgn);
15 
16 VOID
17 FASTCALL
IntGdiReleaseRaoRgn(PDC pDC)18 IntGdiReleaseRaoRgn(PDC pDC)
19 {
20     INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
21     PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
22     pDC->fs |= DC_DIRTY_RAO;
23     Entry->Flags |= GDI_ENTRY_VALIDATE_VIS; // Need to validate Vis.
24 }
25 
26 VOID
27 FASTCALL
IntGdiReleaseVisRgn(PDC pDC)28 IntGdiReleaseVisRgn(PDC pDC)
29 {
30     IntGdiReleaseRaoRgn(pDC);
31     REGION_Delete(pDC->prgnVis);
32     pDC->prgnVis = prgnDefault; // Vis can not be NULL!!!
33 }
34 
35 //
36 // Updating Vis Region Attribute for DC Attributes.
37 // BTW: This system region has an user attribute for it.
38 //
39 VOID
40 FASTCALL
UpdateVisRgn(PDC pdc)41 UpdateVisRgn(
42     PDC pdc)
43 {
44     INT Index = GDI_HANDLE_GET_INDEX(pdc->BaseObject.hHmgr);
45     PGDI_TABLE_ENTRY pEntry = &GdiHandleTable->Entries[Index];
46 
47     /* Setup Vis Region Attribute information to User side */
48     pEntry->Flags |= GDI_ENTRY_VALIDATE_VIS;
49     pdc->pdcattr->VisRectRegion.iComplexity = REGION_GetRgnBox(pdc->prgnVis, &pdc->pdcattr->VisRectRegion.Rect);
50     pdc->pdcattr->VisRectRegion.AttrFlags = ATTR_RGN_VALID;
51     pEntry->Flags &= ~GDI_ENTRY_VALIDATE_VIS;
52 }
53 
54 //
55 //  Selecting Vis Region.
56 //
57 VOID
58 FASTCALL
GdiSelectVisRgn(HDC hdc,PREGION prgn)59 GdiSelectVisRgn(
60     HDC hdc,
61     PREGION prgn)
62 {
63     DC *dc;
64 
65     if (!(dc = DC_LockDc(hdc)))
66     {
67         EngSetLastError(ERROR_INVALID_HANDLE);
68         return;
69     }
70 
71     if (!prgn)
72     {
73        DPRINT1("SVR: Setting NULL Region\n");
74        IntGdiReleaseVisRgn(dc);
75        IntSetDefaultRegion(dc);
76        DC_UnlockDc(dc);
77        return;
78     }
79 
80     dc->fs |= DC_DIRTY_RAO;
81 
82     ASSERT(dc->prgnVis != NULL);
83     ASSERT(prgn != NULL);
84 
85     REGION_bCopy(dc->prgnVis, prgn);
86     REGION_bOffsetRgn(dc->prgnVis, -dc->ptlDCOrig.x, -dc->ptlDCOrig.y);
87 
88     DC_UnlockDc(dc);
89 }
90 
91 _Success_(return!=ERROR)
92 int
93 FASTCALL
IntSelectClipRgn(_In_ PDC dc,_In_ PREGION prgn,_In_ int fnMode)94 IntSelectClipRgn(
95     _In_ PDC dc,
96     _In_ PREGION prgn,
97     _In_ int fnMode)
98 {
99     int Ret = ERROR;
100     PREGION prgnNClip, prgnOrigClip = dc->dclevel.prgnClip;
101 
102     //
103     // No Coping Regions and no intersecting Regions or an User calling w NULL Region or have the Original Clip Region.
104     //
105     if (fnMode != RGN_COPY && (fnMode != RGN_AND || !prgn || prgnOrigClip))
106     {
107         prgnNClip = IntSysCreateRectpRgn(0, 0, 0, 0);
108 
109         // Have Original Clip Region.
110         if (prgnOrigClip)
111         {
112            // This will fail on NULL prgn.
113            Ret = IntGdiCombineRgn(prgnNClip, prgnOrigClip, prgn, fnMode);
114 
115            if (Ret)
116            {
117               REGION_Delete(prgnOrigClip);
118               dc->dclevel.prgnClip = prgnNClip;
119               IntGdiReleaseRaoRgn(dc);
120            }
121            else
122               REGION_Delete(prgnNClip);
123         }
124         else // NULL Original Clip Region, setup a new one and process mode.
125         {
126             PREGION prgnClip;
127             RECTL rcl;
128 #if 0
129             PSURFACE pSurface;
130 
131             // See IntSetDefaultRegion.
132 
133             rcl.left   = 0;
134             rcl.top    = 0;
135             rcl.right  = dc->dclevel.sizl.cx;
136             rcl.bottom = dc->dclevel.sizl.cy;
137 
138             //EngAcquireSemaphoreShared(pdc->ppdev->hsemDevLock);
139             if (dc->ppdev->flFlags & PDEV_META_DEVICE)
140             {
141                 pSurface = dc->dclevel.pSurface;
142                 if (pSurface && pSurface->flags & PDEV_SURFACE)
143                 {
144                    rcl.left   += dc->ppdev->ptlOrigion.x;
145                    rcl.top    += dc->ppdev->ptlOrigion.y;
146                    rcl.right  += dc->ppdev->ptlOrigion.x;
147                    rcl.bottom += dc->ppdev->ptlOrigion.y;
148                 }
149             }
150             //EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
151 //#if 0
152             rcl.left   += dc->ptlDCOrig.x;
153             rcl.top    += dc->ptlDCOrig.y;
154             rcl.right  += dc->ptlDCOrig.x;
155             rcl.bottom += dc->ptlDCOrig.y;
156 #endif
157             REGION_GetRgnBox(dc->prgnVis, &rcl);
158 
159             prgnClip = IntSysCreateRectpRgnIndirect(&rcl);
160 
161             Ret = IntGdiCombineRgn(prgnNClip, prgnClip, prgn, fnMode);
162 
163             if (Ret)
164             {
165                 dc->dclevel.prgnClip = prgnNClip;
166                 IntGdiReleaseRaoRgn(dc);
167             }
168             else
169                 REGION_Delete(prgnNClip);
170 
171             REGION_Delete(prgnClip);
172         }
173         return Ret;
174     }
175 
176     // Fall through to normal RectOS mode.
177 
178     //
179     // Handle NULL Region and Original Clip Region.
180     //
181     if (!prgn)
182     {
183         if (prgnOrigClip)
184         {
185             REGION_Delete(dc->dclevel.prgnClip);
186             dc->dclevel.prgnClip = NULL;
187             IntGdiReleaseRaoRgn(dc);
188         }
189         return SIMPLEREGION;
190     }
191 
192     //
193     // Combine the new Clip region with original Clip and caller Region.
194     //
195     if ( prgnOrigClip &&
196         (Ret = IntGdiCombineRgn(prgnOrigClip, prgn, NULL, RGN_COPY)) ) // Clip could fail.
197     {
198         IntGdiReleaseRaoRgn(dc);
199     }
200     else // NULL original Clip, just copy caller region to new.
201     {
202        prgnNClip = IntSysCreateRectpRgn(0, 0, 0, 0);
203        REGION_bCopy(prgnNClip, prgn);
204        Ret = REGION_Complexity(prgnNClip);
205        dc->dclevel.prgnClip = prgnNClip;
206        IntGdiReleaseRaoRgn(dc);
207     }
208     return Ret;
209 }
210 
211 //
212 // Call from Gdi Batch Subsystem.
213 //
214 // Was setup to just handle RGN_COPY only and return VOID, since this was called from Gdi32.
215 // Tested in place of the other, complexity aside.
216 //
217 
218 _Success_(return!=ERROR)
219 int
220 FASTCALL
IntGdiExtSelectClipRect(_In_ PDC dc,_In_ PRECTL prcl,_In_ int fnMode)221 IntGdiExtSelectClipRect(
222     _In_ PDC dc,
223     _In_ PRECTL prcl,
224     _In_ int fnMode)
225 {
226     int Ret = ERROR;
227     PREGION prgn;
228     RECTL rect;
229     BOOL NoRegion = fnMode & GDIBS_NORECT;
230 
231     fnMode &= ~GDIBS_NORECT;
232 
233     if (NoRegion) // NULL Region.
234     {
235         if (fnMode == RGN_COPY)
236         {
237            Ret = IntSelectClipRgn( dc, NULL, RGN_COPY);
238 
239            if (dc->fs & DC_DIRTY_RAO)
240                CLIPPING_UpdateGCRegion(dc);
241 
242            if (Ret) // Copy? Return Vis complexity.
243                Ret = REGION_Complexity(dc->prgnVis);
244         }
245     }
246     else // Have a box to build a region with.
247     {                             //       See CORE-16246 : Needs to be a one box Clip Region.
248         if ( dc->dclevel.prgnClip && (REGION_Complexity(dc->dclevel.prgnClip) == SIMPLEREGION) )
249         {
250             REGION_GetRgnBox(dc->dclevel.prgnClip, &rect);
251 
252             if (prcl->left   == rect.left  &&
253                 prcl->top    == rect.top   &&
254                 prcl->right  == rect.right &&
255                 prcl->bottom == rect.bottom)
256             {
257                 return REGION_Complexity( dc->prgnRao ? dc->prgnRao : dc->prgnVis );
258             }
259         }
260 
261         prgn = IntSysCreateRectpRgnIndirect(prcl);
262 
263         Ret = IntSelectClipRgn( dc, prgn, fnMode);
264 
265         if (dc->fs & DC_DIRTY_RAO)
266             CLIPPING_UpdateGCRegion(dc);
267 
268         if (Ret) // In this case NtGdiExtSelectClipRgn tests pass.
269             Ret = REGION_Complexity( dc->prgnRao ? dc->prgnRao : dc->prgnVis );
270 
271         REGION_Delete(prgn);
272     }
273     return Ret;
274 }
275 
276 _Success_(return!=ERROR)
277 int
278 FASTCALL
IntGdiExtSelectClipRgn(_In_ PDC dc,_In_ PREGION prgn,_In_ int fnMode)279 IntGdiExtSelectClipRgn(
280     _In_ PDC dc,
281     _In_ PREGION prgn,
282     _In_ int fnMode)
283 {
284     int Ret = ERROR;
285 
286     if (!prgn)
287     {
288         if (fnMode == RGN_COPY)
289         {
290            if ((Ret = IntSelectClipRgn( dc, NULL, RGN_COPY)))
291                Ret = REGION_Complexity(dc->prgnVis);
292         }
293     }
294     else
295     {
296         if ((Ret = IntSelectClipRgn( dc, prgn, fnMode)))
297         {
298             DPRINT("IntGdiExtSelectClipRgn A %d\n",Ret);
299             // Update the Rao, it must be this way for now.
300             if (dc->fs & DC_DIRTY_RAO)
301                 CLIPPING_UpdateGCRegion(dc);
302 
303             Ret = REGION_Complexity( dc->prgnRao ? dc->prgnRao : dc->prgnVis );
304             DPRINT("IntGdiExtSelectClipRgn B %d\n",Ret);
305         }
306     }
307     return Ret;
308 }
309 
310 int
311 APIENTRY
NtGdiExtSelectClipRgn(HDC hDC,HRGN hrgn,int fnMode)312 NtGdiExtSelectClipRgn(
313     HDC  hDC,
314     HRGN  hrgn,
315     int  fnMode)
316 {
317     int retval;
318     DC *dc;
319     PREGION prgn;
320 
321     if ( fnMode < RGN_AND || fnMode > RGN_COPY )
322     {
323         EngSetLastError(ERROR_INVALID_PARAMETER);
324         return ERROR;
325     }
326 
327     if (!(dc = DC_LockDc(hDC)))
328     {
329         EngSetLastError(ERROR_INVALID_HANDLE);
330         return ERROR;
331     }
332 
333     prgn = REGION_LockRgn(hrgn);
334 
335     if ((prgn == NULL) && (fnMode != RGN_COPY))
336     {
337         //EngSetLastError(ERROR_INVALID_HANDLE); doesn't set this.
338         retval = ERROR;
339     }
340     else
341     {
342 #if 0   // Testing GDI Batch.
343         {
344             RECTL rcl;
345             if (prgn)
346                 REGION_GetRgnBox(prgn, &rcl);
347             else
348                 fnMode |= GDIBS_NORECT;
349             retval = IntGdiExtSelectClipRect(dc, &rcl, fnMode);
350         }
351 #else
352         retval = IntGdiExtSelectClipRgn(dc, prgn, fnMode);
353 #endif
354     }
355 
356     if (prgn)
357         REGION_UnlockRgn(prgn);
358 
359     DC_UnlockDc(dc);
360     return retval;
361 }
362 
363 _Success_(return!=ERROR)
364 INT
365 FASTCALL
GdiGetClipBox(_In_ HDC hdc,_Out_ LPRECT prc)366 GdiGetClipBox(
367     _In_ HDC hdc,
368     _Out_ LPRECT prc)
369 {
370     PDC pdc;
371     INT iComplexity;
372 
373     /* Lock the DC */
374     pdc = DC_LockDc(hdc);
375     if (!pdc)
376     {
377         return ERROR;
378     }
379 
380     /* Update RAO region if necessary */
381     if (pdc->fs & DC_DIRTY_RAO)
382         CLIPPING_UpdateGCRegion(pdc);
383 
384     /* Check if we have a RAO region (intersection of API and VIS region) */
385     if (pdc->prgnRao)
386     {
387         /* We have a RAO region, use it */
388         iComplexity = REGION_GetRgnBox(pdc->prgnRao, prc);
389     }
390     else
391     {
392         /* No RAO region means no API region, so use the VIS region */
393         ASSERT(pdc->prgnVis);
394         iComplexity = REGION_GetRgnBox(pdc->prgnVis, prc);
395     }
396 
397     /* Unlock the DC */
398     DC_UnlockDc(pdc);
399 
400     /* Convert the rect to logical coordinates */
401     IntDPtoLP(pdc, (LPPOINT)prc, 2);
402 
403     /* Return the complexity */
404     return iComplexity;
405 }
406 
407 _Success_(return!=ERROR)
408 INT
409 APIENTRY
NtGdiGetAppClipBox(_In_ HDC hdc,_Out_ LPRECT prc)410 NtGdiGetAppClipBox(
411     _In_ HDC hdc,
412     _Out_ LPRECT prc)
413 {
414     RECT rect;
415     INT iComplexity;
416 
417     /* Call the internal function */
418     iComplexity = GdiGetClipBox(hdc, &rect);
419 
420     if (iComplexity != ERROR)
421     {
422         _SEH2_TRY
423         {
424             ProbeForWrite(prc, sizeof(RECT), 1);
425             *prc = rect;
426         }
427         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
428         {
429             iComplexity = ERROR;
430         }
431         _SEH2_END
432     }
433 
434     /* Return the complexity */
435     return iComplexity;
436 }
437 
438 INT
439 APIENTRY
NtGdiExcludeClipRect(_In_ HDC hdc,_In_ INT xLeft,_In_ INT yTop,_In_ INT xRight,_In_ INT yBottom)440 NtGdiExcludeClipRect(
441     _In_ HDC hdc,
442     _In_ INT xLeft,
443     _In_ INT yTop,
444     _In_ INT xRight,
445     _In_ INT yBottom)
446 {
447     INT iComplexity = ERROR;
448     RECTL rect;
449     PDC pdc;
450     PREGION prgn;
451 
452     /* Lock the DC */
453     pdc = DC_LockDc(hdc);
454     if (pdc == NULL)
455     {
456         EngSetLastError(ERROR_INVALID_HANDLE);
457         return ERROR;
458     }
459 
460     /* Convert coordinates to device space */
461     rect.left   = xLeft;
462     rect.top    = yTop;
463     rect.right  = xRight;
464     rect.bottom = yBottom;
465     RECTL_vMakeWellOrdered(&rect);
466     IntLPtoDP(pdc, (LPPOINT)&rect, 2);
467 
468     prgn = IntSysCreateRectpRgnIndirect(&rect);
469     if ( prgn )
470     {
471         iComplexity = IntSelectClipRgn( pdc, prgn, RGN_DIFF );
472 
473         REGION_Delete(prgn);
474     }
475 
476     /* Emulate Windows behavior */
477     if (iComplexity == SIMPLEREGION)
478         iComplexity = COMPLEXREGION;
479 
480     /* Unlock the DC */
481     DC_UnlockDc(pdc);
482 
483     return iComplexity;
484 }
485 
486 INT
487 APIENTRY
NtGdiIntersectClipRect(_In_ HDC hdc,_In_ INT xLeft,_In_ INT yTop,_In_ INT xRight,_In_ INT yBottom)488 NtGdiIntersectClipRect(
489     _In_ HDC hdc,
490     _In_ INT xLeft,
491     _In_ INT yTop,
492     _In_ INT xRight,
493     _In_ INT yBottom)
494 {
495     INT iComplexity = ERROR;
496     RECTL rect;
497     PDC pdc;
498     PREGION prgn;
499 
500     DPRINT("NtGdiIntersectClipRect(%p, %d,%d-%d,%d)\n",
501             hdc, xLeft, yTop, xRight, yBottom);
502 
503     /* Lock the DC */
504     pdc = DC_LockDc(hdc);
505     if (!pdc)
506     {
507         EngSetLastError(ERROR_INVALID_HANDLE);
508         return ERROR;
509     }
510 
511     /* Convert coordinates to device space */
512     rect.left   = xLeft;
513     rect.top    = yTop;
514     rect.right  = xRight;
515     rect.bottom = yBottom;
516     RECTL_vMakeWellOrdered(&rect);
517     IntLPtoDP(pdc, (LPPOINT)&rect, 2);
518 
519     prgn = IntSysCreateRectpRgnIndirect(&rect);
520     if ( prgn )
521     {
522         iComplexity = IntSelectClipRgn( pdc, prgn, RGN_AND );
523 
524         REGION_Delete(prgn);
525     }
526 
527     /* Emulate Windows behavior */
528     if ( iComplexity == SIMPLEREGION )
529         iComplexity = COMPLEXREGION;
530 
531     /* Unlock the DC */
532     DC_UnlockDc(pdc);
533 
534     return iComplexity;
535 }
536 
537 INT
538 APIENTRY
NtGdiOffsetClipRgn(_In_ HDC hdc,_In_ INT xOffset,_In_ INT yOffset)539 NtGdiOffsetClipRgn(
540     _In_ HDC hdc,
541     _In_ INT xOffset,
542     _In_ INT yOffset)
543 {
544     INT iComplexity;
545     PDC pdc;
546     POINTL apt[2];
547 
548     /* Lock the DC */
549     pdc = DC_LockDc(hdc);
550     if (pdc == NULL)
551     {
552         if (!hdc) EngSetLastError(ERROR_INVALID_HANDLE);
553         return ERROR;
554     }
555 
556     /* Check if we have a clip region */
557     if (pdc->dclevel.prgnClip != NULL)
558     {
559         /* Convert coordinates into device space. Note that we need to convert
560            2 coordinates to account for rotation / shear / offset */
561         apt[0].x = 0;
562         apt[0].y = 0;
563         apt[1].x = xOffset;
564         apt[1].y = yOffset;
565         IntLPtoDP(pdc, apt, 2);
566 
567         /* Offset the clip region */
568         if (!REGION_bOffsetRgn(pdc->dclevel.prgnClip,
569                                apt[1].x - apt[0].x,
570                                apt[1].y - apt[0].y))
571         {
572             iComplexity = ERROR;
573         }
574         else
575         {
576             IntGdiReleaseRaoRgn(pdc);
577             UpdateVisRgn(pdc);
578             iComplexity = REGION_Complexity(pdc->dclevel.prgnClip);
579         }
580 
581         /* Mark the RAO region as dirty */
582         pdc->fs |= DC_DIRTY_RAO;
583     }
584     else
585     {
586         /* NULL means no clipping, i.e. the "whole" region */
587         iComplexity = SIMPLEREGION;
588     }
589 
590     /* Unlock the DC and return the complexity */
591     DC_UnlockDc(pdc);
592     return iComplexity;
593 }
594 
NtGdiPtVisible(HDC hDC,int X,int Y)595 BOOL APIENTRY NtGdiPtVisible(HDC  hDC,
596                     int  X,
597                     int  Y)
598 {
599     BOOL ret = FALSE;
600     PDC dc;
601     PREGION prgn;
602 
603     if(!(dc = DC_LockDc(hDC)))
604     {
605         EngSetLastError(ERROR_INVALID_HANDLE);
606         return FALSE;
607     }
608 
609     prgn = dc->prgnRao ? dc->prgnRao : dc->prgnVis;
610 
611     if (prgn)
612     {
613         POINT pt = {X, Y};
614         IntLPtoDP(dc, &pt, 1);
615         ret = REGION_PtInRegion(prgn, pt.x, pt.y);
616     }
617 
618     DC_UnlockDc(dc);
619 
620     return ret;
621 }
622 
623 BOOL
624 APIENTRY
NtGdiRectVisible(HDC hDC,LPRECT UnsafeRect)625 NtGdiRectVisible(
626     HDC hDC,
627     LPRECT UnsafeRect)
628 {
629     NTSTATUS Status = STATUS_SUCCESS;
630     PDC dc = DC_LockDc(hDC);
631     BOOL Result = FALSE;
632     RECTL Rect;
633     PREGION prgn;
634 
635     if (!dc)
636     {
637         EngSetLastError(ERROR_INVALID_HANDLE);
638         return FALSE;
639     }
640 
641     _SEH2_TRY
642     {
643         ProbeForRead(UnsafeRect,
644                    sizeof(RECT),
645                    1);
646         Rect = *UnsafeRect;
647     }
648     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
649     {
650         Status = _SEH2_GetExceptionCode();
651     }
652     _SEH2_END;
653 
654     if(!NT_SUCCESS(Status))
655     {
656         DC_UnlockDc(dc);
657         SetLastNtError(Status);
658         return FALSE;
659     }
660 
661     if (dc->fs & DC_DIRTY_RAO)
662         CLIPPING_UpdateGCRegion(dc);
663 
664     prgn = dc->prgnRao ? dc->prgnRao : dc->prgnVis;
665     if (prgn)
666     {
667          IntLPtoDP(dc, (LPPOINT)&Rect, 2);
668          Result = REGION_RectInRegion(prgn, &Rect);
669     }
670     DC_UnlockDc(dc);
671 
672     return Result;
673 }
674 
675 int
676 FASTCALL
IntGdiSetMetaRgn(PDC pDC)677 IntGdiSetMetaRgn(PDC pDC)
678 {
679     INT Ret = ERROR;
680 
681     if ( pDC->dclevel.prgnMeta )
682     {
683         if ( pDC->dclevel.prgnClip )
684         {
685             PREGION prgn = IntSysCreateRectpRgn(0,0,0,0);
686             if ( prgn )
687             {
688                 if (REGION_bIntersectRegion(prgn, pDC->dclevel.prgnMeta, pDC->dclevel.prgnClip))
689                 {
690                     // See Restore/SaveDC
691                     REGION_Delete(pDC->dclevel.prgnMeta);
692                     pDC->dclevel.prgnMeta = prgn;
693 
694                     REGION_Delete(pDC->dclevel.prgnClip);
695                     pDC->dclevel.prgnClip = NULL;
696                     IntGdiReleaseRaoRgn(pDC);
697 
698                     Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
699                 }
700                 else
701                     REGION_Delete(prgn);
702             }
703         }
704         else
705             Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
706     }
707     else
708     {
709         if ( pDC->dclevel.prgnClip )
710         {
711             Ret = REGION_Complexity(pDC->dclevel.prgnClip);
712             pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
713             pDC->dclevel.prgnClip = NULL;
714         }
715         else
716             Ret = SIMPLEREGION;
717     }
718 
719     return Ret;
720 }
721 
722 
NtGdiSetMetaRgn(HDC hDC)723 int APIENTRY NtGdiSetMetaRgn(HDC  hDC)
724 {
725   INT Ret;
726   PDC pDC = DC_LockDc(hDC);
727 
728   if (!pDC)
729   {
730      EngSetLastError(ERROR_INVALID_PARAMETER);
731      return ERROR;
732   }
733   Ret = IntGdiSetMetaRgn(pDC);
734 
735   DC_UnlockDc(pDC);
736   return Ret;
737 }
738 
739 VOID
740 FASTCALL
CLIPPING_UpdateGCRegion(PDC pDC)741 CLIPPING_UpdateGCRegion(PDC pDC)
742 {
743     // Moved from Release Rao. Though it still gets over written.
744     RECTL_vSetEmptyRect(&pDC->erclClip);
745 
746     /* Must have VisRgn set to a valid state! */
747     ASSERT (pDC->prgnVis);
748 #if 0 // (w2k3) This works with limitations. (w7u) ReactOS relies on Rao.
749     if ( !pDC->dclevel.prgnClip &&
750          !pDC->dclevel.prgnMeta &&
751          !pDC->prgnAPI)
752     {
753         if (pDC->prgnRao)
754             REGION_Delete(pDC->prgnRao);
755         pDC->prgnRao = NULL;
756 
757         REGION_bOffsetRgn(pDC->prgnVis, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
758 
759         RtlCopyMemory(&pDC->erclClip,
760                       &pDC->prgnVis->rdh.rcBound,
761                        sizeof(RECTL));
762 
763         IntEngUpdateClipRegion(&pDC->co,
764                                 pDC->prgnVis->rdh.nCount,
765                                 pDC->prgnVis->Buffer,
766                                &pDC->erclClip);
767 
768         REGION_bOffsetRgn(pDC->prgnVis, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
769 
770         pDC->fs &= ~DC_DIRTY_RAO;
771         UpdateVisRgn(pDC);
772         return;
773     }
774 #endif
775     if (pDC->prgnAPI)
776     {
777         REGION_Delete(pDC->prgnAPI);
778         pDC->prgnAPI = NULL;
779     }
780 
781     if (pDC->dclevel.prgnMeta || pDC->dclevel.prgnClip)
782     {
783         pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
784         if (!pDC->prgnAPI)
785         {
786             /* Best we can do here. Better than crashing. */
787             ERR("Failed to allocate prgnAPI! Expect drawing issues!\n");
788             return;
789         }
790 
791         if (!pDC->dclevel.prgnMeta)
792         {
793             REGION_bCopy(pDC->prgnAPI,
794                          pDC->dclevel.prgnClip);
795         }
796         else if (!pDC->dclevel.prgnClip)
797         {
798             REGION_bCopy(pDC->prgnAPI,
799                          pDC->dclevel.prgnMeta);
800         }
801         else
802         {
803             REGION_bIntersectRegion(pDC->prgnAPI,
804                                     pDC->dclevel.prgnClip,
805                                     pDC->dclevel.prgnMeta);
806         }
807     }
808 
809     if (pDC->prgnRao)
810         REGION_Delete(pDC->prgnRao);
811 
812     pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
813     if (!pDC->prgnRao)
814     {
815         /* Best we can do here. Better than crashing. */
816         ERR("Failed to allocate prgnRao! Expect drawing issues!\n");
817         return;
818     }
819 
820     if (pDC->prgnAPI)
821     {
822         REGION_bIntersectRegion(pDC->prgnRao,
823                                 pDC->prgnVis,
824                                 pDC->prgnAPI);
825     }
826     else
827     {
828         REGION_bCopy(pDC->prgnRao,
829                      pDC->prgnVis);
830     }
831 
832 
833     REGION_bOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
834 
835     RtlCopyMemory(&pDC->erclClip,
836                   &pDC->prgnRao->rdh.rcBound,
837                   sizeof(RECTL));
838 
839     pDC->fs &= ~DC_DIRTY_RAO;
840     UpdateVisRgn(pDC);
841 
842     // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
843     // the rects from region objects rects in pClipRgn->Buffer.
844     // With pDC->co.pClipRgn->Buffer,
845     // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
846 
847     IntEngUpdateClipRegion(&pDC->co,
848                            pDC->prgnRao->rdh.nCount,
849                            pDC->prgnRao->Buffer,
850                            &pDC->erclClip);
851 
852     REGION_bOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
853 }
854 
855 /* EOF */
856