[ros-diffs] [tkreuzer] 27815: UserScrollDC (complete rewrite): - include the region that could not be copied (invisible before) into invalid region - use less regions and calculations - return the type of the invalidated region (used by NtUserScrollWindowEx) - Remove LPtoDP and DPtoPL. Everything is now in logical coordinates. NtUserScrollDC: - use SEH for buffer transfer NtUserScrollWindowEx: - use SEH for buffer transfer instead of MmCopyFromCaller - use SEH to write back to usermode - return the type of invalid region not of the invalidated region (nothing if SW_INVALIDATE is not set) - use members of WINDOW_OBJECT instead of calling IntWinListChildren Use hungarian notation for variables fixes bug 2237 See issue #2237 for more details.

tkreuzer at svn.reactos.org tkreuzer at svn.reactos.org
Wed Jul 25 23:51:57 CEST 2007


Author: tkreuzer
Date: Thu Jul 26 01:51:56 2007
New Revision: 27815

URL: http://svn.reactos.org/svn/reactos?rev=27815&view=rev
Log:
UserScrollDC (complete rewrite):
- include the region that could not be copied (invisible before) into invalid region
- use less regions and calculations
- return the type of the invalidated region (used by NtUserScrollWindowEx)
- Remove LPtoDP and DPtoPL. Everything is now in logical coordinates.
NtUserScrollDC:
- use SEH for buffer transfer
NtUserScrollWindowEx:
- use SEH for buffer transfer instead of MmCopyFromCaller
- use SEH to write back to usermode
- return the type of invalid region not of the invalidated region (nothing if SW_INVALIDATE is not set)
- use members of WINDOW_OBJECT instead of calling IntWinListChildren
Use hungarian notation for variables

fixes bug 2237
See issue #2237 for more details.

Modified:
    trunk/reactos/subsystems/win32/win32k/ntuser/painting.c

Modified: trunk/reactos/subsystems/win32/win32k/ntuser/painting.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/win32k/ntuser/painting.c?rev=27815&r1=27814&r2=27815&view=diff
==============================================================================
--- trunk/reactos/subsystems/win32/win32k/ntuser/painting.c (original)
+++ trunk/reactos/subsystems/win32/win32k/ntuser/painting.c Thu Jul 26 01:51:56 2007
@@ -1109,102 +1109,84 @@
 
 
 static
