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 81 using base::TimeDelta; 82 using base::TimeTicks; 83 using ui::ViewProp; 84 using WebKit::WebInputEvent; 85 using WebKit::WebMouseEvent; 86 using WebKit::WebTextDirection; 87 88 namespace content { 89 namespace { 90 91 // Tooltips will wrap after this width. Yes, wrap. Imagine that! 92 const int kTooltipMaxWidthPixels = 300; 93 94 // Maximum number of characters we allow in a tooltip. 95 const int kMaxTooltipLength = 1024; 96 97 // A custom MSAA object id used to determine if a screen reader is actively 98 // listening for MSAA events. 99 const 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. 103 const 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. 112 const int kMouseLockBorderPercentage = 15; 113 114 // A callback function for EnumThreadWindows to enumerate and dismiss 115 // any owned popup windows. 116 BOOL 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 129 void 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 137 void PostTaskOnIOThread(const tracked_objects::Location& from_here, 138 base::Closure task) { 139 BrowserThread::PostTask(BrowserThread::IO, from_here, task); 140 } 141 142 bool 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 179 bool 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 203 WebKit::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 227 static const int kTouchMask = 0x7; 228 229 inline int GetTouchType(const TOUCHINPUT& point) { 230 return point.dwFlags & kTouchMask; 231 } 232 233 inline void SetTouchType(TOUCHINPUT* point, int type) { 234 point->dwFlags = (point->dwFlags & kTouchMask) | type; 235 } 236 237 ui::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| 256 WebKit::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 273 WebKit::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 281 class 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 301 bool ShouldSendPinchGesture() { 302 static bool pinch_allowed = 303 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePinch); 304 return pinch_allowed; 305 } 306 307 void 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 336 const wchar_t kRenderWidgetHostHWNDClass[] = L"Chrome_RenderWidgetHostHWND"; 337 338 // Wrapper for maintaining touchstate associated with a WebTouchEvent. 339 class 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 384 typedef void (*MetroSetFrameWindow)(HWND window); 385 typedef void (*MetroCloseFrameWindow)(HWND window); 386 387 /////////////////////////////////////////////////////////////////////////////// 388 // RenderWidgetHostViewWin, public: 389 390 RenderWidgetHostViewWin::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 423 RenderWidgetHostViewWin::~RenderWidgetHostViewWin() { 424 UnlockMouse(); 425 ResetTooltip(); 426 } 427 428 void RenderWidgetHostViewWin::CreateWnd(HWND parent) { 429 // ATL function to create the window. 430 Create(parent); 431 } 432 433 /////////////////////////////////////////////////////////////////////////////// 434 // RenderWidgetHostViewWin, RenderWidgetHostView implementation: 435 436 void RenderWidgetHostViewWin::InitAsChild( 437 gfx::NativeView parent_view) { 438 CreateWnd(parent_view); 439 } 440 441 void 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 448 void 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 456 RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const { 457 return render_widget_host_; 458 } 459 460 void 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 474 void 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 499 void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) { 500 SetBounds(gfx::Rect(GetPixelBounds().origin(), size)); 501 } 502 503 void 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 522 gfx::NativeView RenderWidgetHostViewWin::GetNativeView() const { 523 return m_hWnd; 524 } 525 526 gfx::NativeViewId RenderWidgetHostViewWin::GetNativeViewId() const { 527 return reinterpret_cast<gfx::NativeViewId>(m_hWnd); 528 } 529 530 gfx::NativeViewAccessible 531 RenderWidgetHostViewWin::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 544 void 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 561 void 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 567 static 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 573 void 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 597 bool RenderWidgetHostViewWin::IsActivatable() const { 598 // Popups should not be activated. 599 return popup_type_ == WebKit::WebPopupTypeNone; 600 } 601 602 void RenderWidgetHostViewWin::Focus() { 603 if (IsWindow()) 604 SetFocus(); 605 } 606 607 void RenderWidgetHostViewWin::Blur() { 608 NOTREACHED(); 609 } 610 611 bool RenderWidgetHostViewWin::HasFocus() const { 612 return ::GetFocus() == m_hWnd; 613 } 614 615 bool 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 622 void RenderWidgetHostViewWin::Show() { 623 ShowWindow(SW_SHOW); 624 WasShown(); 625 } 626 627 void 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 641 bool RenderWidgetHostViewWin::IsShowing() { 642 return !!IsWindowVisible(); 643 } 644 645 gfx::Rect RenderWidgetHostViewWin::GetViewBounds() const { 646 return ui::win::ScreenToDIPRect(GetPixelBounds()); 647 } 648 649 gfx::Rect RenderWidgetHostViewWin::GetPixelBounds() const { 650 CRect window_rect; 651 GetWindowRect(&window_rect); 652 return gfx::Rect(window_rect); 653 } 654 655 void RenderWidgetHostViewWin::UpdateCursor(const WebCursor& cursor) { 656 current_cursor_ = cursor; 657 UpdateCursorIfOverSelf(); 658 } 659 660 void 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 686 void RenderWidgetHostViewWin::SetIsLoading(bool is_loading) { 687 is_loading_ = is_loading; 688 UpdateCursorIfOverSelf(); 689 } 690 691 void 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 709 void 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 720 void RenderWidgetHostViewWin::ScrollOffsetChanged() { 721 } 722 723 void RenderWidgetHostViewWin::ImeCancelComposition() { 724 imm32_manager_->CancelIME(m_hWnd); 725 } 726 727 void 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 734 void 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 760 void 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 797 void RenderWidgetHostViewWin::RenderProcessGone(base::TerminationStatus status, 798 int error_code) { 799 UpdateCursorIfOverSelf(); 800 Destroy(); 801 } 802 803 bool RenderWidgetHostViewWin::CanSubscribeFrame() const { 804 return render_widget_host_ != NULL; 805 } 806 807 void RenderWidgetHostViewWin::WillWmDestroy() { 808 CleanupCompositorWindow(); 809 if (base::win::IsTSFAwareRequired() && GetFocus() == m_hWnd) 810 ui::TSFBridge::GetInstance()->RemoveFocusedClient(this); 811 } 812 813 void 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 838 void 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 869 BackingStore* RenderWidgetHostViewWin::AllocBackingStore( 870 const gfx::Size& size) { 871 return new BackingStoreWin(render_widget_host_, size); 872 } 873 874 void 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 890 void 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 909 bool RenderWidgetHostViewWin::CanCopyToVideoFrame() const { 910 return accelerated_surface_.get() && render_widget_host_ && 911 render_widget_host_->is_accelerated_compositing_active(); 912 } 913 914 void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) { 915 RenderWidgetHostViewBase::SetBackground(background); 916 render_widget_host_->SetBackground(background); 917 } 918 919 void 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 938 void 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 947 bool RenderWidgetHostViewWin::DispatchLongPressGestureEvent( 948 ui::GestureEvent* event) { 949 return ForwardGestureEventToRenderer(event); 950 } 951 952 bool 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 967 void RenderWidgetHostViewWin::SetHasHorizontalScrollbar( 968 bool has_horizontal_scrollbar) { 969 } 970 971 void RenderWidgetHostViewWin::SetScrollOffsetPinning( 972 bool is_pinned_to_left, bool is_pinned_to_right) { 973 } 974 975 void 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 996 void RenderWidgetHostViewWin::ConfirmCompositionText() { 997 if (!base::win::IsTSFAwareRequired()) { 998 NOTREACHED(); 999 return; 1000 } 1001 // TODO(nona): Implement this function. 1002 NOTIMPLEMENTED(); 1003 } 1004 1005 void RenderWidgetHostViewWin::ClearCompositionText() { 1006 if (!base::win::IsTSFAwareRequired()) { 1007 NOTREACHED(); 1008 return; 1009 } 1010 // TODO(nona): Implement this function. 1011 NOTIMPLEMENTED(); 1012 } 1013 1014 void 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 1025 void 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 1034 gfx::NativeWindow RenderWidgetHostViewWin::GetAttachedWindow() const { 1035 return m_hWnd; 1036 } 1037 1038 ui::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 1046 ui::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 1054 bool 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 1064 gfx::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 1074 bool 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 1089 bool 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 1099 bool 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 1109 bool 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 1119 bool 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 1129 bool 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 1139 bool 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 1149 bool 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 1171 void RenderWidgetHostViewWin::OnInputMethodChanged() { 1172 if (!base::win::IsTSFAwareRequired()) { 1173 NOTREACHED(); 1174 return; 1175 } 1176 // TODO(nona): Implement this function. 1177 NOTIMPLEMENTED(); 1178 } 1179 1180 bool 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 1191 void 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 1203 void RenderWidgetHostViewWin::EnsureCaretInRect(const gfx::Rect& rect) { 1204 // TODO(nona): Implement this function. 1205 NOTIMPLEMENTED(); 1206 } 1207 1208 /////////////////////////////////////////////////////////////////////////////// 1209 // RenderWidgetHostViewWin, private: 1210 1211 LRESULT 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 1228 void 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 1240 void 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 1259 void 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 1409 void 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 1429 void 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 1435 void RenderWidgetHostViewWin::SetClickthroughRegion(SkRegion* region) { 1436 transparent_region_.reset(region); 1437 } 1438 1439 LRESULT 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 1452 LRESULT RenderWidgetHostViewWin::OnEraseBkgnd(HDC dc) { 1453 TRACE_EVENT0("browser", "RenderWidgetHostViewWin::OnEraseBkgnd"); 1454 return 1; 1455 } 1456 1457 LRESULT 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 1464 void 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 1479 void 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 1493 void 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 1500 void 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 1521 void 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 1566 void 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 1574 LRESULT 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 1603 LRESULT 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 1632 LRESULT 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 1650 LRESULT 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 1707 LRESULT 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 1727 LRESULT 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 1755 LRESULT 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 1880 LRESULT 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 1979 LRESULT 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 2016 WebTouchState::WebTouchState(const RenderWidgetHostViewWin* window) 2017 : window_(window) { } 2018 2019 size_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 2116 void 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 2136 bool 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 2151 WebKit::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 2166 bool 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_. 2208 unsigned 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 2219 LRESULT 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 2277 void 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 2288 LRESULT 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 2326 LRESULT 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 2364 LRESULT 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 2375 void RenderWidgetHostViewWin::OnAccessibilityNotifications( 2376 const std::vector<AccessibilityHostMsg_NotificationParams>& params) { 2377 CreateBrowserAccessibilityManagerIfNeeded(); 2378 GetBrowserAccessibilityManager()->OnAccessibilityNotifications(params); 2379 } 2380 2381 bool 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 2418 void 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 2433 void 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 2455 static 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. 2470 static 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 2483 void 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 2490 void RenderWidgetHostViewWin::GetScreenInfo(WebKit::WebScreenInfo* results) { 2491 GetScreenInfoForWindow(GetNativeViewId(), results); 2492 } 2493 2494 gfx::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. 2515 gfx::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(¤tRect); 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 2568 void 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 2616 void RenderWidgetHostViewWin::AcceleratedSurfaceBuffersSwapped( 2617 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, 2618 int gpu_host_id) { 2619 NOTREACHED(); 2620 } 2621 2622 void RenderWidgetHostViewWin::AcceleratedSurfacePostSubBuffer( 2623 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, 2624 int gpu_host_id) { 2625 NOTREACHED(); 2626 } 2627 2628 void RenderWidgetHostViewWin::AcceleratedSurfaceSuspend() { 2629 if (!accelerated_surface_) 2630 return; 2631 2632 accelerated_surface_->Suspend(); 2633 } 2634 2635 void RenderWidgetHostViewWin::AcceleratedSurfaceRelease() { 2636 } 2637 2638 bool 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 2646 void RenderWidgetHostViewWin::SetAccessibilityFocus(int acc_obj_id) { 2647 if (!render_widget_host_) 2648 return; 2649 2650 render_widget_host_->AccessibilitySetFocus(acc_obj_id); 2651 } 2652 2653 void RenderWidgetHostViewWin::AccessibilityDoDefaultAction(int acc_obj_id) { 2654 if (!render_widget_host_) 2655 return; 2656 2657 render_widget_host_->AccessibilityDoDefaultAction(acc_obj_id); 2658 } 2659 2660 void 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 2668 void 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 2676 void 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 2685 gfx::Point RenderWidgetHostViewWin::GetLastTouchEventLocation() const { 2686 return last_touch_location_; 2687 } 2688 2689 void RenderWidgetHostViewWin::FatalAccessibilityTreeError() { 2690 render_widget_host_->FatalAccessibilityTreeError(); 2691 SetBrowserAccessibilityManager(NULL); 2692 } 2693 2694 LRESULT 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 2721 LRESULT 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 2741 void 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 2760 LRESULT 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 2787 void 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 2804 bool RenderWidgetHostViewWin::Send(IPC::Message* message) { 2805 if (!render_widget_host_) 2806 return false; 2807 return render_widget_host_->Send(message); 2808 } 2809 2810 void 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 2848 void RenderWidgetHostViewWin::ResetTooltip() { 2849 if (::IsWindow(tooltip_hwnd_)) 2850 ::DestroyWindow(tooltip_hwnd_); 2851 tooltip_hwnd_ = NULL; 2852 } 2853 2854 bool 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 2880 void 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 2958 void 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 2965 void 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 2983 CPoint RenderWidgetHostViewWin::GetClientCenter() const { 2984 CRect rect; 2985 GetClientRect(&rect); 2986 return rect.CenterPoint(); 2987 } 2988 2989 void 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 3013 void 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(¤t_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 3035 LRESULT 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 3082 LRESULT 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 3126 LRESULT 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 3159 void 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 3175 void 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 3190 RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( 3191 RenderWidgetHost* widget) { 3192 return new RenderWidgetHostViewWin(widget); 3193 } 3194 3195 // static 3196 void RenderWidgetHostViewPort::GetDefaultScreenInfo( 3197 WebKit::WebScreenInfo* results) { 3198 GetScreenInfoForWindow(0, results); 3199 } 3200 3201 } // namespace content 3202