From e4aff981658a2f3bb2d9374cfebddd9daf78dfaf Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Wed, 25 Jul 2007 21:51:56 +0000 Subject: [PATCH] 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. svn path=/trunk/; revision=27815 --- .../subsystems/win32/win32k/ntuser/painting.c | 378 ++++++++++-------- 1 file changed, 218 insertions(+), 160 deletions(-) diff --git a/reactos/subsystems/win32/win32k/ntuser/painting.c b/reactos/subsystems/win32/win32k/ntuser/painting.c index eafc46ac56c..6185bafdd15 100644 --- a/reactos/subsystems/win32/win32k/ntuser/painting.c +++ b/reactos/subsystems/win32/win32k/ntuser/painting.c @@ -1109,102 +1109,84 @@ CLEANUP: static -DWORD FASTCALL -UserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll, - const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate) +INT FASTCALL +UserScrollDC(HDC hDC, INT dx, INT dy, const RECT *prcScroll, + const RECT *prcClip, HRGN hrgnUpdate, LPRECT prcUpdate) { - RECT rSrc, rClipped_src, rClip, rDst, offset; - PDC DC; + PDC pDC; + RECT rcScroll, rcSrc, rcDst; + INT Result; - /* - * Compute device clipping region (in device coordinates). - */ - - DC = DC_LockDc(hDC); - if (NULL == DC) + IntGdiGetClipBox(hDC, &rcScroll); + if (prcScroll) { - return FALSE; + IntGdiIntersectRect(&rcScroll, &rcScroll, prcScroll); } - if (lprcScroll) - rSrc = *lprcScroll; - 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) + if (prcClip) { - 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); + IntGdiIntersectRect(&rcScroll, &rcScroll, prcClip); } - /* - * 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. - */ + rcDst = rcScroll; + IntGdiOffsetRect(&rcDst, dx, dy); + IntGdiIntersectRect(&rcDst, &rcDst, &rcScroll); + rcSrc = rcDst; + IntGdiOffsetRect(&rcSrc, -dx, -dy); - if (hrgnUpdate || lprcUpdate) + if (!NtGdiBitBlt(hDC, rcDst.left, rcDst.top, + rcDst.right - rcDst.left, rcDst.bottom - rcDst.top, + hDC, rcSrc.left, rcSrc.top, SRCCOPY, 0, 0)) { - HRGN hRgn = hrgnUpdate, hRgn2; + return ERROR; + } - 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); + /* 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; - 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) + pDC = DC_LockDc(hDC); + if (!pDC) { - NtGdiGetRgnBox(hRgn, lprcUpdate); - - /* Put the lprcUpdate in logical coordinate */ - NtGdiDPtoLP(hDC, (LPPOINT)lprcUpdate, 2); + 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(hRgn); - NtGdiDeleteObject(hRgn2); + { + NtGdiDeleteObject(hrgnOwn); + } } - return TRUE; + else + Result = NULLREGION; + + return Result; } @@ -1218,21 +1200,78 @@ UserScrollDC(HDC hDC, INT dx, INT dy, const RECT *lprcScroll, */ 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 @@ CLEANUP: */ DWORD STDCALL -NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect, - const RECT *UnsafeClipRect, HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags) +NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *prcUnsafeScroll, + const RECT *prcUnsafeClip, HRGN hrgnUpdate, LPRECT prcUnsafeUpdate, UINT flags) { - RECT rc, cliprc, caretrc, rect, clipRect; + 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,129 +1306,150 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect, } UserRefObjectCo(Window, &Ref); - IntGetClientRect(Window, &rc); + IntGetClientRect(Window, &rcScroll); - if (NULL != UnsafeRect) + _SEH_TRY { - Status = MmCopyFromCaller(&rect, UnsafeRect, sizeof(RECT)); - if (! NT_SUCCESS(Status)) + if (prcUnsafeScroll) { - SetLastNtError(Status); - RETURN( ERROR); + ProbeForRead(prcUnsafeScroll, sizeof(*prcUnsafeScroll), 1); + IntGdiIntersectRect(&rcScroll, &rcScroll, prcUnsafeScroll); } - IntGdiIntersectRect(&rc, &rc, &rect); + + 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 (NULL != UnsafeClipRect) - { - Status = MmCopyFromCaller(&clipRect, UnsafeClipRect, sizeof(RECT)); - if (! NT_SUCCESS(Status)) - { - SetLastNtError(Status); - RETURN( ERROR); - } - IntGdiIntersectRect(&cliprc, &rc, &clipRect); - } - else - cliprc = rc; - - if (cliprc.right <= cliprc.left || cliprc.bottom <= cliprc.top || + if (rcClip.right <= rcClip.left || rcClip.bottom <= rcClip.top || (dx == 0 && dy == 0)) { - RETURN( NULLREGION); + RETURN(NULLREGION); } - caretrc = rc; - hwndCaret = co_IntFixCaret(Window, &caretrc, flags); - if (hrgnUpdate) - bOwnRgn = FALSE; - else if (bUpdate) - hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0); + hrgnOwn = hrgnUpdate; + else + hrgnOwn = NtGdiCreateRectRgn(0, 0, 0, 0); hDC = UserGetDCEx(Window, 0, DCX_CACHE | DCX_USESTYLE); - if (hDC) + if (!hDC) { - UserScrollDC(hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate); - UserReleaseDC(Window, hDC, FALSE); + /* 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 * the scroll. */ hrgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0); - Result = co_UserGetUpdateRgn(Window, hrgnTemp, FALSE); - if (Result != NULLREGION) + if (co_UserGetUpdateRgn(Window, hrgnTemp, FALSE) != NULLREGION) { - HRGN hrgnClip = UnsafeIntCreateRectRgnIndirect(&cliprc); + 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) + PWINDOW_OBJECT Child; + RECT rcChild; + POINT ClientOrigin; + USER_REFERENCE_ENTRY WndRef; + RECT rcDummy; + + IntGetClientOrigin(Window, &ClientOrigin); + for (Child = Window->FirstChild; Child; Child = Child->NextSibling) { - int i; - RECT r, dummy; - POINT ClientOrigin; - PWINDOW_OBJECT Wnd; - USER_REFERENCE_ENTRY WndRef; + rcChild = Child->WindowRect; + rcChild.left -= ClientOrigin.x; + rcChild.top -= ClientOrigin.y; + rcChild.right -= ClientOrigin.x; + rcChild.bottom -= ClientOrigin.y; - IntGetClientOrigin(Window, &ClientOrigin); - for (i = 0; List[i]; i++) + 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);