1// Copyright (c) 2012 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 "content/browser/renderer_host/render_widget_host_view_win.h"
6
7#include <InputScope.h>
8#include <wtsapi32.h>
9#pragma comment(lib, "wtsapi32.lib")
10
11#include <algorithm>
12#include <map>
13#include <stack>
14
15#include "base/bind.h"
16#include "base/bind_helpers.h"
17#include "base/command_line.h"
18#include "base/debug/trace_event.h"
19#include "base/i18n/rtl.h"
20#include "base/metrics/histogram.h"
21#include "base/threading/thread.h"
22#include "base/win/metro.h"
23#include "base/win/scoped_comptr.h"
24#include "base/win/scoped_gdi_object.h"
25#include "base/win/win_util.h"
26#include "base/win/windows_version.h"
27#include "base/win/wrapped_window_proc.h"
28#include "content/browser/accessibility/browser_accessibility_manager_win.h"
29#include "content/browser/accessibility/browser_accessibility_state_impl.h"
30#include "content/browser/accessibility/browser_accessibility_win.h"
31#include "content/browser/gpu/gpu_data_manager_impl.h"
32#include "content/browser/gpu/gpu_process_host.h"
33#include "content/browser/gpu/gpu_process_host_ui_shim.h"
34#include "content/browser/renderer_host/backing_store.h"
35#include "content/browser/renderer_host/backing_store_win.h"
36#include "content/browser/renderer_host/input/web_input_event_builders_win.h"
37#include "content/browser/renderer_host/render_process_host_impl.h"
38#include "content/browser/renderer_host/render_widget_host_impl.h"
39#include "content/browser/renderer_host/ui_events_helper.h"
40#include "content/common/accessibility_messages.h"
41#include "content/common/gpu/gpu_messages.h"
42#include "content/common/plugin_constants_win.h"
43#include "content/common/view_messages.h"
44#include "content/common/webplugin_geometry.h"
45#include "content/public/browser/browser_thread.h"
46#include "content/public/browser/child_process_data.h"
47#include "content/public/browser/content_browser_client.h"
48#include "content/public/browser/native_web_keyboard_event.h"
49#include "content/public/browser/notification_service.h"
50#include "content/public/browser/notification_types.h"
51#include "content/public/browser/render_view_host.h"
52#include "content/public/common/content_switches.h"
53#include "content/public/common/page_zoom.h"
54#include "content/public/common/process_type.h"
55#include "skia/ext/skia_utils_win.h"
56#include "third_party/WebKit/public/web/WebCompositionUnderline.h"
57#include "third_party/WebKit/public/web/WebInputEvent.h"
58#include "third_party/skia/include/core/SkRegion.h"
59#include "ui/base/events/event.h"
60#include "ui/base/events/event_utils.h"
61#include "ui/base/ime/composition_text.h"
62#include "ui/base/ime/win/imm32_manager.h"
63#include "ui/base/ime/win/tsf_input_scope.h"
64#include "ui/base/l10n/l10n_util_win.h"
65#include "ui/base/text/text_elider.h"
66#include "ui/base/touch/touch_device.h"
67#include "ui/base/touch/touch_enabled.h"
68#include "ui/base/ui_base_switches.h"
69#include "ui/base/view_prop.h"
70#include "ui/base/win/dpi.h"
71#include "ui/base/win/hwnd_util.h"
72#include "ui/base/win/mouse_wheel_util.h"
73#include "ui/base/win/touch_input.h"
74#include "ui/gfx/canvas.h"
75#include "ui/gfx/rect.h"
76#include "ui/gfx/rect_conversions.h"
77#include "ui/gfx/screen.h"
78#include "webkit/common/cursors/webcursor.h"
79#include "win8/util/win8_util.h"
80
81using base::TimeDelta;
82using base::TimeTicks;
83using ui::ViewProp;
84using WebKit::WebInputEvent;
85using WebKit::WebMouseEvent;
86using WebKit::WebTextDirection;
87
88namespace content {
89namespace {
90
91// Tooltips will wrap after this width. Yes, wrap. Imagine that!
92const int kTooltipMaxWidthPixels = 300;
93
94// Maximum number of characters we allow in a tooltip.
95const int kMaxTooltipLength = 1024;
96
97// A custom MSAA object id used to determine if a screen reader is actively
98// listening for MSAA events.
99const int kIdCustom = 1;
100
101// The delay before the compositor host window is destroyed. This gives the GPU
102// process a grace period to stop referencing it.
103const int kDestroyCompositorHostWindowDelay = 10000;
104
105// In mouse lock mode, we need to prevent the (invisible) cursor from hitting
106// the border of the view, in order to get valid movement information. However,
107// forcing the cursor back to the center of the view after each mouse move
108// doesn't work well. It reduces the frequency of useful WM_MOUSEMOVE messages
109// significantly. Therefore, we move the cursor to the center of the view only
110// if it approaches the border. |kMouseLockBorderPercentage| specifies the width
111// of the border area, in percentage of the corresponding dimension.
112const int kMouseLockBorderPercentage = 15;
113
114// A callback function for EnumThreadWindows to enumerate and dismiss
115// any owned popup windows.
116BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) {
117  const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg);
118
119  if (::IsWindowVisible(window)) {
120    const HWND owner = ::GetWindow(window, GW_OWNER);
121    if (toplevel_hwnd == owner) {
122      ::PostMessage(window, WM_CANCELMODE, 0, 0);
123    }
124  }
125
126  return TRUE;
127}
128
129void SendToGpuProcessHost(int gpu_host_id, scoped_ptr<IPC::Message> message) {
130  GpuProcessHost* gpu_process_host = GpuProcessHost::FromID(gpu_host_id);
131  if (!gpu_process_host)
132    return;
133
134  gpu_process_host->Send(message.release());
135}
136
137void PostTaskOnIOThread(const tracked_objects::Location& from_here,
138                        base::Closure task) {
139  BrowserThread::PostTask(BrowserThread::IO, from_here, task);
140}
141
142bool DecodeZoomGesture(HWND hwnd, const GESTUREINFO& gi,
143                       PageZoom* zoom, POINT* zoom_center) {
144  static long start = 0;
145  static POINT zoom_first;
146
147  if (gi.dwFlags == GF_BEGIN) {
148    start = gi.ullArguments;
149    zoom_first.x = gi.ptsLocation.x;
150    zoom_first.y = gi.ptsLocation.y;
151    ScreenToClient(hwnd, &zoom_first);
152    return false;
153  }
154
155  if (gi.dwFlags == GF_END)
156    return false;
157
158  POINT zoom_second = {0};
159  zoom_second.x = gi.ptsLocation.x;
160  zoom_second.y = gi.ptsLocation.y;
161  ScreenToClient(hwnd, &zoom_second);
162
163  if (zoom_first.x == zoom_second.x && zoom_first.y == zoom_second.y)
164    return false;
165
166  zoom_center->x = (zoom_first.x + zoom_second.x) / 2;
167  zoom_center->y = (zoom_first.y + zoom_second.y) / 2;
168
169  double zoom_factor =
170      static_cast<double>(gi.ullArguments)/static_cast<double>(start);
171
172  *zoom = zoom_factor >= 1 ? PAGE_ZOOM_IN : PAGE_ZOOM_OUT;
173
174  start = gi.ullArguments;
175  zoom_first = zoom_second;
176  return true;
177}
178
179bool DecodeScrollGesture(const GESTUREINFO& gi,
180                         POINT* start,
181                         POINT* delta){
182  // Windows gestures are streams of messages with begin/end messages that
183  // separate each new gesture. We key off the begin message to reset
184  // the static variables.
185  static POINT last_pt;
186  static POINT start_pt;
187
188  if (gi.dwFlags == GF_BEGIN) {
189    delta->x = 0;
190    delta->y = 0;
191    start_pt.x = gi.ptsLocation.x;
192    start_pt.y = gi.ptsLocation.y;
193  } else {
194    delta->x = gi.ptsLocation.x - last_pt.x;
195    delta->y = gi.ptsLocation.y - last_pt.y;
196  }
197  last_pt.x = gi.ptsLocation.x;
198  last_pt.y = gi.ptsLocation.y;
199  *start = start_pt;
200  return true;
201}
202
203WebKit::WebMouseWheelEvent MakeFakeScrollWheelEvent(HWND hwnd,
204                                                    POINT start,
205                                                    POINT delta) {
206  WebKit::WebMouseWheelEvent result;
207  result.type = WebInputEvent::MouseWheel;
208  result.timeStampSeconds = ::GetMessageTime() / 1000.0;
209  result.button = WebMouseEvent::ButtonNone;
210  result.globalX = start.x;
211  result.globalY = start.y;
212  // Map to window coordinates.
213  POINT client_point = { result.globalX, result.globalY };
214  MapWindowPoints(0, hwnd, &client_point, 1);
215  result.x = client_point.x;
216  result.y = client_point.y;
217  result.windowX = result.x;
218  result.windowY = result.y;
219  // Note that we support diagonal scrolling.
220  result.deltaX = static_cast<float>(delta.x);
221  result.wheelTicksX = WHEEL_DELTA;
222  result.deltaY = static_cast<float>(delta.y);
223  result.wheelTicksY = WHEEL_DELTA;
224  return result;
225}
226
227static const int kTouchMask = 0x7;
228
229inline int GetTouchType(const TOUCHINPUT& point) {
230  return point.dwFlags & kTouchMask;
231}
232
233inline void SetTouchType(TOUCHINPUT* point, int type) {
234  point->dwFlags = (point->dwFlags & kTouchMask) | type;
235}
236
237ui::EventType ConvertToUIEvent(WebKit::WebTouchPoint::State t) {
238  switch (t) {
239    case WebKit::WebTouchPoint::StatePressed:
240      return ui::ET_TOUCH_PRESSED;
241    case WebKit::WebTouchPoint::StateMoved:
242      return ui::ET_TOUCH_MOVED;
243    case WebKit::WebTouchPoint::StateStationary:
244      return ui::ET_TOUCH_STATIONARY;
245    case WebKit::WebTouchPoint::StateReleased:
246      return ui::ET_TOUCH_RELEASED;
247    case WebKit::WebTouchPoint::StateCancelled:
248      return ui::ET_TOUCH_CANCELLED;
249    default:
250      DCHECK(false) << "Unexpected ui type. " << t;
251      return ui::ET_UNKNOWN;
252  }
253}
254
255// Creates a WebGestureEvent corresponding to the given |gesture|
256WebKit::WebGestureEvent CreateWebGestureEvent(HWND hwnd,
257                                              const ui::GestureEvent& gesture) {
258  WebKit::WebGestureEvent gesture_event =
259      MakeWebGestureEventFromUIEvent(gesture);
260
261  POINT client_point = gesture.location().ToPOINT();
262  POINT screen_point = gesture.location().ToPOINT();
263  MapWindowPoints(hwnd, HWND_DESKTOP, &screen_point, 1);
264
265  gesture_event.x = client_point.x;
266  gesture_event.y = client_point.y;
267  gesture_event.globalX = screen_point.x;
268  gesture_event.globalY = screen_point.y;
269
270  return gesture_event;
271}
272
273WebKit::WebGestureEvent CreateFlingCancelEvent(double time_stamp) {
274  WebKit::WebGestureEvent gesture_event;
275  gesture_event.timeStampSeconds = time_stamp;
276  gesture_event.type = WebKit::WebGestureEvent::GestureFlingCancel;
277  gesture_event.sourceDevice = WebKit::WebGestureEvent::Touchscreen;
278  return gesture_event;
279}
280
281class TouchEventFromWebTouchPoint : public ui::TouchEvent {
282 public:
283  TouchEventFromWebTouchPoint(const WebKit::WebTouchPoint& touch_point,
284                              base::TimeDelta& timestamp)
285      : ui::TouchEvent(ConvertToUIEvent(touch_point.state),
286                       touch_point.position,
287                       touch_point.id,
288                       timestamp) {
289    set_radius(touch_point.radiusX, touch_point.radiusY);
290    set_rotation_angle(touch_point.rotationAngle);
291    set_force(touch_point.force);
292    set_flags(ui::GetModifiersFromKeyState());
293  }
294
295  virtual ~TouchEventFromWebTouchPoint() {}
296
297 private:
298  DISALLOW_COPY_AND_ASSIGN(TouchEventFromWebTouchPoint);
299};
300
301bool ShouldSendPinchGesture() {
302  static bool pinch_allowed =
303      CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePinch);
304  return pinch_allowed;
305}
306
307void GetScreenInfoForWindow(gfx::NativeViewId id,
308                            WebKit::WebScreenInfo* results) {
309  HWND window = gfx::NativeViewFromId(id);
310
311  HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
312
313  MONITORINFOEX monitor_info;
314  monitor_info.cbSize = sizeof(MONITORINFOEX);
315  if (!GetMonitorInfo(monitor, &monitor_info))
316    return;
317
318  DEVMODE dev_mode;
319  dev_mode.dmSize = sizeof(dev_mode);
320  dev_mode.dmDriverExtra = 0;
321  EnumDisplaySettings(monitor_info.szDevice, ENUM_CURRENT_SETTINGS, &dev_mode);
322
323  WebKit::WebScreenInfo screen_info;
324  screen_info.depth = dev_mode.dmBitsPerPel;
325  screen_info.depthPerComponent = dev_mode.dmBitsPerPel / 3;  // Assumes RGB
326  screen_info.deviceScaleFactor = ui::win::GetDeviceScaleFactor();
327  screen_info.isMonochrome = dev_mode.dmColor == DMCOLOR_MONOCHROME;
328  screen_info.rect = gfx::Rect(monitor_info.rcMonitor);
329  screen_info.availableRect = gfx::Rect(monitor_info.rcWork);
330
331  *results = screen_info;
332}
333
334}  // namespace
335
336const wchar_t kRenderWidgetHostHWNDClass[] = L"Chrome_RenderWidgetHostHWND";
337
338// Wrapper for maintaining touchstate associated with a WebTouchEvent.
339class WebTouchState {
340 public:
341  explicit WebTouchState(const RenderWidgetHostViewWin* window);
342
343  // Updates the current touchpoint state with the supplied touches.
344  // Touches will be consumed only if they are of the same type (e.g. down,
345  // up, move). Returns the number of consumed touches.
346  size_t UpdateTouchPoints(TOUCHINPUT* points, size_t count);
347
348  // Marks all active touchpoints as released.
349  bool ReleaseTouchPoints();
350
351  // The contained WebTouchEvent.
352  const WebKit::WebTouchEvent& touch_event() { return touch_event_; }
353
354  // Returns if any touches are modified in the event.
355  bool is_changed() { return touch_event_.changedTouchesLength != 0; }
356
357 private:
358  typedef std::map<unsigned int, int> MapType;
359
360  // Adds a touch point or returns NULL if there's not enough space.
361  WebKit::WebTouchPoint* AddTouchPoint(TOUCHINPUT* touch_input);
362
363  // Copy details from a TOUCHINPUT to an existing WebTouchPoint, returning
364  // true if the resulting point is a stationary move.
365  bool UpdateTouchPoint(WebKit::WebTouchPoint* touch_point,
366                        TOUCHINPUT* touch_input);
367
368  // Find (or create) a mapping for _os_touch_id_.
369  unsigned int GetMappedTouch(unsigned int os_touch_id);
370
371  // Remove any mappings that are no longer in use.
372  void RemoveExpiredMappings();
373
374  WebKit::WebTouchEvent touch_event_;
375  const RenderWidgetHostViewWin* const window_;
376
377  // Maps OS touch Id's into an internal (WebKit-friendly) touch-id.
378  // WebKit expects small consecutive integers, starting at 0.
379  MapType touch_map_;
380
381  DISALLOW_COPY_AND_ASSIGN(WebTouchState);
382};
383
384typedef void (*MetroSetFrameWindow)(HWND window);
385typedef void (*MetroCloseFrameWindow)(HWND window);
386
387///////////////////////////////////////////////////////////////////////////////
388// RenderWidgetHostViewWin, public:
389
390RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget)
391    : render_widget_host_(RenderWidgetHostImpl::From(widget)),
392      compositor_host_window_(NULL),
393      hide_compositor_window_at_next_paint_(false),
394      track_mouse_leave_(false),
395      imm32_manager_(new ui::IMM32Manager),
396      ime_notification_(false),
397      capture_enter_key_(false),
398      is_hidden_(false),
399      about_to_validate_and_paint_(false),
400      close_on_deactivate_(false),
401      being_destroyed_(false),
402      tooltip_hwnd_(NULL),
403      tooltip_showing_(false),
404      weak_factory_(this),
405      is_loading_(false),
406      text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
407      text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
408      can_compose_inline_(true),
409      is_fullscreen_(false),
410      ignore_mouse_movement_(true),
411      composition_range_(ui::Range::InvalidRange()),
412      touch_state_(new WebTouchState(this)),
413      pointer_down_context_(false),
414      last_touch_location_(-1, -1),
415      touch_events_enabled_(ui::AreTouchEventsEnabled()),
416      gesture_recognizer_(ui::GestureRecognizer::Create(this)) {
417  render_widget_host_->SetView(this);
418  registrar_.Add(this,
419                 NOTIFICATION_RENDERER_PROCESS_TERMINATED,
420                 NotificationService::AllBrowserContextsAndSources());
421}
422
423RenderWidgetHostViewWin::~RenderWidgetHostViewWin() {
424  UnlockMouse();
425  ResetTooltip();
426}
427
428void RenderWidgetHostViewWin::CreateWnd(HWND parent) {
429  // ATL function to create the window.
430  Create(parent);
431}
432
433///////////////////////////////////////////////////////////////////////////////
434// RenderWidgetHostViewWin, RenderWidgetHostView implementation:
435
436void RenderWidgetHostViewWin::InitAsChild(
437    gfx::NativeView parent_view) {
438  CreateWnd(parent_view);
439}
440
441void RenderWidgetHostViewWin::InitAsPopup(
442    RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
443  close_on_deactivate_ = true;
444  DoPopupOrFullscreenInit(parent_host_view->GetNativeView(), pos,
445                          WS_EX_TOOLWINDOW);
446}
447
448void RenderWidgetHostViewWin::InitAsFullscreen(
449    RenderWidgetHostView* reference_host_view) {
450  gfx::Rect pos = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(
451      reference_host_view->GetNativeView()).bounds();
452  is_fullscreen_ = true;
453  DoPopupOrFullscreenInit(ui::GetWindowToParentTo(true), pos, 0);
454}
455
456RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const {
457  return render_widget_host_;
458}
459
460void RenderWidgetHostViewWin::WasShown() {
461  if (!is_hidden_)
462    return;
463
464  if (web_contents_switch_paint_time_.is_null())
465    web_contents_switch_paint_time_ = TimeTicks::Now();
466  is_hidden_ = false;
467
468  // |render_widget_host_| may be NULL if the WebContentsImpl is in the process
469  // of closing.
470  if (render_widget_host_)
471    render_widget_host_->WasShown();
472}
473
474void RenderWidgetHostViewWin::WasHidden() {
475  if (is_hidden_)
476    return;
477
478  // If we receive any more paint messages while we are hidden, we want to
479  // ignore them so we don't re-allocate the backing store.  We will paint
480  // everything again when we become selected again.
481  is_hidden_ = true;
482
483  ResetTooltip();
484
485  // If we have a renderer, then inform it that we are being hidden so it can
486  // reduce its resource utilization.
487  if (render_widget_host_)
488    render_widget_host_->WasHidden();
489
490  if (accelerated_surface_)
491    accelerated_surface_->WasHidden();
492
493  if (GetBrowserAccessibilityManager())
494    GetBrowserAccessibilityManager()->WasHidden();
495
496  web_contents_switch_paint_time_ = base::TimeTicks();
497}
498
499void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) {
500  SetBounds(gfx::Rect(GetPixelBounds().origin(), size));
501}
502
503void RenderWidgetHostViewWin::SetBounds(const gfx::Rect& rect) {
504  if (is_hidden_)
505    return;
506
507  // No SWP_NOREDRAW as autofill popups can move and the underneath window
508  // should redraw in that case.
509  UINT swp_flags = SWP_NOSENDCHANGING | SWP_NOOWNERZORDER | SWP_NOCOPYBITS |
510      SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE;
511
512  // If the style is not popup, you have to convert the point to client
513  // coordinate.
514  POINT point = { rect.x(), rect.y() };
515  if (GetStyle() & WS_CHILD)
516    ScreenToClient(&point);
517
518  SetWindowPos(NULL, point.x, point.y, rect.width(), rect.height(), swp_flags);
519  render_widget_host_->WasResized();
520}
521
522gfx::NativeView RenderWidgetHostViewWin::GetNativeView() const {
523  return m_hWnd;
524}
525
526gfx::NativeViewId RenderWidgetHostViewWin::GetNativeViewId() const {
527  return reinterpret_cast<gfx::NativeViewId>(m_hWnd);
528}
529
530gfx::NativeViewAccessible
531RenderWidgetHostViewWin::GetNativeViewAccessible() {
532  if (render_widget_host_ &&
533      !BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) {
534    // Attempt to detect screen readers by sending an event with our custom id.
535    NotifyWinEvent(EVENT_SYSTEM_ALERT, m_hWnd, kIdCustom, CHILDID_SELF);
536  }
537
538  CreateBrowserAccessibilityManagerIfNeeded();
539
540  return GetBrowserAccessibilityManager()->GetRoot()->
541      ToBrowserAccessibilityWin();
542}
543
544void RenderWidgetHostViewWin::CreateBrowserAccessibilityManagerIfNeeded() {
545  if (GetBrowserAccessibilityManager())
546    return;
547
548  HRESULT hr = ::CreateStdAccessibleObject(
549      m_hWnd, OBJID_WINDOW, IID_IAccessible,
550      reinterpret_cast<void **>(&window_iaccessible_));
551  DCHECK(SUCCEEDED(hr));
552
553  SetBrowserAccessibilityManager(
554      new BrowserAccessibilityManagerWin(
555          m_hWnd,
556          window_iaccessible_.get(),
557          BrowserAccessibilityManagerWin::GetEmptyDocument(),
558          this));
559}
560
561void RenderWidgetHostViewWin::MovePluginWindows(
562    const gfx::Vector2d& scroll_offset,
563    const std::vector<WebPluginGeometry>& plugin_window_moves) {
564  MovePluginWindowsHelper(m_hWnd, plugin_window_moves);
565}
566
567static BOOL CALLBACK AddChildWindowToVector(HWND hwnd, LPARAM lparam) {
568  std::vector<HWND>* vector = reinterpret_cast<std::vector<HWND>*>(lparam);
569  vector->push_back(hwnd);
570  return TRUE;
571}
572
573void RenderWidgetHostViewWin::CleanupCompositorWindow() {
574  if (!compositor_host_window_)
575    return;
576
577  ui::SetWindowUserData(compositor_host_window_, NULL);
578
579  // Hide the compositor and parent it to the desktop rather than destroying
580  // it immediately. The GPU process has a grace period to stop accessing the
581  // window. TODO(apatrick): the GPU process should acknowledge that it has
582  // finished with the window handle and the browser process should destroy it
583  // at that point.
584  ::ShowWindow(compositor_host_window_, SW_HIDE);
585  ::SetParent(compositor_host_window_, NULL);
586
587  BrowserThread::PostDelayedTask(
588      BrowserThread::UI,
589      FROM_HERE,
590      base::Bind(base::IgnoreResult(&::DestroyWindow),
591                 compositor_host_window_),
592      base::TimeDelta::FromMilliseconds(kDestroyCompositorHostWindowDelay));
593
594  compositor_host_window_ = NULL;
595}
596
597bool RenderWidgetHostViewWin::IsActivatable() const {
598  // Popups should not be activated.
599  return popup_type_ == WebKit::WebPopupTypeNone;
600}
601
602void RenderWidgetHostViewWin::Focus() {
603  if (IsWindow())
604    SetFocus();
605}
606
607void RenderWidgetHostViewWin::Blur() {
608  NOTREACHED();
609}
610
611bool RenderWidgetHostViewWin::HasFocus() const {
612  return ::GetFocus() == m_hWnd;
613}
614
615bool RenderWidgetHostViewWin::IsSurfaceAvailableForCopy() const {
616  if (render_widget_host_->is_accelerated_compositing_active())
617    return accelerated_surface_.get() && accelerated_surface_->IsReadyForCopy();
618  else
619    return !!render_widget_host_->GetBackingStore(false);
620}
621
622void RenderWidgetHostViewWin::Show() {
623  ShowWindow(SW_SHOW);
624  WasShown();
625}
626
627void RenderWidgetHostViewWin::Hide() {
628  if (!is_fullscreen_ && GetParent() == ui::GetWindowToParentTo(true)) {
629    LOG(WARNING) << "Hide() called twice in a row: " << this << ":"
630        << GetParent();
631    return;
632  }
633
634  if (::GetFocus() == m_hWnd)
635    ::SetFocus(NULL);
636  ShowWindow(SW_HIDE);
637
638  WasHidden();
639}
640
641bool RenderWidgetHostViewWin::IsShowing() {
642  return !!IsWindowVisible();
643}
644
645gfx::Rect RenderWidgetHostViewWin::GetViewBounds() const {
646  return ui::win::ScreenToDIPRect(GetPixelBounds());
647}
648
649gfx::Rect RenderWidgetHostViewWin::GetPixelBounds() const {
650  CRect window_rect;
651  GetWindowRect(&window_rect);
652  return gfx::Rect(window_rect);
653}
654
655void RenderWidgetHostViewWin::UpdateCursor(const WebCursor& cursor) {
656  current_cursor_ = cursor;
657  UpdateCursorIfOverSelf();
658}
659
660void RenderWidgetHostViewWin::UpdateCursorIfOverSelf() {
661  static HCURSOR kCursorArrow = LoadCursor(NULL, IDC_ARROW);
662  static HCURSOR kCursorAppStarting = LoadCursor(NULL, IDC_APPSTARTING);
663  static HINSTANCE module_handle = GetModuleHandle(
664      GetContentClient()->browser()->GetResourceDllName());
665
666  // If the mouse is over our HWND, then update the cursor state immediately.
667  CPoint pt;
668  GetCursorPos(&pt);
669  if (WindowFromPoint(pt) == m_hWnd) {
670    // We cannot pass in NULL as the module handle as this would only work for
671    // standard win32 cursors. We can also receive cursor types which are
672    // defined as webkit resources. We need to specify the module handle of
673    // chrome.dll while loading these cursors.
674    HCURSOR display_cursor = current_cursor_.GetCursor(module_handle);
675
676    // If a page is in the loading state, we want to show the Arrow+Hourglass
677    // cursor only when the current cursor is the ARROW cursor. In all other
678    // cases we should continue to display the current cursor.
679    if (is_loading_ && display_cursor == kCursorArrow)
680      display_cursor = kCursorAppStarting;
681
682    SetCursor(display_cursor);
683  }
684}
685
686void RenderWidgetHostViewWin::SetIsLoading(bool is_loading) {
687  is_loading_ = is_loading;
688  UpdateCursorIfOverSelf();
689}
690
691void RenderWidgetHostViewWin::TextInputTypeChanged(
692    ui::TextInputType type,
693    bool can_compose_inline,
694    ui::TextInputMode input_mode) {
695  if (text_input_type_ != type ||
696      text_input_mode_ != input_mode ||
697      can_compose_inline_ != can_compose_inline) {
698    const bool text_input_type_changed = (text_input_type_ != type) ||
699                                         (text_input_mode_ != input_mode);
700    text_input_type_ = type;
701    text_input_mode_ = input_mode;
702    can_compose_inline_ = can_compose_inline;
703    UpdateIMEState();
704    if (text_input_type_changed)
705      UpdateInputScopeIfNecessary(text_input_type_);
706  }
707}
708
709void RenderWidgetHostViewWin::SelectionBoundsChanged(
710    const ViewHostMsg_SelectionBounds_Params& params) {
711  bool is_enabled = (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE &&
712      text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD);
713  // Only update caret position if the input method is enabled.
714  if (is_enabled) {
715    caret_rect_ = gfx::UnionRects(params.anchor_rect, params.focus_rect);
716    imm32_manager_->UpdateCaretRect(m_hWnd, caret_rect_);
717  }
718}
719
720void RenderWidgetHostViewWin::ScrollOffsetChanged() {
721}
722
723void RenderWidgetHostViewWin::ImeCancelComposition() {
724  imm32_manager_->CancelIME(m_hWnd);
725}
726
727void RenderWidgetHostViewWin::ImeCompositionRangeChanged(
728    const ui::Range& range,
729    const std::vector<gfx::Rect>& character_bounds) {
730  composition_range_ = range;
731  composition_character_bounds_ = character_bounds;
732}
733
734void RenderWidgetHostViewWin::Redraw() {
735  RECT damage_bounds;
736  GetUpdateRect(&damage_bounds, FALSE);
737
738  base::win::ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
739  GetUpdateRgn(damage_region, FALSE);
740
741  // Paint the invalid region synchronously.  Our caller will not paint again
742  // until we return, so by painting to the screen here, we ensure effective
743  // rate-limiting of backing store updates.  This helps a lot on pages that
744  // have animations or fairly expensive layout (e.g., google maps).
745  //
746  // We paint this window synchronously, however child windows (i.e. plugins)
747  // are painted asynchronously.  By avoiding synchronous cross-process window
748  // message dispatching we allow scrolling to be smooth, and also avoid the
749  // browser process locking up if the plugin process is hung.
750  //
751  RedrawWindow(NULL, damage_region, RDW_UPDATENOW | RDW_NOCHILDREN);
752
753  // Send the invalid rect in screen coordinates.
754  gfx::Rect invalid_screen_rect(damage_bounds);
755  invalid_screen_rect.Offset(GetPixelBounds().OffsetFromOrigin());
756
757  PaintPluginWindowsHelper(m_hWnd, invalid_screen_rect);
758}
759
760void RenderWidgetHostViewWin::DidUpdateBackingStore(
761    const gfx::Rect& scroll_rect,
762    const gfx::Vector2d& scroll_delta,
763    const std::vector<gfx::Rect>& copy_rects,
764    const ui::LatencyInfo& latency_info) {
765  software_latency_info_.MergeWith(latency_info);
766  if (is_hidden_)
767    return;
768
769  // Schedule invalidations first so that the ScrollWindowEx call is closer to
770  // Redraw.  That minimizes chances of "flicker" resulting if the screen
771  // refreshes before we have a chance to paint the exposed area.  Somewhat
772  // surprisingly, this ordering matters.
773
774  for (size_t i = 0; i < copy_rects.size(); ++i) {
775    gfx::Rect pixel_rect = ui::win::DIPToScreenRect(copy_rects[i]);
776    // Damage might not be DIP aligned.
777    pixel_rect.Inset(-1, -1);
778    RECT bounds = pixel_rect.ToRECT();
779    InvalidateRect(&bounds, false);
780  }
781
782  if (!scroll_rect.IsEmpty()) {
783    gfx::Rect pixel_rect = ui::win::DIPToScreenRect(scroll_rect);
784    // Damage might not be DIP aligned.
785    pixel_rect.Inset(-1, -1);
786    RECT clip_rect = pixel_rect.ToRECT();
787    float scale = ui::win::GetDeviceScaleFactor();
788    int dx = static_cast<int>(scale * scroll_delta.x());
789    int dy = static_cast<int>(scale * scroll_delta.y());
790    ScrollWindowEx(dx, dy, NULL, &clip_rect, NULL, NULL, SW_INVALIDATE);
791  }
792
793  if (!about_to_validate_and_paint_)
794    Redraw();
795}
796
797void RenderWidgetHostViewWin::RenderProcessGone(base::TerminationStatus status,
798                                                int error_code) {
799  UpdateCursorIfOverSelf();
800  Destroy();
801}
802
803bool RenderWidgetHostViewWin::CanSubscribeFrame() const {
804  return render_widget_host_ != NULL;
805}
806
807void RenderWidgetHostViewWin::WillWmDestroy() {
808  CleanupCompositorWindow();
809  if (base::win::IsTSFAwareRequired() && GetFocus() == m_hWnd)
810    ui::TSFBridge::GetInstance()->RemoveFocusedClient(this);
811}
812
813void RenderWidgetHostViewWin::Destroy() {
814  // We've been told to destroy.
815  // By clearing close_on_deactivate_, we prevent further deactivations
816  // (caused by windows messages resulting from the DestroyWindow) from
817  // triggering further destructions.  The deletion of this is handled by
818  // OnFinalMessage();
819  close_on_deactivate_ = false;
820  render_widget_host_ = NULL;
821  being_destroyed_ = true;
822  CleanupCompositorWindow();
823
824  // This releases the resources associated with input scope.
825  UpdateInputScopeIfNecessary(ui::TEXT_INPUT_TYPE_NONE);
826
827  if (is_fullscreen_ && win8::IsSingleWindowMetroMode()) {
828    MetroCloseFrameWindow close_frame_window =
829        reinterpret_cast<MetroCloseFrameWindow>(
830            ::GetProcAddress(base::win::GetMetroModule(), "CloseFrameWindow"));
831    DCHECK(close_frame_window);
832    close_frame_window(m_hWnd);
833  }
834
835  DestroyWindow();
836}
837
838void RenderWidgetHostViewWin::SetTooltipText(const string16& tooltip_text) {
839  if (!is_hidden_)
840    EnsureTooltip();
841
842  // Clamp the tooltip length to kMaxTooltipLength so that we don't
843  // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
844  // to do this itself).
845  const string16 new_tooltip_text =
846      ui::TruncateString(tooltip_text, kMaxTooltipLength);
847
848  if (new_tooltip_text != tooltip_text_) {
849    tooltip_text_ = new_tooltip_text;
850
851    // Need to check if the tooltip is already showing so that we don't
852    // immediately show the tooltip with no delay when we move the mouse from
853    // a region with no tooltip to a region with a tooltip.
854    if (::IsWindow(tooltip_hwnd_) && tooltip_showing_) {
855      ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
856      ::SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
857    }
858  } else {
859    // Make sure the tooltip gets closed after TTN_POP gets sent. For some
860    // reason this doesn't happen automatically, so moving the mouse around
861    // within the same link/image/etc doesn't cause the tooltip to re-appear.
862    if (!tooltip_showing_) {
863      if (::IsWindow(tooltip_hwnd_))
864        ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
865    }
866  }
867}
868
869BackingStore* RenderWidgetHostViewWin::AllocBackingStore(
870    const gfx::Size& size) {
871  return new BackingStoreWin(render_widget_host_, size);
872}
873
874void RenderWidgetHostViewWin::CopyFromCompositingSurface(
875    const gfx::Rect& src_subrect,
876    const gfx::Size& dst_size,
877    const base::Callback<void(bool, const SkBitmap&)>& callback) {
878  base::ScopedClosureRunner scoped_callback_runner(
879      base::Bind(callback, false, SkBitmap()));
880  if (!accelerated_surface_)
881    return;
882
883  if (dst_size.IsEmpty() || src_subrect.IsEmpty())
884    return;
885
886  scoped_callback_runner.Release();
887  accelerated_surface_->AsyncCopyTo(src_subrect, dst_size, callback);
888}
889
890void RenderWidgetHostViewWin::CopyFromCompositingSurfaceToVideoFrame(
891    const gfx::Rect& src_subrect,
892    const scoped_refptr<media::VideoFrame>& target,
893    const base::Callback<void(bool)>& callback) {
894  base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false));
895  if (!accelerated_surface_)
896    return;
897
898  if (!target || (target->format() != media::VideoFrame::YV12 &&
899                  target->format() != media::VideoFrame::I420))
900    return;
901
902  if (src_subrect.IsEmpty())
903    return;
904
905  scoped_callback_runner.Release();
906  accelerated_surface_->AsyncCopyToVideoFrame(src_subrect, target, callback);
907}
908
909bool RenderWidgetHostViewWin::CanCopyToVideoFrame() const {
910  return accelerated_surface_.get() && render_widget_host_ &&
911      render_widget_host_->is_accelerated_compositing_active();
912}
913
914void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) {
915  RenderWidgetHostViewBase::SetBackground(background);
916  render_widget_host_->SetBackground(background);
917}
918
919void RenderWidgetHostViewWin::ProcessAckedTouchEvent(
920    const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
921  DCHECK(touch_events_enabled_);
922
923  ScopedVector<ui::TouchEvent> events;
924  if (!MakeUITouchEventsFromWebTouchEvents(touch, &events, LOCAL_COORDINATES))
925    return;
926
927  ui::EventResult result = (ack_result ==
928      INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED;
929  for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(),
930      end = events.end(); iter != end; ++iter)  {
931    scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
932    gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture(
933        *(*iter), result, this));
934    ProcessGestures(gestures.get());
935  }
936}
937
938void RenderWidgetHostViewWin::UpdateDesiredTouchMode() {
939  // Make sure that touch events even make sense.
940  if (base::win::GetVersion() < base::win::VERSION_WIN7)
941    return;
942  if (touch_events_enabled_) {
943    CHECK(RegisterTouchWindow(m_hWnd, TWF_WANTPALM));
944  }
945}
946
947bool RenderWidgetHostViewWin::DispatchLongPressGestureEvent(
948    ui::GestureEvent* event) {
949  return ForwardGestureEventToRenderer(event);
950}
951
952bool RenderWidgetHostViewWin::DispatchCancelTouchEvent(
953    ui::TouchEvent* event) {
954  if (!render_widget_host_ || !touch_events_enabled_ ||
955      !render_widget_host_->ShouldForwardTouchEvent()) {
956    return false;
957  }
958  DCHECK(event->type() == WebKit::WebInputEvent::TouchCancel);
959  WebKit::WebTouchEvent cancel_event;
960  cancel_event.type = WebKit::WebInputEvent::TouchCancel;
961  cancel_event.timeStampSeconds = event->time_stamp().InSecondsF();
962  render_widget_host_->ForwardTouchEventWithLatencyInfo(
963      cancel_event, *event->latency());
964  return true;
965}
966
967void RenderWidgetHostViewWin::SetHasHorizontalScrollbar(
968    bool has_horizontal_scrollbar) {
969}
970
971void RenderWidgetHostViewWin::SetScrollOffsetPinning(
972    bool is_pinned_to_left, bool is_pinned_to_right) {
973}
974
975void RenderWidgetHostViewWin::SetCompositionText(
976    const ui::CompositionText& composition) {
977  if (!base::win::IsTSFAwareRequired()) {
978    NOTREACHED();
979    return;
980  }
981  if (!render_widget_host_)
982     return;
983  // ui::CompositionUnderline should be identical to
984  // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely.
985  COMPILE_ASSERT(sizeof(ui::CompositionUnderline) ==
986                 sizeof(WebKit::WebCompositionUnderline),
987                 ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff);
988  const std::vector<WebKit::WebCompositionUnderline>& underlines =
989      reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>(
990          composition.underlines);
991  render_widget_host_->ImeSetComposition(composition.text, underlines,
992                                         composition.selection.end(),
993                                         composition.selection.end());
994}
995
996void RenderWidgetHostViewWin::ConfirmCompositionText()  {
997  if (!base::win::IsTSFAwareRequired()) {
998    NOTREACHED();
999    return;
1000  }
1001  // TODO(nona): Implement this function.
1002  NOTIMPLEMENTED();
1003}
1004
1005void RenderWidgetHostViewWin::ClearCompositionText() {
1006  if (!base::win::IsTSFAwareRequired()) {
1007    NOTREACHED();
1008    return;
1009  }
1010  // TODO(nona): Implement this function.
1011  NOTIMPLEMENTED();
1012}
1013
1014void RenderWidgetHostViewWin::InsertText(const string16& text) {
1015  if (!base::win::IsTSFAwareRequired()) {
1016    NOTREACHED();
1017    return;
1018  }
1019  if (render_widget_host_)
1020    render_widget_host_->ImeConfirmComposition(text,
1021                                               ui::Range::InvalidRange(),
1022                                               false);
1023}
1024
1025void RenderWidgetHostViewWin::InsertChar(char16 ch, int flags) {
1026  if (!base::win::IsTSFAwareRequired()) {
1027    NOTREACHED();
1028    return;
1029  }
1030  // TODO(nona): Implement this function.
1031  NOTIMPLEMENTED();
1032}
1033
1034gfx::NativeWindow RenderWidgetHostViewWin::GetAttachedWindow() const {
1035  return m_hWnd;
1036}
1037
1038ui::TextInputType RenderWidgetHostViewWin::GetTextInputType() const {
1039  if (!base::win::IsTSFAwareRequired()) {
1040    NOTREACHED();
1041    return ui::TEXT_INPUT_TYPE_NONE;
1042  }
1043  return text_input_type_;
1044}
1045
1046ui::TextInputMode RenderWidgetHostViewWin::GetTextInputMode() const {
1047  if (!base::win::IsTSFAwareRequired()) {
1048    NOTREACHED();
1049    return ui::TEXT_INPUT_MODE_DEFAULT;
1050  }
1051  return ui::TEXT_INPUT_MODE_DEFAULT;
1052}
1053
1054bool RenderWidgetHostViewWin::CanComposeInline() const {
1055  if (!base::win::IsTSFAwareRequired()) {
1056    NOTREACHED();
1057    return false;
1058  }
1059  // TODO(nona): Implement this function.
1060  NOTIMPLEMENTED();
1061  return false;
1062}
1063
1064gfx::Rect RenderWidgetHostViewWin::GetCaretBounds() {
1065  if (!base::win::IsTSFAwareRequired()) {
1066    NOTREACHED();
1067    return gfx::Rect(0, 0, 0, 0);
1068  }
1069  RECT tmp_rect = caret_rect_.ToRECT();
1070  ClientToScreen(&tmp_rect);
1071  return gfx::Rect(tmp_rect);
1072}
1073
1074bool RenderWidgetHostViewWin::GetCompositionCharacterBounds(
1075    uint32 index, gfx::Rect* rect) {
1076  if (!base::win::IsTSFAwareRequired()) {
1077    NOTREACHED();
1078    return false;
1079  }
1080  DCHECK(rect);
1081  if (index >= composition_character_bounds_.size())
1082    return false;
1083  RECT rec = composition_character_bounds_[index].ToRECT();
1084  ClientToScreen(&rec);
1085  *rect = gfx::Rect(rec);
1086  return true;
1087}
1088
1089bool RenderWidgetHostViewWin::HasCompositionText() {
1090  if (!base::win::IsTSFAwareRequired()) {
1091    NOTREACHED();
1092    return false;
1093  }
1094  // TODO(nona): Implement this function.
1095  NOTIMPLEMENTED();
1096  return false;
1097}
1098
1099bool RenderWidgetHostViewWin::GetTextRange(ui::Range* range) {
1100  if (!base::win::IsTSFAwareRequired()) {
1101    NOTREACHED();
1102    return false;
1103  }
1104  range->set_start(selection_text_offset_);
1105  range->set_end(selection_text_offset_ + selection_text_.length());
1106  return false;
1107}
1108
1109bool RenderWidgetHostViewWin::GetCompositionTextRange(ui::Range* range) {
1110  if (!base::win::IsTSFAwareRequired()) {
1111    NOTREACHED();
1112    return false;
1113  }
1114  // TODO(nona): Implement this function.
1115  NOTIMPLEMENTED();
1116  return false;
1117}
1118
1119bool RenderWidgetHostViewWin::GetSelectionRange(ui::Range* range) {
1120  if (!base::win::IsTSFAwareRequired()) {
1121    NOTREACHED();
1122    return false;
1123  }
1124  range->set_start(selection_range_.start());
1125  range->set_end(selection_range_.end());
1126  return false;
1127}
1128
1129bool RenderWidgetHostViewWin::SetSelectionRange(const ui::Range& range) {
1130  if (!base::win::IsTSFAwareRequired()) {
1131    NOTREACHED();
1132    return false;
1133  }
1134  // TODO(nona): Implement this function.
1135  NOTIMPLEMENTED();
1136  return false;
1137}
1138
1139bool RenderWidgetHostViewWin::DeleteRange(const ui::Range& range) {
1140  if (!base::win::IsTSFAwareRequired()) {
1141    NOTREACHED();
1142    return false;
1143  }
1144  // TODO(nona): Implement this function.
1145  NOTIMPLEMENTED();
1146  return false;
1147}
1148
1149bool RenderWidgetHostViewWin::GetTextFromRange(const ui::Range& range,
1150                                               string16* text) {
1151  if (!base::win::IsTSFAwareRequired()) {
1152    NOTREACHED();
1153    return false;
1154  }
1155  ui::Range selection_text_range(selection_text_offset_,
1156      selection_text_offset_ + selection_text_.length());
1157  if (!selection_text_range.Contains(range)) {
1158    text->clear();
1159    return false;
1160  }
1161  if (selection_text_range.EqualsIgnoringDirection(range)) {
1162    *text = selection_text_;
1163  } else {
1164    *text = selection_text_.substr(
1165        range.GetMin() - selection_text_offset_,
1166        range.length());
1167  }
1168  return true;
1169}
1170
1171void RenderWidgetHostViewWin::OnInputMethodChanged() {
1172  if (!base::win::IsTSFAwareRequired()) {
1173    NOTREACHED();
1174    return;
1175  }
1176  // TODO(nona): Implement this function.
1177  NOTIMPLEMENTED();
1178}
1179
1180bool RenderWidgetHostViewWin::ChangeTextDirectionAndLayoutAlignment(
1181      base::i18n::TextDirection direction) {
1182  if (!base::win::IsTSFAwareRequired()) {
1183    NOTREACHED();
1184    return false;
1185  }
1186  // TODO(nona): Implement this function.
1187  NOTIMPLEMENTED();
1188  return false;
1189}
1190
1191void RenderWidgetHostViewWin::ExtendSelectionAndDelete(
1192    size_t before,
1193    size_t after) {
1194  if (!base::win::IsTSFAwareRequired()) {
1195    NOTREACHED();
1196    return;
1197  }
1198  if (!render_widget_host_)
1199    return;
1200  render_widget_host_->ExtendSelectionAndDelete(before, after);
1201}
1202
1203void RenderWidgetHostViewWin::EnsureCaretInRect(const gfx::Rect& rect) {
1204  // TODO(nona): Implement this function.
1205  NOTIMPLEMENTED();
1206}
1207
1208///////////////////////////////////////////////////////////////////////////////
1209// RenderWidgetHostViewWin, private:
1210
1211LRESULT RenderWidgetHostViewWin::OnCreate(CREATESTRUCT* create_struct) {
1212  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCreate");
1213  // Call the WM_INPUTLANGCHANGE message handler to initialize the input locale
1214  // of a browser process.
1215  OnInputLangChange(0, 0);
1216  // Marks that window as supporting mouse-wheel messages rerouting so it is
1217  // scrolled when under the mouse pointer even if inactive.
1218  props_.push_back(ui::SetWindowSupportsRerouteMouseWheel(m_hWnd));
1219
1220  WTSRegisterSessionNotification(m_hWnd, NOTIFY_FOR_THIS_SESSION);
1221
1222  UpdateDesiredTouchMode();
1223  UpdateIMEState();
1224
1225  return 0;
1226}
1227
1228void RenderWidgetHostViewWin::OnActivate(UINT action, BOOL minimized,
1229                                         HWND window) {
1230  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnActivate");
1231  // If the container is a popup, clicking elsewhere on screen should close the
1232  // popup.
1233  if (close_on_deactivate_ && action == WA_INACTIVE) {
1234    // Send a windows message so that any derived classes
1235    // will get a change to override the default handling
1236    SendMessage(WM_CANCELMODE);
1237  }
1238}
1239
1240void RenderWidgetHostViewWin::OnDestroy() {
1241  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnDestroy");
1242  DetachPluginsHelper(m_hWnd);
1243
1244  props_.clear();
1245
1246  if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
1247      IsTouchWindow(m_hWnd, NULL)) {
1248    UnregisterTouchWindow(m_hWnd);
1249  }
1250
1251  CleanupCompositorWindow();
1252
1253  WTSUnRegisterSessionNotification(m_hWnd);
1254
1255  ResetTooltip();
1256  TrackMouseLeave(false);
1257}
1258
1259void RenderWidgetHostViewWin::OnPaint(HDC unused_dc) {
1260  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnPaint");
1261
1262  // Grab the region to paint before creation of paint_dc since it clears the
1263  // damage region.
1264  base::win::ScopedGDIObject<HRGN> damage_region(CreateRectRgn(0, 0, 0, 0));
1265  GetUpdateRgn(damage_region, FALSE);
1266
1267  CPaintDC paint_dc(m_hWnd);
1268
1269  if (!render_widget_host_)
1270    return;
1271
1272  DCHECK(render_widget_host_->GetProcess()->HasConnection());
1273
1274  // If the GPU process is rendering to a child window, compositing is
1275  // already triggered by damage to compositor_host_window_, so all we need to
1276  // do here is clear borders during resize.
1277  if (compositor_host_window_ &&
1278      render_widget_host_->is_accelerated_compositing_active()) {
1279    RECT host_rect, child_rect;
1280    GetClientRect(&host_rect);
1281    if (::GetClientRect(compositor_host_window_, &child_rect) &&
1282        (child_rect.right < host_rect.right ||
1283         child_rect.bottom < host_rect.bottom)) {
1284      paint_dc.FillRect(&host_rect,
1285          reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
1286    }
1287    return;
1288  }
1289
1290  if (accelerated_surface_.get() &&
1291      render_widget_host_->is_accelerated_compositing_active()) {
1292    AcceleratedPaint(paint_dc.m_hDC);
1293    return;
1294  }
1295
1296  about_to_validate_and_paint_ = true;
1297  BackingStoreWin* backing_store = static_cast<BackingStoreWin*>(
1298      render_widget_host_->GetBackingStore(true));
1299
1300  // We initialize |paint_dc| (and thus call BeginPaint()) after calling
1301  // GetBackingStore(), so that if it updates the invalid rect we'll catch the
1302  // changes and repaint them.
1303  about_to_validate_and_paint_ = false;
1304
1305  if (compositor_host_window_ && hide_compositor_window_at_next_paint_) {
1306    ::ShowWindow(compositor_host_window_, SW_HIDE);
1307    hide_compositor_window_at_next_paint_ = false;
1308  }
1309
1310  gfx::Rect damaged_rect(paint_dc.m_ps.rcPaint);
1311  if (damaged_rect.IsEmpty())
1312    return;
1313
1314  if (backing_store) {
1315    gfx::Rect bitmap_rect(gfx::Point(),
1316                          ui::win::DIPToScreenSize(backing_store->size()));
1317
1318    bool manage_colors = BackingStoreWin::ColorManagementEnabled();
1319    if (manage_colors)
1320      SetICMMode(paint_dc.m_hDC, ICM_ON);
1321
1322    // Blit only the damaged regions from the backing store.
1323    DWORD data_size = GetRegionData(damage_region, 0, NULL);
1324    scoped_ptr<char[]> region_data_buf;
1325    RGNDATA* region_data = NULL;
1326    RECT* region_rects = NULL;
1327
1328    if (data_size) {
1329      region_data_buf.reset(new char[data_size]);
1330      region_data = reinterpret_cast<RGNDATA*>(region_data_buf.get());
1331      region_rects = reinterpret_cast<RECT*>(region_data->Buffer);
1332      data_size = GetRegionData(damage_region, data_size, region_data);
1333    }
1334
1335    if (!data_size) {
1336      // Grabbing the damaged regions failed, fake with the whole rect.
1337      data_size = sizeof(RGNDATAHEADER) + sizeof(RECT);
1338      region_data_buf.reset(new char[data_size]);
1339      region_data = reinterpret_cast<RGNDATA*>(region_data_buf.get());
1340      region_rects = reinterpret_cast<RECT*>(region_data->Buffer);
1341      region_data->rdh.nCount = 1;
1342      region_rects[0] = damaged_rect.ToRECT();
1343    }
1344
1345    for (DWORD i = 0; i < region_data->rdh.nCount; ++i) {
1346      gfx::Rect paint_rect =
1347          gfx::IntersectRects(bitmap_rect, gfx::Rect(region_rects[i]));
1348      if (!paint_rect.IsEmpty()) {
1349        BitBlt(paint_dc.m_hDC,
1350               paint_rect.x(),
1351               paint_rect.y(),
1352               paint_rect.width(),
1353               paint_rect.height(),
1354               backing_store->hdc(),
1355               paint_rect.x(),
1356               paint_rect.y(),
1357               SRCCOPY);
1358      }
1359    }
1360
1361    if (manage_colors)
1362      SetICMMode(paint_dc.m_hDC, ICM_OFF);
1363
1364    // Fill the remaining portion of the damaged_rect with the background
1365    if (damaged_rect.right() > bitmap_rect.right()) {
1366      RECT r;
1367      r.left = std::max(bitmap_rect.right(), damaged_rect.x());
1368      r.right = damaged_rect.right();
1369      r.top = damaged_rect.y();
1370      r.bottom = std::min(bitmap_rect.bottom(), damaged_rect.bottom());
1371      DrawBackground(r, &paint_dc);
1372    }
1373    if (damaged_rect.bottom() > bitmap_rect.bottom()) {
1374      RECT r;
1375      r.left = damaged_rect.x();
1376      r.right = damaged_rect.right();
1377      r.top = std::max(bitmap_rect.bottom(), damaged_rect.y());
1378      r.bottom = damaged_rect.bottom();
1379      DrawBackground(r, &paint_dc);
1380    }
1381    if (!whiteout_start_time_.is_null()) {
1382      TimeDelta whiteout_duration = TimeTicks::Now() - whiteout_start_time_;
1383      UMA_HISTOGRAM_TIMES("MPArch.RWHH_WhiteoutDuration", whiteout_duration);
1384
1385      // Reset the start time to 0 so that we start recording again the next
1386      // time the backing store is NULL...
1387      whiteout_start_time_ = TimeTicks();
1388    }
1389    if (!web_contents_switch_paint_time_.is_null()) {
1390      TimeDelta web_contents_switch_paint_duration = TimeTicks::Now() -
1391          web_contents_switch_paint_time_;
1392      UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration",
1393          web_contents_switch_paint_duration);
1394      // Reset contents_switch_paint_time_ to 0 so future tab selections are
1395      // recorded.
1396      web_contents_switch_paint_time_ = TimeTicks();
1397    }
1398
1399    software_latency_info_.swap_timestamp = TimeTicks::HighResNow();
1400    render_widget_host_->FrameSwapped(software_latency_info_);
1401    software_latency_info_.Clear();
1402  } else {
1403    DrawBackground(paint_dc.m_ps.rcPaint, &paint_dc);
1404    if (whiteout_start_time_.is_null())
1405      whiteout_start_time_ = TimeTicks::Now();
1406  }
1407}
1408
1409void RenderWidgetHostViewWin::DrawBackground(const RECT& dirty_rect,
1410                                             CPaintDC* dc) {
1411  if (!background_.empty()) {
1412    gfx::Rect dirty_area(dirty_rect);
1413    gfx::Canvas canvas(dirty_area.size(), ui::SCALE_FACTOR_100P, true);
1414    canvas.Translate(-dirty_area.OffsetFromOrigin());
1415
1416    gfx::Rect dc_rect(dc->m_ps.rcPaint);
1417    // TODO(pkotwicz): Fix |background_| such that it is an ImageSkia.
1418    canvas.TileImageInt(gfx::ImageSkia::CreateFrom1xBitmap(background_),
1419                        0, 0, dc_rect.width(), dc_rect.height());
1420
1421    skia::DrawToNativeContext(canvas.sk_canvas(), *dc, dirty_area.x(),
1422                              dirty_area.y(), NULL);
1423  } else {
1424    HBRUSH white_brush = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
1425    dc->FillRect(&dirty_rect, white_brush);
1426  }
1427}
1428
1429void RenderWidgetHostViewWin::OnNCPaint(HRGN update_region) {
1430  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNCPaint");
1431  // Do nothing.  This suppresses the resize corner that Windows would
1432  // otherwise draw for us.
1433}
1434
1435void RenderWidgetHostViewWin::SetClickthroughRegion(SkRegion* region) {
1436  transparent_region_.reset(region);
1437}
1438
1439LRESULT RenderWidgetHostViewWin::OnNCHitTest(const CPoint& point) {
1440  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNCHitTest");
1441  RECT rc;
1442  GetWindowRect(&rc);
1443  if (transparent_region_.get() &&
1444      transparent_region_->contains(point.x - rc.left, point.y - rc.top)) {
1445    SetMsgHandled(TRUE);
1446    return HTTRANSPARENT;
1447  }
1448  SetMsgHandled(FALSE);
1449  return 0;
1450}
1451
1452LRESULT RenderWidgetHostViewWin::OnEraseBkgnd(HDC dc) {
1453  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnEraseBkgnd");
1454  return 1;
1455}
1456
1457LRESULT RenderWidgetHostViewWin::OnSetCursor(HWND window, UINT hittest_code,
1458                                             UINT mouse_message_id) {
1459  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSetCursor");
1460  UpdateCursorIfOverSelf();
1461  return 0;
1462}
1463
1464void RenderWidgetHostViewWin::OnSetFocus(HWND window) {
1465  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSetFocus");
1466  if (!render_widget_host_)
1467    return;
1468
1469  if (GetBrowserAccessibilityManager())
1470    GetBrowserAccessibilityManager()->GotFocus(pointer_down_context_);
1471
1472  render_widget_host_->GotFocus();
1473  render_widget_host_->SetActive(true);
1474
1475  if (base::win::IsTSFAwareRequired())
1476    ui::TSFBridge::GetInstance()->SetFocusedClient(m_hWnd, this);
1477}
1478
1479void RenderWidgetHostViewWin::OnKillFocus(HWND window) {
1480  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnKillFocus");
1481  if (!render_widget_host_)
1482    return;
1483
1484  render_widget_host_->SetActive(false);
1485  render_widget_host_->Blur();
1486
1487  last_touch_location_ = gfx::Point(-1, -1);
1488
1489  if (base::win::IsTSFAwareRequired())
1490    ui::TSFBridge::GetInstance()->RemoveFocusedClient(this);
1491}
1492
1493void RenderWidgetHostViewWin::OnCaptureChanged(HWND window) {
1494  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCaptureChanged");
1495  if (render_widget_host_)
1496    render_widget_host_->LostCapture();
1497  pointer_down_context_ = false;
1498}
1499
1500void RenderWidgetHostViewWin::OnCancelMode() {
1501  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnCancelMode");
1502  if (render_widget_host_)
1503    render_widget_host_->LostCapture();
1504
1505  if ((is_fullscreen_ || close_on_deactivate_) &&
1506      !weak_factory_.HasWeakPtrs()) {
1507    // Dismiss popups and menus.  We do this asynchronously to avoid changing
1508    // activation within this callstack, which may interfere with another window
1509    // being activated.  We can synchronously hide the window, but we need to
1510    // not change activation while doing so.
1511    SetWindowPos(NULL, 0, 0, 0, 0,
1512                 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
1513                 SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
1514    base::MessageLoop::current()->PostTask(
1515        FROM_HERE,
1516        base::Bind(&RenderWidgetHostViewWin::ShutdownHost,
1517                   weak_factory_.GetWeakPtr()));
1518  }
1519}
1520
1521void RenderWidgetHostViewWin::OnInputLangChange(DWORD character_set,
1522                                                HKL input_language_id) {
1523  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnInputLangChange");
1524  // Send the given Locale ID to the IMM32Manager object and retrieves whether
1525  // or not the current input context has IMEs.
1526  // If the current input context has IMEs, a browser process has to send a
1527  // request to a renderer process that it needs status messages about
1528  // the focused edit control from the renderer process.
1529  // On the other hand, if the current input context does not have IMEs, the
1530  // browser process also has to send a request to the renderer process that
1531  // it does not need the status messages any longer.
1532  // To minimize the number of this notification request, we should check if
1533  // the browser process is actually retrieving the status messages (this
1534  // state is stored in ime_notification_) and send a request only if the
1535  // browser process has to update this status, its details are listed below:
1536  // * If a browser process is not retrieving the status messages,
1537  //   (i.e. ime_notification_ == false),
1538  //   send this request only if the input context does have IMEs,
1539  //   (i.e. ime_status == true);
1540  //   When it successfully sends the request, toggle its notification status,
1541  //   (i.e.ime_notification_ = !ime_notification_ = true).
1542  // * If a browser process is retrieving the status messages
1543  //   (i.e. ime_notification_ == true),
1544  //   send this request only if the input context does not have IMEs,
1545  //   (i.e. ime_status == false).
1546  //   When it successfully sends the request, toggle its notification status,
1547  //   (i.e.ime_notification_ = !ime_notification_ = false).
1548  // To analyze the above actions, we can optimize them into the ones
1549  // listed below:
1550  // 1 Sending a request only if ime_status_ != ime_notification_, and;
1551  // 2 Copying ime_status to ime_notification_ if it sends the request
1552  //   successfully (because Action 1 shows ime_status = !ime_notification_.)
1553  bool ime_status = imm32_manager_->SetInputLanguage();
1554  if (ime_status != ime_notification_) {
1555    if (render_widget_host_) {
1556      render_widget_host_->SetInputMethodActive(ime_status);
1557      ime_notification_ = ime_status;
1558    }
1559  }
1560  // Call DefWindowProc() for consistency with other Chrome windows.
1561  // TODO(hbono): This is a speculative fix for Bug 36354 and this code may be
1562  // reverted if it does not fix it.
1563  SetMsgHandled(FALSE);
1564}
1565
1566void RenderWidgetHostViewWin::OnThemeChanged() {
1567  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnThemeChanged");
1568  if (!render_widget_host_)
1569    return;
1570  render_widget_host_->Send(new ViewMsg_ThemeChanged(
1571      render_widget_host_->GetRoutingID()));
1572}
1573
1574LRESULT RenderWidgetHostViewWin::OnNotify(int w_param, NMHDR* header) {
1575  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnNotify");
1576  if (tooltip_hwnd_ == NULL)
1577    return 0;
1578
1579  switch (header->code) {
1580    case TTN_GETDISPINFO: {
1581      NMTTDISPINFOW* tooltip_info = reinterpret_cast<NMTTDISPINFOW*>(header);
1582      tooltip_info->szText[0] = L'\0';
1583      tooltip_info->lpszText = const_cast<WCHAR*>(tooltip_text_.c_str());
1584      ::SendMessage(
1585        tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, kTooltipMaxWidthPixels);
1586      SetMsgHandled(TRUE);
1587      break;
1588    }
1589    case TTN_POP:
1590      tooltip_showing_ = false;
1591      SetMsgHandled(TRUE);
1592      break;
1593    case TTN_SHOW:
1594      // Tooltip shouldn't be shown when the mouse is locked.
1595      DCHECK(!mouse_locked_);
1596      tooltip_showing_ = true;
1597      SetMsgHandled(TRUE);
1598      break;
1599  }
1600  return 0;
1601}
1602
1603LRESULT RenderWidgetHostViewWin::OnImeSetContext(
1604    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1605  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeSetContext");
1606  if (!render_widget_host_)
1607    return 0;
1608
1609  // We need status messages about the focused input control from a
1610  // renderer process when:
1611  //   * the current input context has IMEs, and;
1612  //   * an application is activated.
1613  // This seems to tell we should also check if the current input context has
1614  // IMEs before sending a request, however, this WM_IME_SETCONTEXT is
1615  // fortunately sent to an application only while the input context has IMEs.
1616  // Therefore, we just start/stop status messages according to the activation
1617  // status of this application without checks.
1618  bool activated = (wparam == TRUE);
1619  if (render_widget_host_) {
1620    render_widget_host_->SetInputMethodActive(activated);
1621    ime_notification_ = activated;
1622  }
1623
1624  if (ime_notification_)
1625    imm32_manager_->CreateImeWindow(m_hWnd);
1626
1627  imm32_manager_->CleanupComposition(m_hWnd);
1628  return imm32_manager_->SetImeWindowStyle(
1629      m_hWnd, message, wparam, lparam, &handled);
1630}
1631
1632LRESULT RenderWidgetHostViewWin::OnImeStartComposition(
1633    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1634  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeStartComposition");
1635  if (!render_widget_host_)
1636    return 0;
1637
1638  // Reset the composition status and create IME windows.
1639  imm32_manager_->CreateImeWindow(m_hWnd);
1640  imm32_manager_->ResetComposition(m_hWnd);
1641  // When the focus is on an element that does not draw composition by itself
1642  // (i.e., PPAPI plugin not handling IME), let IME to draw the text. Otherwise
1643  // we have to prevent WTL from calling ::DefWindowProc() because the function
1644  // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
1645  // over-write the position of IME windows.
1646  handled = (can_compose_inline_ ? TRUE : FALSE);
1647  return 0;
1648}
1649
1650LRESULT RenderWidgetHostViewWin::OnImeComposition(
1651    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1652  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeComposition");
1653  if (!render_widget_host_)
1654    return 0;
1655
1656  // At first, update the position of the IME window.
1657  imm32_manager_->UpdateImeWindow(m_hWnd);
1658
1659  // ui::CompositionUnderline should be identical to
1660  // WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely.
1661  COMPILE_ASSERT(sizeof(ui::CompositionUnderline) ==
1662                 sizeof(WebKit::WebCompositionUnderline),
1663                 ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff);
1664
1665  // Retrieve the result string and its attributes of the ongoing composition
1666  // and send it to a renderer process.
1667  ui::CompositionText composition;
1668  if (imm32_manager_->GetResult(m_hWnd, lparam, &composition.text)) {
1669    render_widget_host_->ImeConfirmComposition(
1670        composition.text, ui::Range::InvalidRange(), false);
1671    imm32_manager_->ResetComposition(m_hWnd);
1672    // Fall though and try reading the composition string.
1673    // Japanese IMEs send a message containing both GCS_RESULTSTR and
1674    // GCS_COMPSTR, which means an ongoing composition has been finished
1675    // by the start of another composition.
1676  }
1677  // Retrieve the composition string and its attributes of the ongoing
1678  // composition and send it to a renderer process.
1679  if (imm32_manager_->GetComposition(m_hWnd, lparam, &composition)) {
1680    // TODO(suzhe): due to a bug of webkit, we can't use selection range with
1681    // composition string. See: https://bugs.webkit.org/show_bug.cgi?id=37788
1682    composition.selection = ui::Range(composition.selection.end());
1683
1684    // TODO(suzhe): convert both renderer_host and renderer to use
1685    // ui::CompositionText.
1686    const std::vector<WebKit::WebCompositionUnderline>& underlines =
1687        reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>(
1688            composition.underlines);
1689    render_widget_host_->ImeSetComposition(
1690        composition.text, underlines,
1691        composition.selection.start(), composition.selection.end());
1692  }
1693  // We have to prevent WTL from calling ::DefWindowProc() because we do not
1694  // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
1695  handled = TRUE;
1696  if (!can_compose_inline_) {
1697    // When the focus is on an element that does not draw composition by itself
1698    // (i.e., PPAPI plugin not handling IME), let IME to draw the text, which
1699    // is the default behavior of DefWindowProc. Note, however, even in this
1700    // case we don't want GCS_RESULTSTR to be converted to WM_IME_CHAR messages.
1701    // Thus we explicitly drop the flag.
1702    return ::DefWindowProc(m_hWnd, message, wparam, lparam & ~GCS_RESULTSTR);
1703  }
1704  return 0;
1705}
1706
1707LRESULT RenderWidgetHostViewWin::OnImeEndComposition(
1708    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1709  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeEndComposition");
1710  if (!render_widget_host_)
1711    return 0;
1712
1713  if (imm32_manager_->is_composing()) {
1714    // A composition has been ended while there is an ongoing composition,
1715    // i.e. the ongoing composition has been canceled.
1716    // We need to reset the composition status both of the IMM32Manager object
1717    // and of the renderer process.
1718    render_widget_host_->ImeCancelComposition();
1719    imm32_manager_->ResetComposition(m_hWnd);
1720  }
1721  imm32_manager_->DestroyImeWindow(m_hWnd);
1722  // Let WTL call ::DefWindowProc() and release its resources.
1723  handled = FALSE;
1724  return 0;
1725}
1726
1727LRESULT RenderWidgetHostViewWin::OnImeRequest(
1728    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
1729  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnImeRequest");
1730  if (!render_widget_host_) {
1731    handled = FALSE;
1732    return 0;
1733  }
1734
1735  // Should not receive WM_IME_REQUEST message, if IME is disabled.
1736  if (text_input_type_ == ui::TEXT_INPUT_TYPE_NONE ||
1737      text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD) {
1738    handled = FALSE;
1739    return 0;
1740  }
1741
1742  switch (wparam) {
1743    case IMR_RECONVERTSTRING:
1744      return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam));
1745    case IMR_DOCUMENTFEED:
1746      return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam));
1747    case IMR_QUERYCHARPOSITION:
1748      return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam));
1749    default:
1750      handled = FALSE;
1751      return 0;
1752  }
1753}
1754
1755LRESULT RenderWidgetHostViewWin::OnMouseEvent(UINT message, WPARAM wparam,
1756                                              LPARAM lparam, BOOL& handled) {
1757  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnMouseEvent");
1758  handled = TRUE;
1759
1760  if (message == WM_MOUSELEAVE)
1761    ignore_mouse_movement_ = true;
1762
1763  if (mouse_locked_) {
1764    HandleLockedMouseEvent(message, wparam, lparam);
1765    MoveCursorToCenterIfNecessary();
1766    return 0;
1767  }
1768
1769  if (::IsWindow(tooltip_hwnd_)) {
1770    // Forward mouse events through to the tooltip window
1771    MSG msg;
1772    msg.hwnd = m_hWnd;
1773    msg.message = message;
1774    msg.wParam = wparam;
1775    msg.lParam = lparam;
1776    SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, NULL,
1777                reinterpret_cast<LPARAM>(&msg));
1778  }
1779
1780  // Due to a bug in Windows, the simulated mouse events for a touch event
1781  // outside our bounds are delivered to us if we were previously focused
1782  // causing crbug.com/159982. As a workaround, we check if this event is a
1783  // simulated mouse event outside our bounds, and if so, we send it to the
1784  // right window.
1785  if ((message == WM_LBUTTONDOWN || message == WM_LBUTTONUP) &&
1786      ui::IsMouseEventFromTouch(message)) {
1787    CPoint cursor_pos(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
1788    ClientToScreen(&cursor_pos);
1789    if (!GetPixelBounds().Contains(cursor_pos.x, cursor_pos.y)) {
1790      HWND window = WindowFromPoint(cursor_pos);
1791      if (window) {
1792        LRESULT nc_hit_result = SendMessage(window, WM_NCHITTEST, 0,
1793            MAKELPARAM(cursor_pos.x, cursor_pos.y));
1794        const bool in_client_area = (nc_hit_result == HTCLIENT);
1795        int event_type;
1796        if (message == WM_LBUTTONDOWN)
1797          event_type = in_client_area ? WM_LBUTTONDOWN : WM_NCLBUTTONDOWN;
1798        else
1799          event_type = in_client_area ? WM_LBUTTONUP : WM_NCLBUTTONUP;
1800
1801        // Convert the coordinates to the target window.
1802        RECT window_bounds;
1803        ::GetWindowRect(window, &window_bounds);
1804        int window_x = cursor_pos.x - window_bounds.left;
1805        int window_y = cursor_pos.y - window_bounds.top;
1806        if (in_client_area) {
1807          ::PostMessage(window, event_type, wparam,
1808              MAKELPARAM(window_x, window_y));
1809        } else {
1810          ::PostMessage(window, event_type, nc_hit_result,
1811              MAKELPARAM(cursor_pos.x, cursor_pos.y));
1812        }
1813        return 0;
1814      }
1815    }
1816  }
1817
1818  // TODO(jcampan): I am not sure if we should forward the message to the
1819  // WebContentsImpl first in the case of popups.  If we do, we would need to
1820  // convert the click from the popup window coordinates to the WebContentsImpl'
1821  // window coordinates. For now we don't forward the message in that case to
1822  // address bug #907474.
1823  // Note: GetParent() on popup windows returns the top window and not the
1824  // parent the window was created with (the parent and the owner of the popup
1825  // is the first non-child view of the view that was specified to the create
1826  // call).  So the WebContentsImpl's window would have to be specified to the
1827  // RenderViewHostHWND as there is no way to retrieve it from the HWND.
1828
1829  // Don't forward if the container is a popup or fullscreen widget.
1830  if (!is_fullscreen_ && !close_on_deactivate_) {
1831    switch (message) {
1832      case WM_LBUTTONDOWN:
1833      case WM_MBUTTONDOWN:
1834      case WM_RBUTTONDOWN:
1835        // Finish the ongoing composition whenever a mouse click happens.
1836        // It matches IE's behavior.
1837        if (base::win::IsTSFAwareRequired()) {
1838          ui::TSFBridge::GetInstance()->CancelComposition();
1839        } else {
1840          imm32_manager_->CleanupComposition(m_hWnd);
1841        }
1842        // Fall through.
1843      case WM_MOUSEMOVE:
1844      case WM_MOUSELEAVE: {
1845        // Give the WebContentsImpl first crack at the message. It may want to
1846        // prevent forwarding to the renderer if some higher level browser
1847        // functionality is invoked.
1848        LPARAM parent_msg_lparam = lparam;
1849        if (message != WM_MOUSELEAVE) {
1850          // For the messages except WM_MOUSELEAVE, before forwarding them to
1851          // parent window, we should adjust cursor position from client
1852          // coordinates in current window to client coordinates in its parent
1853          // window.
1854          CPoint cursor_pos(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
1855          ClientToScreen(&cursor_pos);
1856          GetParent().ScreenToClient(&cursor_pos);
1857          parent_msg_lparam = MAKELPARAM(cursor_pos.x, cursor_pos.y);
1858        }
1859        if (SendMessage(GetParent(), message, wparam, parent_msg_lparam) != 0) {
1860          TRACE_EVENT0("browser", "EarlyOut_SentToParent");
1861          return 1;
1862        }
1863      }
1864    }
1865  }
1866
1867  if (message == WM_LBUTTONDOWN && pointer_down_context_ &&
1868      GetBrowserAccessibilityManager()) {
1869    GetBrowserAccessibilityManager()->GotMouseDown();
1870  }
1871
1872  if (message == WM_LBUTTONUP && ui::IsMouseEventFromTouch(message) &&
1873      base::win::IsMetroProcess())
1874    pointer_down_context_ = false;
1875
1876  ForwardMouseEventToRenderer(message, wparam, lparam);
1877  return 0;
1878}
1879
1880LRESULT RenderWidgetHostViewWin::OnKeyEvent(UINT message, WPARAM wparam,
1881                                            LPARAM lparam, BOOL& handled) {
1882  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnKeyEvent");
1883  handled = TRUE;
1884
1885  // When Escape is pressed, force fullscreen windows to close if necessary.
1886  if ((message == WM_KEYDOWN || message == WM_KEYUP) && wparam == VK_ESCAPE) {
1887    if (is_fullscreen_) {
1888      SendMessage(WM_CANCELMODE);
1889      return 0;
1890    }
1891  }
1892
1893  // If we are a pop-up, forward tab related messages to our parent HWND, so
1894  // that we are dismissed appropriately and so that the focus advance in our
1895  // parent.
1896  // TODO(jcampan): http://b/issue?id=1192881 Could be abstracted in the
1897  //                FocusManager.
1898  if (close_on_deactivate_ &&
1899      (((message == WM_KEYDOWN || message == WM_KEYUP) && (wparam == VK_TAB)) ||
1900        (message == WM_CHAR && wparam == L'\t'))) {
1901    // First close the pop-up.
1902    SendMessage(WM_CANCELMODE);
1903    // Then move the focus by forwarding the tab key to the parent.
1904    return ::SendMessage(GetParent(), message, wparam, lparam);
1905  }
1906
1907  if (!render_widget_host_)
1908    return 0;
1909
1910  // Bug 1845: we need to update the text direction when a user releases
1911  // either a right-shift key or a right-control key after pressing both of
1912  // them. So, we just update the text direction while a user is pressing the
1913  // keys, and we notify the text direction when a user releases either of them.
1914  // Bug 9718: http://crbug.com/9718 To investigate IE and notepad, this
1915  // shortcut is enabled only on a PC having RTL keyboard layouts installed.
1916  // We should emulate them.
1917  if (ui::IMM32Manager::IsRTLKeyboardLayoutInstalled()) {
1918    if (message == WM_KEYDOWN) {
1919      if (wparam == VK_SHIFT) {
1920        base::i18n::TextDirection dir;
1921        if (ui::IMM32Manager::IsCtrlShiftPressed(&dir)) {
1922          render_widget_host_->UpdateTextDirection(
1923              dir == base::i18n::RIGHT_TO_LEFT ?
1924              WebKit::WebTextDirectionRightToLeft :
1925              WebKit::WebTextDirectionLeftToRight);
1926        }
1927      } else if (wparam != VK_CONTROL) {
1928        // Bug 9762: http://crbug.com/9762 A user pressed a key except shift
1929        // and control keys.
1930        // When a user presses a key while he/she holds control and shift keys,
1931        // we cancel sending an IPC message in NotifyTextDirection() below and
1932        // ignore succeeding UpdateTextDirection() calls while we call
1933        // NotifyTextDirection().
1934        // To cancel it, this call set a flag that prevents sending an IPC
1935        // message in NotifyTextDirection() only if we are going to send it.
1936        // It is harmless to call this function if we aren't going to send it.
1937        render_widget_host_->CancelUpdateTextDirection();
1938      }
1939    } else if (message == WM_KEYUP &&
1940               (wparam == VK_SHIFT || wparam == VK_CONTROL)) {
1941      // We send an IPC message only if we need to update the text direction.
1942      render_widget_host_->NotifyTextDirection();
1943    }
1944  }
1945
1946  // Special processing for enter key: When user hits enter in omnibox
1947  // we change focus to render host after the navigation, so repeat WM_KEYDOWNs
1948  // and WM_KEYUP are going to render host, despite being initiated in other
1949  // window. This code filters out these messages.
1950  bool ignore_keyboard_event = false;
1951  if (wparam == VK_RETURN) {
1952    if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) {
1953      if (KF_REPEAT & HIWORD(lparam)) {
1954        // this is a repeated key
1955        if (!capture_enter_key_)
1956          ignore_keyboard_event = true;
1957      } else {
1958        capture_enter_key_ = true;
1959      }
1960    } else if (message == WM_KEYUP || message == WM_SYSKEYUP) {
1961      if (!capture_enter_key_)
1962        ignore_keyboard_event = true;
1963      capture_enter_key_ = false;
1964    } else {
1965      // Ignore all other keyboard events for the enter key if not captured.
1966      if (!capture_enter_key_)
1967        ignore_keyboard_event = true;
1968    }
1969  }
1970
1971  if (render_widget_host_ && !ignore_keyboard_event) {
1972    MSG msg = { m_hWnd, message, wparam, lparam };
1973    render_widget_host_->ForwardKeyboardEvent(NativeWebKeyboardEvent(msg));
1974  }
1975
1976  return 0;
1977}
1978
1979LRESULT RenderWidgetHostViewWin::OnWheelEvent(UINT message, WPARAM wparam,
1980                                              LPARAM lparam, BOOL& handled) {
1981  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnWheelEvent");
1982  // Forward the mouse-wheel message to the window under the mouse if it belongs
1983  // to us.
1984  if (message == WM_MOUSEWHEEL &&
1985      ui::RerouteMouseWheel(m_hWnd, wparam, lparam)) {
1986    handled = TRUE;
1987    return 0;
1988  }
1989
1990  // We get mouse wheel/scroll messages even if we are not in the foreground.
1991  // So here we check if we have any owned popup windows in the foreground and
1992  // dismiss them.
1993  if (m_hWnd != GetForegroundWindow()) {
1994    HWND toplevel_hwnd = ::GetAncestor(m_hWnd, GA_ROOT);
1995    EnumThreadWindows(
1996        GetCurrentThreadId(),
1997        DismissOwnedPopups,
1998        reinterpret_cast<LPARAM>(toplevel_hwnd));
1999  }
2000
2001  if (render_widget_host_) {
2002    WebKit::WebMouseWheelEvent wheel_event =
2003        WebMouseWheelEventBuilder::Build(m_hWnd, message, wparam, lparam);
2004    float scale = ui::win::GetDeviceScaleFactor();
2005    wheel_event.x /= scale;
2006    wheel_event.y /= scale;
2007    wheel_event.deltaX /= scale;
2008    wheel_event.deltaY /= scale;
2009
2010    render_widget_host_->ForwardWheelEvent(wheel_event);
2011  }
2012  handled = TRUE;
2013  return 0;
2014}
2015
2016WebTouchState::WebTouchState(const RenderWidgetHostViewWin* window)
2017    : window_(window) { }
2018
2019size_t WebTouchState::UpdateTouchPoints(
2020    TOUCHINPUT* points, size_t count) {
2021  // First we reset all touch event state. This involves removing any released
2022  // touchpoints and marking the rest as stationary. After that we go through
2023  // and alter/add any touchpoints (from the touch input buffer) that we can
2024  // coalesce into a single message. The return value is the number of consumed
2025  // input message.
2026  WebKit::WebTouchPoint* point = touch_event_.touches;
2027  WebKit::WebTouchPoint* end = point + touch_event_.touchesLength;
2028  while (point < end) {
2029    if (point->state == WebKit::WebTouchPoint::StateReleased) {
2030      *point = *(--end);
2031      --touch_event_.touchesLength;
2032    } else {
2033      point->state = WebKit::WebTouchPoint::StateStationary;
2034      point++;
2035    }
2036  }
2037  touch_event_.changedTouchesLength = 0;
2038  touch_event_.modifiers = content::EventFlagsToWebEventModifiers(
2039      ui::GetModifiersFromKeyState());
2040
2041  // Consume all events of the same type and add them to the changed list.
2042  int last_type = 0;
2043  for (size_t i = 0; i < count; ++i) {
2044    unsigned int mapped_id = GetMappedTouch(points[i].dwID);
2045
2046    WebKit::WebTouchPoint* point = NULL;
2047    for (unsigned j = 0; j < touch_event_.touchesLength; ++j) {
2048      if (static_cast<DWORD>(touch_event_.touches[j].id) == mapped_id) {
2049        point =  &touch_event_.touches[j];
2050        break;
2051      }
2052    }
2053
2054    // Use a move instead if we see a down on a point we already have.
2055    int type = GetTouchType(points[i]);
2056    if (point && type == TOUCHEVENTF_DOWN)
2057      SetTouchType(&points[i], TOUCHEVENTF_MOVE);
2058
2059    // Stop processing when the event type changes.
2060    if (touch_event_.changedTouchesLength && type != last_type)
2061      return i;
2062
2063    touch_event_.timeStampSeconds = points[i].dwTime / 1000.0;
2064
2065    last_type = type;
2066    switch (type) {
2067      case TOUCHEVENTF_DOWN: {
2068        if (!(point = AddTouchPoint(&points[i])))
2069          continue;
2070        touch_event_.type = WebKit::WebInputEvent::TouchStart;
2071        break;
2072      }
2073
2074      case TOUCHEVENTF_UP: {
2075        if (!point)  // Just throw away a stray up.
2076          continue;
2077        point->state = WebKit::WebTouchPoint::StateReleased;
2078        UpdateTouchPoint(point, &points[i]);
2079        touch_event_.type = WebKit::WebInputEvent::TouchEnd;
2080        break;
2081      }
2082
2083      case TOUCHEVENTF_MOVE: {
2084        if (point) {
2085          point->state = WebKit::WebTouchPoint::StateMoved;
2086          // Don't update the message if the point didn't really move.
2087          if (UpdateTouchPoint(point, &points[i]))
2088            continue;
2089          touch_event_.type = WebKit::WebInputEvent::TouchMove;
2090        } else if (touch_event_.changedTouchesLength) {
2091          RemoveExpiredMappings();
2092          // Can't add a point if we're already handling move events.
2093          return i;
2094        } else {
2095          // Treat a move with no existing point as a down.
2096          if (!(point = AddTouchPoint(&points[i])))
2097            continue;
2098          last_type = TOUCHEVENTF_DOWN;
2099          SetTouchType(&points[i], TOUCHEVENTF_DOWN);
2100          touch_event_.type = WebKit::WebInputEvent::TouchStart;
2101        }
2102        break;
2103      }
2104
2105      default:
2106        NOTREACHED();
2107        continue;
2108    }
2109    touch_event_.changedTouches[touch_event_.changedTouchesLength++] = *point;
2110  }
2111
2112  RemoveExpiredMappings();
2113  return count;
2114}
2115
2116void WebTouchState::RemoveExpiredMappings() {
2117  WebTouchState::MapType new_map;
2118  for (MapType::iterator it = touch_map_.begin();
2119      it != touch_map_.end();
2120      ++it) {
2121    WebKit::WebTouchPoint* point = touch_event_.touches;
2122    WebKit::WebTouchPoint* end = point + touch_event_.touchesLength;
2123    while (point < end) {
2124      if ((point->id == it->second) &&
2125          (point->state != WebKit::WebTouchPoint::StateReleased)) {
2126        new_map.insert(*it);
2127        break;
2128      }
2129      point++;
2130    }
2131  }
2132  touch_map_.swap(new_map);
2133}
2134
2135
2136bool WebTouchState::ReleaseTouchPoints() {
2137  if (touch_event_.touchesLength == 0)
2138    return false;
2139  // Mark every active touchpoint as released.
2140  touch_event_.type = WebKit::WebInputEvent::TouchEnd;
2141  touch_event_.changedTouchesLength = touch_event_.touchesLength;
2142  for (unsigned int i = 0; i < touch_event_.touchesLength; ++i) {
2143    touch_event_.touches[i].state = WebKit::WebTouchPoint::StateReleased;
2144    touch_event_.changedTouches[i].state =
2145        WebKit::WebTouchPoint::StateReleased;
2146  }
2147
2148  return true;
2149}
2150
2151WebKit::WebTouchPoint* WebTouchState::AddTouchPoint(
2152    TOUCHINPUT* touch_input) {
2153  DCHECK(touch_event_.touchesLength <
2154      WebKit::WebTouchEvent::touchesLengthCap);
2155  if (touch_event_.touchesLength >=
2156      WebKit::WebTouchEvent::touchesLengthCap)
2157    return NULL;
2158  WebKit::WebTouchPoint* point =
2159      &touch_event_.touches[touch_event_.touchesLength++];
2160  point->state = WebKit::WebTouchPoint::StatePressed;
2161  point->id = GetMappedTouch(touch_input->dwID);
2162  UpdateTouchPoint(point, touch_input);
2163  return point;
2164}
2165
2166bool WebTouchState::UpdateTouchPoint(
2167    WebKit::WebTouchPoint* touch_point,
2168    TOUCHINPUT* touch_input) {
2169  CPoint coordinates(
2170    TOUCH_COORD_TO_PIXEL(touch_input->x) / ui::win::GetUndocumentedDPIScale(),
2171    TOUCH_COORD_TO_PIXEL(touch_input->y) / ui::win::GetUndocumentedDPIScale());
2172  int radius_x = 1;
2173  int radius_y = 1;
2174  if (touch_input->dwMask & TOUCHINPUTMASKF_CONTACTAREA) {
2175    // Some touch drivers send a contact area of "-1", yet flag it as valid.
2176    radius_x = std::max(1,
2177        static_cast<int>(TOUCH_COORD_TO_PIXEL(touch_input->cxContact) /
2178                         ui::win::GetUndocumentedDPIScale()));
2179    radius_y = std::max(1,
2180        static_cast<int>(TOUCH_COORD_TO_PIXEL(touch_input->cyContact) /
2181                         ui::win::GetUndocumentedDPIScale()));
2182  }
2183
2184  // Detect and exclude stationary moves.
2185  if (GetTouchType(*touch_input) == TOUCHEVENTF_MOVE &&
2186      touch_point->screenPosition.x == coordinates.x &&
2187      touch_point->screenPosition.y == coordinates.y &&
2188      touch_point->radiusX == radius_x &&
2189      touch_point->radiusY == radius_y) {
2190    touch_point->state = WebKit::WebTouchPoint::StateStationary;
2191    return true;
2192  }
2193
2194  touch_point->screenPosition.x = coordinates.x;
2195  touch_point->screenPosition.y = coordinates.y;
2196  window_->ScreenToClient(&coordinates);
2197  static float scale = ui::win::GetDeviceScaleFactor();
2198  touch_point->position.x = coordinates.x / scale;
2199  touch_point->position.y = coordinates.y / scale;
2200  touch_point->radiusX = radius_x;
2201  touch_point->radiusY = radius_y;
2202  touch_point->force = 0;
2203  touch_point->rotationAngle = 0;
2204  return false;
2205}
2206
2207// Find (or create) a mapping for _os_touch_id_.
2208unsigned int WebTouchState::GetMappedTouch(unsigned int os_touch_id) {
2209  MapType::iterator it = touch_map_.find(os_touch_id);
2210  if (it != touch_map_.end())
2211    return it->second;
2212  int next_value = 0;
2213  for (it = touch_map_.begin(); it != touch_map_.end(); ++it)
2214    next_value = std::max(next_value, it->second + 1);
2215  touch_map_[os_touch_id] = next_value;
2216  return next_value;
2217}
2218
2219LRESULT RenderWidgetHostViewWin::OnTouchEvent(UINT message, WPARAM wparam,
2220                                              LPARAM lparam, BOOL& handled) {
2221  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnTouchEvent");
2222  // Finish the ongoing composition whenever a touch event happens.
2223  // It matches IE's behavior.
2224  if (base::win::IsTSFAwareRequired()) {
2225    ui::TSFBridge::GetInstance()->CancelComposition();
2226  } else {
2227    imm32_manager_->CleanupComposition(m_hWnd);
2228  }
2229
2230  // TODO(jschuh): Add support for an arbitrary number of touchpoints.
2231  size_t total = std::min(static_cast<int>(LOWORD(wparam)),
2232      static_cast<int>(WebKit::WebTouchEvent::touchesLengthCap));
2233  TOUCHINPUT points[WebKit::WebTouchEvent::touchesLengthCap];
2234
2235  if (!total || !ui::GetTouchInputInfoWrapper((HTOUCHINPUT)lparam, total,
2236                                              points, sizeof(TOUCHINPUT))) {
2237    TRACE_EVENT0("browser", "EarlyOut_NothingToDo");
2238    return 0;
2239  }
2240
2241  if (total == 1 && (points[0].dwFlags & TOUCHEVENTF_DOWN)) {
2242    pointer_down_context_ = true;
2243    last_touch_location_ = gfx::Point(
2244        TOUCH_COORD_TO_PIXEL(points[0].x) / ui::win::GetUndocumentedDPIScale(),
2245        TOUCH_COORD_TO_PIXEL(points[0].y) / ui::win::GetUndocumentedDPIScale());
2246  }
2247
2248  bool should_forward = render_widget_host_->ShouldForwardTouchEvent() &&
2249      touch_events_enabled_;
2250
2251  // Send a copy of the touch events on to the gesture recognizer.
2252  for (size_t start = 0; start < total;) {
2253    start += touch_state_->UpdateTouchPoints(points + start, total - start);
2254    if (should_forward) {
2255      if (touch_state_->is_changed())
2256        render_widget_host_->ForwardTouchEventWithLatencyInfo(
2257            touch_state_->touch_event(), ui::LatencyInfo());
2258    } else {
2259      const WebKit::WebTouchEvent& touch_event = touch_state_->touch_event();
2260      base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds(
2261          touch_event.timeStampSeconds * 1000);
2262      for (size_t i = 0; i < touch_event.touchesLength; ++i) {
2263        scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
2264        gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture(
2265            TouchEventFromWebTouchPoint(touch_event.touches[i], timestamp),
2266            ui::ER_UNHANDLED, this));
2267        ProcessGestures(gestures.get());
2268      }
2269    }
2270  }
2271
2272  CloseTouchInputHandle((HTOUCHINPUT)lparam);
2273
2274  return 0;
2275}
2276
2277void RenderWidgetHostViewWin::ProcessGestures(
2278    ui::GestureRecognizer::Gestures* gestures) {
2279  if ((gestures == NULL) || gestures->empty())
2280    return;
2281  for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin();
2282      g_it != gestures->end();
2283      ++g_it) {
2284    ForwardGestureEventToRenderer(*g_it);
2285  }
2286}
2287
2288LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT message,
2289                                                 WPARAM wparam,
2290                                                 LPARAM lparam,
2291                                                 BOOL& handled) {
2292  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnMouseActivate");
2293  if (!render_widget_host_)
2294    return MA_NOACTIVATE;
2295
2296  if (!IsActivatable())
2297    return MA_NOACTIVATE;
2298
2299  HWND focus_window = GetFocus();
2300  if (!::IsWindow(focus_window) || !IsChild(focus_window)) {
2301    // We handle WM_MOUSEACTIVATE to set focus to the underlying plugin
2302    // child window. This is to ensure that keyboard events are received
2303    // by the plugin. The correct way to fix this would be send over
2304    // an event to the renderer which would then eventually send over
2305    // a setFocus call to the plugin widget. This would ensure that
2306    // the renderer (webkit) knows about the plugin widget receiving
2307    // focus.
2308    // TODO(iyengar) Do the right thing as per the above comment.
2309    POINT cursor_pos = {0};
2310    ::GetCursorPos(&cursor_pos);
2311    ::ScreenToClient(m_hWnd, &cursor_pos);
2312    HWND child_window = ::RealChildWindowFromPoint(m_hWnd, cursor_pos);
2313    if (::IsWindow(child_window) && child_window != m_hWnd) {
2314      if (ui::GetClassName(child_window) == kWrapperNativeWindowClassName)
2315        child_window = ::GetWindow(child_window, GW_CHILD);
2316
2317      ::SetFocus(child_window);
2318      return MA_NOACTIVATE;
2319    }
2320  }
2321  handled = FALSE;
2322  render_widget_host_->OnPointerEventActivate();
2323  return MA_ACTIVATE;
2324}
2325
2326LRESULT RenderWidgetHostViewWin::OnGestureEvent(
2327      UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
2328  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnGestureEvent");
2329
2330  DCHECK(!touch_events_enabled_);
2331  handled = FALSE;
2332
2333  GESTUREINFO gi = {sizeof(GESTUREINFO)};
2334  HGESTUREINFO gi_handle = reinterpret_cast<HGESTUREINFO>(lparam);
2335  if (!::GetGestureInfo(gi_handle, &gi)) {
2336    DWORD error = GetLastError();
2337    NOTREACHED() << "Unable to get gesture info. Error : " << error;
2338    return 0;
2339  }
2340
2341  if (gi.dwID == GID_ZOOM) {
2342    PageZoom zoom = PAGE_ZOOM_RESET;
2343    POINT zoom_center = {0};
2344    if (DecodeZoomGesture(m_hWnd, gi, &zoom, &zoom_center)) {
2345      handled = TRUE;
2346      Send(new ViewMsg_ZoomFactor(render_widget_host_->GetRoutingID(),
2347                                  zoom, zoom_center.x, zoom_center.y));
2348    }
2349  } else if (gi.dwID == GID_PAN) {
2350    // Right now we only decode scroll gestures and we forward to the page
2351    // as scroll events.
2352    POINT start;
2353    POINT delta;
2354    if (DecodeScrollGesture(gi, &start, &delta)) {
2355      handled = TRUE;
2356      render_widget_host_->ForwardWheelEvent(
2357          MakeFakeScrollWheelEvent(m_hWnd, start, delta));
2358    }
2359  }
2360  ::CloseGestureInfoHandle(gi_handle);
2361  return 0;
2362}
2363
2364LRESULT RenderWidgetHostViewWin::OnMoveOrSize(
2365    UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
2366  // Reset the cliping rectangle if the mouse is locked.
2367  if (mouse_locked_) {
2368    CRect rect;
2369    GetWindowRect(&rect);
2370    ::ClipCursor(&rect);
2371  }
2372  return 0;
2373}
2374
2375void RenderWidgetHostViewWin::OnAccessibilityNotifications(
2376    const std::vector<AccessibilityHostMsg_NotificationParams>& params) {
2377  CreateBrowserAccessibilityManagerIfNeeded();
2378  GetBrowserAccessibilityManager()->OnAccessibilityNotifications(params);
2379}
2380
2381bool RenderWidgetHostViewWin::LockMouse() {
2382  if (mouse_locked_)
2383    return true;
2384
2385  mouse_locked_ = true;
2386
2387  // Hide the tooltip window if it is currently visible. When the mouse is
2388  // locked, no mouse message is relayed to the tooltip window, so we don't need
2389  // to worry that it will reappear.
2390  if (::IsWindow(tooltip_hwnd_) && tooltip_showing_) {
2391    ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
2392    // Sending a TTM_POP message doesn't seem to actually hide the tooltip
2393    // window, although we will receive a TTN_POP notification. As a result,
2394    // ShowWindow() is explicitly called to hide the window.
2395    ::ShowWindow(tooltip_hwnd_, SW_HIDE);
2396  }
2397
2398  // TODO(yzshen): ShowCursor(FALSE) causes SetCursorPos() to be ignored on
2399  // Remote Desktop.
2400  ::ShowCursor(FALSE);
2401
2402  move_to_center_request_.pending = false;
2403  last_mouse_position_.locked_global = last_mouse_position_.unlocked_global;
2404
2405  // Must set the clip rectangle before MoveCursorToCenterIfNecessary()
2406  // so that if the cursor is moved it uses the clip rect set to the window
2407  // rect. Otherwise, MoveCursorToCenterIfNecessary() may move the cursor
2408  // to the center of the screen, and then we would clip to the window
2409  // rect, thus moving the cursor and causing a movement delta.
2410  CRect rect;
2411  GetWindowRect(&rect);
2412  ::ClipCursor(&rect);
2413  MoveCursorToCenterIfNecessary();
2414
2415  return true;
2416}
2417
2418void RenderWidgetHostViewWin::UnlockMouse() {
2419  if (!mouse_locked_)
2420    return;
2421
2422  mouse_locked_ = false;
2423
2424  ::ClipCursor(NULL);
2425  ::SetCursorPos(last_mouse_position_.unlocked_global.x(),
2426                 last_mouse_position_.unlocked_global.y());
2427  ::ShowCursor(TRUE);
2428
2429  if (render_widget_host_)
2430    render_widget_host_->LostMouseLock();
2431}
2432
2433void RenderWidgetHostViewWin::Observe(
2434    int type,
2435    const NotificationSource& source,
2436    const NotificationDetails& details) {
2437  DCHECK(type == NOTIFICATION_RENDERER_PROCESS_TERMINATED);
2438
2439  // Get the RenderProcessHost that posted this notification, and exit
2440  // if it's not the one associated with this host view.
2441  RenderProcessHost* render_process_host =
2442      Source<RenderProcessHost>(source).ptr();
2443  DCHECK(render_process_host);
2444  if (!render_widget_host_ ||
2445      render_process_host != render_widget_host_->GetProcess()) {
2446    return;
2447  }
2448
2449  // If it was our RenderProcessHost that posted the notification,
2450  // clear the BrowserAccessibilityManager, because the renderer is
2451  // dead and any accessibility information we have is now stale.
2452  SetBrowserAccessibilityManager(NULL);
2453}
2454
2455static void PaintCompositorHostWindow(HWND hWnd) {
2456  PAINTSTRUCT paint;
2457  BeginPaint(hWnd, &paint);
2458
2459  RenderWidgetHostViewWin* win = static_cast<RenderWidgetHostViewWin*>(
2460      ui::GetWindowUserData(hWnd));
2461  // Trigger composite to rerender window.
2462  if (win)
2463    win->AcceleratedPaint(paint.hdc);
2464
2465  EndPaint(hWnd, &paint);
2466}
2467
2468// WndProc for the compositor host window. We use this instead of Default so
2469// we can drop WM_PAINT and WM_ERASEBKGD messages on the floor.
2470static LRESULT CALLBACK CompositorHostWindowProc(HWND hWnd, UINT message,
2471                                                 WPARAM wParam, LPARAM lParam) {
2472  switch (message) {
2473  case WM_ERASEBKGND:
2474    return 0;
2475  case WM_PAINT:
2476    PaintCompositorHostWindow(hWnd);
2477    return 0;
2478  default:
2479    return DefWindowProc(hWnd, message, wParam, lParam);
2480  }
2481}
2482
2483void RenderWidgetHostViewWin::AcceleratedPaint(HDC dc) {
2484  if (render_widget_host_)
2485    render_widget_host_->ScheduleComposite();
2486  if (accelerated_surface_)
2487    accelerated_surface_->Present(dc);
2488}
2489
2490void RenderWidgetHostViewWin::GetScreenInfo(WebKit::WebScreenInfo* results) {
2491  GetScreenInfoForWindow(GetNativeViewId(), results);
2492}
2493
2494gfx::Rect RenderWidgetHostViewWin::GetBoundsInRootWindow() {
2495  RECT window_rect = {0};
2496  HWND root_window = GetAncestor(m_hWnd, GA_ROOT);
2497  ::GetWindowRect(root_window, &window_rect);
2498  gfx::Rect rect(window_rect);
2499
2500  // Maximized windows are outdented from the work area by the frame thickness
2501  // even though this "frame" is not painted.  This confuses code (and people)
2502  // that think of a maximized window as corresponding exactly to the work area.
2503  // Correct for this by subtracting the frame thickness back off.
2504  if (::IsZoomed(root_window)) {
2505    rect.Inset(GetSystemMetrics(SM_CXSIZEFRAME),
2506               GetSystemMetrics(SM_CYSIZEFRAME));
2507  }
2508
2509  return ui::win::ScreenToDIPRect(rect);
2510}
2511
2512// Creates a HWND within the RenderWidgetHostView that will serve as a host
2513// for a HWND that the GPU process will create. The host window is used
2514// to Z-position the GPU's window relative to other plugin windows.
2515gfx::GLSurfaceHandle RenderWidgetHostViewWin::GetCompositingSurface() {
2516  // If the window has been created, don't recreate it a second time
2517  if (compositor_host_window_)
2518    return gfx::GLSurfaceHandle(compositor_host_window_, gfx::NATIVE_TRANSPORT);
2519
2520  // On Vista and later we present directly to the view window rather than a
2521  // child window.
2522  if (GpuDataManagerImpl::GetInstance()->IsUsingAcceleratedSurface()) {
2523    if (!accelerated_surface_)
2524      accelerated_surface_.reset(new AcceleratedSurface(m_hWnd));
2525    return gfx::GLSurfaceHandle(m_hWnd, gfx::NATIVE_TRANSPORT);
2526  }
2527
2528  // On XP we need a child window that can be resized independently of the
2529  // parent.
2530  static ATOM atom = 0;
2531  static HMODULE instance = NULL;
2532  if (!atom) {
2533    WNDCLASSEX window_class;
2534    base::win::InitializeWindowClass(
2535        L"CompositorHostWindowClass",
2536        &base::win::WrappedWindowProc<CompositorHostWindowProc>,
2537        0, 0, 0, NULL, NULL, NULL, NULL, NULL,
2538        &window_class);
2539    instance = window_class.hInstance;
2540    atom = RegisterClassEx(&window_class);
2541    DCHECK(atom);
2542  }
2543
2544  RECT currentRect;
2545  GetClientRect(&currentRect);
2546
2547  // Ensure window does not have zero area because D3D cannot create a zero
2548  // area swap chain.
2549  int width = std::max(1,
2550      static_cast<int>(currentRect.right - currentRect.left));
2551  int height = std::max(1,
2552      static_cast<int>(currentRect.bottom - currentRect.top));
2553
2554  compositor_host_window_ = CreateWindowEx(
2555      WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
2556      MAKEINTATOM(atom), 0,
2557      WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED,
2558      0, 0, width, height, m_hWnd, 0, instance, 0);
2559  ui::CheckWindowCreated(compositor_host_window_);
2560
2561  ui::SetWindowUserData(compositor_host_window_, this);
2562
2563  gfx::GLSurfaceHandle surface_handle(compositor_host_window_,
2564                                      gfx::NATIVE_TRANSPORT);
2565  return surface_handle;
2566}
2567
2568void RenderWidgetHostViewWin::OnAcceleratedCompositingStateChange() {
2569  bool show = render_widget_host_->is_accelerated_compositing_active();
2570  // When we first create the compositor, we will get a show request from
2571  // the renderer before we have gotten the create request from the GPU. In this
2572  // case, simply ignore the show request.
2573  if (compositor_host_window_ == NULL)
2574    return;
2575
2576  if (show) {
2577    ::ShowWindow(compositor_host_window_, SW_SHOW);
2578
2579    // Get all the child windows of this view, including the compositor window.
2580    std::vector<HWND> all_child_windows;
2581    ::EnumChildWindows(m_hWnd, AddChildWindowToVector,
2582        reinterpret_cast<LPARAM>(&all_child_windows));
2583
2584    // Build a list of just the plugin window handles
2585    std::vector<HWND> plugin_windows;
2586    bool compositor_host_window_found = false;
2587    for (size_t i = 0; i < all_child_windows.size(); ++i) {
2588      if (all_child_windows[i] != compositor_host_window_)
2589        plugin_windows.push_back(all_child_windows[i]);
2590      else
2591        compositor_host_window_found = true;
2592    }
2593    DCHECK(compositor_host_window_found);
2594
2595    // Set all the plugin windows to be "after" the compositor window.
2596    // When the compositor window is created, gets placed above plugins.
2597    for (size_t i = 0; i < plugin_windows.size(); ++i) {
2598      HWND next;
2599      if (i + 1 < plugin_windows.size())
2600        next = plugin_windows[i+1];
2601      else
2602        next = compositor_host_window_;
2603      ::SetWindowPos(plugin_windows[i], next, 0, 0, 0, 0,
2604          SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
2605    }
2606  } else {
2607    // Drop the backing store for the accelerated surface when the accelerated
2608    // compositor is disabled. Otherwise, a flash of the last presented frame
2609    // could appear when it is next enabled.
2610    if (accelerated_surface_)
2611      accelerated_surface_->Suspend();
2612    hide_compositor_window_at_next_paint_ = true;
2613  }
2614}
2615
2616void RenderWidgetHostViewWin::AcceleratedSurfaceBuffersSwapped(
2617    const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params,
2618    int gpu_host_id) {
2619  NOTREACHED();
2620}
2621
2622void RenderWidgetHostViewWin::AcceleratedSurfacePostSubBuffer(
2623    const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params,
2624    int gpu_host_id) {
2625  NOTREACHED();
2626}
2627
2628void RenderWidgetHostViewWin::AcceleratedSurfaceSuspend() {
2629    if (!accelerated_surface_)
2630      return;
2631
2632    accelerated_surface_->Suspend();
2633}
2634
2635void RenderWidgetHostViewWin::AcceleratedSurfaceRelease() {
2636}
2637
2638bool RenderWidgetHostViewWin::HasAcceleratedSurface(
2639      const gfx::Size& desired_size) {
2640  // TODO(jbates) Implement this so this view can use GetBackingStore for both
2641  // software and GPU frames. Defaulting to false just makes GetBackingStore
2642  // only useable for software frames.
2643  return false;
2644}
2645
2646void RenderWidgetHostViewWin::SetAccessibilityFocus(int acc_obj_id) {
2647  if (!render_widget_host_)
2648    return;
2649
2650  render_widget_host_->AccessibilitySetFocus(acc_obj_id);
2651}
2652
2653void RenderWidgetHostViewWin::AccessibilityDoDefaultAction(int acc_obj_id) {
2654  if (!render_widget_host_)
2655    return;
2656
2657  render_widget_host_->AccessibilityDoDefaultAction(acc_obj_id);
2658}
2659
2660void RenderWidgetHostViewWin::AccessibilityScrollToMakeVisible(
2661    int acc_obj_id, gfx::Rect subfocus) {
2662  if (!render_widget_host_)
2663    return;
2664
2665  render_widget_host_->AccessibilityScrollToMakeVisible(acc_obj_id, subfocus);
2666}
2667
2668void RenderWidgetHostViewWin::AccessibilityScrollToPoint(
2669    int acc_obj_id, gfx::Point point) {
2670  if (!render_widget_host_)
2671    return;
2672
2673  render_widget_host_->AccessibilityScrollToPoint(acc_obj_id, point);
2674}
2675
2676void RenderWidgetHostViewWin::AccessibilitySetTextSelection(
2677    int acc_obj_id, int start_offset, int end_offset) {
2678  if (!render_widget_host_)
2679    return;
2680
2681  render_widget_host_->AccessibilitySetTextSelection(
2682      acc_obj_id, start_offset, end_offset);
2683}
2684
2685gfx::Point RenderWidgetHostViewWin::GetLastTouchEventLocation() const {
2686  return last_touch_location_;
2687}
2688
2689void RenderWidgetHostViewWin::FatalAccessibilityTreeError() {
2690  render_widget_host_->FatalAccessibilityTreeError();
2691  SetBrowserAccessibilityManager(NULL);
2692}
2693
2694LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam,
2695                                             LPARAM lparam, BOOL& handled) {
2696  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnGetObject");
2697  if (kIdCustom == lparam) {
2698    // An MSAA client requestes our custom id. Assume that we have detected an
2699    // active windows screen reader.
2700    BrowserAccessibilityState::GetInstance()->OnScreenReaderDetected();
2701    render_widget_host_->SetAccessibilityMode(
2702        BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode());
2703
2704    // Return with failure.
2705    return static_cast<LRESULT>(0L);
2706  }
2707
2708  if (lparam != OBJID_CLIENT) {
2709    handled = false;
2710    return static_cast<LRESULT>(0L);
2711  }
2712
2713  IAccessible* iaccessible = GetNativeViewAccessible();
2714  if (iaccessible)
2715    return LresultFromObject(IID_IAccessible, wparam, iaccessible);
2716
2717  handled = false;
2718  return static_cast<LRESULT>(0L);
2719}
2720
2721LRESULT RenderWidgetHostViewWin::OnParentNotify(UINT message, WPARAM wparam,
2722                                                LPARAM lparam, BOOL& handled) {
2723  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnParentNotify");
2724  handled = FALSE;
2725
2726  if (!render_widget_host_)
2727    return 0;
2728
2729  switch (LOWORD(wparam)) {
2730    case WM_LBUTTONDOWN:
2731    case WM_RBUTTONDOWN:
2732    case WM_MBUTTONDOWN:
2733      render_widget_host_->StartUserGesture();
2734      break;
2735    default:
2736      break;
2737  }
2738  return 0;
2739}
2740
2741void RenderWidgetHostViewWin::OnFinalMessage(HWND window) {
2742  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnFinalMessage");
2743  // When the render widget host is being destroyed, it ends up calling
2744  // Destroy() which NULLs render_widget_host_.
2745  // Note: the following bug http://crbug.com/24248 seems to report that
2746  // OnFinalMessage is called with a deleted |render_widget_host_|. It is not
2747  // clear how this could happen, hence the NULLing of render_widget_host_
2748  // above.
2749  if (!render_widget_host_ && !being_destroyed_) {
2750    // If you hit this NOTREACHED, please add a comment to report it on
2751    // http://crbug.com/24248, including what you did when it happened and if
2752    // you can repro.
2753    NOTREACHED();
2754  }
2755  if (render_widget_host_)
2756    render_widget_host_->ViewDestroyed();
2757  delete this;
2758}
2759
2760LRESULT RenderWidgetHostViewWin::OnSessionChange(UINT message,
2761                                                 WPARAM wparam,
2762                                                 LPARAM lparam,
2763                                                 BOOL& handled) {
2764  handled = FALSE;
2765  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnSessionChange");
2766
2767  if (!accelerated_surface_)
2768    return 0;
2769
2770  switch (wparam) {
2771    case WTS_SESSION_LOCK:
2772      accelerated_surface_->SetIsSessionLocked(true);
2773      break;
2774    case WTS_SESSION_UNLOCK:
2775      // Force a repaint to update the window contents.
2776      if (!is_hidden_)
2777        InvalidateRect(NULL, FALSE);
2778      accelerated_surface_->SetIsSessionLocked(false);
2779      break;
2780    default:
2781      break;
2782  }
2783
2784  return 0;
2785}
2786
2787void RenderWidgetHostViewWin::TrackMouseLeave(bool track) {
2788  if (track == track_mouse_leave_)
2789    return;
2790  track_mouse_leave_ = track;
2791
2792  DCHECK(m_hWnd);
2793
2794  TRACKMOUSEEVENT tme;
2795  tme.cbSize = sizeof(TRACKMOUSEEVENT);
2796  tme.dwFlags = TME_LEAVE;
2797  if (!track_mouse_leave_)
2798    tme.dwFlags |= TME_CANCEL;
2799  tme.hwndTrack = m_hWnd;
2800
2801  TrackMouseEvent(&tme);
2802}
2803
2804bool RenderWidgetHostViewWin::Send(IPC::Message* message) {
2805  if (!render_widget_host_)
2806    return false;
2807  return render_widget_host_->Send(message);
2808}
2809
2810void RenderWidgetHostViewWin::EnsureTooltip() {
2811  UINT message = TTM_NEWTOOLRECT;
2812
2813  TOOLINFO ti = {0};
2814  ti.cbSize = sizeof(ti);
2815  ti.hwnd = m_hWnd;
2816  ti.uId = 0;
2817  if (!::IsWindow(tooltip_hwnd_)) {
2818    message = TTM_ADDTOOL;
2819    tooltip_hwnd_ = CreateWindowEx(
2820        WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
2821        TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0, m_hWnd, NULL,
2822        NULL, NULL);
2823    if (!tooltip_hwnd_) {
2824      // Tooltip creation can inexplicably fail. See bug 82913 for details.
2825      LOG_GETLASTERROR(WARNING) <<
2826          "Tooltip creation failed, tooltips won't work";
2827      return;
2828    }
2829    ti.uFlags = TTF_TRANSPARENT;
2830    ti.lpszText = LPSTR_TEXTCALLBACK;
2831
2832    // Ensure web content tooltips are displayed for at least this amount of
2833    // time, to give users a chance to read longer messages.
2834    const int kMinimumAutopopDurationMs = 10 * 1000;
2835    int autopop_duration_ms =
2836        SendMessage(tooltip_hwnd_, TTM_GETDELAYTIME, TTDT_AUTOPOP, NULL);
2837    if (autopop_duration_ms < kMinimumAutopopDurationMs) {
2838      SendMessage(tooltip_hwnd_, TTM_SETDELAYTIME, TTDT_AUTOPOP,
2839                  kMinimumAutopopDurationMs);
2840    }
2841  }
2842
2843  CRect cr;
2844  GetClientRect(&ti.rect);
2845  SendMessage(tooltip_hwnd_, message, NULL, reinterpret_cast<LPARAM>(&ti));
2846}
2847
2848void RenderWidgetHostViewWin::ResetTooltip() {
2849  if (::IsWindow(tooltip_hwnd_))
2850    ::DestroyWindow(tooltip_hwnd_);
2851  tooltip_hwnd_ = NULL;
2852}
2853
2854bool RenderWidgetHostViewWin::ForwardGestureEventToRenderer(
2855    ui::GestureEvent* gesture) {
2856  if (!render_widget_host_)
2857    return false;
2858
2859  // Pinch gestures are disabled by default on windows desktop. See
2860  // crbug.com/128477 and crbug.com/148816
2861  if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN ||
2862      gesture->type() == ui::ET_GESTURE_PINCH_UPDATE ||
2863      gesture->type() == ui::ET_GESTURE_PINCH_END) &&
2864      !ShouldSendPinchGesture()) {
2865    return true;
2866  }
2867
2868  WebKit::WebGestureEvent web_gesture = CreateWebGestureEvent(m_hWnd, *gesture);
2869  if (web_gesture.type == WebKit::WebGestureEvent::Undefined)
2870    return false;
2871  if (web_gesture.type == WebKit::WebGestureEvent::GestureTapDown) {
2872    render_widget_host_->ForwardGestureEvent(
2873        CreateFlingCancelEvent(gesture->time_stamp().InSecondsF()));
2874  }
2875  render_widget_host_->ForwardGestureEventWithLatencyInfo(web_gesture,
2876                                                          *gesture->latency());
2877  return true;
2878}
2879
2880void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message,
2881                                                          WPARAM wparam,
2882                                                          LPARAM lparam) {
2883  TRACE_EVENT0("browser",
2884               "RenderWidgetHostViewWin::ForwardMouseEventToRenderer");
2885  if (!render_widget_host_) {
2886    TRACE_EVENT0("browser", "EarlyOut_NoRWH");
2887    return;
2888  }
2889
2890  gfx::Point point = ui::win::ScreenToDIPPoint(
2891      gfx::Point(static_cast<short>(LOWORD(lparam)),
2892                 static_cast<short>(HIWORD(lparam))));
2893  lparam = MAKELPARAM(point.x(), point.y());
2894
2895  WebMouseEvent event(
2896      WebMouseEventBuilder::Build(m_hWnd, message, wparam, lparam));
2897
2898  if (mouse_locked_) {
2899    event.movementX = event.globalX - last_mouse_position_.locked_global.x();
2900    event.movementY = event.globalY - last_mouse_position_.locked_global.y();
2901    last_mouse_position_.locked_global.SetPoint(event.globalX, event.globalY);
2902
2903    event.x = last_mouse_position_.unlocked.x();
2904    event.y = last_mouse_position_.unlocked.y();
2905    event.windowX = last_mouse_position_.unlocked.x();
2906    event.windowY = last_mouse_position_.unlocked.y();
2907    event.globalX = last_mouse_position_.unlocked_global.x();
2908    event.globalY = last_mouse_position_.unlocked_global.y();
2909  } else {
2910    if (ignore_mouse_movement_) {
2911      ignore_mouse_movement_ = false;
2912      event.movementX = 0;
2913      event.movementY = 0;
2914    } else {
2915      event.movementX =
2916          event.globalX - last_mouse_position_.unlocked_global.x();
2917      event.movementY =
2918          event.globalY - last_mouse_position_.unlocked_global.y();
2919    }
2920
2921    last_mouse_position_.unlocked.SetPoint(event.windowX, event.windowY);
2922    last_mouse_position_.unlocked_global.SetPoint(event.globalX, event.globalY);
2923  }
2924
2925  // Windows sends (fake) mouse messages for touch events. Don't send these to
2926  // the render widget.
2927  if (!touch_events_enabled_ || !ui::IsMouseEventFromTouch(message)) {
2928    // Send the event to the renderer before changing mouse capture, so that
2929    // the capturelost event arrives after mouseup.
2930    render_widget_host_->ForwardMouseEvent(event);
2931
2932    switch (event.type) {
2933      case WebInputEvent::MouseMove:
2934        TrackMouseLeave(true);
2935        break;
2936      case WebInputEvent::MouseLeave:
2937        TrackMouseLeave(false);
2938        break;
2939      case WebInputEvent::MouseDown:
2940        SetCapture();
2941        break;
2942      case WebInputEvent::MouseUp:
2943        if (GetCapture() == m_hWnd)
2944          ReleaseCapture();
2945        break;
2946    }
2947  }
2948
2949  if (IsActivatable() && event.type == WebInputEvent::MouseDown) {
2950    // This is a temporary workaround for bug 765011 to get focus when the
2951    // mouse is clicked. This happens after the mouse down event is sent to
2952    // the renderer because normally Windows does a WM_SETFOCUS after
2953    // WM_LBUTTONDOWN.
2954    SetFocus();
2955  }
2956}
2957
2958void RenderWidgetHostViewWin::ShutdownHost() {
2959  weak_factory_.InvalidateWeakPtrs();
2960  if (render_widget_host_)
2961    render_widget_host_->Shutdown();
2962  // Do not touch any members at this point, |this| has been deleted.
2963}
2964
2965void RenderWidgetHostViewWin::DoPopupOrFullscreenInit(HWND parent_hwnd,
2966                                                      const gfx::Rect& pos,
2967                                                      DWORD ex_style) {
2968  Create(parent_hwnd, NULL, NULL, WS_POPUP, ex_style);
2969  gfx::Rect screen_rect = ui::win::DIPToScreenRect(pos);
2970  MoveWindow(screen_rect.x(), screen_rect.y(), screen_rect.width(),
2971      screen_rect.height(), TRUE);
2972  ShowWindow(IsActivatable() ? SW_SHOW : SW_SHOWNA);
2973
2974  if (is_fullscreen_ && win8::IsSingleWindowMetroMode()) {
2975    MetroSetFrameWindow set_frame_window =
2976        reinterpret_cast<MetroSetFrameWindow>(
2977            ::GetProcAddress(base::win::GetMetroModule(), "SetFrameWindow"));
2978    DCHECK(set_frame_window);
2979    set_frame_window(m_hWnd);
2980  }
2981}
2982
2983CPoint RenderWidgetHostViewWin::GetClientCenter() const {
2984  CRect rect;
2985  GetClientRect(&rect);
2986  return rect.CenterPoint();
2987}
2988
2989void RenderWidgetHostViewWin::MoveCursorToCenterIfNecessary() {
2990  DCHECK(mouse_locked_);
2991
2992  CRect rect;
2993  GetClipCursor(&rect);
2994  int border_x = rect.Width() * kMouseLockBorderPercentage / 100;
2995  int border_y = rect.Height() * kMouseLockBorderPercentage / 100;
2996
2997  bool should_move =
2998      last_mouse_position_.locked_global.x() < rect.left + border_x ||
2999      last_mouse_position_.locked_global.x() > rect.right - border_x ||
3000      last_mouse_position_.locked_global.y() < rect.top + border_y ||
3001      last_mouse_position_.locked_global.y() > rect.bottom - border_y;
3002
3003  if (should_move) {
3004    move_to_center_request_.pending = true;
3005    move_to_center_request_.target = rect.CenterPoint();
3006    if (!::SetCursorPos(move_to_center_request_.target.x(),
3007                        move_to_center_request_.target.y())) {
3008      LOG_GETLASTERROR(WARNING) << "Failed to set cursor position.";
3009    }
3010  }
3011}
3012
3013void RenderWidgetHostViewWin::HandleLockedMouseEvent(UINT message,
3014                                                     WPARAM wparam,
3015                                                     LPARAM lparam) {
3016  TRACE_EVENT0("browser", "RenderWidgetHostViewWin::HandleLockedMouseEvent");
3017  DCHECK(mouse_locked_);
3018
3019  if (message == WM_MOUSEMOVE && move_to_center_request_.pending) {
3020    // Ignore WM_MOUSEMOVE messages generated by
3021    // MoveCursorToCenterIfNecessary().
3022    CPoint current_position(LOWORD(lparam), HIWORD(lparam));
3023    ClientToScreen(&current_position);
3024    if (move_to_center_request_.target.x() == current_position.x &&
3025        move_to_center_request_.target.y() == current_position.y) {
3026      move_to_center_request_.pending = false;
3027      last_mouse_position_.locked_global = move_to_center_request_.target;
3028      return;
3029    }
3030  }
3031
3032  ForwardMouseEventToRenderer(message, wparam, lparam);
3033}
3034
3035LRESULT RenderWidgetHostViewWin::OnDocumentFeed(RECONVERTSTRING* reconv) {
3036  size_t target_offset;
3037  size_t target_length;
3038  bool has_composition;
3039  if (!composition_range_.is_empty()) {
3040    target_offset = composition_range_.GetMin();
3041    target_length = composition_range_.length();
3042    has_composition = true;
3043  } else if (selection_range_.IsValid()) {
3044    target_offset = selection_range_.GetMin();
3045    target_length = selection_range_.length();
3046    has_composition = false;
3047  } else {
3048    return 0;
3049  }
3050
3051  size_t len = selection_text_.length();
3052  size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
3053
3054  if (target_offset < selection_text_offset_ ||
3055      target_offset + target_length > selection_text_offset_ + len) {
3056    return 0;
3057  }
3058
3059  if (!reconv)
3060    return need_size;
3061
3062  if (reconv->dwSize < need_size)
3063    return 0;
3064
3065  reconv->dwVersion = 0;
3066  reconv->dwStrLen = len;
3067  reconv->dwStrOffset = sizeof(RECONVERTSTRING);
3068  reconv->dwCompStrLen = has_composition ? target_length: 0;
3069  reconv->dwCompStrOffset =
3070      (target_offset - selection_text_offset_) * sizeof(WCHAR);
3071  reconv->dwTargetStrLen = target_length;
3072  reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
3073  memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING),
3074         selection_text_.c_str(), len * sizeof(WCHAR));
3075
3076  // According to Microsft API document, IMR_RECONVERTSTRING and
3077  // IMR_DOCUMENTFEED should return reconv, but some applications return
3078  // need_size.
3079  return reinterpret_cast<LRESULT>(reconv);
3080}
3081
3082LRESULT RenderWidgetHostViewWin::OnReconvertString(RECONVERTSTRING* reconv) {
3083  // If there is a composition string already, we don't allow reconversion.
3084  if (imm32_manager_->is_composing())
3085    return 0;
3086
3087  if (selection_range_.is_empty())
3088    return 0;
3089
3090  if (selection_text_.empty())
3091    return 0;
3092
3093  if (selection_range_.GetMin() < selection_text_offset_ ||
3094      selection_range_.GetMax() >
3095      selection_text_offset_ + selection_text_.length()) {
3096    return 0;
3097  }
3098
3099  size_t len = selection_range_.length();
3100  size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
3101
3102  if (!reconv)
3103    return need_size;
3104
3105  if (reconv->dwSize < need_size)
3106    return 0;
3107
3108  reconv->dwVersion = 0;
3109  reconv->dwStrLen = len;
3110  reconv->dwStrOffset = sizeof(RECONVERTSTRING);
3111  reconv->dwCompStrLen = len;
3112  reconv->dwCompStrOffset = 0;
3113  reconv->dwTargetStrLen = len;
3114  reconv->dwTargetStrOffset = 0;
3115
3116  size_t offset = selection_range_.GetMin() - selection_text_offset_;
3117  memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING),
3118         selection_text_.c_str() + offset, len * sizeof(WCHAR));
3119
3120  // According to Microsft API document, IMR_RECONVERTSTRING and
3121  // IMR_DOCUMENTFEED should return reconv, but some applications return
3122  // need_size.
3123  return reinterpret_cast<LRESULT>(reconv);
3124}
3125
3126LRESULT RenderWidgetHostViewWin::OnQueryCharPosition(
3127    IMECHARPOSITION* position) {
3128  DCHECK(position);
3129
3130  if (position->dwSize < sizeof(IMECHARPOSITION))
3131    return 0;
3132
3133  RECT target_rect = {};
3134  if (imm32_manager_->is_composing() && !composition_range_.is_empty() &&
3135      position->dwCharPos < composition_character_bounds_.size()) {
3136    target_rect =
3137        composition_character_bounds_[position->dwCharPos].ToRECT();
3138  } else if (position->dwCharPos == 0) {
3139    // When there is no on-going composition but |position->dwCharPos| is 0,
3140    // use the caret rect. This behavior is the same to RichEdit. In fact,
3141    // CUAS (Cicero Unaware Application Support) relies on this behavior to
3142    // implement ITfContextView::GetTextExt on top of IMM32-based applications.
3143    target_rect = caret_rect_.ToRECT();
3144  } else {
3145    return 0;
3146  }
3147  ClientToScreen(&target_rect);
3148
3149  RECT document_rect = GetPixelBounds().ToRECT();
3150  ClientToScreen(&document_rect);
3151
3152  position->pt.x = target_rect.left;
3153  position->pt.y = target_rect.top;
3154  position->cLineHeight = target_rect.bottom - target_rect.top;
3155  position->rcDocument = document_rect;
3156  return 1;
3157}
3158
3159void RenderWidgetHostViewWin::UpdateIMEState() {
3160  if (base::win::IsTSFAwareRequired()) {
3161    ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(this);
3162    return;
3163  }
3164  if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE &&
3165      text_input_type_ != ui::TEXT_INPUT_TYPE_PASSWORD) {
3166    imm32_manager_->EnableIME(m_hWnd);
3167    imm32_manager_->SetUseCompositionWindow(!can_compose_inline_);
3168  } else {
3169    imm32_manager_->DisableIME(m_hWnd);
3170  }
3171
3172  imm32_manager_->SetTextInputMode(m_hWnd, text_input_mode_);
3173}
3174
3175void RenderWidgetHostViewWin::UpdateInputScopeIfNecessary(
3176    ui::TextInputType text_input_type) {
3177  // The text store is responsible for handling input scope when TSF-aware is
3178  // required.
3179  if (base::win::IsTSFAwareRequired())
3180    return;
3181
3182  ui::tsf_inputscope::SetInputScopeForTsfUnawareWindow(
3183      m_hWnd, text_input_type, ui::TEXT_INPUT_MODE_DEFAULT);
3184}
3185
3186////////////////////////////////////////////////////////////////////////////////
3187// RenderWidgetHostView, public:
3188
3189// static
3190RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
3191    RenderWidgetHost* widget) {
3192  return new RenderWidgetHostViewWin(widget);
3193}
3194
3195// static
3196void RenderWidgetHostViewPort::GetDefaultScreenInfo(
3197      WebKit::WebScreenInfo* results) {
3198  GetScreenInfoForWindow(0, results);
3199}
3200
3201}  // namespace content
3202