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