-DWORD FASTCALL
-UserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
-             const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate)
-{
-   RECT rSrc, rClipped_src, rClip, rDst, offset;
-   PDC DC;
-
-   /*
-    * Compute device clipping region (in device coordinates).
-    */
-
-   DC = DC_LockDc(hDC);
-   if (NULL == DC)
-   {
-      return FALSE;
-   }
-   if (lprcScroll)
-      rSrc = *lprcScroll;
+INT FASTCALL
+UserScrollDC(HDC hDC, INT dx, INT dy, const RECT *prcScroll,
+             const RECT *prcClip, HRGN hrgnUpdate, LPRECT prcUpdate)
+{
+   PDC pDC;
+   RECT rcScroll, rcSrc, rcDst;
+   INT Result;
+
+   IntGdiGetClipBox(hDC, &rcScroll);
+   if (prcScroll)
+   {
+      IntGdiIntersectRect(&rcScroll, &rcScroll, prcScroll);
+   }
+   if (prcClip)
+   {
+      IntGdiIntersectRect(&rcScroll, &rcScroll, prcClip);
+   }
+
+   rcDst = rcScroll;
+   IntGdiOffsetRect(&rcDst, dx, dy);
+   IntGdiIntersectRect(&rcDst, &rcDst, &rcScroll);
+   rcSrc = rcDst;
+   IntGdiOffsetRect(&rcSrc, -dx, -dy);
+
+   if (!NtGdiBitBlt(hDC, rcDst.left, rcDst.top,
+                    rcDst.right - rcDst.left, rcDst.bottom - rcDst.top,
+                    hDC, rcSrc.left, rcSrc.top, SRCCOPY, 0, 0))
+   {
+      return ERROR;
+   }
+
+   /* Calculate the region that was invalidated by moving or 
+      could not be copied, because it was not visible */
+   if (hrgnUpdate || prcUpdate)
+   {
+      HRGN hrgnOwn, hrgnVisible, hrgnDst;
+
+      pDC = DC_LockDc(hDC);
+      if (!pDC)
+      {
+         return FALSE;
+      }
+      hrgnVisible = pDC->w.hVisRgn;  // pDC->w.hGCClipRgn?
+      DC_UnlockDc(pDC);
+
+      if (hrgnUpdate)
+      {
+         hrgnOwn = hrgnUpdate;
+         if (!NtGdiSetRectRgn(hrgnOwn, rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom))
+         {
+            return ERROR;
+         }
+      }
+      else
+      {
+         hrgnOwn = UnsafeIntCreateRectRgnIndirect(&rcScroll);
+      }
+
+      hrgnDst = UnsafeIntCreateRectRgnIndirect(&rcSrc);
+      NtGdiCombineRgn(hrgnDst, hrgnDst, hrgnVisible, RGN_AND);
+      NtGdiOffsetRgn(hrgnDst, dx, dy);
+      Result = NtGdiCombineRgn(hrgnOwn, hrgnOwn, hrgnDst, RGN_DIFF);
+      NtGdiDeleteObject(hrgnDst);
+
+      if (prcUpdate)
+      {
+         NtGdiGetRgnBox(hrgnOwn, prcUpdate);
+      }
+
+      if (!hrgnUpdate)
+      {
+         NtGdiDeleteObject(hrgnOwn);
+      }
+   }
    else
-      IntGdiGetClipBox(hDC, &rSrc);
-   IntLPtoDP(DC, (LPPOINT)&rSrc, 2);
-
-   if (lprcClip)
-      rClip = *lprcClip;
-   else
-      IntGdiGetClipBox(hDC, &rClip);
-   IntLPtoDP(DC, (LPPOINT)&rClip, 2);
-
-   IntGdiIntersectRect(&rClipped_src, &rSrc, &rClip);
-
-   rDst = rClipped_src;
-   IntGdiSetRect(&offset, 0, 0, dx, dy);
-   IntLPtoDP(DC, (LPPOINT)&offset, 2);
-   IntGdiOffsetRect(&rDst, offset.right - offset.left,  offset.bottom - offset.top);
-   IntGdiIntersectRect(&rDst, &rDst, &rClip);
-
-   /*
-    * Copy bits, if possible.
-    */
-
-   if (rDst.bottom > rDst.top && rDst.right > rDst.left)
-   {
-      RECT rDst_lp = rDst, rSrc_lp = rDst;
-
-      IntGdiOffsetRect(&rSrc_lp, offset.left - offset.right, offset.top - offset.bottom);
-      IntDPtoLP(DC, (LPPOINT)&rDst_lp, 2);
-      IntDPtoLP(DC, (LPPOINT)&rSrc_lp, 2);
-      DC_UnlockDc(DC);
-
-      if (!NtGdiBitBlt(hDC, rDst_lp.left, rDst_lp.top, rDst_lp.right - rDst_lp.left,
-                       rDst_lp.bottom - rDst_lp.top, hDC, rSrc_lp.left, rSrc_lp.top,
-                       SRCCOPY, 0, 0))
-         return FALSE;
-   }
-   else
-   {
-      DC_UnlockDc(DC);
-   }
-
-   /*
-    * Compute update areas.  This is the clipped source or'ed with the
-    * unclipped source translated minus the clipped src translated (rDst)
-    * all clipped to rClip.
-    */
-
-   if (hrgnUpdate || lprcUpdate)
-   {
-      HRGN hRgn = hrgnUpdate, hRgn2;
-
-      if (hRgn)
-         NtGdiSetRectRgn(hRgn, rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom);
-      else
-         hRgn = NtGdiCreateRectRgn(rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom);
-
-      hRgn2 = UnsafeIntCreateRectRgnIndirect(&rSrc);
-      NtGdiOffsetRgn(hRgn2, offset.right - offset.left,  offset.bottom - offset.top);
-      NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_OR);
-
-      NtGdiSetRectRgn(hRgn2, rDst.left, rDst.top, rDst.right, rDst.bottom);
-      NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_DIFF);
-
-      NtGdiSetRectRgn(hRgn2, rClip.left, rClip.top, rClip.right, rClip.bottom);
-      NtGdiCombineRgn(hRgn, hRgn, hRgn2, RGN_AND);
-
-      if (lprcUpdate)
-      {
-         NtGdiGetRgnBox(hRgn, lprcUpdate);
-
-         /* Put the lprcUpdate in logical coordinate */
-         NtGdiDPtoLP(hDC, (LPPOINT)lprcUpdate, 2);
-      }
-      if (!hrgnUpdate)
-         NtGdiDeleteObject(hRgn);
-      NtGdiDeleteObject(hRgn2);
-   }
-   return TRUE;
+      Result = NULLREGION;
+
+   return Result;
 }
 
 
