diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-27 00:18:19 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-27 00:18:19 +0000 |
commit | 08c761bbfc715127e0102e5c7e25321cdaecc572 (patch) | |
tree | 01503d7b2f7f30b61bddbce05e5f531582c6496a /views | |
parent | f9b522727619a692447c4575e03e17dab3550ae2 (diff) | |
download | chromium_src-08c761bbfc715127e0102e5c7e25321cdaecc572.zip chromium_src-08c761bbfc715127e0102e5c7e25321cdaecc572.tar.gz chromium_src-08c761bbfc715127e0102e5c7e25321cdaecc572.tar.bz2 |
Fix various layered window updating bugs.
As it turns out, you can NOT rely on Windows to track the invalid rect for layered windows. This is likely because Windows doesn't believe them to have an invalid rect - it is up to the app to handle updating them.
So, sadly, this means adding an invalid_rect_ field to WidgetWin and using it to track the invalid rect instead of InvalidateRect() - but only for WS_EX_LAYERED.
I also split the layered window updating code out of RedrawInvalidRect for readability.
http://crbug.com/74300
http://crbug.com/74301
TEST=see bugs
TBR=sky
Review URL: http://codereview.chromium.org/6591027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@76172 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/widget/widget_win.cc | 75 | ||||
-rw-r--r-- | views/widget/widget_win.h | 11 |
2 files changed, 52 insertions, 34 deletions
diff --git a/views/widget/widget_win.cc b/views/widget/widget_win.cc index d1447de..8cde70f 100644 --- a/views/widget/widget_win.cc +++ b/views/widget/widget_win.cc @@ -527,9 +527,15 @@ View* WidgetWin::GetDraggedView() { } void WidgetWin::SchedulePaintInRect(const gfx::Rect& rect) { - // InvalidateRect() expects client coordinates. - RECT r = rect.ToRECT(); - InvalidateRect(hwnd(), &r, FALSE); + if (use_layered_buffer_) { + // We must update the back-buffer immediately, since Windows' handling of + // invalid rects is somewhat mysterious. + layered_window_invalid_rect_ = layered_window_invalid_rect_.Union(rect); + } else { + // InvalidateRect() expects client coordinates. + RECT r = rect.ToRECT(); + InvalidateRect(hwnd(), &r, FALSE); + } } void WidgetWin::SetCursor(gfx::NativeCursor cursor) { @@ -997,12 +1003,6 @@ void WidgetWin::OnWindowPosChanging(WINDOWPOS* window_pos) { } void WidgetWin::OnWindowPosChanged(WINDOWPOS* window_pos) { - // Layered windows need to be explicitly invalidated, but any calls to - // SchedulePaint() prior to the window being shown are ignored by Windows, so - // we must manually invalidate the widget when it is shown. Non-layered - // windows are automatically invalidated by Windows when they are shown. - if (use_layered_buffer_ && window_pos->flags & SWP_SHOWWINDOW) - InvalidateRect(hwnd(), NULL, FALSE); SetMsgHandled(FALSE); } @@ -1175,9 +1175,9 @@ Window* WidgetWin::GetWindowImpl(HWND hwnd) { } void WidgetWin::SizeContents(const gfx::Size& window_size) { - contents_.reset(new gfx::CanvasSkia(window_size.width(), - window_size.height(), - false)); + layered_window_contents_.reset(new gfx::CanvasSkia(window_size.width(), + window_size.height(), + false)); } RootView* WidgetWin::GetFocusedViewRootView() { @@ -1234,33 +1234,42 @@ void WidgetWin::MakeMSG(MSG* msg, UINT message, WPARAM w_param, LPARAM l_param, } void WidgetWin::RedrawInvalidRect() { - RECT r = { 0, 0, 0, 0 }; - if (GetUpdateRect(hwnd(), &r, FALSE) && !IsRectEmpty(&r)) { - if (use_layered_buffer_) { - // We need to clip to the dirty rect ourselves. - contents_->save(SkCanvas::kClip_SaveFlag); - contents_->ClipRectInt(r.left, r.top, r.right - r.left, - r.bottom - r.top); - GetRootView()->Paint(contents_.get()); - contents_->restore(); - - RECT wr; - GetWindowRect(&wr); - SIZE size = {wr.right - wr.left, wr.bottom - wr.top}; - POINT position = {wr.left, wr.top}; - HDC dib_dc = contents_->getTopPlatformDevice().getBitmapDC(); - POINT zero = {0, 0}; - BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA}; - UpdateLayeredWindow(hwnd(), NULL, &position, &size, dib_dc, &zero, - RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); - ValidateRect(hwnd(), &r); - } else { + if (use_layered_buffer_) { + RedrawLayeredWindowContents(); + } else { + RECT r = { 0, 0, 0, 0 }; + if (GetUpdateRect(hwnd(), &r, FALSE) && !IsRectEmpty(&r)) { RedrawWindow(hwnd(), &r, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN); } } } +void WidgetWin::RedrawLayeredWindowContents() { + if (layered_window_invalid_rect_.IsEmpty()) + return; + + // We need to clip to the dirty rect ourselves. + layered_window_contents_->save(SkCanvas::kClip_SaveFlag); + layered_window_contents_->ClipRectInt(layered_window_invalid_rect_.x(), + layered_window_invalid_rect_.y(), + layered_window_invalid_rect_.width(), + layered_window_invalid_rect_.height()); + GetRootView()->Paint(layered_window_contents_.get()); + layered_window_contents_->restore(); + + RECT wr; + GetWindowRect(&wr); + SIZE size = {wr.right - wr.left, wr.bottom - wr.top}; + POINT position = {wr.left, wr.top}; + HDC dib_dc = layered_window_contents_->getTopPlatformDevice().getBitmapDC(); + POINT zero = {0, 0}; + BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA}; + UpdateLayeredWindow(hwnd(), NULL, &position, &size, dib_dc, &zero, + RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); + layered_window_invalid_rect_.SetRect(0, 0, 0, 0); +} + //////////////////////////////////////////////////////////////////////////////// // Widget, public: diff --git a/views/widget/widget_win.h b/views/widget/widget_win.h index 820c4a7..6130ad1 100644 --- a/views/widget/widget_win.h +++ b/views/widget/widget_win.h @@ -502,6 +502,10 @@ class WidgetWin : public ui::WindowImpl, // Synchronously paints the invalid contents of the Widget. void RedrawInvalidRect(); + // Synchronously updates the invalid contents of the Widget. Valid for + // layered windows only. + void RedrawLayeredWindowContents(); + // A delegate implementation that handles events received here. internal::NativeWidgetDelegate* delegate_; @@ -531,7 +535,12 @@ class WidgetWin : public ui::WindowImpl, // A canvas that contains the window contents in the case of a layered // window. - scoped_ptr<gfx::CanvasSkia> contents_; + scoped_ptr<gfx::CanvasSkia> layered_window_contents_; + + // We must track the invalid rect for a layered window ourselves, since + // Windows will not do this properly with InvalidateRect()/GetUpdateRect(). + // (In fact, it'll return misleading information from GetUpdateRect()). + gfx::Rect layered_window_invalid_rect_; // Whether or not the window should delete itself when it is destroyed. // Set this to false via its setter for stack allocated instances. |