ScrollDC and X11DRV_SCROLLDC should scroll only pixels coming from

within the visible region, clipped to the clipping region if that
exists. Add the destination of pixels coming from the outside of this
region to the update region. With tests that depend on this.
This commit is contained in:
Rein Klazes 2005-03-25 17:11:04 +00:00 committed by Alexandre Julliard
parent 2fb7c8754a
commit a807c5efce
4 changed files with 182 additions and 145 deletions

View File

@ -3348,7 +3348,7 @@ static void test_button_messages(void)
/************* painting message test ********************/ /************* painting message test ********************/
static void dump_region(HRGN hrgn) void dump_region(HRGN hrgn)
{ {
DWORD i, size; DWORD i, size;
RGNDATA *data = NULL; RGNDATA *data = NULL;

View File

@ -45,6 +45,8 @@
#define LONG_PTR INT_PTR #define LONG_PTR INT_PTR
#define ULONG_PTR UINT_PTR #define ULONG_PTR UINT_PTR
void dump_region(HRGN hrgn);
static HWND (WINAPI *pGetAncestor)(HWND,UINT); static HWND (WINAPI *pGetAncestor)(HWND,UINT);
static BOOL (WINAPI *pGetWindowInfo)(HWND,WINDOWINFO*); static BOOL (WINAPI *pGetWindowInfo)(HWND,WINDOWINFO*);
@ -2581,6 +2583,62 @@ static void test_window_styles()
check_window_style(0, WS_EX_APPWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_APPWINDOW|WS_EX_WINDOWEDGE); check_window_style(0, WS_EX_APPWINDOW, WS_CLIPSIBLINGS|WS_CAPTION, WS_EX_APPWINDOW|WS_EX_WINDOWEDGE);
} }
void test_scrollvalidate( HWND parent)
{
HDC hdc;
HRGN hrgn=CreateRectRgn(0,0,0,0);
HRGN exprgn, tmprgn, clipping;
RECT rc, rcu, cliprc;
/* create two overlapping child windows. The visual region
* of hwnd1 is clipped by the overlapping part of
* hwnd2 because of the WS_CLIPSIBLING style */
HWND hwnd2 = CreateWindowExA(0, "static", NULL,
WS_CHILD| WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER ,
75, 30, 100, 100, parent, 0, 0, NULL);
HWND hwnd1 = CreateWindowExA(0, "static", NULL,
WS_CHILD| WS_VISIBLE | WS_CLIPSIBLINGS | WS_BORDER ,
25, 50, 100, 100, parent, 0, 0, NULL);
ShowWindow( parent, SW_SHOW);
UpdateWindow( parent);
GetClientRect( hwnd1, &rc);
cliprc=rc;
clipping = CreateRectRgn( 10, 10, 90, 90);
hdc = GetDC( hwnd1);
/* for a visual touch */
TextOut( hdc, 0,10, "0123456789", 10);
ScrollDC( hdc, -10, -5, &rc, &cliprc, hrgn, &rcu);
if (winetest_debug > 0) dump_region(hrgn);
/* create a region with what is expected */
exprgn = CreateRectRgn( 39,0,49,74);
tmprgn = CreateRectRgn( 88,79,98,93);
CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
tmprgn = CreateRectRgn( 0,93,98,98);
CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
ok( EqualRgn( exprgn, hrgn), "wrong update region\n");
trace("update rect is %ld,%ld - %ld,%ld\n",
rcu.left,rcu.top,rcu.right,rcu.bottom);
/* now with clipping region */
SelectClipRgn( hdc, clipping);
ScrollDC( hdc, -10, -5, &rc, &cliprc, hrgn, &rcu);
if (winetest_debug > 0) dump_region(hrgn);
/* create a region with what is expected */
exprgn = CreateRectRgn( 39,10,49,74);
tmprgn = CreateRectRgn( 80,79,90,85);
CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
tmprgn = CreateRectRgn( 10,85,90,90);
CombineRgn( exprgn, exprgn, tmprgn, RGN_OR);
ok( EqualRgn( exprgn, hrgn), "wrong update region\n");
trace("update rect is %ld,%ld - %ld,%ld\n",
rcu.left,rcu.top,rcu.right,rcu.bottom);
ReleaseDC( hwnd1, hdc);
/* clean up */
DeleteObject( hrgn);
DeleteObject( exprgn);
DeleteObject( tmprgn);
DestroyWindow( hwnd1);
DestroyWindow( hwnd2);
}
START_TEST(win) START_TEST(win)
{ {
pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" ); pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
@ -2639,6 +2697,7 @@ START_TEST(win)
test_mouse_input(hwndMain); test_mouse_input(hwndMain);
test_validatergn(hwndMain); test_validatergn(hwndMain);
test_nccalcscroll( hwndMain); test_nccalcscroll( hwndMain);
test_scrollvalidate( hwndMain);
UnhookWindowsHookEx(hhook); UnhookWindowsHookEx(hhook);

View File

@ -35,96 +35,147 @@
WINE_DEFAULT_DEBUG_CHANNEL(scroll); WINE_DEFAULT_DEBUG_CHANNEL(scroll);
static void dump_region( char *p, HRGN hrgn)
{
DWORD i, size;
RGNDATA *data = NULL;
RECT *rect;
if (!hrgn) {
TRACE( "%s null region\n", p );
return;
}
if (!(size = GetRegionData( hrgn, 0, NULL ))) {
return;
}
if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
GetRegionData( hrgn, size, data );
TRACE("%s %ld rects:", p, data->rdh.nCount );
for (i = 0, rect = (RECT *)data->Buffer; i<20 && i < data->rdh.nCount; i++, rect++)
TRACE( " %s", wine_dbgstr_rect( rect));
TRACE("\n");
HeapFree( GetProcessHeap(), 0, data );
}
/************************************************************************* /*************************************************************************
* ScrollDC (X11DRV.@) * ScrollDC (X11DRV.@)
*/ */
BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll, BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll,
const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate ) const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate )
{ {
RECT rSrc, rClipped_src, rClip, rDst, offset; RECT rcSrc, rcClip, offset;
INT dxdev, dydev, res;
HRGN DstRgn, clipRgn, visrgn;
INT code = X11DRV_START_EXPOSURES; INT code = X11DRV_START_EXPOSURES;
TRACE("dx,dy %d,%d lprcScroll %p lprcClip %p hrgnUpdate %p lprcUpdate %p\n",
dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate);
/* enable X-exposure events */
if (hrgnUpdate || lprcUpdate) if (hrgnUpdate || lprcUpdate)
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL ); ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
/* get the visible region */
/* compute device clipping region (in device coordinates) */ visrgn=CreateRectRgn( 0, 0, 0, 0);
GetRandomRgn( hdc, visrgn, SYSRGN);
if (lprcScroll) rSrc = *lprcScroll; if( !(GetVersion() & 0x80000000)) {
else GetClipBox( hdc, &rSrc ); /* Window NT/2k/XP */
LPtoDP(hdc, (LPPOINT)&rSrc, 2); POINT org;
GetDCOrgEx(hdc, &org);
if (lprcClip) rClip = *lprcClip; OffsetRgn( visrgn, -org.x, -org.y);
else GetClipBox( hdc, &rClip ); }
LPtoDP(hdc, (LPPOINT)&rClip, 2); /* intersect with the clipping Region if the DC has one */
clipRgn = CreateRectRgn( 0, 0, 0, 0);
IntersectRect( &rClipped_src, &rSrc, &rClip ); if (GetClipRgn( hdc, clipRgn) != 1) {
TRACE("rSrc %s rClip %s clipped rSrc %s\n", wine_dbgstr_rect(&rSrc), DeleteObject(clipRgn);
wine_dbgstr_rect(&rClip), wine_dbgstr_rect(&rClipped_src)); clipRgn=NULL;
} else
rDst = rClipped_src; CombineRgn( visrgn, visrgn, clipRgn, RGN_AND);
/* only those pixels in the scroll rectangle that remain in the clipping
* rect are scrolled. So first combine Scroll and Clipping rectangles,
* if available */
if( lprcScroll)
if( lprcClip)
IntersectRect( &rcClip, lprcClip, lprcScroll);
else
rcClip = *lprcScroll;
else
if( lprcClip)
rcClip = *lprcClip;
else
GetClipBox( hdc, &rcClip);
/* Then clip again to get the source rectangle that will remain in the
* clipping rect */
rcSrc = rcClip;
OffsetRect( &rcSrc, -dx, -dy);
IntersectRect( &rcSrc, &rcSrc, &rcClip);
/* now convert to device coordinates */
LPtoDP(hdc, (LPPOINT)&rcSrc, 2);
/* also dx and dy */
SetRect(&offset, 0, 0, dx, dy); SetRect(&offset, 0, 0, dx, dy);
LPtoDP(hdc, (LPPOINT)&offset, 2); LPtoDP(hdc, (LPPOINT)&offset, 2);
OffsetRect( &rDst, offset.right - offset.left, offset.bottom - offset.top ); dxdev = offset.right - offset.left;
TRACE("rDst before clipping %s\n", wine_dbgstr_rect(&rDst)); dydev= offset.bottom - offset.top;
IntersectRect( &rDst, &rDst, &rClip ); /* now intersect with the visible region to get the pixels that will
TRACE("rDst after clipping %s\n", wine_dbgstr_rect(&rDst)); * actually scroll */
DstRgn = CreateRectRgnIndirect( &rcSrc);
if (!IsRectEmpty(&rDst)) res = CombineRgn( DstRgn, DstRgn, visrgn, RGN_AND);
{ /* and translate, giving the destination region */
/* copy bits */ OffsetRgn( DstRgn, dxdev, dydev);
RECT rDst_lp = rDst, rSrc_lp = rDst; if( TRACE_ON( scroll)) dump_region( "Destination scroll region: ", DstRgn);
/* if there are any, do it */
OffsetRect( &rSrc_lp, offset.left - offset.right, offset.top - offset.bottom ); if( res > NULLREGION) {
DPtoLP(hdc, (LPPOINT)&rDst_lp, 2); RECT rect ;
DPtoLP(hdc, (LPPOINT)&rSrc_lp, 2); /* clip to the destination region, so we can BitBlt with a simple
* bounding rectangle */
if (!BitBlt( hdc, rDst_lp.left, rDst_lp.top, if( clipRgn)
rDst_lp.right - rDst_lp.left, rDst_lp.bottom - rDst_lp.top, ExtSelectClipRgn( hdc, DstRgn, RGN_AND);
hdc, rSrc_lp.left, rSrc_lp.top, SRCCOPY)) else
return FALSE; SelectClipRgn( hdc, DstRgn);
GetRgnBox( DstRgn, &rect);
DPtoLP(hdc, (LPPOINT)&rect, 2);
BitBlt( hdc, rect.left, rect.top,
rect.right - rect.left, rect.bottom -rect.top,
hdc, rect.left - dx, rect.top - dy, SRCCOPY);
} }
/* compute the update areas. This is the combined clip rectangle
/* compute update areas. This is the clipped source or'ed with the unclipped source translated minus the * minus the scrolled region, and intersected with the visible
clipped src translated (rDst) all clipped to rClip */ * region. */
if (hrgnUpdate || lprcUpdate) if (hrgnUpdate || lprcUpdate)
{ {
HRGN hrgn = hrgnUpdate, hrgn2, hrgn3 = 0; HRGN hrgn = hrgnUpdate;
HRGN ExpRgn = 0;
/* collect all the exposures */
code = X11DRV_END_EXPOSURES; code = X11DRV_END_EXPOSURES;
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(hrgn3), (LPSTR)&hrgn3 ); ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code,
sizeof(ExpRgn), (LPSTR)&ExpRgn );
if (hrgn) SetRectRgn( hrgn, rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom ); /* Covert the combined clip rectangle to device coordinates */
else hrgn = CreateRectRgn( rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom ); LPtoDP(hdc, (LPPOINT)&rcClip, 2);
if( hrgn )
hrgn2 = CreateRectRgnIndirect( &rSrc ); SetRectRgn( hrgn, rcClip.left, rcClip.top, rcClip.right,
OffsetRgn(hrgn2, offset.right - offset.left, offset.bottom - offset.top ); rcClip.bottom);
CombineRgn(hrgn, hrgn, hrgn2, RGN_OR); else
hrgn = CreateRectRgnIndirect( &rcClip);
SetRectRgn( hrgn2, rDst.left, rDst.top, rDst.right, rDst.bottom ); CombineRgn( hrgn, hrgn, visrgn, RGN_AND);
CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF ); CombineRgn( hrgn, hrgn, DstRgn, RGN_DIFF);
/* add the exposures to this */
SetRectRgn( hrgn2, rClip.left, rClip.top, rClip.right, rClip.bottom ); if( ExpRgn) {
CombineRgn( hrgn, hrgn, hrgn2, RGN_AND ); if( TRACE_ON( scroll)) dump_region( "Expose region: ", ExpRgn);
CombineRgn( hrgn, hrgn, ExpRgn, RGN_OR);
if (hrgn3) DeleteObject( ExpRgn);
{
CombineRgn( hrgn, hrgn, hrgn3, RGN_OR );
DeleteObject( hrgn3 );
} }
if( TRACE_ON( scroll)) dump_region( "Update region: ", hrgn);
if( lprcUpdate ) if( lprcUpdate) {
{
GetRgnBox( hrgn, lprcUpdate ); GetRgnBox( hrgn, lprcUpdate );
/* Put the lprcUpdate in logical coordinates */
/* Put the lprcUpdate in logical coordinate */
DPtoLP( hdc, (LPPOINT)lprcUpdate, 2 ); DPtoLP( hdc, (LPPOINT)lprcUpdate, 2 );
TRACE("returning lprcUpdate %s\n", wine_dbgstr_rect(lprcUpdate)); TRACE("returning lprcUpdate %s\n", wine_dbgstr_rect(lprcUpdate));
} }
if (!hrgnUpdate) DeleteObject( hrgn ); if( !hrgnUpdate)
DeleteObject( hrgn2 ); DeleteObject( hrgn);
} }
SelectClipRgn( hdc, clipRgn);
DeleteObject( visrgn);
DeleteObject( DstRgn);
if( clipRgn) DeleteObject( clipRgn);
return TRUE; return TRUE;
} }

