Author: tkreuzer
Date: Thu Dec 18 08:13:10 2014
New Revision: 65738

URL: http://svn.reactos.org/svn/reactos?rev=65738&view=rev
Log:
[GDI32]
Rewrite CombineRgn, enabling full handling in usermode if the resulting region 
is either a rectangular or a NULL region.

Modified:
    trunk/reactos/win32ss/gdi/gdi32/objects/region.c

Modified: trunk/reactos/win32ss/gdi/gdi32/objects/region.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/gdi/gdi32/objects/region.c?rev=65738&r1=65737&r2=65738&view=diff
==============================================================================
--- trunk/reactos/win32ss/gdi/gdi32/objects/region.c    [iso-8859-1] (original)
+++ trunk/reactos/win32ss/gdi/gdi32/objects/region.c    [iso-8859-1] Thu Dec 18 
08:13:10 2014
@@ -187,215 +187,364 @@
 
 /* FUNCTIONS *****************************************************************/
 
+FORCEINLINE
+ULONG
+SetRectRgnEx(
+    HRGN hrgn,
+    PRGN_ATTR prgnattr,
+    INT xLeft,
+    INT yTop,
+    INT xRight,
+    INT yBottom)
+{
+    if (!SetRectRgn(hrgn, xLeft, yTop, xRight, yBottom))
+    {
+        return ERROR;
+    }
+
+    return prgnattr->iComplexity;
+
+}
+
 /*
  * @implemented
  */
 INT
 WINAPI
