Chromium Code Reviews| Index: content/browser/renderer_host/legacy_render_widget_host_win.cc |
| diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc |
| index 5126ad2bc2da97d1c829ad9f6913ecaeb5de0424..1b814bbd908f94ad3a5b994f1c17eef6f564513a 100644 |
| --- a/content/browser/renderer_host/legacy_render_widget_host_win.cc |
| +++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc |
| @@ -4,8 +4,11 @@ |
| #include "content/browser/renderer_host/legacy_render_widget_host_win.h" |
| +#include <directmanipulation.h> |
| + |
| #include "base/command_line.h" |
| #include "base/memory/scoped_ptr.h" |
| +#include "base/win/scoped_comptr.h" |
| #include "base/win/windows_version.h" |
| #include "content/browser/accessibility/browser_accessibility_manager_win.h" |
| #include "content/browser/accessibility/browser_accessibility_win.h" |
| @@ -22,6 +25,128 @@ |
| namespace content { |
| +// Windows 10 provides a new API called Direct Manipulation which generates |
| +// smooth scroll events via WM_MOUSEWHEEL messages with predictable deltas |
| +// on high precision touch pads. This basically requires the application window |
| +// to register as a Direct Manipulation consumer. The way mouse wheel messages |
| +// are dispatched is |
| +// 1. The foreground window is checked to see if it is a Direct Manipulation |
| +// consumer. |
| +// 2. If it is then Direct Manipulation takes over and sends the following |
| +// messages. WM_POINTERACTIVATE, WM_POINTERDOWN and DM_POINTERHITTEST. |
| +// 3. It then posts WM_MOUSEWHEEL messages with precision deltas which vary |
| +// based on the amount of the scroll. |
| +// 4. If the foreground window is not a Direct Manipulation consumer, it |
| +// then takes a fallback route where it posts WM_MOUSEWHEEL messages |
| +// with precision but varying deltas to the window. There is a also |
| +// a slight delay in receiving the first set of mouse wheel messages. |
| +// This causes scrolling in Chrome to appear janky and jumpy. |
| +// Our approach for addressing this is to do the absolute minimum to |
| +// register our window as a Direct Manipulation consumer. This class |
| +// provides the necessary functionality to register the legacy HWND as a |
| +// Direct Manipulation consumer. We don't rely on Direct manipulation |
| +// to do the smooth scrolling in the background thread as documented on |
| +// msdn. |
| +class DirectManipulationHelper { |
|
sky
2015/08/11 15:43:12
Would it make more sense to do this in views so th
ananta
2015/08/11 20:52:08
I guess so. I moved the DirectManipulationHelper c
|
| + public: |
| + DirectManipulationHelper() {} |
| + |
| + // This function instantiates Direct Manipulation and creates a viewport for |
| + // the passed in |window|. |
| + // consumer. Most of the code is boiler plate and is based on the sample. |
| + bool Initialize(HWND window) { |
| + DCHECK(::IsWindow(window)); |
| + |
| + HRESULT hr = manager_.CreateInstance(CLSID_DirectManipulationManager, |
| + nullptr, CLSCTX_INPROC_SERVER); |
| + CHECK(SUCCEEDED(hr)); |
|
sky
2015/08/11 15:43:12
Do these all need to be CHECKs, if any of these fa
ananta
2015/08/11 20:52:08
Added a TODO to remove the CHECKs once this stabli
|
| + |
| + hr = compositor_.CreateInstance(CLSID_DCompManipulationCompositor, |
| + nullptr, CLSCTX_INPROC_SERVER); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + hr = manager_->GetUpdateManager(IID_PPV_ARGS(update_manager_.Receive())); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + hr = compositor_->SetUpdateManager(update_manager_.get()); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + hr = frame_info_.QueryFrom(compositor_.get()); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + hr = manager_->CreateViewport(frame_info_.get(), window, |
| + IID_PPV_ARGS(view_port_outer_.Receive())); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + // |
| + // Enable the desired configuration for each viewport. |
| + // |
| + DIRECTMANIPULATION_CONFIGURATION configuration = |
| + DIRECTMANIPULATION_CONFIGURATION_INTERACTION |
| + | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X |
| + | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y |
| + | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA |
| + | DIRECTMANIPULATION_CONFIGURATION_RAILS_X |
| + | DIRECTMANIPULATION_CONFIGURATION_RAILS_Y |
| + | DIRECTMANIPULATION_CONFIGURATION_SCALING |
| + | DIRECTMANIPULATION_CONFIGURATION_SCALING_INERTIA; |
| + |
| + hr = view_port_outer_->ActivateConfiguration(configuration); |
| + CHECK(SUCCEEDED(hr)); |
| + return true; |
|
sky
2015/08/11 15:43:12
Seems like you always return true.
ananta
2015/08/11 20:52:08
Changed the type to void
|
| + } |
| + |
| + // Sets the bounds of the fake Direct manipulation viewport to match those |
| + // of the legacy window. |
| + void SetBounds(const gfx::Rect& bounds) { |
| + base::win::ScopedComPtr<IDirectManipulationPrimaryContent> |
| + primary_content_outer; |
| + HRESULT hr = view_port_outer_->GetPrimaryContent( |
| + IID_PPV_ARGS(primary_content_outer.Receive())); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + base::win::ScopedComPtr<IDirectManipulationContent> content_outer; |
| + hr = content_outer.QueryFrom(primary_content_outer.get()); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + RECT rect = bounds.ToRECT(); |
| + |
| + hr = view_port_outer_->SetViewportRect(&rect); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + hr = content_outer->SetContentRect(&rect); |
| + CHECK(SUCCEEDED(hr)); |
| + } |
| + |
| + // Registers the passed in |window| as a Direct Manipulation consumer. |
| + void Activate(HWND window) { |
| + DCHECK(::IsWindow(window)); |
| + HRESULT hr = manager_->Activate(window); |
| + CHECK(SUCCEEDED(hr)); |
| + } |
| + |
| + // Passes the WM_MOUSEWHEEL messages to Direct Manipulation. This is for |
| + // logistics purposes. |
| + void HandleMouseWheel(HWND window, UINT message, WPARAM w_param, |
| + LPARAM l_param) { |
| + MSG msg = { window, message, w_param, l_param}; |
| + |
| + HRESULT hr = view_port_outer_->SetContact(DIRECTMANIPULATION_MOUSEFOCUS); |
| + if (SUCCEEDED(hr)) { |
| + BOOL handled = FALSE; |
| + manager_->ProcessInput(&msg, &handled); |
| + view_port_outer_->ReleaseContact(DIRECTMANIPULATION_MOUSEFOCUS); |
| + } |
| + } |
| + |
| + private: |
| + base::win::ScopedComPtr<IDirectManipulationManager2> manager_; |
| + base::win::ScopedComPtr<IDirectManipulationCompositor> compositor_; |
| + base::win::ScopedComPtr<IDirectManipulationUpdateManager> update_manager_; |
| + base::win::ScopedComPtr<IDirectManipulationFrameInfoProvider> frame_info_; |
| + base::win::ScopedComPtr<IDirectManipulationViewport2> view_port_outer_; |
| +}; |
|
sky
2015/08/11 15:43:12
DISALLOW...
ananta
2015/08/11 20:52:08
Done.
|
| + |
| // A custom MSAA object id used to determine if a screen reader or some |
| // other client is listening on MSAA events - if so, we enable full web |
| // accessibility support. |
| @@ -75,6 +200,8 @@ HWND LegacyRenderWidgetHostHWND::GetParent() { |
| void LegacyRenderWidgetHostHWND::Show() { |
| ::ShowWindow(hwnd(), SW_SHOW); |
| + if (direct_manipulation_helper_) |
| + direct_manipulation_helper_->Activate(hwnd()); |
| } |
| void LegacyRenderWidgetHostHWND::Hide() { |
| @@ -86,6 +213,8 @@ void LegacyRenderWidgetHostHWND::SetBounds(const gfx::Rect& bounds) { |
| ::SetWindowPos(hwnd(), NULL, bounds_in_pixel.x(), bounds_in_pixel.y(), |
| bounds_in_pixel.width(), bounds_in_pixel.height(), |
| SWP_NOREDRAW); |
| + if (direct_manipulation_helper_) |
| + direct_manipulation_helper_->SetBounds(bounds_in_pixel); |
| } |
| void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) { |
| @@ -126,6 +255,11 @@ bool LegacyRenderWidgetHostHWND::Init() { |
| CHILDID_SELF); |
| } |
| + if (base::win::GetVersion() >= base::win::VERSION_WIN10) { |
| + direct_manipulation_helper_.reset(new DirectManipulationHelper); |
| + direct_manipulation_helper_->Initialize(hwnd()); |
| + } |
| + |
| return !!SUCCEEDED(hr); |
| } |
| @@ -242,6 +376,12 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message, |
| handled = TRUE; |
| } |
| } |
| + |
| + if (direct_manipulation_helper_ && |
| + (message == WM_MOUSEWHEEL || message == WM_MOUSEHWHEEL)) { |
| + direct_manipulation_helper_->HandleMouseWheel(hwnd(), message, w_param, |
| + l_param); |
| + } |
| return ret; |
| } |