View File

@ -188,88 +188,15 @@ BOOL WINAPI ScrollWindow( HWND hwnd, INT dx, INT dy,
/************************************************************************* /*************************************************************************
* ScrollDC (USER32.@) * ScrollDC (USER32.@)
* *
* dx, dy, lprcScroll and lprcClip are all in logical coordinates (msdn is wrong) * dx, dy, lprcScroll and lprcClip are all in logical coordinates (msdn is
* hrgnUpdate is returned in device coordinates with rcUpdate in logical coordinates. * wrong) hrgnUpdate is returned in device coordinates with rcUpdate in
* logical coordinates.
*/ */
BOOL WINAPI ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll, BOOL WINAPI ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll,
const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate ) const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate )
{ {
RECT rSrc, rClipped_src, rClip, rDst, offset;
TRACE( "%p %d,%d hrgnUpdate=%p lprcUpdate = %p\n", hdc, dx, dy, hrgnUpdate, lprcUpdate );
if (lprcClip) TRACE( "lprcClip = %s\n", wine_dbgstr_rect(lprcClip));
if (lprcScroll) TRACE( "lprcScroll = %s\n", wine_dbgstr_rect(lprcScroll));
if (USER_Driver.pScrollDC) if (USER_Driver.pScrollDC)
return USER_Driver.pScrollDC( hdc, dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate ); return USER_Driver.pScrollDC( hdc, dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate );
return FALSE;
/* compute device clipping region (in device coordinates) */
if (lprcScroll) rSrc = *lprcScroll;
else GetClipBox( hdc, &rSrc );
LPtoDP(hdc, (LPPOINT)&rSrc, 2);
if (lprcClip) rClip = *lprcClip;
else GetClipBox( hdc, &rClip );
LPtoDP(hdc, (LPPOINT)&rClip, 2);
IntersectRect( &rClipped_src, &rSrc, &rClip );
TRACE("rSrc %s rClip %s clipped rSrc %s\n", wine_dbgstr_rect(&rSrc),
wine_dbgstr_rect(&rClip), wine_dbgstr_rect(&rClipped_src));
rDst = rClipped_src;
SetRect(&offset, 0, 0, dx, dy);
LPtoDP(hdc, (LPPOINT)&offset, 2);
OffsetRect( &rDst, offset.right - offset.left, offset.bottom - offset.top );
TRACE("rDst before clipping %s\n", wine_dbgstr_rect(&rDst));
IntersectRect( &rDst, &rDst, &rClip );
TRACE("rDst after clipping %s\n", wine_dbgstr_rect(&rDst));
if (!IsRectEmpty(&rDst))
{
/* copy bits */
RECT rDst_lp = rDst, rSrc_lp = rDst;
OffsetRect( &rSrc_lp, offset.left - offset.right, offset.top - offset.bottom );
DPtoLP(hdc, (LPPOINT)&rDst_lp, 2);
DPtoLP(hdc, (LPPOINT)&rSrc_lp, 2);
if (!BitBlt( 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))
return FALSE;
}
/* 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) SetRectRgn( hrgn, rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom );
else hrgn = CreateRectRgn( rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom );
hrgn2 = CreateRectRgnIndirect( &rSrc );
OffsetRgn(hrgn2, offset.right - offset.left, offset.bottom - offset.top );
CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
SetRectRgn( hrgn2, rDst.left, rDst.top, rDst.right, rDst.bottom );
CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
SetRectRgn( hrgn2, rClip.left, rClip.top, rClip.right, rClip.bottom );
CombineRgn( hrgn, hrgn, hrgn2, RGN_AND );
if( lprcUpdate )
{
GetRgnBox( hrgn, lprcUpdate );
/* Put the lprcUpdate in logical coordinate */
DPtoLP( hdc, (LPPOINT)lprcUpdate, 2 );
TRACE("returning lprcUpdate %s\n", wine_dbgstr_rect(lprcUpdate));
}
if (!hrgnUpdate) DeleteObject( hrgn );
DeleteObject( hrgn2 );
}
return TRUE;
} }