@@ -1218,21 +1200,78 @@
  */
 
 DWORD STDCALL
-NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll,
-               const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate)
+NtUserScrollDC(HDC hDC, INT dx, INT dy, const RECT *prcUnsafeScroll,
+               const RECT *prcUnsafeClip, HRGN hrgnUpdate, LPRECT prcUnsafeUpdate)
 {
    DECLARE_RETURN(DWORD);
+   RECT rcScroll, rcClip, rcUpdate;
+   NTSTATUS Status = STATUS_SUCCESS;
 
    DPRINT("Enter NtUserScrollDC\n");
    UserEnterExclusive();
 
-   RETURN( UserScrollDC(hDC, dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate));
+   _SEH_TRY
+   {
+      if (prcUnsafeScroll)
+      {
+         ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1);
+         rcScroll = *prcUnsafeScroll;
+      }
+      if (prcUnsafeClip)
+      {
+         ProbeForRead(prcUnsafeClip, sizeof(*prcUnsafeClip), 1);
+         rcClip = *prcUnsafeClip;
+      }
+      if (prcUnsafeUpdate)
+      {
+         ProbeForWrite(prcUnsafeUpdate, sizeof(*prcUnsafeUpdate), 1);
+      }
+   }
+   _SEH_HANDLE
+   {
+      Status = _SEH_GetExceptionCode();
+   }
+   _SEH_END
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      RETURN(FALSE);
+   }
+
+   if (UserScrollDC(hDC, dx, dy, 
+                    prcUnsafeScroll? &rcScroll : 0,
+                    prcUnsafeClip? &rcClip : 0, hrgnUpdate,
+                    prcUnsafeUpdate? &rcUpdate : NULL) == ERROR)
+   {
+      /* FIXME: SetLastError? */
+      RETURN(FALSE);
+   }
+
+   if (prcUnsafeUpdate)
+   {
+      _SEH_TRY
+      {
+         *prcUnsafeUpdate = rcUpdate;
+      }
+      _SEH_HANDLE
+      {
+         Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END
+      if (!NT_SUCCESS(Status))
+      {
+         /* FIXME: SetLastError? */
+         /* FIXME: correct? We have already scrolled! */
+         RETURN(FALSE);
+      }
+   }
+
+   RETURN(TRUE);
 
 CLEANUP:
    DPRINT("Leave NtUserScrollDC, ret=%i\n",_ret_);
    UserLeave();
    END_CLEANUP;
-
 }
 
 /*
@@ -1243,18 +1282,16 @@
  */
 
 DWORD STDCALL
-NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
-                     const RECT *UnsafeClipRect, HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags)
-{
-   RECT rc, cliprc, caretrc, rect, clipRect;
+NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *prcUnsafeScroll,
+                     const RECT *prcUnsafeClip, HRGN hrgnUpdate, LPRECT prcUnsafeUpdate, UINT flags)
+{
+   RECT rcScroll, rcClip, rcCaret, rcUpdate;
    INT Result;
    PWINDOW_OBJECT Window = NULL, CaretWnd;
    HDC hDC;
-   HRGN hrgnTemp;
+   HRGN hrgnOwn = NULL, hrgnTemp;
    HWND hwndCaret;
-   BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
-   BOOL bOwnRgn = TRUE;
-   NTSTATUS Status;
+   NTSTATUS Status = STATUS_SUCCESS;
    DECLARE_RETURN(DWORD);
    USER_REFERENCE_ENTRY Ref, CaretRef;
 
@@ -1269,52 +1306,59 @@
    }
    UserRefObjectCo(Window, &Ref);
 
