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; | 
| } |