-CombineRgn(HRGN  hDest,
-           HRGN  hSrc1,
-           HRGN  hSrc2,
-           INT  CombineMode)
-{
-    PRGN_ATTR pRgn_Attr_Dest = NULL;
-    PRGN_ATTR pRgn_Attr_Src1 = NULL;
-    PRGN_ATTR pRgn_Attr_Src2 = NULL;
-    INT Complexity;
-    BOOL Ret;
-
-// HACK
-    return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-
-    Ret = GdiGetHandleUserData((HGDIOBJ) hDest, GDI_OBJECT_TYPE_REGION, 
(PVOID) &pRgn_Attr_Dest);
-    Ret = GdiGetHandleUserData((HGDIOBJ) hSrc1, GDI_OBJECT_TYPE_REGION, 
(PVOID) &pRgn_Attr_Src1);
-
-    if ( !Ret ||
-            !pRgn_Attr_Dest ||
-            !pRgn_Attr_Src1 ||
-            pRgn_Attr_Src1->iComplexity > SIMPLEREGION )
-        return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-
-    /* Handle COPY and use only src1. */
-    if ( CombineMode == RGN_COPY )
-    {
-        switch (pRgn_Attr_Src1->iComplexity)
-        {
-        case NULLREGION:
-            Ret = SetRectRgn( hDest, 0, 0, 0, 0);
-            if (Ret)
-                return NULLREGION;
-            goto ERROR_Exit;
-
-        case SIMPLEREGION:
-            Ret = SetRectRgn( hDest,
-                              pRgn_Attr_Src1->Rect.left,
-                              pRgn_Attr_Src1->Rect.top,
-                              pRgn_Attr_Src1->Rect.right,
-                              pRgn_Attr_Src1->Rect.bottom );
-            if (Ret)
-                return SIMPLEREGION;
-            goto ERROR_Exit;
-
-        case COMPLEXREGION:
-        default:
-            return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-        }
-    }
-
-    Ret = GdiGetHandleUserData((HGDIOBJ) hSrc2, GDI_OBJECT_TYPE_REGION, 
(PVOID) &pRgn_Attr_Src2);
-    if ( !Ret ||
-            !pRgn_Attr_Src2 ||
-            pRgn_Attr_Src2->iComplexity > SIMPLEREGION )
-        return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-
-    /* All but AND. */
-    if ( CombineMode != RGN_AND)
-    {
-        if ( CombineMode <= RGN_AND)
-        {
-            /*
-               There might be some type of junk in the call, so go K.
-               If this becomes a problem, need to setup parameter check at the 
top.
-             */
-            DPRINT1("Might be junk! CombineMode %d\n",CombineMode);
-            return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-        }
-
-        if ( CombineMode > RGN_XOR) /* Handle DIFF. */
-        {
-            if ( CombineMode != RGN_DIFF)
-            {
-                /* Filter check! Well, must be junk?, so go K. */
-                DPRINT1("RGN_COPY was handled! CombineMode %d\n",CombineMode);
-                return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-            }
-            /* Now handle DIFF. */
-            if ( pRgn_Attr_Src1->iComplexity == NULLREGION )
-            {
-                if (SetRectRgn( hDest, 0, 0, 0, 0))
-                    return NULLREGION;
-                goto ERROR_Exit;
-            }
-
-            if ( pRgn_Attr_Src2->iComplexity != NULLREGION )
-            {
-                Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, 
&pRgn_Attr_Src2->Rect);
-
-                if ( Complexity != DIFF_RGN )
+CombineRgn(
+    _In_ HRGN hrgnDest,
+    _In_ HRGN hrgnSrc1,
+    _In_ HRGN hrgnSrc2,
+    _In_ INT  iCombineMode)
+{
+    PRGN_ATTR prngattrDest = NULL;
+    PRGN_ATTR prngattrSrc1 = NULL;
+    PRGN_ATTR prngattrSrc2 = NULL;
+    RECT rcTemp;
+
+    /* Get the region attribute for dest and source 1 */
+    prngattrDest = GdiGetRgnAttr(hrgnDest);
+    prngattrSrc1 = GdiGetRgnAttr(hrgnSrc1);
+
+    /* If that failed or if the source 1 region is complex, go to win32k */
+    if ((prngattrDest == NULL) || (prngattrSrc1 == NULL) ||
+        (prngattrSrc1->iComplexity > SIMPLEREGION))
+    {
+        return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
+    }
+
+    /* Handle RGN_COPY first, it needs only hrgnSrc1 */
+    if (iCombineMode == RGN_COPY)
+    {
+        /* Check if the source region is a NULLREGION */
+        if (prngattrSrc1->iComplexity == NULLREGION)
+        {
+            /* The dest region is a NULLREGION, too */
+            return SetRectRgn(hrgnDest, 0, 0, 0, 0) ? NULLREGION : ERROR;
+        }
+
+        /* We already know that the source region cannot be complex, so
+           create a rect region from the bounds of the source rect */
+        return SetRectRgnEx(hrgnDest,
+                            prngattrDest,
+                            prngattrSrc1->Rect.left,
+                            prngattrSrc1->Rect.top,
+                            prngattrSrc1->Rect.right,
+                            prngattrSrc1->Rect.bottom);
+    }
+
+    /* For all other operations we need hrgnSrc2 */
+    prngattrSrc2 = GdiGetRgnAttr(hrgnSrc2);
+
+    /* If we got no attribute or the region is complex, go to win32k */
+    if ((prngattrSrc2 == NULL) || (prngattrSrc2->iComplexity > SIMPLEREGION))
+    {
+        return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
+    }
+
+    /* Handle RGN_AND */
+    if (iCombineMode == RGN_AND)
+    {
+        /* Check if either of the regions is a NULLREGION */
+        if ((prngattrSrc1->iComplexity == NULLREGION) ||
+            (prngattrSrc2->iComplexity == NULLREGION))
+        {
+            /* Result is also a NULLREGION */
+            return SetRectRgn(hrgnDest, 0, 0, 0, 0) ? NULLREGION : ERROR;
+        }
+
+        /* Get the intersection of the 2 rects */
+        if (!IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect))
+        {
+            /* The rects do not intersect, result is a NULLREGION */
+            return SetRectRgn(hrgnDest, 0, 0, 0, 0) ? NULLREGION : ERROR;
+        }
+
+        /* Use the intersection of the rects */
+        return SetRectRgnEx(hrgnDest,
+                            prngattrDest,
+                            rcTemp.left,
+                            rcTemp.top,
+                            rcTemp.right,
+                            rcTemp.bottom);
+    }
+
+    /* Handle RGN_DIFF */
+    if (iCombineMode == RGN_DIFF)
+    {
+        /* Check if source 1 is a NULLREGION */
+        if (prngattrSrc1->iComplexity == NULLREGION)
+        {
+            /* The result is a NULLREGION as well */
+            return SetRectRgn(hrgnDest, 0, 0, 0, 0) ? NULLREGION : ERROR;
+        }
+
+        /* Get the intersection of the 2 rects */
+        if ((prngattrSrc2->iComplexity == NULLREGION) ||
+            !IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect))
+        {
+            /* The rects do not intersect, dest equals source 1 */
+            return SetRectRgnEx(hrgnDest,
+                                prngattrDest,
+                                prngattrSrc1->Rect.left,
+                                prngattrSrc1->Rect.top,
+                                prngattrSrc1->Rect.right,
+                                prngattrSrc1->Rect.bottom);
+        }
+
+        /* We need to check is whether we can subtract the rects. For that
+           we call SubtractRect, which will give us the bounding box of the
+           subtraction. The function returns FALSE if the resulting rect is
+           empty */
+        if (!SubtractRect(&rcTemp, &prngattrSrc1->Rect, &rcTemp))
+        {
+            /* The result is a NULLREGION */
+            return SetRectRgn(hrgnDest, 0, 0, 0, 0) ? NULLREGION : ERROR;
+        }
+
+        /* Now check if the result of SubtractRect matches the source 1 rect.
+           Since we already know that the rects intersect, the result can
+           only match the source 1 rect, if it could not be "cut" on either
+           side, but the overlapping was on a corner, so the new bounding box
+           equals the previous rect */
+        if (!EqualRect(&rcTemp, &prngattrSrc1->Rect))
+        {
+            /* We got a properly subtracted rect, so use it. */
+            return SetRectRgnEx(hrgnDest,
+                                prngattrDest,
+                                rcTemp.left,
+                                rcTemp.top,
+                                rcTemp.right,
+                                rcTemp.bottom);
+        }
+
+        /* The result would be a complex region, go to win32k */
+        return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
+    }
+
+    /* Handle OR and XOR */
+    if ((iCombineMode == RGN_OR) || (iCombineMode == RGN_XOR))
+    {
+        /* Check if source 1 is a NULLREGION */
+        if (prngattrSrc1->iComplexity == NULLREGION)
+        {
+            /* Check if source 2 is also a NULLREGION */
+            if (prngattrSrc2->iComplexity == NULLREGION)
+            {
+                /* Both are NULLREGIONs, result is also a NULLREGION */
+                return SetRectRgn(hrgnDest, 0, 0, 0, 0) ? NULLREGION : ERROR;
+            }
+
+            /* The result is equal to source 2 */
+            return SetRectRgnEx(hrgnDest,
+                                prngattrDest,
+                                prngattrSrc2->Rect.left,
+                                prngattrSrc2->Rect.top,
+                                prngattrSrc2->Rect.right,
+                                prngattrSrc2->Rect.bottom );
+        }
+
+        /* Check if only source 2 is a NULLREGION */
+        if (prngattrSrc2->iComplexity == NULLREGION)
+        {
+            /* The result is equal to source 1 */
+            return SetRectRgnEx(hrgnDest,
+                                prngattrDest,
+                                prngattrSrc1->Rect.left,
+                                prngattrSrc1->Rect.top,
+                                prngattrSrc1->Rect.right,
+                                prngattrSrc1->Rect.bottom);
+        }
+
+        /* Do the rects have the same x extent */
+        if ((prngattrSrc1->Rect.left == prngattrSrc2->Rect.left) &&
+            (prngattrSrc1->Rect.right == prngattrSrc2->Rect.right))
+        {
+            /* Do the rects also have the same y extent */
+            if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) &&
+                (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom))
+            {
+                /* Rects are equal, if this is RGN_OR, the result is source 1 
*/
+                if (iCombineMode == RGN_OR)
                 {
-                    if ( Complexity != INVERTED_RGN)
-                        /* If same or overlapping and norm just go K. */
-                        return NtGdiCombineRgn(hDest, hSrc1, hSrc2, 
CombineMode);
-
-                    if (SetRectRgn( hDest, 0, 0, 0, 0))
-                        return NULLREGION;
-                    goto ERROR_Exit;
+                    /* The result is equal to source 1 */
+                    return SetRectRgnEx(hrgnDest,
+                                        prngattrDest,
+                                        prngattrSrc1->Rect.left,
+                                        prngattrSrc1->Rect.top,
+                                        prngattrSrc1->Rect.right,
+                                        prngattrSrc1->Rect.bottom );
                 }
-            }
-        }
-        else /* Handle OR or XOR. */
-        {
-            if ( pRgn_Attr_Src1->iComplexity == NULLREGION )
-            {
-                if ( pRgn_Attr_Src2->iComplexity != NULLREGION )
+                else
                 {
-                    /* Src1 null and not NULL, set from src2. */
-                    Ret = SetRectRgn( hDest,
-                                      pRgn_Attr_Src2->Rect.left,
-                                      pRgn_Attr_Src2->Rect.top,
-                                      pRgn_Attr_Src2->Rect.right,
-                                      pRgn_Attr_Src2->Rect.bottom );
-                    if (Ret)
-                        return SIMPLEREGION;
-                    goto ERROR_Exit;
+                    /* XORing with itself yields an empty region */
+                    return SetRectRgn(hrgnDest, 0, 0, 0, 0) ? NULLREGION : 
ERROR;
                 }
-                /* Both are NULL. */
-                if (SetRectRgn( hDest, 0, 0, 0, 0))
-                    return NULLREGION;
-                goto ERROR_Exit;
-            }
-            /* Src1 is not NULL. */
-            if ( pRgn_Attr_Src2->iComplexity != NULLREGION )
-            {
-                if ( CombineMode != RGN_OR ) /* Filter XOR, so go K. */
-                    return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-
-                Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, 
&pRgn_Attr_Src2->Rect);
-                /* If inverted use Src2. */
-                if ( Complexity == INVERTED_RGN)
+            }
+
+            /* Check if the rects are disjoint */
+            if ((prngattrSrc2->Rect.bottom < prngattrSrc1->Rect.top) ||
+                (prngattrSrc2->Rect.top > prngattrSrc1->Rect.bottom))
+            {
+                /* The result would be a complex region, go to win32k */
+                return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, 
iCombineMode);
+            }
+
+            /* Check if this is OR */
+            if (iCombineMode == RGN_OR)
+            {
+                /* Use the maximum extent of both rects combined */
+                return SetRectRgnEx(hrgnDest,
+                                    prngattrDest,
+                                    prngattrSrc1->Rect.left,
+                                    min(prngattrSrc1->Rect.top, 
prngattrSrc2->Rect.top),
+                                    prngattrSrc1->Rect.right,
+                                    max(prngattrSrc1->Rect.bottom, 
prngattrSrc2->Rect.bottom));
+            }
+
+            /* Check if the rects are adjacent */
+            if (prngattrSrc2->Rect.bottom == prngattrSrc1->Rect.top)
+            {
+                /* The result is the combined rects */
+                return SetRectRgnEx(hrgnDest,
+                                    prngattrDest,
+                                    prngattrSrc1->Rect.left,
+                                    prngattrSrc2->Rect.top,
+                                    prngattrSrc1->Rect.right,
+                                    prngattrSrc1->Rect.bottom );
+            }
+            else if (prngattrSrc2->Rect.top == prngattrSrc1->Rect.bottom)
+            {
+                /* The result is the combined rects */
+                return SetRectRgnEx(hrgnDest,
+                                    prngattrDest,
+                                    prngattrSrc1->Rect.left,
+                                    prngattrSrc1->Rect.top,
+                                    prngattrSrc1->Rect.right,
+                                    prngattrSrc2->Rect.bottom );
+            }
+
+            /* When we are here, this is RGN_XOR and the rects overlap */
+            return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
+        }
+
+        /* Do the rects have the same y extent */
+        if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) &&
+            (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom))
+        {
+            /* Check if the rects are disjoint */
+            if ((prngattrSrc2->Rect.right < prngattrSrc1->Rect.left) ||
+                (prngattrSrc2->Rect.left > prngattrSrc1->Rect.right))
+            {
+                /* The result would be a complex region, go to win32k */
+                return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, 
iCombineMode);
+            }
+
+            /* Check if this is OR */
+            if (iCombineMode == RGN_OR)
+            {
+                /* Use the maximum extent of both rects combined */
+                return SetRectRgnEx(hrgnDest,
+                                    prngattrDest,
+                                    min(prngattrSrc1->Rect.left, 
prngattrSrc2->Rect.left),
+                                    prngattrSrc1->Rect.top,
+                                    max(prngattrSrc1->Rect.right, 
prngattrSrc2->Rect.right),
+                                    prngattrSrc1->Rect.bottom);
+            }
+
+            /* Check if the rects are adjacent */
+            if (prngattrSrc2->Rect.right == prngattrSrc1->Rect.left)
+            {
+                /* The result is the combined rects */
+                return SetRectRgnEx(hrgnDest,
+                                    prngattrDest,
+                                    prngattrSrc2->Rect.left,
+                                    prngattrSrc1->Rect.top,
+                                    prngattrSrc1->Rect.right,
+                                    prngattrSrc1->Rect.bottom );
+            }
+            else if (prngattrSrc2->Rect.left == prngattrSrc1->Rect.right)
+            {
+                /* The result is the combined rects */
+                return SetRectRgnEx(hrgnDest,
+                                    prngattrDest,
+                                    prngattrSrc1->Rect.left,
+                                    prngattrSrc1->Rect.top,
+                                    prngattrSrc2->Rect.right,
+                                    prngattrSrc1->Rect.bottom );
+            }
+
+            /* When we are here, this is RGN_XOR and the rects overlap */
+            return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
+        }
+
+        /* Last case: RGN_OR and one rect is completely within the other */
+        if (iCombineMode == RGN_OR)
+        {
+            /* Check if rect 1 can contain rect 2 */
+            if (prngattrSrc1->Rect.left <= prngattrSrc2->Rect.left)
+            {
+                /* rect 1 might be the outer one, check of that is true */
+                if ((prngattrSrc1->Rect.right >= prngattrSrc2->Rect.right) &&
+                    (prngattrSrc1->Rect.top <= prngattrSrc2->Rect.top) &&
+                    (prngattrSrc1->Rect.bottom >= prngattrSrc2->Rect.bottom))
                 {
-                    Ret = SetRectRgn( hDest,
-                                      pRgn_Attr_Src2->Rect.left,
-                                      pRgn_Attr_Src2->Rect.top,
-                                      pRgn_Attr_Src2->Rect.right,
-                                      pRgn_Attr_Src2->Rect.bottom );
-                    if (Ret)
-                        return SIMPLEREGION;
-                    goto ERROR_Exit;
+                    /* Rect 1 contains rect 2, use it */
+                    return SetRectRgnEx(hrgnDest,
+                                        prngattrDest,
+                                        prngattrSrc1->Rect.left,
+                                        prngattrSrc1->Rect.top,
+                                        prngattrSrc1->Rect.right,
+                                        prngattrSrc1->Rect.bottom );
                 }
-                /* Not NULL or overlapping or differentiated, go to K. */
-                if ( Complexity != SAME_RGN)
-                    return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-                /* If same, just fall through. */
-            }
-        }
-        Ret = SetRectRgn( hDest,
-                          pRgn_Attr_Src1->Rect.left,
-                          pRgn_Attr_Src1->Rect.top,
-                          pRgn_Attr_Src1->Rect.right,
-                          pRgn_Attr_Src1->Rect.bottom );
-        if (Ret)
-            return SIMPLEREGION;
-        goto ERROR_Exit;
-    }
-
-    /* Handle AND.  */
-    if ( pRgn_Attr_Src1->iComplexity != NULLREGION &&
-            pRgn_Attr_Src2->iComplexity != NULLREGION )
-    {
-        Complexity = ComplexityFromRects( &pRgn_Attr_Src1->Rect, 
&pRgn_Attr_Src2->Rect);
-
-        if ( Complexity == DIFF_RGN ) /* Differentiated in anyway just NULL 
rgn. */
-        {
-            if (SetRectRgn( hDest, 0, 0, 0, 0))
-                return NULLREGION;
-            goto ERROR_Exit;
-        }
-
-        if ( Complexity != INVERTED_RGN) /* Not inverted and overlapping. */
-        {
-            if ( Complexity != SAME_RGN) /* Must be norm and overlapping. */
-                return NtGdiCombineRgn(hDest, hSrc1, hSrc2, CombineMode);
-            /* Merge from src2.  */
-            Ret = SetRectRgn( hDest,
-                              pRgn_Attr_Src2->Rect.left,
-                              pRgn_Attr_Src2->Rect.top,
-                              pRgn_Attr_Src2->Rect.right,
-                              pRgn_Attr_Src2->Rect.bottom );
-            if (Ret)
-                return SIMPLEREGION;
-            goto ERROR_Exit;
-        }
-        /* Inverted so merge from src1. */
-        Ret = SetRectRgn( hDest,
-                          pRgn_Attr_Src1->Rect.left,
-                          pRgn_Attr_Src1->Rect.top,
-                          pRgn_Attr_Src1->Rect.right,
-                          pRgn_Attr_Src1->Rect.bottom );
-        if (Ret)
-            return SIMPLEREGION;
-        goto ERROR_Exit;
-    }
-
-    /* It's all NULL! */
-    if (SetRectRgn( hDest, 0, 0, 0, 0))
-        return NULLREGION;
-
-ERROR_Exit:
-    /* Even on error the flag is set dirty and force server side to redraw. */
-    pRgn_Attr_Dest->AttrFlags |= ATTR_RGN_DIRTY;
+            }
+            else
+            {
+                /* rect 2 might be the outer one, check of that is true */
+                if ((prngattrSrc2->Rect.right >= prngattrSrc1->Rect.right) &&
+                    (prngattrSrc2->Rect.top <= prngattrSrc1->Rect.top) &&
+                    (prngattrSrc2->Rect.bottom >= prngattrSrc1->Rect.bottom))
+                {
+                    /* Rect 2 contains rect 1, use it */
+                    return SetRectRgnEx(hrgnDest,
+                                        prngattrDest,
+                                        prngattrSrc2->Rect.left,
+                                        prngattrSrc2->Rect.top,
+                                        prngattrSrc2->Rect.right,
+                                        prngattrSrc2->Rect.bottom );
+                }
+            }
+        }
+
+        /* We couldn't handle the operation, go to win32k */
+        return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
+    }
+
+    DPRINT1("Invalid iCombineMode %d\n", iCombineMode);
+    SetLastError(ERROR_INVALID_PARAMETER);
     return ERROR;
 }
+
 
 /*
  * @implemented
@@ -670,7 +819,7 @@
                         }
                         else
                         {
-                            Ret = pDc_Attr->VisRectRegion.iComplexity;
+                            Ret = pDc_Attr->VisRectRegion.Flags;
                             pgO->fnMode |= 0x80000000; // Set no hrgn mode.
                         }
                         pTeb->GdiTebBatch.Offset += sizeof(GDIBSEXTSELCLPRGN);


Reply via email to