-   IntGetClientRect(Window, &rc);
-
-   if (NULL != UnsafeRect)
-   {
-      Status = MmCopyFromCaller(&rect, UnsafeRect, sizeof(RECT));
-      if (! NT_SUCCESS(Status))
-      {
-         SetLastNtError(Status);
-         RETURN( ERROR);
-      }
-      IntGdiIntersectRect(&rc, &rc, &rect);
-   }
-
-   if (NULL != UnsafeClipRect)
-   {
-      Status = MmCopyFromCaller(&clipRect, UnsafeClipRect, sizeof(RECT));
-      if (! NT_SUCCESS(Status))
-      {
-         SetLastNtError(Status);
-         RETURN( ERROR);
-      }
-      IntGdiIntersectRect(&cliprc, &rc, &clipRect);
-   }
+   IntGetClientRect(Window, &rcScroll);
+
+   _SEH_TRY
+   {
+      if (prcUnsafeScroll)
+      {
+         ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1);
+         IntGdiIntersectRect(&rcScroll, &rcScroll, prcUnsafeScroll);
+      }
+
+      if (prcUnsafeClip)
+      {
+         ProbeForRead(prcUnsafeClip, sizeof(*prcUnsafeClip), 1);
+         IntGdiIntersectRect(&rcClip, &rcScroll, prcUnsafeClip);
+      }
+      else
+         rcClip = rcScroll;
+   }
+   _SEH_HANDLE
+   {
+      Status = _SEH_GetExceptionCode();
+   }
+   _SEH_END
+
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      RETURN(ERROR);
+   }
+
+   if (rcClip.right <= rcClip.left || rcClip.bottom <= rcClip.top ||
+         (dx == 0 && dy == 0))
+   {
+      RETURN(NULLREGION);
+   }
+
+   if (hrgnUpdate)
+      hrgnOwn = hrgnUpdate;
    else
-      cliprc = rc;
-
-   if (cliprc.right <= cliprc.left || cliprc.bottom <= cliprc.top ||
-         (dx == 0 && dy == 0))
-   {
-      RETURN( NULLREGION);
-   }
-
-   caretrc = rc;
-   hwndCaret = co_IntFixCaret(Window, &caretrc, flags);
-
-   if (hrgnUpdate)
-      bOwnRgn = FALSE;
-   else if (bUpdate)
-      hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0);
+      hrgnOwn = NtGdiCreateRectRgn(0, 0, 0, 0);
 
    hDC = UserGetDCEx(Window, 0, DCX_CACHE | DCX_USESTYLE);
-   if (hDC)
-   {
-      UserScrollDC(hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate);
-      UserReleaseDC(Window, hDC, FALSE);
-   }
+   if (!hDC)
+   {
+      /* FIXME: SetLastError? */
+      RETURN(ERROR);
+   }
+
+   rcCaret = rcScroll;
+   hwndCaret = co_IntFixCaret(Window, &rcCaret, flags);
+
+   Result = UserScrollDC(hDC, dx, dy, &rcScroll, &rcClip, hrgnOwn, prcUnsafeUpdate? &rcUpdate : NULL);
+   UserReleaseDC(Window, hDC, FALSE);
 
    /*
     * Take into account the fact that some damage may have occurred during
@@ -1322,76 +1366,90 @@
     */
 
    hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
