Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / renderer_host / legacy_render_widget_host_win.cc
blob9c2e1a2e512ccf646dec9ce48388b4e5b44a3e6b
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
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/legacy_render_widget_host_win.h"
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/win/windows_version.h"
10 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
11 #include "content/browser/accessibility/browser_accessibility_win.h"
12 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
13 #include "content/public/browser/browser_accessibility_state.h"
14 #include "content/public/common/content_switches.h"
15 #include "ui/base/touch/touch_enabled.h"
16 #include "ui/base/view_prop.h"
17 #include "ui/base/win/internal_constants.h"
18 #include "ui/base/win/window_event_target.h"
19 #include "ui/gfx/geometry/rect.h"
20 #include "ui/gfx/win/dpi.h"
22 namespace content {
24 // A custom MSAA object id used to determine if a screen reader or some
25 // other client is listening on MSAA events - if so, we enable full web
26 // accessibility support.
27 const int kIdScreenReaderHoneyPot = 1;
29 // static
30 LegacyRenderWidgetHostHWND* LegacyRenderWidgetHostHWND::Create(
31 HWND parent) {
32 // content_unittests passes in the desktop window as the parent. We allow
33 // the LegacyRenderWidgetHostHWND instance to be created in this case for
34 // these tests to pass.
35 if (CommandLine::ForCurrentProcess()->HasSwitch(
36 switches::kDisableLegacyIntermediateWindow) ||
37 (!GetWindowEventTarget(parent) && parent != ::GetDesktopWindow()))
38 return NULL;
40 LegacyRenderWidgetHostHWND* legacy_window_instance =
41 new LegacyRenderWidgetHostHWND(parent);
42 // If we failed to create the child, or if the switch to disable the legacy
43 // window is passed in, then return NULL.
44 if (!::IsWindow(legacy_window_instance->hwnd())) {
45 delete legacy_window_instance;
46 return NULL;
48 legacy_window_instance->Init();
49 return legacy_window_instance;
52 void LegacyRenderWidgetHostHWND::Destroy() {
53 if (::IsWindow(hwnd()))
54 ::DestroyWindow(hwnd());
57 void LegacyRenderWidgetHostHWND::UpdateParent(HWND parent) {
58 ::SetParent(hwnd(), parent);
59 // If the new parent is the desktop Window, then we disable the child window
60 // to ensure that it does not receive any input events. It should not because
61 // of WS_EX_TRANSPARENT. This is only for safety.
62 if (parent == ::GetDesktopWindow()) {
63 ::EnableWindow(hwnd(), FALSE);
64 } else {
65 ::EnableWindow(hwnd(), TRUE);
69 HWND LegacyRenderWidgetHostHWND::GetParent() {
70 return ::GetParent(hwnd());
73 void LegacyRenderWidgetHostHWND::OnManagerDeleted() {
74 manager_ = NULL;
77 void LegacyRenderWidgetHostHWND::Show() {
78 ::ShowWindow(hwnd(), SW_SHOW);
81 void LegacyRenderWidgetHostHWND::Hide() {
82 ::ShowWindow(hwnd(), SW_HIDE);
85 void LegacyRenderWidgetHostHWND::SetBounds(const gfx::Rect& bounds) {
86 gfx::Rect bounds_in_pixel = gfx::win::DIPToScreenRect(bounds);
87 ::SetWindowPos(hwnd(), NULL, bounds_in_pixel.x(), bounds_in_pixel.y(),
88 bounds_in_pixel.width(), bounds_in_pixel.height(), 0);
91 void LegacyRenderWidgetHostHWND::OnFinalMessage(HWND hwnd) {
92 if (manager_)
93 manager_->OnAccessibleHwndDeleted();
94 if (host_) {
95 host_->OnLegacyWindowDestroyed();
96 host_ = NULL;
98 delete this;
101 LegacyRenderWidgetHostHWND::LegacyRenderWidgetHostHWND(HWND parent)
102 : manager_(NULL),
103 mouse_tracking_enabled_(false),
104 host_(NULL) {
105 RECT rect = {0};
106 Base::Create(parent, rect, L"Chrome Legacy Window",
107 WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
108 WS_EX_TRANSPARENT);
111 LegacyRenderWidgetHostHWND::~LegacyRenderWidgetHostHWND() {
112 DCHECK(!::IsWindow(hwnd()));
115 bool LegacyRenderWidgetHostHWND::Init() {
116 if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
117 ui::AreTouchEventsEnabled())
118 RegisterTouchWindow(hwnd(), TWF_WANTPALM);
120 HRESULT hr = ::CreateStdAccessibleObject(
121 hwnd(), OBJID_WINDOW, IID_IAccessible,
122 reinterpret_cast<void **>(window_accessible_.Receive()));
123 DCHECK(SUCCEEDED(hr));
125 if (!BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) {
126 // Attempt to detect screen readers or other clients who want full
127 // accessibility support, by seeing if they respond to this event.
128 NotifyWinEvent(EVENT_SYSTEM_ALERT, hwnd(), kIdScreenReaderHoneyPot,
129 CHILDID_SELF);
132 return !!SUCCEEDED(hr);
135 // static
136 ui::WindowEventTarget* LegacyRenderWidgetHostHWND::GetWindowEventTarget(
137 HWND parent) {
138 return reinterpret_cast<ui::WindowEventTarget*>(ui::ViewProp::GetValue(
139 parent, ui::WindowEventTarget::kWin32InputEventTarget));
142 LRESULT LegacyRenderWidgetHostHWND::OnEraseBkGnd(UINT message,
143 WPARAM w_param,
144 LPARAM l_param) {
145 return 1;
148 LRESULT LegacyRenderWidgetHostHWND::OnGetObject(UINT message,
149 WPARAM w_param,
150 LPARAM l_param) {
151 // Only the lower 32 bits of l_param are valid when checking the object id
152 // because it sometimes gets sign-extended incorrectly (but not always).
153 DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(l_param));
155 if (kIdScreenReaderHoneyPot == obj_id) {
156 // When an MSAA client has responded to our fake event on this id,
157 // enable screen reader support.
158 BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
159 return static_cast<LRESULT>(0L);
162 if (OBJID_CLIENT != obj_id || !manager_)
163 return static_cast<LRESULT>(0L);
165 base::win::ScopedComPtr<IAccessible> root(
166 manager_->GetRoot()->ToBrowserAccessibilityWin());
167 return LresultFromObject(IID_IAccessible, w_param,
168 static_cast<IAccessible*>(root.Detach()));
171 // We send keyboard/mouse/touch messages to the parent window via SendMessage.
172 // While this works, this has the side effect of converting input messages into
173 // sent messages which changes their priority and could technically result
174 // in these messages starving other messages in the queue. Additionally
175 // keyboard/mouse hooks would not see these messages. The alternative approach
176 // is to set and release capture as needed on the parent to ensure that it
177 // receives all mouse events. However that was shelved due to possible issues
178 // with capture changes.
179 LRESULT LegacyRenderWidgetHostHWND::OnKeyboardRange(UINT message,
180 WPARAM w_param,
181 LPARAM l_param,
182 BOOL& handled) {
183 LRESULT ret = 0;
184 if (GetWindowEventTarget(GetParent())) {
185 bool msg_handled = false;
186 ret = GetWindowEventTarget(GetParent())->HandleKeyboardMessage(
187 message, w_param, l_param, &msg_handled);
188 handled = msg_handled;
190 return ret;
193 LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
194 WPARAM w_param,
195 LPARAM l_param,
196 BOOL& handled) {
197 if (message == WM_MOUSEMOVE) {
198 if (!mouse_tracking_enabled_) {
199 mouse_tracking_enabled_ = true;
200 TRACKMOUSEEVENT tme;
201 tme.cbSize = sizeof(tme);
202 tme.dwFlags = TME_LEAVE;
203 tme.hwndTrack = hwnd();
204 tme.dwHoverTime = 0;
205 TrackMouseEvent(&tme);
208 // The offsets for WM_NCXXX and WM_MOUSEWHEEL and WM_MOUSEHWHEEL messages are
209 // in screen coordinates. We should not be converting them to parent
210 // coordinates.
211 if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) &&
212 (message != WM_MOUSEWHEEL && message != WM_MOUSEHWHEEL)) {
213 POINT mouse_coords;
214 mouse_coords.x = GET_X_LPARAM(l_param);
215 mouse_coords.y = GET_Y_LPARAM(l_param);
216 ::MapWindowPoints(hwnd(), GetParent(), &mouse_coords, 1);
217 l_param = MAKELPARAM(mouse_coords.x, mouse_coords.y);
220 LRESULT ret = 0;
222 if (GetWindowEventTarget(GetParent())) {
223 bool msg_handled = false;
224 ret = GetWindowEventTarget(GetParent())->HandleMouseMessage(
225 message, w_param, l_param, &msg_handled);
226 handled = msg_handled;
227 // If the parent did not handle non client mouse messages, we call
228 // DefWindowProc on the message with the parent window handle. This
229 // ensures that WM_SYSCOMMAND is generated for the parent and we are
230 // out of the picture.
231 if (!handled &&
232 (message >= WM_NCMOUSEMOVE && message <= WM_NCXBUTTONDBLCLK)) {
233 ret = ::DefWindowProc(GetParent(), message, w_param, l_param);
234 handled = TRUE;
237 return ret;
240 LRESULT LegacyRenderWidgetHostHWND::OnMouseLeave(UINT message,
241 WPARAM w_param,
242 LPARAM l_param) {
243 mouse_tracking_enabled_ = false;
244 LRESULT ret = 0;
245 if ((::GetCapture() != GetParent()) && GetWindowEventTarget(GetParent())) {
246 // We should send a WM_MOUSELEAVE to the parent window only if the mouse
247 // has moved outside the bounds of the parent.
248 POINT cursor_pos;
249 ::GetCursorPos(&cursor_pos);
250 if (::WindowFromPoint(cursor_pos) != GetParent()) {
251 bool msg_handled = false;
252 ret = GetWindowEventTarget(GetParent())->HandleMouseMessage(
253 message, w_param, l_param, &msg_handled);
254 SetMsgHandled(msg_handled);
257 return ret;
260 LRESULT LegacyRenderWidgetHostHWND::OnMouseActivate(UINT message,
261 WPARAM w_param,
262 LPARAM l_param) {
263 // Don't pass this to DefWindowProc. That results in the WM_MOUSEACTIVATE
264 // message going all the way to the parent which then messes up state
265 // related to focused views, etc. This is because it treats this as if
266 // it lost activation.
267 // Our dummy window should not interfere with focus and activation in
268 // the parent. Return MA_ACTIVATE here ensures that focus state in the parent
269 // is preserved. The only exception is if the parent was created with the
270 // WS_EX_NOACTIVATE style.
271 if (::GetWindowLong(GetParent(), GWL_EXSTYLE) & WS_EX_NOACTIVATE)
272 return MA_NOACTIVATE;
273 // On Windows, if we select the menu item by touch and if the window at the
274 // location is another window on the same thread, that window gets a
275 // WM_MOUSEACTIVATE message and ends up activating itself, which is not
276 // correct. We workaround this by setting a property on the window at the
277 // current cursor location. We check for this property in our
278 // WM_MOUSEACTIVATE handler and don't activate the window if the property is
279 // set.
280 if (::GetProp(hwnd(), ui::kIgnoreTouchMouseActivateForWindow)) {
281 ::RemoveProp(hwnd(), ui::kIgnoreTouchMouseActivateForWindow);
282 return MA_NOACTIVATE;
284 return MA_ACTIVATE;
287 LRESULT LegacyRenderWidgetHostHWND::OnTouch(UINT message,
288 WPARAM w_param,
289 LPARAM l_param) {
290 LRESULT ret = 0;
291 if (GetWindowEventTarget(GetParent())) {
292 bool msg_handled = false;
293 ret = GetWindowEventTarget(GetParent())->HandleTouchMessage(
294 message, w_param, l_param, &msg_handled);
295 SetMsgHandled(msg_handled);
297 return ret;
300 LRESULT LegacyRenderWidgetHostHWND::OnScroll(UINT message,
301 WPARAM w_param,
302 LPARAM l_param) {
303 LRESULT ret = 0;
304 if (GetWindowEventTarget(GetParent())) {
305 bool msg_handled = false;
306 ret = GetWindowEventTarget(GetParent())->HandleScrollMessage(
307 message, w_param, l_param, &msg_handled);
308 SetMsgHandled(msg_handled);
310 return ret;
313 LRESULT LegacyRenderWidgetHostHWND::OnNCHitTest(UINT message,
314 WPARAM w_param,
315 LPARAM l_param) {
316 if (GetWindowEventTarget(GetParent())) {
317 bool msg_handled = false;
318 LRESULT hit_test = GetWindowEventTarget(
319 GetParent())->HandleNcHitTestMessage(message, w_param, l_param,
320 &msg_handled);
321 // If the parent returns HTNOWHERE which can happen for popup windows, etc
322 // we return HTCLIENT.
323 if (hit_test == HTNOWHERE)
324 hit_test = HTCLIENT;
325 return hit_test;
327 return HTNOWHERE;
330 LRESULT LegacyRenderWidgetHostHWND::OnNCPaint(UINT message,
331 WPARAM w_param,
332 LPARAM l_param) {
333 return 0;
336 LRESULT LegacyRenderWidgetHostHWND::OnPaint(UINT message,
337 WPARAM w_param,
338 LPARAM l_param) {
339 PAINTSTRUCT ps = {0};
340 ::BeginPaint(hwnd(), &ps);
341 ::EndPaint(hwnd(), &ps);
342 return 0;
345 LRESULT LegacyRenderWidgetHostHWND::OnSetCursor(UINT message,
346 WPARAM w_param,
347 LPARAM l_param) {
348 return 0;
351 LRESULT LegacyRenderWidgetHostHWND::OnNCCalcSize(UINT message,
352 WPARAM w_param,
353 LPARAM l_param) {
354 // Prevent scrollbars, etc from drawing.
355 return 0;
358 LRESULT LegacyRenderWidgetHostHWND::OnSize(UINT message,
359 WPARAM w_param,
360 LPARAM l_param) {
361 // Certain trackpad drivers on Windows have bugs where in they don't generate
362 // WM_MOUSEWHEEL messages for the trackpoint and trackpad scrolling gestures
363 // unless there is an entry for Chrome with the class name of the Window.
364 // Additionally others check if the window WS_VSCROLL/WS_HSCROLL styles and
365 // generate the legacy WM_VSCROLL/WM_HSCROLL messages.
366 // We add these styles to ensure that trackpad/trackpoint scrolling
367 // work.
368 long current_style = ::GetWindowLong(hwnd(), GWL_STYLE);
369 ::SetWindowLong(hwnd(), GWL_STYLE,
370 current_style | WS_VSCROLL | WS_HSCROLL);
371 return 0;
374 } // namespace content