• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 #include "chrome/browser/renderer_host/render_widget_host_view_win.h"
6 
7 #include <algorithm>
8 
9 #include "base/command_line.h"
10 #include "base/i18n/rtl.h"
11 #include "base/metrics/histogram.h"
12 #include "base/process_util.h"
13 #include "base/threading/thread.h"
14 #include "base/win/scoped_comptr.h"
15 #include "base/win/scoped_gdi_object.h"
16 #include "base/win/wrapped_window_proc.h"
17 #include "chrome/browser/accessibility/browser_accessibility_manager.h"
18 #include "chrome/browser/accessibility/browser_accessibility_state.h"
19 #include "chrome/browser/accessibility/browser_accessibility_win.h"
20 #include "chrome/browser/browser_trial.h"
21 #include "chrome/common/chrome_constants.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/render_messages.h"
24 #include "content/browser/browser_thread.h"
25 #include "content/browser/plugin_process_host.h"
26 #include "content/browser/renderer_host/backing_store.h"
27 #include "content/browser/renderer_host/backing_store_win.h"
28 #include "content/browser/renderer_host/render_process_host.h"
29 #include "content/browser/renderer_host/render_widget_host.h"
30 #include "content/common/native_web_keyboard_event.h"
31 #include "content/common/notification_service.h"
32 #include "content/common/plugin_messages.h"
33 #include "content/common/view_messages.h"
34 #include "grit/webkit_resources.h"
35 #include "skia/ext/skia_utils_win.h"
36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h"
37 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
38 #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebInputEventFactory.h"
39 #include "ui/base/ime/composition_text.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/base/l10n/l10n_util_win.h"
42 #include "ui/base/resource/resource_bundle.h"
43 #include "ui/base/view_prop.h"
44 #include "ui/base/win/hwnd_util.h"
45 #include "ui/gfx/canvas.h"
46 #include "ui/gfx/canvas_skia.h"
47 #include "ui/gfx/gdi_util.h"
48 #include "ui/gfx/rect.h"
49 #include "views/accessibility/native_view_accessibility_win.h"
50 #include "views/focus/focus_manager.h"
51 #include "views/focus/focus_util_win.h"
52 // Included for views::kReflectedMessage - TODO(beng): move this to win_util.h!
53 #include "views/widget/widget_win.h"
54 #include "webkit/glue/webaccessibility.h"
55 #include "webkit/glue/webcursor.h"
56 #include "webkit/plugins/npapi/plugin_constants_win.h"
57 #include "webkit/plugins/npapi/webplugin.h"
58 #include "webkit/plugins/npapi/webplugin_delegate_impl.h"
59 
60 using base::TimeDelta;
61 using base::TimeTicks;
62 using ui::ViewProp;
63 using WebKit::WebInputEvent;
64 using WebKit::WebInputEventFactory;
65 using WebKit::WebMouseEvent;
66 using WebKit::WebTextDirection;
67 using webkit::npapi::WebPluginGeometry;
68 
69 const wchar_t kRenderWidgetHostHWNDClass[] = L"Chrome_RenderWidgetHostHWND";
70 
71 namespace {
72 
73 // Tooltips will wrap after this width. Yes, wrap. Imagine that!
74 const int kTooltipMaxWidthPixels = 300;
75 
76 // Maximum number of characters we allow in a tooltip.
77 const int kMaxTooltipLength = 1024;
78 
79 // A custom MSAA object id used to determine if a screen reader is actively
80 // listening for MSAA events.
81 const int kIdCustom = 1;
82 
83 // The delay before the compositor host window is destroyed. This gives the GPU
84 // process a grace period to stop referencing it.
85 const int kDestroyCompositorHostWindowDelay = 10000;
86 
87 const char* const kRenderWidgetHostViewKey = "__RENDER_WIDGET_HOST_VIEW__";
88 
89 // A callback function for EnumThreadWindows to enumerate and dismiss
90 // any owned popop windows
DismissOwnedPopups(HWND window,LPARAM arg)91 BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) {
92   const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg);
93 
94   if (::IsWindowVisible(window)) {
95     const HWND owner = ::GetWindow(window, GW_OWNER);
96     if (toplevel_hwnd == owner) {
97       ::PostMessage(window, WM_CANCELMODE, 0, 0);
98     }
99   }
100 
101   return TRUE;
102 }
103 
104 class NotifyPluginProcessHostTask : public Task {
105  public:
NotifyPluginProcessHostTask(HWND window,HWND parent)106   NotifyPluginProcessHostTask(HWND window, HWND parent)
107     : window_(window), parent_(parent), tries_(kMaxTries) { }
108 
109  private:
Run()110   void Run() {
111     DWORD plugin_process_id;
112     bool found_starting_plugin_process = false;
113     GetWindowThreadProcessId(window_, &plugin_process_id);
114     for (BrowserChildProcessHost::Iterator iter(
115              ChildProcessInfo::PLUGIN_PROCESS);
116          !iter.Done(); ++iter) {
117       PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
118       if (!plugin->handle()) {
119         found_starting_plugin_process = true;
120         continue;
121       }
122       if (base::GetProcId(plugin->handle()) == plugin_process_id) {
123         plugin->AddWindow(parent_);
124         return;
125       }
126     }
127 
128     if (found_starting_plugin_process) {
129       // A plugin process has started but we don't have its handle yet.  Since
130       // it's most likely the one for this plugin, try a few more times after a
131       // delay.
132       if (tries_--) {
133         MessageLoop::current()->PostDelayedTask(FROM_HERE, this, kTryDelayMs);
134         return;
135       }
136     }
137 
138     // The plugin process might have died in the time to execute the task, don't
139     // leak the HWND.
140     PostMessage(parent_, WM_CLOSE, 0, 0);
141   }
142 
143   HWND window_;  // Plugin HWND, created and destroyed in the plugin process.
144   HWND parent_;  // Parent HWND, created and destroyed on the browser UI thread.
145 
146   int tries_;
147 
148   // How many times we try to find a PluginProcessHost whose process matches
149   // the HWND.
150   static const int kMaxTries = 5;
151   // How long to wait between each try.
152   static const int kTryDelayMs = 200;
153 };
154 
155 // Windows callback for OnDestroy to detach the plugin windows.
DetachPluginWindowsCallback(HWND window,LPARAM param)156 BOOL CALLBACK DetachPluginWindowsCallback(HWND window, LPARAM param) {
157   if (webkit::npapi::WebPluginDelegateImpl::IsPluginDelegateWindow(window) &&
158       !IsHungAppWindow(window)) {
159     ::ShowWindow(window, SW_HIDE);
160     SetParent(window, NULL);
161   }
162   return TRUE;
163 }
164 
165 // Draw the contents of |backing_store_dc| onto |paint_rect| with a 70% grey
166 // filter.
DrawDeemphasized(const SkColor & color,const gfx::Rect & paint_rect,HDC backing_store_dc,HDC paint_dc)167 void DrawDeemphasized(const SkColor& color,
168                       const gfx::Rect& paint_rect,
169                       HDC backing_store_dc,
170                       HDC paint_dc) {
171   gfx::CanvasSkia canvas(paint_rect.width(), paint_rect.height(), true);
172   HDC dc = canvas.beginPlatformPaint();
173   BitBlt(dc,
174          0,
175          0,
176          paint_rect.width(),
177          paint_rect.height(),
178          backing_store_dc,
179          paint_rect.x(),
180          paint_rect.y(),
181          SRCCOPY);
182   canvas.endPlatformPaint();
183   canvas.FillRectInt(color, 0, 0, paint_rect.width(), paint_rect.height());
184   canvas.getTopPlatformDevice().drawToHDC(paint_dc, paint_rect.x(),
185                                           paint_rect.y(), NULL);
186 }
187 
188 // The plugin wrapper window which lives in the browser process has this proc
189 // as its window procedure. We only handle the WM_PARENTNOTIFY message sent by
190 // windowed plugins for mouse input. This is forwarded off to the wrappers
191 // parent which is typically the RVH window which turns on user gesture.
PluginWrapperWindowProc(HWND window,unsigned int message,WPARAM wparam,LPARAM lparam)192 LRESULT CALLBACK PluginWrapperWindowProc(HWND window, unsigned int message,
193                                          WPARAM wparam, LPARAM lparam) {
194   if (message == WM_PARENTNOTIFY) {
195     switch (LOWORD(wparam)) {
196       case WM_LBUTTONDOWN:
197       case WM_RBUTTONDOWN:
198       case WM_MBUTTONDOWN:
199         ::SendMessage(GetParent(window), message, wparam, lparam);
200         return 0;
201       default:
202         break;
203     }
204   }
205   return ::DefWindowProc(window, message, wparam, lparam);
206 }
207 
208 }  // namespace
209 
210 // RenderWidgetHostView --------------------------------------------------------
211 
212 // static
CreateViewForWidget(RenderWidgetHost * widget)213 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
214     RenderWidgetHost* widget) {
215   return new RenderWidgetHostViewWin(widget);
216 }
217 
218 ///////////////////////////////////////////////////////////////////////////////
219 // RenderWidgetHostViewWin, public:
220 
RenderWidgetHostViewWin(RenderWidgetHost * widget)221 RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget)
222     : render_widget_host_(widget),
223       compositor_host_window_(NULL),
224       hide_compositor_window_at_next_paint_(false),
225       track_mouse_leave_(false),
226       ime_notification_(false),
227       capture_enter_key_(false),
228       is_hidden_(false),
229       about_to_validate_and_paint_(false),
230       close_on_deactivate_(false),
231       being_destroyed_(false),
232       tooltip_hwnd_(NULL),
233       tooltip_showing_(false),
234       shutdown_factory_(this),
235       parent_hwnd_(NULL),
236       is_loading_(false),
237       overlay_color_(0),
238       text_input_type_(WebKit::WebTextInputTypeNone) {
239   render_widget_host_->set_view(this);
240   registrar_.Add(this,
241                  NotificationType::RENDERER_PROCESS_TERMINATED,
242                  NotificationService::AllSources());
243 }
244 
~RenderWidgetHostViewWin()245 RenderWidgetHostViewWin::~RenderWidgetHostViewWin() {
246   ResetTooltip();
247 }
248 
CreateWnd(HWND parent)249 void RenderWidgetHostViewWin::CreateWnd(HWND parent) {
250   Create(parent);  // ATL function to create the window.
251 }
252 
253 ///////////////////////////////////////////////////////////////////////////////
254 // RenderWidgetHostViewWin, RenderWidgetHostView implementation:
255 
InitAsPopup(RenderWidgetHostView * parent_host_view,const gfx::Rect & pos)256 void RenderWidgetHostViewWin::InitAsPopup(
257     RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
258   parent_hwnd_ = parent_host_view->GetNativeView();
259   close_on_deactivate_ = true;
260   Create(parent_hwnd_, NULL, NULL, WS_POPUP, WS_EX_TOOLWINDOW);
261   MoveWindow(pos.x(), pos.y(), pos.width(), pos.height(), TRUE);
262   // Popups are not activated.
263   ShowWindow(IsActivatable() ? SW_SHOW : SW_SHOWNA);
264 }
265 
InitAsFullscreen()266 void RenderWidgetHostViewWin::InitAsFullscreen() {
267   NOTIMPLEMENTED() << "Fullscreen not implemented on Win";
268 }
269 
GetRenderWidgetHost() const270 RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const {
271   return render_widget_host_;
272 }
273 
DidBecomeSelected()274 void RenderWidgetHostViewWin::DidBecomeSelected() {
275   if (!is_hidden_)
276     return;
277 
278   if (tab_switch_paint_time_.is_null())
279     tab_switch_paint_time_ = TimeTicks::Now();
280   is_hidden_ = false;
281   EnsureTooltip();
282   render_widget_host_->WasRestored();
283 }
284 
WasHidden()285 void RenderWidgetHostViewWin::WasHidden() {
286   if (is_hidden_)
287     return;
288 
289   // If we receive any more paint messages while we are hidden, we want to
290   // ignore them so we don't re-allocate the backing store.  We will paint
291   // everything again when we become selected again.
292   is_hidden_ = true;
293 
294   ResetTooltip();
295 
296   // If we have a renderer, then inform it that we are being hidden so it can
297   // reduce its resource utilization.
298   render_widget_host_->WasHidden();
299 
300   // TODO(darin): what about constrained windows?  it doesn't look like they
301   // see a message when their parent is hidden.  maybe there is something more
302   // generic we can do at the TabContents API level instead of relying on
303   // Windows messages.
304 }
305 
SetSize(const gfx::Size & size)306 void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) {
307   SetBounds(gfx::Rect(GetViewBounds().origin(), size));
308 }
309 
SetBounds(const gfx::Rect & rect)310 void RenderWidgetHostViewWin::SetBounds(const gfx::Rect& rect) {
311   if (is_hidden_)
312     return;
313 
314   // No SWP_NOREDRAW as autofill popups can move and the underneath window
315   // should redraw in that case.
316   UINT swp_flags = SWP_NOSENDCHANGING | SWP_NOOWNERZORDER | SWP_NOCOPYBITS |
317       SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE;
318 
319   // If the style is not popup, you have to convert the point to client
320   // coordinate.
321   POINT point = { rect.x(), rect.y() };
322   if (GetStyle() & WS_CHILD)
323     ScreenToClient(&point);
324 
325   SetWindowPos(NULL, point.x, point.y, rect.width(), rect.height(), swp_flags);
326   render_widget_host_->WasResized();
327   EnsureTooltip();
328 }
329 
GetNativeView()330 gfx::NativeView RenderWidgetHostViewWin::GetNativeView() {
331   return m_hWnd;
332 }
333 
MovePluginWindows(const std::vector<WebPluginGeometry> & plugin_window_moves)334 void RenderWidgetHostViewWin::MovePluginWindows(
335     const std::vector<WebPluginGeometry>& plugin_window_moves) {
336   if (plugin_window_moves.empty())
337     return;
338 
339   bool oop_plugins =
340     !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) &&
341     !CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessPlugins);
342 
343   HDWP defer_window_pos_info =
344       ::BeginDeferWindowPos(static_cast<int>(plugin_window_moves.size()));
345 
346   if (!defer_window_pos_info) {
347     NOTREACHED();
348     return;
349   }
350 
351   for (size_t i = 0; i < plugin_window_moves.size(); ++i) {
352     unsigned long flags = 0;
353     const WebPluginGeometry& move = plugin_window_moves[i];
354     HWND window = move.window;
355 
356     // As the plugin parent window which lives on the browser UI thread is
357     // destroyed asynchronously, it is possible that we have a stale window
358     // sent in by the renderer for moving around.
359     // Note: get the parent before checking if the window is valid, to avoid a
360     // race condition where the window is destroyed after the check but before
361     // the GetParent call.
362     HWND parent = ::GetParent(window);
363     if (!::IsWindow(window))
364       continue;
365 
366     if (oop_plugins) {
367       if (parent == m_hWnd) {
368         // The plugin window is a direct child of this window, add an
369         // intermediate window that lives on this thread to speed up scrolling.
370         // Note this only works with out of process plugins since we depend on
371         // PluginProcessHost to destroy the intermediate HWNDs.
372         parent = ReparentWindow(window);
373         ::ShowWindow(window, SW_SHOW);  // Window was created hidden.
374       } else if (::GetParent(parent) != m_hWnd) {
375         // The renderer should only be trying to move windows that are children
376         // of its render widget window. However, this may happen as a result of
377         // a race condition, so we ignore it and not kill the plugin process.
378         continue;
379       }
380 
381       // We move the intermediate parent window which doesn't result in cross-
382       // process synchronous Windows messages.
383       window = parent;
384     }
385 
386     if (move.visible)
387       flags |= SWP_SHOWWINDOW;
388     else
389       flags |= SWP_HIDEWINDOW;
390 
391     if (move.rects_valid) {
392       HRGN hrgn = ::CreateRectRgn(move.clip_rect.x(),
393                                   move.clip_rect.y(),
394                                   move.clip_rect.right(),
395                                   move.clip_rect.bottom());
396       gfx::SubtractRectanglesFromRegion(hrgn, move.cutout_rects);
397 
398       // Note: System will own the hrgn after we call SetWindowRgn,
399       // so we don't need to call DeleteObject(hrgn)
400       ::SetWindowRgn(window, hrgn, !move.clip_rect.IsEmpty());
401     } else {
402       flags |= SWP_NOMOVE;
403       flags |= SWP_NOSIZE;
404     }
405 
406     defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info,
407                                              window, NULL,
408                                              move.window_rect.x(),
409                                              move.window_rect.y(),
410                                              move.window_rect.width(),
411                                              move.window_rect.height(), flags);
412     if (!defer_window_pos_info) {
413       DCHECK(false) << "DeferWindowPos failed, so all plugin moves ignored.";
414       return;
415     }
416   }
417 
418   ::EndDeferWindowPos(defer_window_pos_info);
419 }
420 
ReparentWindow(HWND window)421 HWND RenderWidgetHostViewWin::ReparentWindow(HWND window) {
422   static ATOM window_class = 0;
423   if (!window_class) {
424     WNDCLASSEX wcex;
425     wcex.cbSize         = sizeof(WNDCLASSEX);
426     wcex.style          = CS_DBLCLKS;
427     wcex.lpfnWndProc    = base::win::WrappedWindowProc<PluginWrapperWindowProc>;
428     wcex.cbClsExtra     = 0;
429     wcex.cbWndExtra     = 0;
430     wcex.hInstance      = GetModuleHandle(NULL);
431     wcex.hIcon          = 0;
432     wcex.hCursor        = 0;
433     wcex.hbrBackground  = reinterpret_cast<HBRUSH>(COLOR_WINDOW+1);
434     wcex.lpszMenuName   = 0;
435     wcex.lpszClassName  = webkit::npapi::kWrapperNativeWindowClassName;
436     wcex.hIconSm        = 0;
437     window_class = RegisterClassEx(&wcex);
438   }
439   DCHECK(window_class);
440 
441   HWND parent = CreateWindowEx(
442       WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
443       MAKEINTATOM(window_class), 0,
444       WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
445       0, 0, 0, 0, ::GetParent(window), 0, GetModuleHandle(NULL), 0);
446   ui::CheckWindowCreated(parent);
447   ::SetParent(window, parent);
448   BrowserThread::PostTask(
449       BrowserThread::IO, FROM_HERE,
450       new NotifyPluginProcessHostTask(window, parent));
451   return parent;
452 }
453 
AddChildWindowToVector(HWND hwnd,LPARAM lparam)454 static BOOL CALLBACK AddChildWindowToVector(HWND hwnd, LPARAM lparam) {
455   std::vector<HWND>* vector = reinterpret_cast<std::vector<HWND>*>(lparam);
456   vector->push_back(hwnd);
457   return TRUE;
458 }
459 
CleanupCompositorWindow()460 void RenderWidgetHostViewWin::CleanupCompositorWindow() {
461   if (!compositor_host_window_)
462     return;
463 
464   // Hide the compositor and parent it to the desktop rather than destroying
465   // it immediately. The GPU process has a grace period to stop accessing the
466   // window. TODO(apatrick): the GPU process should acknowledge that it has
467   // finished with the window handle and the browser process should destroy it
468   // at that point.
469   ::ShowWindow(compositor_host_window_, SW_HIDE);
470   ::SetParent(compositor_host_window_, NULL);
471 
472   BrowserThread::PostDelayedTask(
473       BrowserThread::UI,
474       FROM_HERE,
475       NewRunnableFunction(::DestroyWindow, compositor_host_window_),
476       kDestroyCompositorHostWindowDelay);
477 
478   compositor_host_window_ = NULL;
479 }
480 
IsActivatable() const481 bool RenderWidgetHostViewWin::IsActivatable() const {
482   // Popups should not be activated.
483   return popup_type_ == WebKit::WebPopupTypeNone;
484 }
485 
Focus()486 void RenderWidgetHostViewWin::Focus() {
487   if (IsWindow())
488     SetFocus();
489 }
490 
Blur()491 void RenderWidgetHostViewWin::Blur() {
492   views::FocusManager* focus_manager =
493       views::FocusManager::GetFocusManagerForNativeView(m_hWnd);
494   // We don't have a FocusManager if we are hidden.
495   if (focus_manager)
496     focus_manager->ClearFocus();
497 }
498 
HasFocus()499 bool RenderWidgetHostViewWin::HasFocus() {
500   return ::GetFocus() == m_hWnd;
501 }
502 
Show()503 void RenderWidgetHostViewWin::Show() {
504   DCHECK(parent_hwnd_);
505   DCHECK(parent_hwnd_ != GetDesktopWindow());
506   SetParent(parent_hwnd_);
507   ShowWindow(SW_SHOW);
508 
509   // Save away our HWND in the parent window as a property so that the
510   // accessibility code can find it.
511   accessibility_prop_.reset(new ViewProp(
512       GetParent(),
513       views::kViewsNativeHostPropForAccessibility,
514       m_hWnd));
515 
516   DidBecomeSelected();
517 }
518 
Hide()519 void RenderWidgetHostViewWin::Hide() {
520   if (GetParent() == GetDesktopWindow()) {
521     LOG(WARNING) << "Hide() called twice in a row: " << this << ":" <<
522         parent_hwnd_ << ":" << GetParent();
523     return;
524   }
525 
526   accessibility_prop_.reset();
527 
528   if (::GetFocus() == m_hWnd)
529     ::SetFocus(NULL);
530   ShowWindow(SW_HIDE);
531 
532   // Cache the old parent, then orphan the window so we stop receiving messages
533   parent_hwnd_ = GetParent();
534   SetParent(NULL);
535 
536   WasHidden();
537 }
538 
IsShowing()539 bool RenderWidgetHostViewWin::IsShowing() {
540   return !!IsWindowVisible();
541 }
542 
GetViewBounds() const543 gfx::Rect RenderWidgetHostViewWin::GetViewBounds() const {
544   CRect window_rect;
545   GetWindowRect(&window_rect);
546   return gfx::Rect(window_rect);
547 }
548 
UpdateCursor(const WebCursor & cursor)549 void RenderWidgetHostViewWin::UpdateCursor(const WebCursor& cursor) {
550   current_cursor_ = cursor;
551   UpdateCursorIfOverSelf();
552 }
553 
UpdateCursorIfOverSelf()554 void RenderWidgetHostViewWin::UpdateCursorIfOverSelf() {
555   static HCURSOR kCursorArrow = LoadCursor(NULL, IDC_ARROW);
556   static HCURSOR kCursorAppStarting = LoadCursor(NULL, IDC_APPSTARTING);
557   static HINSTANCE module_handle =
558       GetModuleHandle(chrome::kBrowserResourcesDll);
559 
560   // If the mouse is over our HWND, then update the cursor state immediately.
561   CPoint pt;
562   GetCursorPos(&pt);
563   if (WindowFromPoint(pt) == m_hWnd) {
564     BOOL result = ::ScreenToClient(m_hWnd, &pt);
565     DCHECK(result);
566     // We cannot pass in NULL as the module handle as this would only work for
567     // standard win32 cursors. We can also receive cursor types which are
568     // defined as webkit resources. We need to specify the module handle of
569     // chrome.dll while loading these cursors.
570     HCURSOR display_cursor = current_cursor_.GetCursor(module_handle);
571 
572     // If a page is in the loading state, we want to show the Arrow+Hourglass
573     // cursor only when the current cursor is the ARROW cursor. In all other
574     // cases we should continue to display the current cursor.
575     if (is_loading_ && display_cursor == kCursorArrow)
576       display_cursor = kCursorAppStarting;
577 
578     SetCursor(display_cursor);
579   }
580 }
581 
SetIsLoading(bool is_loading)582 void RenderWidgetHostViewWin::SetIsLoading(bool is_loading) {
583   is_loading_ = is_loading;
584   UpdateCursorIfOverSelf();
585 }
586 
ImeUpdateTextInputState(WebKit::WebTextInputType type,const gfx::Rect & caret_rect)587 void RenderWidgetHostViewWin::ImeUpdateTextInputState(
588     WebKit::WebTextInputType type,
589     const gfx::Rect& caret_rect) {
590   if (text_input_type_ != type) {
591     text_input_type_ = type;
592     if (type == WebKit::WebTextInputTypeText)
593       ime_input_.EnableIME(m_hWnd);
594     else
595       ime_input_.DisableIME(m_hWnd);
596   }
597 
598   // Only update caret position if the input method is enabled.
599   if (type == WebKit::WebTextInputTypeText)
600     ime_input_.UpdateCaretRect(m_hWnd, caret_rect);
601 }
602 
ImeCancelComposition()603 void RenderWidgetHostViewWin::ImeCancelComposition() {
604   ime_input_.CancelIME(m_hWnd);
605 }
606 
EnumChildProc(HWND hwnd,LPARAM lparam)607 BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam) {
608   if (!webkit::npapi::WebPluginDelegateImpl::IsPluginDelegateWindow(hwnd))
609     return TRUE;
610 
611   gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam);
612   static UINT msg = RegisterWindowMessage(webkit::npapi::kPaintMessageName);
613   WPARAM wparam = rect->x() << 16 | rect->y();
614   lparam = rect->width() << 16 | rect->height();
615 
616   // SendMessage gets the message across much quicker than PostMessage, since it
617   // doesn't get queued.  When the plugin thread calls PeekMessage or other
618   // Win32 APIs, sent messages are dispatched automatically.
619   SendNotifyMessage(hwnd, msg, wparam, lparam);
620 
621   return TRUE;
622 }
623 
Redraw()624 void RenderWidgetHostViewWin::Redraw() {
625   RECT damage_bounds;
626   GetUpdateRect(&damage_bounds, FALSE);
627 
628   base::win::ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
629   GetUpdateRgn(damage_region, FALSE);
630 
631   // Paint the invalid region synchronously.  Our caller will not paint again
632   // until we return, so by painting to the screen here, we ensure effective
633   // rate-limiting of backing store updates.  This helps a lot on pages that
634   // have animations or fairly expensive layout (e.g., google maps).
635   //
636   // We paint this window synchronously, however child windows (i.e. plugins)
637   // are painted asynchronously.  By avoiding synchronous cross-process window
638   // message dispatching we allow scrolling to be smooth, and also avoid the
639   // browser process locking up if the plugin process is hung.
640   //
641   RedrawWindow(NULL, damage_region, RDW_UPDATENOW | RDW_NOCHILDREN);
642 
643   // Send the invalid rect in screen coordinates.
644   gfx::Rect screen_rect = GetViewBounds();
645   gfx::Rect invalid_screen_rect(damage_bounds);
646   invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y());
647 
648   LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect);
649   EnumChildWindows(m_hWnd, EnumChildProc, lparam);
650 }
651 
DidUpdateBackingStore(const gfx::Rect & scroll_rect,int scroll_dx,int scroll_dy,const std::vector<gfx::Rect> & copy_rects)652 void RenderWidgetHostViewWin::DidUpdateBackingStore(
653     const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
654     const std::vector<gfx::Rect>& copy_rects) {
655   if (is_hidden_)
656     return;
657 
658   // Schedule invalidations first so that the ScrollWindowEx call is closer to
659   // Redraw.  That minimizes chances of "flicker" resulting if the screen
660   // refreshes before we have a chance to paint the exposed area.  Somewhat
661   // surprisingly, this ordering matters.
662 
663   for (size_t i = 0; i < copy_rects.size(); ++i)
664     InvalidateRect(&copy_rects[i].ToRECT(), false);
665 
666   if (!scroll_rect.IsEmpty()) {
667     RECT clip_rect = scroll_rect.ToRECT();
668     ScrollWindowEx(scroll_dx, scroll_dy, NULL, &clip_rect, NULL, NULL,
669                    SW_INVALIDATE);
670   }
671 
672   if (!about_to_validate_and_paint_)
673     Redraw();
674 }
675 
RenderViewGone(base::TerminationStatus status,int error_code)676 void RenderWidgetHostViewWin::RenderViewGone(base::TerminationStatus status,
677                                              int error_code) {
678   // TODO(darin): keep this around, and draw sad-tab into it.
679   UpdateCursorIfOverSelf();
680   being_destroyed_ = true;
681   CleanupCompositorWindow();
682   DestroyWindow();
683 }
684 
WillWmDestroy()685 void RenderWidgetHostViewWin::WillWmDestroy() {
686   CleanupCompositorWindow();
687 }
688 
WillDestroyRenderWidget(RenderWidgetHost * rwh)689 void RenderWidgetHostViewWin::WillDestroyRenderWidget(RenderWidgetHost* rwh) {
690   if (rwh == render_widget_host_)
691     render_widget_host_ = NULL;
692 }
693 
Destroy()694 void RenderWidgetHostViewWin::Destroy() {
695   // We've been told to destroy.
696   // By clearing close_on_deactivate_, we prevent further deactivations
697   // (caused by windows messages resulting from the DestroyWindow) from
698   // triggering further destructions.  The deletion of this is handled by
699   // OnFinalMessage();
700   close_on_deactivate_ = false;
701   being_destroyed_ = true;
702   CleanupCompositorWindow();
703   DestroyWindow();
704 }
705 
SetTooltipText(const std::wstring & tooltip_text)706 void RenderWidgetHostViewWin::SetTooltipText(const std::wstring& tooltip_text) {
707   // Clamp the tooltip length to kMaxTooltipLength so that we don't
708   // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
709   // to do this itself).
710   const std::wstring& new_tooltip_text =
711       l10n_util::TruncateString(tooltip_text, kMaxTooltipLength);
712 
713   if (new_tooltip_text != tooltip_text_) {
714     tooltip_text_ = new_tooltip_text;
715 
716     // Need to check if the tooltip is already showing so that we don't
717     // immediately show the tooltip with no delay when we move the mouse from
718     // a region with no tooltip to a region with a tooltip.
719     if (::IsWindow(tooltip_hwnd_) && tooltip_showing_) {
720       ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
721       ::SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
722     }
723   } else {
724     // Make sure the tooltip gets closed after TTN_POP gets sent. For some
725     // reason this doesn't happen automatically, so moving the mouse around
726     // within the same link/image/etc doesn't cause the tooltip to re-appear.
727     if (!tooltip_showing_) {
728       if (::IsWindow(tooltip_hwnd_))
729         ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
730     }
731   }
732 }
733 
AllocBackingStore(const gfx::Size & size)734 BackingStore* RenderWidgetHostViewWin::AllocBackingStore(
735     const gfx::Size& size) {
736   return new BackingStoreWin(render_widget_host_, size);
737 }
738 
SetBackground(const SkBitmap & background)739 void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) {
740   RenderWidgetHostView::SetBackground(background);
741   Send(new ViewMsg_SetBackground(render_widget_host_->routing_id(),
742                                  background));
743 }
744 
ContainsNativeView(gfx::NativeView native_view) const745 bool RenderWidgetHostViewWin::ContainsNativeView(
746     gfx::NativeView native_view) const {
747   if (m_hWnd == native_view)
748     return true;
749 
750   // Traverse the set of parents of the given view to determine if native_view
751   // is a descendant of this window.
752   HWND parent_window = ::GetParent(native_view);
753   while (parent_window) {
754     if (parent_window == m_hWnd)
755       return true;
756     parent_window = ::GetParent(parent_window);
757   }
758 
759   return false;
760 }
761 
SetVisuallyDeemphasized(const SkColor * color,bool animate)762 void RenderWidgetHostViewWin::SetVisuallyDeemphasized(const SkColor* color,
763                                                       bool animate) {
764   // |animate| is not yet implemented, and currently isn't used.
765   CHECK(!animate);
766 
767   SkColor overlay_color = color ? *color : 0;
768   if (overlay_color_ == overlay_color)
769     return;
770   overlay_color_ = overlay_color;
771 
772   InvalidateRect(NULL, FALSE);
773 }
774 
775 ///////////////////////////////////////////////////////////////////////////////
776 // RenderWidgetHostViewWin, private:
777 
OnCreate(CREATESTRUCT * create_struct)778 LRESULT RenderWidgetHostViewWin::OnCreate(CREATESTRUCT* create_struct) {
779   // Call the WM_INPUTLANGCHANGE message handler to initialize the input locale
780   // of a browser process.
781   OnInputLangChange(0, 0);
782   // Marks that window as supporting mouse-wheel messages rerouting so it is
783   // scrolled when under the mouse pointer even if inactive.
784   props_.push_back(views::SetWindowSupportsRerouteMouseWheel(m_hWnd));
785   props_.push_back(new ViewProp(m_hWnd, kRenderWidgetHostViewKey,
786                                 static_cast<RenderWidgetHostView*>(this)));
787   // Save away our HWND in the parent window as a property so that the
788   // accessibility code can find it.
789   accessibility_prop_.reset(new ViewProp(
790       GetParent(),
791       views::kViewsNativeHostPropForAccessibility,
792       m_hWnd));
793 
794   return 0;
795 }
796 
OnActivate(UINT action,BOOL minimized,HWND window)797 void RenderWidgetHostViewWin::OnActivate(UINT action, BOOL minimized,
798                                          HWND window) {
799   // If the container is a popup, clicking elsewhere on screen should close the
800   // popup.
801   if (close_on_deactivate_ && action == WA_INACTIVE) {
802     // Send a windows message so that any derived classes
803     // will get a change to override the default handling
804     SendMessage(WM_CANCELMODE);
805   }
806 }
807 
OnDestroy()808 void RenderWidgetHostViewWin::OnDestroy() {
809   // When a tab is closed all its child plugin windows are destroyed
810   // automatically. This happens before plugins get any notification that its
811   // instances are tearing down.
812   //
813   // Plugins like Quicktime assume that their windows will remain valid as long
814   // as they have plugin instances active. Quicktime crashes in this case
815   // because its windowing code cleans up an internal data structure that the
816   // handler for NPP_DestroyStream relies on.
817   //
818   // The fix is to detach plugin windows from web contents when it is going
819   // away. This will prevent the plugin windows from getting destroyed
820   // automatically. The detached plugin windows will get cleaned up in proper
821   // sequence as part of the usual cleanup when the plugin instance goes away.
822   EnumChildWindows(m_hWnd, DetachPluginWindowsCallback, NULL);
823 
824   props_.reset();
825 
826   CleanupCompositorWindow();
827 
828   ResetTooltip();
829   TrackMouseLeave(false);
830 }
831 
OnPaint(HDC unused_dc)832 void RenderWidgetHostViewWin::OnPaint(HDC unused_dc) {
833   DCHECK(render_widget_host_->process()->HasConnection());
834 
835   // If the GPU process is rendering directly into the View,
836   // call the compositor directly.
837   RenderWidgetHost* render_widget_host = GetRenderWidgetHost();
838   if (render_widget_host->is_accelerated_compositing_active()) {
839     // We initialize paint_dc here so that BeginPaint()/EndPaint()
840     // get called to validate the region.
841     CPaintDC paint_dc(m_hWnd);
842     render_widget_host_->ScheduleComposite();
843     return;
844   }
845 
846   about_to_validate_and_paint_ = true;
847   BackingStoreWin* backing_store = static_cast<BackingStoreWin*>(
848       render_widget_host_->GetBackingStore(true));
849 
850   // We initialize |paint_dc| (and thus call BeginPaint()) after calling
851   // GetBackingStore(), so that if it updates the invalid rect we'll catch the
852   // changes and repaint them.
853   about_to_validate_and_paint_ = false;
854 
855   // Grab the region to paint before creation of paint_dc since it clears the
856   // damage region.
857   base::win::ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
858   GetUpdateRgn(damage_region, FALSE);
859 
860   if (hide_compositor_window_at_next_paint_) {
861     ::ShowWindow(compositor_host_window_, SW_HIDE);
862     hide_compositor_window_at_next_paint_ = false;
863   }
864 
865   CPaintDC paint_dc(m_hWnd);
866 
867   gfx::Rect damaged_rect(paint_dc.m_ps.rcPaint);
868   if (damaged_rect.IsEmpty())
869     return;
870 
871   if (backing_store) {
872     gfx::Rect bitmap_rect(gfx::Point(), backing_store->size());
873 
874     bool manage_colors = BackingStoreWin::ColorManagementEnabled();
875     if (manage_colors)
876       SetICMMode(paint_dc.m_hDC, ICM_ON);
877 
878     // Blit only the damaged regions from the backing store.
879     DWORD data_size = GetRegionData(damage_region, 0, NULL);
880     scoped_array<char> region_data_buf(new char[data_size]);
881     RGNDATA* region_data = reinterpret_cast<RGNDATA*>(region_data_buf.get());
882     GetRegionData(damage_region, data_size, region_data);
883 
884     RECT* region_rects = reinterpret_cast<RECT*>(region_data->Buffer);
885     for (DWORD i = 0; i < region_data->rdh.nCount; ++i) {
886       gfx::Rect paint_rect = bitmap_rect.Intersect(gfx::Rect(region_rects[i]));
887       if (!paint_rect.IsEmpty()) {
888         if (SkColorGetA(overlay_color_) > 0) {
889           DrawDeemphasized(overlay_color_,
890                            paint_rect,
891                            backing_store->hdc(),
892                            paint_dc.m_hDC);
893         } else {
894           BitBlt(paint_dc.m_hDC,
895                  paint_rect.x(),
896                  paint_rect.y(),
897                  paint_rect.width(),
898                  paint_rect.height(),
899                  backing_store->hdc(),
900                  paint_rect.x(),
901                  paint_rect.y(),
902                  SRCCOPY);
903         }
904       }
905     }
906 
907     if (manage_colors)
908       SetICMMode(paint_dc.m_hDC, ICM_OFF);
909 
910     // Fill the remaining portion of the damaged_rect with the background
911     if (damaged_rect.right() > bitmap_rect.right()) {
912       RECT r;
913       r.left = std::max(bitmap_rect.right(), damaged_rect.x());
914       r.right = damaged_rect.right();
915       r.top = damaged_rect.y();
916       r.bottom = std::min(bitmap_rect.bottom(), damaged_rect.bottom());
917       DrawBackground(r, &paint_dc);
918     }
919     if (damaged_rect.bottom() > bitmap_rect.bottom()) {
920       RECT r;
921       r.left = damaged_rect.x();
922       r.right = damaged_rect.right();
923       r.top = std::max(bitmap_rect.bottom(), damaged_rect.y());
924       r.bottom = damaged_rect.bottom();
925       DrawBackground(r, &paint_dc);
926     }
927     if (!whiteout_start_time_.is_null()) {
928       TimeDelta whiteout_duration = TimeTicks::Now() - whiteout_start_time_;
929       UMA_HISTOGRAM_TIMES("MPArch.RWHH_WhiteoutDuration", whiteout_duration);
930 
931       // Reset the start time to 0 so that we start recording again the next
932       // time the backing store is NULL...
933       whiteout_start_time_ = TimeTicks();
934     }
935     if (!tab_switch_paint_time_.is_null()) {
936       TimeDelta tab_switch_paint_duration = TimeTicks::Now() -
937           tab_switch_paint_time_;
938       UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration",
939           tab_switch_paint_duration);
940       // Reset tab_switch_paint_time_ to 0 so future tab selections are
941       // recorded.
942       tab_switch_paint_time_ = TimeTicks();
943     }
944   } else {
945     DrawBackground(paint_dc.m_ps.rcPaint, &paint_dc);
946     if (whiteout_start_time_.is_null())
947       whiteout_start_time_ = TimeTicks::Now();
948   }
949 }
950 
DrawBackground(const RECT & dirty_rect,CPaintDC * dc)951 void RenderWidgetHostViewWin::DrawBackground(const RECT& dirty_rect,
952                                              CPaintDC* dc) {
953   if (!background_.empty()) {
954     gfx::CanvasSkia canvas(dirty_rect.right - dirty_rect.left,
955                            dirty_rect.bottom - dirty_rect.top,
956                            true);  // opaque
957     canvas.TranslateInt(-dirty_rect.left, -dirty_rect.top);
958 
959     const RECT& dc_rect = dc->m_ps.rcPaint;
960     canvas.TileImageInt(background_, 0, 0,
961                         dc_rect.right - dc_rect.left,
962                         dc_rect.bottom - dc_rect.top);
963 
964     canvas.getTopPlatformDevice().drawToHDC(*dc, dirty_rect.left,
965                                             dirty_rect.top, NULL);
966   } else {
967     HBRUSH white_brush = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
968     dc->FillRect(&dirty_rect, white_brush);
969   }
970 }
971 
OnNCPaint(HRGN update_region)972 void RenderWidgetHostViewWin::OnNCPaint(HRGN update_region) {
973   // Do nothing.  This suppresses the resize corner that Windows would
974   // otherwise draw for us.
975 }
976 
OnEraseBkgnd(HDC dc)977 LRESULT RenderWidgetHostViewWin::OnEraseBkgnd(HDC dc) {
978   return 1;
979 }
980 
OnSetCursor(HWND window,UINT hittest_code,UINT mouse_message_id)981 LRESULT RenderWidgetHostViewWin::OnSetCursor(HWND window, UINT hittest_code,
982                                              UINT mouse_message_id) {
983   UpdateCursorIfOverSelf();
984   return 0;
985 }
986 
OnSetFocus(HWND window)987 void RenderWidgetHostViewWin::OnSetFocus(HWND window) {
988   views::FocusManager::GetWidgetFocusManager()->OnWidgetFocusEvent(window,
989                                                                    m_hWnd);
990   if (browser_accessibility_manager_.get())
991     browser_accessibility_manager_->GotFocus();
992   if (render_widget_host_)
993     render_widget_host_->GotFocus();
994 }
995 
OnKillFocus(HWND window)996 void RenderWidgetHostViewWin::OnKillFocus(HWND window) {
997   views::FocusManager::GetWidgetFocusManager()->OnWidgetFocusEvent(m_hWnd,
998                                                                    window);
999 
1000   if (render_widget_host_)
1001     render_widget_host_->Blur();
1002 }
1003 
OnCaptureChanged(HWND window)1004 void RenderWidgetHostViewWin::OnCaptureChanged(HWND window) {
1005   if (render_widget_host_)
1006     render_widget_host_->LostCapture();
1007 }
1008 
OnCancelMode()1009 void RenderWidgetHostViewWin::OnCancelMode() {
1010   if (render_widget_host_)
1011     render_widget_host_->LostCapture();
1012 
1013   if (close_on_deactivate_ && shutdown_factory_.empty()) {
1014     // Dismiss popups and menus.  We do this asynchronously to avoid changing
1015     // activation within this callstack, which may interfere with another window
1016     // being activated.  We can synchronously hide the window, but we need to
1017     // not change activation while doing so.
1018     SetWindowPos(NULL, 0, 0, 0, 0,
1019                  SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
1020                  SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
1021     MessageLoop::current()->PostTask(FROM_HERE,
1022         shutdown_factory_.NewRunnableMethod(
1023             &RenderWidgetHostViewWin::ShutdownHost));
1024   }
1025 }
1026 
OnInputLangChange(DWORD character_set,HKL input_language_id)1027 void RenderWidgetHostViewWin::OnInputLangChange(DWORD character_set,
1028                                                 HKL input_language_id) {
1029   // Send the given Locale ID to the ImeInput object and retrieves whether
1030   // or not the current input context has IMEs.
1031   // If the current input context has IMEs, a browser process has to send a
1032   // request to a renderer process that it needs status messages about
1033   // the focused edit control from the renderer process.
1034   // On the other hand, if the current input context does not have IMEs, the
1035   // browser process also has to send a request to the renderer process that
1036   // it does not need the status messages any longer.
1037   // To minimize the number of this notification request, we should check if
1038   // the browser process is actually retrieving the status messages (this
1039   // state is stored in ime_notification_) and send a request only if the
1040   // browser process has to update this status, its details are listed below:
1041   // * If a browser process is not retrieving the status messages,
1042   //   (i.e. ime_notification_ == false),
1043   //   send this request only if the input context does have IMEs,
1044   //   (i.e. ime_status == true);
1045   //   When it successfully sends the request, toggle its notification status,
1046   //   (i.e.ime_notification_ = !ime_notification_ = true).
1047   // * If a browser process is retrieving the status messages
1048   //   (i.e. ime_notification_ == true),
1049   //   send this request only if the input context does not have IMEs,
1050   //   (i.e. ime_status == false).
1051   //   When it successfully sends the request, toggle its notification status,
1052   //   (i.e.ime_notification_ = !ime_notification_ = false).
1053   // To analyze the above actions, we can optimize them into the ones
1054   // listed below:
1055   // 1 Sending a request only if ime_status_ != ime_notification_, and;
1056   // 2 Copying ime_status to ime_notification_ if it sends the request
1057   //   successfully (because Action 1 shows ime_status = !ime_notification_.)
1058   bool ime_status = ime_input_.SetInputLanguage();
1059   if (ime_status != ime_notification_) {
1060     if (render_widget_host_) {
1061       render_widget_host_->SetInputMethodActive(ime_status);
1062       ime_notification_ = ime_status;
1063     }
1064   }
1065 }
1066 
OnThemeChanged()1067 void RenderWidgetHostViewWin::OnThemeChanged() {
1068   if (render_widget_host_)
1069     render_widget_host_->SystemThemeChanged();
1070 }
1071 
OnNotify(int w_param,NMHDR * header)1072 LRESULT RenderWidgetHostViewWin::OnNotify(int w_param, NMHDR* header) {
1073   if (tooltip_hwnd_ == NULL)
1074     return 0;
1075 
1076   switch (header->code) {
1077     case TTN_GETDISPINFO: {
1078       NMTTDISPINFOW* tooltip_info = reinterpret_cast<NMTTDISPINFOW*>(header);
1079       tooltip_info->szText[0] = L'\0';
1080       tooltip_info->lpszText = const_cast<wchar_t*>(tooltip_text_.c_str());
1081       ::SendMessage(
1082         tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, kTooltipMaxWidthPixels);
1083       SetMsgHandled(TRUE);
1084       break;
1085                           }
1086     case TTN_POP:
1087       tooltip_showing_ = false;
1088       SetMsgHandled(TRUE);
1089       break;
1090     case TTN_SHOW:
1091       tooltip_showing_ = true;
1092       SetMsgHandled(TRUE);
1093       break;
1094   }
1095   return 0;
1096 }
1097 
OnImeSetContext(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1098 LRESULT RenderWidgetHostViewWin::OnImeSetContext(
1099     UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1100   if (!render_widget_host_)
1101     return 0;
1102 
1103   // We need status messages about the focused input control from a
1104   // renderer process when:
1105   //   * the current input context has IMEs, and;
1106   //   * an application is activated.
1107   // This seems to tell we should also check if the current input context has
1108   // IMEs before sending a request, however, this WM_IME_SETCONTEXT is
1109   // fortunately sent to an application only while the input context has IMEs.
1110   // Therefore, we just start/stop status messages according to the activation
1111   // status of this application without checks.
1112   bool activated = (wparam == TRUE);
1113   if (render_widget_host_) {
1114     render_widget_host_->SetInputMethodActive(activated);
1115     ime_notification_ = activated;
1116   }
1117 
1118   if (ime_notification_)
1119     ime_input_.CreateImeWindow(m_hWnd);
1120 
1121   ime_input_.CleanupComposition(m_hWnd);
1122   return ime_input_.SetImeWindowStyle(
1123       m_hWnd, message, wparam, lparam, &handled);
1124 }
1125 
OnImeStartComposition(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1126 LRESULT RenderWidgetHostViewWin::OnImeStartComposition(
1127     UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1128   if (!render_widget_host_)
1129     return 0;
1130 
1131   // Reset the composition status and create IME windows.
1132   ime_input_.CreateImeWindow(m_hWnd);
1133   ime_input_.ResetComposition(m_hWnd);
1134   // We have to prevent WTL from calling ::DefWindowProc() because the function
1135   // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
1136   // over-write the position of IME windows.
1137   handled = TRUE;
1138   return 0;
1139 }
1140 
OnImeComposition(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1141 LRESULT RenderWidgetHostViewWin::OnImeComposition(
1142     UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1143   if (!render_widget_host_)
1144     return 0;
1145 
1146   // At first, update the position of the IME window.
1147   ime_input_.UpdateImeWindow(m_hWnd);
1148 
1149   // ui::CompositionUnderline should be identical to
1150   // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely.
1151   COMPILE_ASSERT(sizeof(ui::CompositionUnderline) ==
1152                  sizeof(WebKit::WebCompositionUnderline),
1153                  ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff);
1154 
1155   // Retrieve the result string and its attributes of the ongoing composition
1156   // and send it to a renderer process.
1157   ui::CompositionText composition;
1158   if (ime_input_.GetResult(m_hWnd, lparam, &composition.text)) {
1159     render_widget_host_->ImeConfirmComposition(composition.text);
1160     ime_input_.ResetComposition(m_hWnd);
1161     // Fall though and try reading the composition string.
1162     // Japanese IMEs send a message containing both GCS_RESULTSTR and
1163     // GCS_COMPSTR, which means an ongoing composition has been finished
1164     // by the start of another composition.
1165   }
1166   // Retrieve the composition string and its attributes of the ongoing
1167   // composition and send it to a renderer process.
1168   if (ime_input_.GetComposition(m_hWnd, lparam, &composition)) {
1169     // TODO(suzhe): due to a bug of webkit, we can't use selection range with
1170     // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
1171     composition.selection = ui::Range(composition.selection.end());
1172 
1173     // TODO(suzhe): convert both renderer_host and renderer to use
1174     // ui::CompositionText.
1175     const std::vector<WebKit::WebCompositionUnderline>& underlines =
1176         reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>(
1177             composition.underlines);
1178     render_widget_host_->ImeSetComposition(
1179         composition.text, underlines,
1180         composition.selection.start(), composition.selection.end());
1181   }
1182   // We have to prevent WTL from calling ::DefWindowProc() because we do not
1183   // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
1184   handled = TRUE;
1185   return 0;
1186 }
1187 
OnImeEndComposition(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1188 LRESULT RenderWidgetHostViewWin::OnImeEndComposition(
1189     UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1190   if (!render_widget_host_)
1191     return 0;
1192 
1193   if (ime_input_.is_composing()) {
1194     // A composition has been ended while there is an ongoing composition,
1195     // i.e. the ongoing composition has been canceled.
1196     // We need to reset the composition status both of the ImeInput object and
1197     // of the renderer process.
1198     render_widget_host_->ImeCancelComposition();
1199     ime_input_.ResetComposition(m_hWnd);
1200   }
1201   ime_input_.DestroyImeWindow(m_hWnd);
1202   // Let WTL call ::DefWindowProc() and release its resources.
1203   handled = FALSE;
1204   return 0;
1205 }
1206 
OnMouseEvent(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1207 LRESULT RenderWidgetHostViewWin::OnMouseEvent(UINT message, WPARAM wparam,
1208                                               LPARAM lparam, BOOL& handled) {
1209   handled = TRUE;
1210 
1211   if (::IsWindow(tooltip_hwnd_)) {
1212     // Forward mouse events through to the tooltip window
1213     MSG msg;
1214     msg.hwnd = m_hWnd;
1215     msg.message = message;
1216     msg.wParam = wparam;
1217     msg.lParam = lparam;
1218     SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, NULL,
1219                 reinterpret_cast<LPARAM>(&msg));
1220   }
1221 
1222   // TODO(jcampan): I am not sure if we should forward the message to the
1223   // TabContents first in the case of popups.  If we do, we would need to
1224   // convert the click from the popup window coordinates to the TabContents'
1225   // window coordinates. For now we don't forward the message in that case to
1226   // address bug #907474.
1227   // Note: GetParent() on popup windows returns the top window and not the
1228   // parent the window was created with (the parent and the owner of the popup
1229   // is the first non-child view of the view that was specified to the create
1230   // call).  So the TabContents window would have to be specified to the
1231   // RenderViewHostHWND as there is no way to retrieve it from the HWND.
1232   if (!close_on_deactivate_) {  // Don't forward if the container is a popup.
1233     switch (message) {
1234       case WM_LBUTTONDOWN:
1235       case WM_MBUTTONDOWN:
1236       case WM_RBUTTONDOWN:
1237         // Finish the ongoing composition whenever a mouse click happens.
1238         // It matches IE's behavior.
1239         ime_input_.CleanupComposition(m_hWnd);
1240         // Fall through.
1241       case WM_MOUSEMOVE:
1242       case WM_MOUSELEAVE: {
1243         // Give the TabContents first crack at the message. It may want to
1244         // prevent forwarding to the renderer if some higher level browser
1245         // functionality is invoked.
1246         LPARAM parent_msg_lparam = lparam;
1247         if (message != WM_MOUSELEAVE) {
1248           // For the messages except WM_MOUSELEAVE, before forwarding them to
1249           // parent window, we should adjust cursor position from client
1250           // coordinates in current window to client coordinates in its parent
1251           // window.
1252           CPoint cursor_pos(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
1253           ClientToScreen(&cursor_pos);
1254           GetParent().ScreenToClient(&cursor_pos);
1255           parent_msg_lparam = MAKELPARAM(cursor_pos.x, cursor_pos.y);
1256         }
1257         if (SendMessage(GetParent(), message, wparam, parent_msg_lparam) != 0)
1258           return 1;
1259       }
1260     }
1261   }
1262 
1263   ForwardMouseEventToRenderer(message, wparam, lparam);
1264   return 0;
1265 }
1266 
OnKeyEvent(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1267 LRESULT RenderWidgetHostViewWin::OnKeyEvent(UINT message, WPARAM wparam,
1268                                             LPARAM lparam, BOOL& handled) {
1269   handled = TRUE;
1270 
1271   // If we are a pop-up, forward tab related messages to our parent HWND, so
1272   // that we are dismissed appropriately and so that the focus advance in our
1273   // parent.
1274   // TODO(jcampan): http://b/issue?id=1192881 Could be abstracted in the
1275   //                FocusManager.
1276   if (close_on_deactivate_ &&
1277       (((message == WM_KEYDOWN || message == WM_KEYUP) && (wparam == VK_TAB)) ||
1278         (message == WM_CHAR && wparam == L'\t'))) {
1279     DCHECK(parent_hwnd_);
1280     // First close the pop-up.
1281     SendMessage(WM_CANCELMODE);
1282     // Then move the focus by forwarding the tab key to the parent.
1283     return ::SendMessage(parent_hwnd_, message, wparam, lparam);
1284   }
1285 
1286   if (!render_widget_host_)
1287     return 0;
1288 
1289   // Bug 1845: we need to update the text direction when a user releases
1290   // either a right-shift key or a right-control key after pressing both of
1291   // them. So, we just update the text direction while a user is pressing the
1292   // keys, and we notify the text direction when a user releases either of them.
1293   // Bug 9718: http://crbug.com/9718 To investigate IE and notepad, this
1294   // shortcut is enabled only on a PC having RTL keyboard layouts installed.
1295   // We should emulate them.
1296   if (ui::ImeInput::IsRTLKeyboardLayoutInstalled()) {
1297     if (message == WM_KEYDOWN) {
1298       if (wparam == VK_SHIFT) {
1299         base::i18n::TextDirection dir;
1300         if (ui::ImeInput::IsCtrlShiftPressed(&dir)) {
1301           render_widget_host_->UpdateTextDirection(
1302               dir == base::i18n::RIGHT_TO_LEFT ?
1303               WebKit::WebTextDirectionRightToLeft :
1304               WebKit::WebTextDirectionLeftToRight);
1305         }
1306       } else if (wparam != VK_CONTROL) {
1307         // Bug 9762: http://crbug.com/9762 A user pressed a key except shift
1308         // and control keys.
1309         // When a user presses a key while he/she holds control and shift keys,
1310         // we cancel sending an IPC message in NotifyTextDirection() below and
1311         // ignore succeeding UpdateTextDirection() calls while we call
1312         // NotifyTextDirection().
1313         // To cancel it, this call set a flag that prevents sending an IPC
1314         // message in NotifyTextDirection() only if we are going to send it.
1315         // It is harmless to call this function if we aren't going to send it.
1316         render_widget_host_->CancelUpdateTextDirection();
1317       }
1318     } else if (message == WM_KEYUP &&
1319                (wparam == VK_SHIFT || wparam == VK_CONTROL)) {
1320       // We send an IPC message only if we need to update the text direction.
1321       render_widget_host_->NotifyTextDirection();
1322     }
1323   }
1324 
1325   // Special processing for enter key: When user hits enter in omnibox
1326   // we change focus to render host after the navigation, so repeat WM_KEYDOWNs
1327   // and WM_KEYUP are going to render host, despite being initiated in other
1328   // window. This code filters out these messages.
1329   bool ignore_keyboard_event = false;
1330   if (wparam == VK_RETURN) {
1331     if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) {
1332       if (KF_REPEAT & HIWORD(lparam)) {
1333         // this is a repeated key
1334         if (!capture_enter_key_)
1335           ignore_keyboard_event = true;
1336       } else {
1337         capture_enter_key_ = true;
1338       }
1339     } else if (message == WM_KEYUP || message == WM_SYSKEYUP) {
1340       if (!capture_enter_key_)
1341         ignore_keyboard_event = true;
1342       capture_enter_key_ = false;
1343     } else {
1344       // Ignore all other keyboard events for the enter key if not captured.
1345       if (!capture_enter_key_)
1346         ignore_keyboard_event = true;
1347     }
1348   }
1349 
1350   if (render_widget_host_ && !ignore_keyboard_event) {
1351     render_widget_host_->ForwardKeyboardEvent(
1352         NativeWebKeyboardEvent(m_hWnd, message, wparam, lparam));
1353   }
1354   return 0;
1355 }
1356 
OnWheelEvent(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1357 LRESULT RenderWidgetHostViewWin::OnWheelEvent(UINT message, WPARAM wparam,
1358                                               LPARAM lparam, BOOL& handled) {
1359   // Forward the mouse-wheel message to the window under the mouse if it belongs
1360   // to us.
1361   if (message == WM_MOUSEWHEEL &&
1362       views::RerouteMouseWheel(m_hWnd, wparam, lparam)) {
1363     handled = TRUE;
1364     return 0;
1365   }
1366 
1367   // Workaround for Thinkpad mousewheel driver. We get mouse wheel/scroll
1368   // messages even if we are not in the foreground. So here we check if
1369   // we have any owned popup windows in the foreground and dismiss them.
1370   if (m_hWnd != GetForegroundWindow()) {
1371     HWND toplevel_hwnd = ::GetAncestor(m_hWnd, GA_ROOT);
1372     EnumThreadWindows(
1373         GetCurrentThreadId(),
1374         DismissOwnedPopups,
1375         reinterpret_cast<LPARAM>(toplevel_hwnd));
1376   }
1377 
1378   // This is a bit of a hack, but will work for now since we don't want to
1379   // pollute this object with TabContents-specific functionality...
1380   bool handled_by_TabContents = false;
1381   if (GetParent()) {
1382     // Use a special reflected message to break recursion. If we send
1383     // WM_MOUSEWHEEL, the focus manager subclass of web contents will
1384     // route it back here.
1385     MSG new_message = {0};
1386     new_message.hwnd = m_hWnd;
1387     new_message.message = message;
1388     new_message.wParam = wparam;
1389     new_message.lParam = lparam;
1390 
1391     handled_by_TabContents =
1392         !!::SendMessage(GetParent(), views::kReflectedMessage, 0,
1393                         reinterpret_cast<LPARAM>(&new_message));
1394   }
1395 
1396   if (!handled_by_TabContents && render_widget_host_) {
1397     render_widget_host_->ForwardWheelEvent(
1398         WebInputEventFactory::mouseWheelEvent(m_hWnd, message, wparam,
1399                                               lparam));
1400   }
1401   handled = TRUE;
1402   return 0;
1403 }
1404 
OnMouseActivate(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1405 LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT message,
1406                                                  WPARAM wparam,
1407                                                  LPARAM lparam,
1408                                                  BOOL& handled) {
1409   if (!IsActivatable())
1410     return MA_NOACTIVATE;
1411 
1412   HWND focus_window = GetFocus();
1413   if (!::IsWindow(focus_window) || !IsChild(focus_window)) {
1414     // We handle WM_MOUSEACTIVATE to set focus to the underlying plugin
1415     // child window. This is to ensure that keyboard events are received
1416     // by the plugin. The correct way to fix this would be send over
1417     // an event to the renderer which would then eventually send over
1418     // a setFocus call to the plugin widget. This would ensure that
1419     // the renderer (webkit) knows about the plugin widget receiving
1420     // focus.
1421     // TODO(iyengar) Do the right thing as per the above comment.
1422     POINT cursor_pos = {0};
1423     ::GetCursorPos(&cursor_pos);
1424     ::ScreenToClient(m_hWnd, &cursor_pos);
1425     HWND child_window = ::RealChildWindowFromPoint(m_hWnd, cursor_pos);
1426     if (::IsWindow(child_window) && child_window != m_hWnd) {
1427       if (ui::GetClassName(child_window) ==
1428               webkit::npapi::kWrapperNativeWindowClassName)
1429         child_window = ::GetWindow(child_window, GW_CHILD);
1430 
1431       ::SetFocus(child_window);
1432       return MA_NOACTIVATE;
1433     }
1434   }
1435   handled = FALSE;
1436   render_widget_host_->OnMouseActivate();
1437   return MA_ACTIVATE;
1438 }
1439 
OnAccessibilityNotifications(const std::vector<ViewHostMsg_AccessibilityNotification_Params> & params)1440 void RenderWidgetHostViewWin::OnAccessibilityNotifications(
1441     const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params) {
1442   if (!browser_accessibility_manager_.get()) {
1443     // Use empty document to process notifications
1444     webkit_glue::WebAccessibility empty_document;
1445     empty_document.role = WebAccessibility::ROLE_DOCUMENT;
1446     empty_document.state = 0;
1447     browser_accessibility_manager_.reset(
1448         BrowserAccessibilityManager::Create(m_hWnd, empty_document, this));
1449   }
1450 
1451   browser_accessibility_manager_->OnAccessibilityNotifications(params);
1452 }
1453 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)1454 void RenderWidgetHostViewWin::Observe(NotificationType type,
1455                                       const NotificationSource& source,
1456                                       const NotificationDetails& details) {
1457   DCHECK(type == NotificationType::RENDERER_PROCESS_TERMINATED);
1458 
1459   // Get the RenderProcessHost that posted this notification, and exit
1460   // if it's not the one associated with this host view.
1461   RenderProcessHost* render_process_host =
1462       Source<RenderProcessHost>(source).ptr();
1463   DCHECK(render_process_host);
1464   if (!render_widget_host_ ||
1465       render_process_host != render_widget_host_->process())
1466     return;
1467 
1468   // If it was our RenderProcessHost that posted the notification,
1469   // clear the BrowserAccessibilityManager, because the renderer is
1470   // dead and any accessibility information we have is now stale.
1471   browser_accessibility_manager_.reset(NULL);
1472 }
1473 
PaintCompositorHostWindow(HWND hWnd)1474 static void PaintCompositorHostWindow(HWND hWnd) {
1475   PAINTSTRUCT paint;
1476   BeginPaint(hWnd, &paint);
1477 
1478   EndPaint(hWnd, &paint);
1479 }
1480 
1481 // WndProc for the compositor host window. We use this instead of Default so
1482 // we can drop WM_PAINT and WM_ERASEBKGD messages on the floor.
CompositorHostWindowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)1483 static LRESULT CALLBACK CompositorHostWindowProc(HWND hWnd, UINT message,
1484                                                  WPARAM wParam, LPARAM lParam) {
1485   switch (message) {
1486   case WM_ERASEBKGND:
1487     return 0;
1488   case WM_DESTROY:
1489     return 0;
1490   case WM_PAINT:
1491     PaintCompositorHostWindow(hWnd);
1492     return 0;
1493   default:
1494     return DefWindowProc(hWnd, message, wParam, lParam);
1495   }
1496 }
1497 
1498 // Creates a HWND within the RenderWidgetHostView that will serve as a host
1499 // for a HWND that the GPU process will create. The host window is used
1500 // to Z-position the GPU's window relative to other plugin windows.
GetCompositingSurface()1501 gfx::PluginWindowHandle RenderWidgetHostViewWin::GetCompositingSurface() {
1502   // If the window has been created, don't recreate it a second time
1503   if (compositor_host_window_)
1504     return compositor_host_window_;
1505 
1506   static ATOM window_class = 0;
1507   if (!window_class) {
1508     WNDCLASSEX wcex;
1509     wcex.cbSize         = sizeof(WNDCLASSEX);
1510     wcex.style          = 0;
1511     wcex.lpfnWndProc    =
1512         base::win::WrappedWindowProc<CompositorHostWindowProc>;
1513     wcex.cbClsExtra     = 0;
1514     wcex.cbWndExtra     = 0;
1515     wcex.hInstance      = GetModuleHandle(NULL);
1516     wcex.hIcon          = 0;
1517     wcex.hCursor        = 0;
1518     wcex.hbrBackground  = NULL;
1519     wcex.lpszMenuName   = 0;
1520     wcex.lpszClassName  = L"CompositorHostWindowClass";
1521     wcex.hIconSm        = 0;
1522     window_class = RegisterClassEx(&wcex);
1523     DCHECK(window_class);
1524   }
1525 
1526   RECT currentRect;
1527   GetClientRect(&currentRect);
1528   int width = currentRect.right - currentRect.left;
1529   int height = currentRect.bottom - currentRect.top;
1530 
1531   compositor_host_window_ = CreateWindowEx(
1532     WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
1533     MAKEINTATOM(window_class), 0,
1534     WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED,
1535     0, 0, width, height, m_hWnd, 0, GetModuleHandle(NULL), 0);
1536   ui::CheckWindowCreated(compositor_host_window_);
1537 
1538   return static_cast<gfx::PluginWindowHandle>(compositor_host_window_);
1539 }
1540 
ShowCompositorHostWindow(bool show)1541 void RenderWidgetHostViewWin::ShowCompositorHostWindow(bool show) {
1542   // When we first create the compositor, we will get a show request from
1543   // the renderer before we have gotten the create request from the GPU. In this
1544   // case, simply ignore the show request.
1545   if (compositor_host_window_ == NULL)
1546     return;
1547 
1548   if (show) {
1549     ::ShowWindow(compositor_host_window_, SW_SHOW);
1550 
1551     // Get all the child windows of this view, including the compositor window.
1552     std::vector<HWND> all_child_windows;
1553     ::EnumChildWindows(m_hWnd, AddChildWindowToVector,
1554         reinterpret_cast<LPARAM>(&all_child_windows));
1555 
1556     // Build a list of just the plugin window handles
1557     std::vector<HWND> plugin_windows;
1558     bool compositor_host_window_found = false;
1559     for (size_t i = 0; i < all_child_windows.size(); ++i) {
1560       if (all_child_windows[i] != compositor_host_window_)
1561         plugin_windows.push_back(all_child_windows[i]);
1562       else
1563         compositor_host_window_found = true;
1564     }
1565     DCHECK(compositor_host_window_found);
1566 
1567     // Set all the plugin windows to be "after" the compositor window.
1568     // When the compositor window is created, gets placed above plugins.
1569     for (size_t i = 0; i < plugin_windows.size(); ++i) {
1570       HWND next;
1571       if (i + 1 < plugin_windows.size())
1572         next = plugin_windows[i+1];
1573       else
1574         next = compositor_host_window_;
1575       ::SetWindowPos(plugin_windows[i], next, 0, 0, 0, 0,
1576           SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
1577     }
1578   } else {
1579     hide_compositor_window_at_next_paint_ = true;
1580   }
1581 }
1582 
SetAccessibilityFocus(int acc_obj_id)1583 void RenderWidgetHostViewWin::SetAccessibilityFocus(int acc_obj_id) {
1584   if (!browser_accessibility_manager_.get() ||
1585       !render_widget_host_ ||
1586       !render_widget_host_->process() ||
1587       !render_widget_host_->process()->HasConnection()) {
1588     return;
1589   }
1590 
1591   render_widget_host_->SetAccessibilityFocus(acc_obj_id);
1592 }
1593 
AccessibilityDoDefaultAction(int acc_obj_id)1594 void RenderWidgetHostViewWin::AccessibilityDoDefaultAction(int acc_obj_id) {
1595   if (!browser_accessibility_manager_.get() ||
1596       !render_widget_host_ ||
1597       !render_widget_host_->process() ||
1598       !render_widget_host_->process()->HasConnection()) {
1599     return;
1600   }
1601 
1602   render_widget_host_->AccessibilityDoDefaultAction(acc_obj_id);
1603 }
1604 
OnGetObject(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1605 LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam,
1606                                              LPARAM lparam, BOOL& handled) {
1607   if (kIdCustom == lparam) {
1608     // An MSAA client requestes our custom id. Assume that we have detected an
1609     // active windows screen reader.
1610     BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
1611     render_widget_host_->EnableRendererAccessibility();
1612 
1613     // Return with failure.
1614     return static_cast<LRESULT>(0L);
1615   }
1616 
1617   if (lparam != OBJID_CLIENT) {
1618     handled = false;
1619     return static_cast<LRESULT>(0L);
1620   }
1621 
1622   if (render_widget_host_ && !render_widget_host_->renderer_accessible()) {
1623     // Attempt to detect screen readers by sending an event with our custom id.
1624     NotifyWinEvent(EVENT_SYSTEM_ALERT, m_hWnd, kIdCustom, CHILDID_SELF);
1625   }
1626 
1627   if (!browser_accessibility_manager_.get()) {
1628     // Return busy document tree while renderer accessibility tree loads.
1629     webkit_glue::WebAccessibility loading_tree;
1630     loading_tree.role = WebAccessibility::ROLE_DOCUMENT;
1631     loading_tree.state = (1 << WebAccessibility::STATE_BUSY);
1632     browser_accessibility_manager_.reset(
1633       BrowserAccessibilityManager::Create(m_hWnd, loading_tree, this));
1634   }
1635 
1636   base::win::ScopedComPtr<IAccessible> root(
1637       browser_accessibility_manager_->GetRoot()->toBrowserAccessibilityWin());
1638   if (root.get())
1639     return LresultFromObject(IID_IAccessible, wparam, root.Detach());
1640 
1641   handled = false;
1642   return static_cast<LRESULT>(0L);
1643 }
1644 
OnParentNotify(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)1645 LRESULT RenderWidgetHostViewWin::OnParentNotify(UINT message, WPARAM wparam,
1646                                                 LPARAM lparam, BOOL& handled) {
1647   handled = FALSE;
1648 
1649   if (!render_widget_host_)
1650     return 0;
1651 
1652   switch (LOWORD(wparam)) {
1653     case WM_LBUTTONDOWN:
1654     case WM_RBUTTONDOWN:
1655     case WM_MBUTTONDOWN:
1656       render_widget_host_->StartUserGesture();
1657       break;
1658     default:
1659       break;
1660   }
1661   return 0;
1662 }
1663 
OnFinalMessage(HWND window)1664 void RenderWidgetHostViewWin::OnFinalMessage(HWND window) {
1665   // When the render widget host is being destroyed, it ends up calling
1666   // WillDestroyRenderWidget (through the RENDER_WIDGET_HOST_DESTROYED
1667   // notification) which NULLs render_widget_host_.
1668   // Note: the following bug http://crbug.com/24248 seems to report that
1669   // OnFinalMessage is called with a deleted |render_widget_host_|. It is not
1670   // clear how this could happen, hence the NULLing of render_widget_host_
1671   // above.
1672   if (!render_widget_host_ && !being_destroyed_) {
1673     // If you hit this NOTREACHED, please add a comment to report it on
1674     // http://crbug.com/24248, including what you did when it happened and if
1675     // you can repro.
1676     NOTREACHED();
1677   }
1678   if (render_widget_host_)
1679     render_widget_host_->ViewDestroyed();
1680   delete this;
1681 }
1682 
TrackMouseLeave(bool track)1683 void RenderWidgetHostViewWin::TrackMouseLeave(bool track) {
1684   if (track == track_mouse_leave_)
1685     return;
1686   track_mouse_leave_ = track;
1687 
1688   DCHECK(m_hWnd);
1689 
1690   TRACKMOUSEEVENT tme;
1691   tme.cbSize = sizeof(TRACKMOUSEEVENT);
1692   tme.dwFlags = TME_LEAVE;
1693   if (!track_mouse_leave_)
1694     tme.dwFlags |= TME_CANCEL;
1695   tme.hwndTrack = m_hWnd;
1696 
1697   TrackMouseEvent(&tme);
1698 }
1699 
Send(IPC::Message * message)1700 bool RenderWidgetHostViewWin::Send(IPC::Message* message) {
1701   if (!render_widget_host_)
1702     return false;
1703   return render_widget_host_->Send(message);
1704 }
1705 
EnsureTooltip()1706 void RenderWidgetHostViewWin::EnsureTooltip() {
1707   UINT message = TTM_NEWTOOLRECT;
1708 
1709   TOOLINFO ti;
1710   ti.cbSize = sizeof(ti);
1711   ti.hwnd = m_hWnd;
1712   ti.uId = 0;
1713   if (!::IsWindow(tooltip_hwnd_)) {
1714     message = TTM_ADDTOOL;
1715     tooltip_hwnd_ = CreateWindowEx(
1716         WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
1717         TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0, m_hWnd, NULL,
1718         NULL, NULL);
1719     ui::CheckWindowCreated(tooltip_hwnd_);
1720     ti.uFlags = TTF_TRANSPARENT;
1721     ti.lpszText = LPSTR_TEXTCALLBACK;
1722   }
1723 
1724   CRect cr;
1725   GetClientRect(&ti.rect);
1726   SendMessage(tooltip_hwnd_, message, NULL, reinterpret_cast<LPARAM>(&ti));
1727 }
1728 
ResetTooltip()1729 void RenderWidgetHostViewWin::ResetTooltip() {
1730   if (::IsWindow(tooltip_hwnd_))
1731     ::DestroyWindow(tooltip_hwnd_);
1732   tooltip_hwnd_ = NULL;
1733 }
1734 
ForwardMouseEventToRenderer(UINT message,WPARAM wparam,LPARAM lparam)1735 void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message,
1736                                                           WPARAM wparam,
1737                                                           LPARAM lparam) {
1738   if (!render_widget_host_)
1739     return;
1740 
1741   WebMouseEvent event(
1742       WebInputEventFactory::mouseEvent(m_hWnd, message, wparam, lparam));
1743 
1744   // Send the event to the renderer before changing mouse capture, so that the
1745   // capturelost event arrives after mouseup.
1746   render_widget_host_->ForwardMouseEvent(event);
1747 
1748   switch (event.type) {
1749     case WebInputEvent::MouseMove:
1750       TrackMouseLeave(true);
1751       break;
1752     case WebInputEvent::MouseLeave:
1753       TrackMouseLeave(false);
1754       break;
1755     case WebInputEvent::MouseDown:
1756       SetCapture();
1757       break;
1758     case WebInputEvent::MouseUp:
1759       if (GetCapture() == m_hWnd)
1760         ReleaseCapture();
1761       break;
1762   }
1763 
1764   if (IsActivatable() && event.type == WebInputEvent::MouseDown) {
1765     // This is a temporary workaround for bug 765011 to get focus when the
1766     // mouse is clicked. This happens after the mouse down event is sent to
1767     // the renderer because normally Windows does a WM_SETFOCUS after
1768     // WM_LBUTTONDOWN.
1769     SetFocus();
1770   }
1771 }
1772 
ShutdownHost()1773 void RenderWidgetHostViewWin::ShutdownHost() {
1774   shutdown_factory_.RevokeAll();
1775   if (render_widget_host_)
1776     render_widget_host_->Shutdown();
1777   // Do not touch any members at this point, |this| has been deleted.
1778 }
1779 
1780 // static
1781 RenderWidgetHostView*
GetRenderWidgetHostViewFromNativeView(gfx::NativeView native_view)1782     RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView(
1783         gfx::NativeView native_view) {
1784   return ::IsWindow(native_view) ?
1785       reinterpret_cast<RenderWidgetHostView*>(
1786           ViewProp::GetValue(native_view, kRenderWidgetHostViewKey)) : NULL;
1787 }
1788