-   Result = co_UserGetUpdateRgn(Window, hrgnTemp, FALSE);
-   if (Result != NULLREGION)
-   {
-      HRGN hrgnClip = UnsafeIntCreateRectRgnIndirect(&cliprc);
+   if (co_UserGetUpdateRgn(Window, hrgnTemp, FALSE) != NULLREGION)
+   {
+      HRGN hrgnClip = UnsafeIntCreateRectRgnIndirect(&rcClip);
       NtGdiOffsetRgn(hrgnTemp, dx, dy);
       NtGdiCombineRgn(hrgnTemp, hrgnTemp, hrgnClip, RGN_AND);
       co_UserRedrawWindow(Window, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE);
       NtGdiDeleteObject(hrgnClip);
    }
-
    NtGdiDeleteObject(hrgnTemp);
 
    if (flags & SW_SCROLLCHILDREN)
    {
-      HWND *List = IntWinListChildren(Window);
-      if (List)
-      {
-         int i;
-         RECT r, dummy;
-         POINT ClientOrigin;
-         PWINDOW_OBJECT Wnd;
-         USER_REFERENCE_ENTRY WndRef;
-
-         IntGetClientOrigin(Window, &ClientOrigin);
-         for (i = 0; List[i]; i++)
+      PWINDOW_OBJECT Child;
+      RECT rcChild;
+      POINT ClientOrigin;
+      USER_REFERENCE_ENTRY WndRef;
+      RECT rcDummy;
+
+      IntGetClientOrigin(Window, &ClientOrigin);
+      for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
+      {
+         rcChild = Child->WindowRect;
+         rcChild.left -= ClientOrigin.x;
+         rcChild.top -= ClientOrigin.y;
+         rcChild.right -= ClientOrigin.x;
+         rcChild.bottom -= ClientOrigin.y;
+
+         if (! prcUnsafeScroll || IntGdiIntersectRect(&rcDummy, &rcChild, &rcScroll))
          {
-            if (!(Wnd = UserGetWindowObject(List[i])))
-               continue;
-
-            r = Wnd->WindowRect;
-            r.left -= ClientOrigin.x;
-            r.top -= ClientOrigin.y;
-            r.right -= ClientOrigin.x;
-            r.bottom -= ClientOrigin.y;
-
-            if (! UnsafeRect || IntGdiIntersectRect(&dummy, &r, &rc))
-            {
-               UserRefObjectCo(Wnd, &WndRef);
-               co_WinPosSetWindowPos(Wnd, 0, r.left + dx, r.top + dy, 0, 0,
-                                     SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
-                                     SWP_NOREDRAW);
-               UserDerefObjectCo(Wnd);
-            }
-
+            UserRefObjectCo(Child, &WndRef);
+            co_WinPosSetWindowPos(Child, 0, rcChild.left + dx, rcChild.top + dy, 0, 0,
+                                  SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
+                                  SWP_NOREDRAW);
+            UserDerefObjectCo(Child);
          }
-         ExFreePool(List);
       }
    }
 
    if (flags & (SW_INVALIDATE | SW_ERASE))
-      co_UserRedrawWindow(Window, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
+   {
+      co_UserRedrawWindow(Window, NULL, hrgnOwn, RDW_INVALIDATE | RDW_ERASE |
                           ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
                           ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0));
-
-   if (bOwnRgn && hrgnUpdate)
-      NtGdiDeleteObject(hrgnUpdate);
+   }
 
    if ((CaretWnd = UserGetWindowObject(hwndCaret)))
    {
       UserRefObjectCo(CaretWnd, &CaretRef);
 
-      co_IntSetCaretPos(caretrc.left + dx, caretrc.top + dy);
+      co_IntSetCaretPos(rcCaret.left + dx, rcCaret.top + dy);
       co_UserShowCaret(CaretWnd);
 
       UserDerefObjectCo(CaretWnd);
    }
 
+   if (prcUnsafeUpdate)
+   {
+      _SEH_TRY
+      {
+         /* Probe here, to not fail on invalid pointer before scrolling */
+         ProbeForWrite(prcUnsafeUpdate, sizeof(*prcUnsafeUpdate), 1);
+         *prcUnsafeUpdate = rcUpdate;
+      }
+      _SEH_HANDLE
+      {
+         Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END
+
+      if (!NT_SUCCESS(Status))
+      {
+         SetLastNtError(Status);
+         RETURN(ERROR);
+      }
+   }
+
    RETURN(Result);
 
 CLEANUP:
+   if (hrgnOwn && !hrgnUpdate)
+   {
+      NtGdiDeleteObject(hrgnOwn);
+   }
+
    if (Window)
       UserDerefObjectCo(Window);
 




More information about the Ros-diffs mailing list