OLD | NEW |
---|---|
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/legacy_render_widget_host_win.h" | 5 #include "content/browser/renderer_host/legacy_render_widget_host_win.h" |
6 | 6 |
7 #include <directmanipulation.h> | |
8 | |
7 #include "base/command_line.h" | 9 #include "base/command_line.h" |
8 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
11 #include "base/win/scoped_comptr.h" | |
9 #include "base/win/windows_version.h" | 12 #include "base/win/windows_version.h" |
10 #include "content/browser/accessibility/browser_accessibility_manager_win.h" | 13 #include "content/browser/accessibility/browser_accessibility_manager_win.h" |
11 #include "content/browser/accessibility/browser_accessibility_win.h" | 14 #include "content/browser/accessibility/browser_accessibility_win.h" |
12 #include "content/browser/renderer_host/render_widget_host_impl.h" | 15 #include "content/browser/renderer_host/render_widget_host_impl.h" |
13 #include "content/browser/renderer_host/render_widget_host_view_aura.h" | 16 #include "content/browser/renderer_host/render_widget_host_view_aura.h" |
14 #include "content/public/browser/browser_accessibility_state.h" | 17 #include "content/public/browser/browser_accessibility_state.h" |
15 #include "content/public/common/content_switches.h" | 18 #include "content/public/common/content_switches.h" |
16 #include "ui/base/touch/touch_enabled.h" | 19 #include "ui/base/touch/touch_enabled.h" |
17 #include "ui/base/view_prop.h" | 20 #include "ui/base/view_prop.h" |
18 #include "ui/base/win/internal_constants.h" | 21 #include "ui/base/win/internal_constants.h" |
19 #include "ui/base/win/window_event_target.h" | 22 #include "ui/base/win/window_event_target.h" |
20 #include "ui/gfx/geometry/rect.h" | 23 #include "ui/gfx/geometry/rect.h" |
21 #include "ui/gfx/win/dpi.h" | 24 #include "ui/gfx/win/dpi.h" |
22 | 25 |
23 namespace content { | 26 namespace content { |
24 | 27 |
28 // Windows 10 provides a new API called Direct Manipulation which generates | |
29 // smooth scroll events via WM_MOUSEWHEEL messages with predictable deltas | |
30 // on high precision touch pads. This basically requires the application window | |
31 // to register as a Direct Manipulation consumer. The way mouse wheel messages | |
32 // are dispatched is | |
33 // 1. The foreground window is checked to see if it is a Direct Manipulation | |
34 // consumer. | |
35 // 2. If it is then Direct Manipulation takes over and sends the following | |
36 // messages. WM_POINTERACTIVATE, WM_POINTERDOWN and DM_POINTERHITTEST. | |
37 // 3. It then posts WM_MOUSEWHEEL messages with precision deltas which vary | |
38 // based on the amount of the scroll. | |
39 // 4. If the foreground window is not a Direct Manipulation consumer, it | |
40 // then takes a fallback route where it posts WM_MOUSEWHEEL messages | |
41 // with precision but varying deltas to the window. There is a also | |
42 // a slight delay in receiving the first set of mouse wheel messages. | |
43 // This causes scrolling in Chrome to appear janky and jumpy. | |
44 // Our approach for addressing this is to do the absolute minimum to | |
45 // register our window as a Direct Manipulation consumer. This class | |
46 // provides the necessary functionality to register the legacy HWND as a | |
47 // Direct Manipulation consumer. We don't rely on Direct manipulation | |
48 // to do the smooth scrolling in the background thread as documented on | |
49 // msdn. | |
50 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
| |
51 public: | |
52 DirectManipulationHelper() {} | |
53 | |
54 // This function instantiates Direct Manipulation and creates a viewport for | |
55 // the passed in |window|. | |
56 // consumer. Most of the code is boiler plate and is based on the sample. | |
57 bool Initialize(HWND window) { | |
58 DCHECK(::IsWindow(window)); | |
59 | |
60 HRESULT hr = manager_.CreateInstance(CLSID_DirectManipulationManager, | |
61 nullptr, CLSCTX_INPROC_SERVER); | |
62 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
| |
63 | |
64 hr = compositor_.CreateInstance(CLSID_DCompManipulationCompositor, | |
65 nullptr, CLSCTX_INPROC_SERVER); | |
66 CHECK(SUCCEEDED(hr)); | |
67 | |
68 hr = manager_->GetUpdateManager(IID_PPV_ARGS(update_manager_.Receive())); | |
69 CHECK(SUCCEEDED(hr)); | |
70 | |
71 hr = compositor_->SetUpdateManager(update_manager_.get()); | |
72 CHECK(SUCCEEDED(hr)); | |
73 | |
74 hr = frame_info_.QueryFrom(compositor_.get()); | |
75 CHECK(SUCCEEDED(hr)); | |
76 | |
77 hr = manager_->CreateViewport(frame_info_.get(), window, | |
78 IID_PPV_ARGS(view_port_outer_.Receive())); | |
79 CHECK(SUCCEEDED(hr)); | |
80 | |
81 // | |
82 // Enable the desired configuration for each viewport. | |
83 // | |
84 DIRECTMANIPULATION_CONFIGURATION configuration = | |
85 DIRECTMANIPULATION_CONFIGURATION_INTERACTION | |
86 | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X | |
87 | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y | |
88 | DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA | |
89 | DIRECTMANIPULATION_CONFIGURATION_RAILS_X | |
90 | DIRECTMANIPULATION_CONFIGURATION_RAILS_Y | |
91 | DIRECTMANIPULATION_CONFIGURATION_SCALING | |
92 | DIRECTMANIPULATION_CONFIGURATION_SCALING_INERTIA; | |
93 | |
94 hr = view_port_outer_->ActivateConfiguration(configuration); | |
95 CHECK(SUCCEEDED(hr)); | |
96 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
| |
97 } | |
98 | |
99 // Sets the bounds of the fake Direct manipulation viewport to match those | |
100 // of the legacy window. | |
101 void SetBounds(const gfx::Rect& bounds) { | |
102 base::win::ScopedComPtr<IDirectManipulationPrimaryContent> | |
103 primary_content_outer; | |
104 HRESULT hr = view_port_outer_->GetPrimaryContent( | |
105 IID_PPV_ARGS(primary_content_outer.Receive())); | |
106 CHECK(SUCCEEDED(hr)); | |
107 | |
108 base::win::ScopedComPtr<IDirectManipulationContent> content_outer; | |
109 hr = content_outer.QueryFrom(primary_content_outer.get()); | |
110 CHECK(SUCCEEDED(hr)); | |
111 | |
112 RECT rect = bounds.ToRECT(); | |
113 | |
114 hr = view_port_outer_->SetViewportRect(&rect); | |
115 CHECK(SUCCEEDED(hr)); | |
116 | |
117 hr = content_outer->SetContentRect(&rect); | |
118 CHECK(SUCCEEDED(hr)); | |
119 } | |
120 | |
121 // Registers the passed in |window| as a Direct Manipulation consumer. | |
122 void Activate(HWND window) { | |
123 DCHECK(::IsWindow(window)); | |
124 HRESULT hr = manager_->Activate(window); | |
125 CHECK(SUCCEEDED(hr)); | |
126 } | |
127 | |
128 // Passes the WM_MOUSEWHEEL messages to Direct Manipulation. This is for | |
129 // logistics purposes. | |
130 void HandleMouseWheel(HWND window, UINT message, WPARAM w_param, | |
131 LPARAM l_param) { | |
132 MSG msg = { window, message, w_param, l_param}; | |
133 | |
134 HRESULT hr = view_port_outer_->SetContact(DIRECTMANIPULATION_MOUSEFOCUS); | |
135 if (SUCCEEDED(hr)) { | |
136 BOOL handled = FALSE; | |
137 manager_->ProcessInput(&msg, &handled); | |
138 view_port_outer_->ReleaseContact(DIRECTMANIPULATION_MOUSEFOCUS); | |
139 } | |
140 } | |
141 | |
142 private: | |
143 base::win::ScopedComPtr<IDirectManipulationManager2> manager_; | |
144 base::win::ScopedComPtr<IDirectManipulationCompositor> compositor_; | |
145 base::win::ScopedComPtr<IDirectManipulationUpdateManager> update_manager_; | |
146 base::win::ScopedComPtr<IDirectManipulationFrameInfoProvider> frame_info_; | |
147 base::win::ScopedComPtr<IDirectManipulationViewport2> view_port_outer_; | |
148 }; | |
sky
2015/08/11 15:43:12
DISALLOW...
ananta
2015/08/11 20:52:08
Done.
| |
149 | |
25 // A custom MSAA object id used to determine if a screen reader or some | 150 // A custom MSAA object id used to determine if a screen reader or some |
26 // other client is listening on MSAA events - if so, we enable full web | 151 // other client is listening on MSAA events - if so, we enable full web |
27 // accessibility support. | 152 // accessibility support. |
28 const int kIdScreenReaderHoneyPot = 1; | 153 const int kIdScreenReaderHoneyPot = 1; |
29 | 154 |
30 // static | 155 // static |
31 LegacyRenderWidgetHostHWND* LegacyRenderWidgetHostHWND::Create( | 156 LegacyRenderWidgetHostHWND* LegacyRenderWidgetHostHWND::Create( |
32 HWND parent) { | 157 HWND parent) { |
33 // content_unittests passes in the desktop window as the parent. We allow | 158 // content_unittests passes in the desktop window as the parent. We allow |
34 // the LegacyRenderWidgetHostHWND instance to be created in this case for | 159 // the LegacyRenderWidgetHostHWND instance to be created in this case for |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
68 ::EnableWindow(hwnd(), TRUE); | 193 ::EnableWindow(hwnd(), TRUE); |
69 } | 194 } |
70 } | 195 } |
71 | 196 |
72 HWND LegacyRenderWidgetHostHWND::GetParent() { | 197 HWND LegacyRenderWidgetHostHWND::GetParent() { |
73 return ::GetParent(hwnd()); | 198 return ::GetParent(hwnd()); |
74 } | 199 } |
75 | 200 |
76 void LegacyRenderWidgetHostHWND::Show() { | 201 void LegacyRenderWidgetHostHWND::Show() { |
77 ::ShowWindow(hwnd(), SW_SHOW); | 202 ::ShowWindow(hwnd(), SW_SHOW); |
203 if (direct_manipulation_helper_) | |
204 direct_manipulation_helper_->Activate(hwnd()); | |
78 } | 205 } |
79 | 206 |
80 void LegacyRenderWidgetHostHWND::Hide() { | 207 void LegacyRenderWidgetHostHWND::Hide() { |
81 ::ShowWindow(hwnd(), SW_HIDE); | 208 ::ShowWindow(hwnd(), SW_HIDE); |
82 } | 209 } |
83 | 210 |
84 void LegacyRenderWidgetHostHWND::SetBounds(const gfx::Rect& bounds) { | 211 void LegacyRenderWidgetHostHWND::SetBounds(const gfx::Rect& bounds) { |
85 gfx::Rect bounds_in_pixel = gfx::win::DIPToScreenRect(bounds); | 212 gfx::Rect bounds_in_pixel = gfx::win::DIPToScreenRect(bounds); |
86 ::SetWindowPos(hwnd(), NULL, bounds_in_pixel.x(), bounds_in_pixel.y(), | 213 ::SetWindowPos(hwnd(), NULL, bounds_in_pixel.x(), bounds_in_pixel.y(), |
87 bounds_in_pixel.width(), bounds_in_pixel.height(), | 214 bounds_in_pixel.width(), bounds_in_pixel.height(), |
88 SWP_NOREDRAW); | 215 SWP_NOREDRAW); |
216 if (direct_manipulation_helper_) | |
217 direct_manipulation_helper_->SetBounds(bounds_in_pixel); | |
89 } | 218 } |
90 | 219 |
91 void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) { | 220 void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) { |
92 if (host_) { | 221 if (host_) { |
93 host_->OnLegacyWindowDestroyed(); | 222 host_->OnLegacyWindowDestroyed(); |
94 host_ = NULL; | 223 host_ = NULL; |
95 } | 224 } |
96 delete this; | 225 delete this; |
97 } | 226 } |
98 | 227 |
(...skipping 20 matching lines...) Expand all Loading... | |
119 reinterpret_cast<void **>(window_accessible_.Receive())); | 248 reinterpret_cast<void **>(window_accessible_.Receive())); |
120 DCHECK(SUCCEEDED(hr)); | 249 DCHECK(SUCCEEDED(hr)); |
121 | 250 |
122 if (!BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) { | 251 if (!BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) { |
123 // Attempt to detect screen readers or other clients who want full | 252 // Attempt to detect screen readers or other clients who want full |
124 // accessibility support, by seeing if they respond to this event. | 253 // accessibility support, by seeing if they respond to this event. |
125 NotifyWinEvent(EVENT_SYSTEM_ALERT, hwnd(), kIdScreenReaderHoneyPot, | 254 NotifyWinEvent(EVENT_SYSTEM_ALERT, hwnd(), kIdScreenReaderHoneyPot, |
126 CHILDID_SELF); | 255 CHILDID_SELF); |
127 } | 256 } |
128 | 257 |
258 if (base::win::GetVersion() >= base::win::VERSION_WIN10) { | |
259 direct_manipulation_helper_.reset(new DirectManipulationHelper); | |
260 direct_manipulation_helper_->Initialize(hwnd()); | |
261 } | |
262 | |
129 return !!SUCCEEDED(hr); | 263 return !!SUCCEEDED(hr); |
130 } | 264 } |
131 | 265 |
132 // static | 266 // static |
133 ui::WindowEventTarget* LegacyRenderWidgetHostHWND::GetWindowEventTarget( | 267 ui::WindowEventTarget* LegacyRenderWidgetHostHWND::GetWindowEventTarget( |
134 HWND parent) { | 268 HWND parent) { |
135 return reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue( | 269 return reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue( |
136 parent, ui::WindowEventTarget::kWin32InputEventTarget)); | 270 parent, ui::WindowEventTarget::kWin32InputEventTarget)); |
137 } | 271 } |
138 | 272 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 // If the parent did not handle non client mouse messages, we call | 369 // If the parent did not handle non client mouse messages, we call |
236 // DefWindowProc on the message with the parent window handle. This | 370 // DefWindowProc on the message with the parent window handle. This |
237 // ensures that WM_SYSCOMMAND is generated for the parent and we are | 371 // ensures that WM_SYSCOMMAND is generated for the parent and we are |
238 // out of the picture. | 372 // out of the picture. |
239 if (!handled && | 373 if (!handled && |
240 (message >= WM_NCMOUSEMOVE && message <= WM_NCXBUTTONDBLCLK)) { | 374 (message >= WM_NCMOUSEMOVE && message <= WM_NCXBUTTONDBLCLK)) { |
241 ret = ::DefWindowProc(GetParent(), message, w_param, l_param); | 375 ret = ::DefWindowProc(GetParent(), message, w_param, l_param); |
242 handled = TRUE; | 376 handled = TRUE; |
243 } | 377 } |
244 } | 378 } |
379 | |
380 if (direct_manipulation_helper_ && | |
381 (message == WM_MOUSEWHEEL || message == WM_MOUSEHWHEEL)) { | |
382 direct_manipulation_helper_->HandleMouseWheel(hwnd(), message, w_param, | |
383 l_param); | |
384 } | |
245 return ret; | 385 return ret; |
246 } | 386 } |
247 | 387 |
248 LRESULT LegacyRenderWidgetHostHWND::OnMouseLeave(UINT message, | 388 LRESULT LegacyRenderWidgetHostHWND::OnMouseLeave(UINT message, |
249 WPARAM w_param, | 389 WPARAM w_param, |
250 LPARAM l_param) { | 390 LPARAM l_param) { |
251 mouse_tracking_enabled_ = false; | 391 mouse_tracking_enabled_ = false; |
252 LRESULT ret = 0; | 392 LRESULT ret = 0; |
253 if ((::GetCapture() != GetParent()) && GetWindowEventTarget(GetParent())) { | 393 if ((::GetCapture() != GetParent()) && GetWindowEventTarget(GetParent())) { |
254 // We should send a WM_MOUSELEAVE to the parent window only if the mouse | 394 // We should send a WM_MOUSELEAVE to the parent window only if the mouse |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
373 // generate the legacy WM_VSCROLL/WM_HSCROLL messages. | 513 // generate the legacy WM_VSCROLL/WM_HSCROLL messages. |
374 // We add these styles to ensure that trackpad/trackpoint scrolling | 514 // We add these styles to ensure that trackpad/trackpoint scrolling |
375 // work. | 515 // work. |
376 long current_style = ::GetWindowLong(hwnd(), GWL_STYLE); | 516 long current_style = ::GetWindowLong(hwnd(), GWL_STYLE); |
377 ::SetWindowLong(hwnd(), GWL_STYLE, | 517 ::SetWindowLong(hwnd(), GWL_STYLE, |
378 current_style | WS_VSCROLL | WS_HSCROLL); | 518 current_style | WS_VSCROLL | WS_HSCROLL); |
379 return 0; | 519 return 0; |
380 } | 520 } |
381 | 521 |
382 } // namespace content | 522 } // namespace content |
OLD | NEW |