Suppress sending mousedown / mouseup when in fling
[chromium-blink-merge.git] / content / browser / renderer_host / render_widget_host_impl.cc
blob057db8493b9f3644b86b64afb10d5643836b2311
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.
5 #include "content/browser/renderer_host/render_widget_host_impl.h"
7 #include <math.h>
8 #include <utility>
10 #include "base/auto_reset.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/debug/trace_event.h"
14 #include "base/i18n/rtl.h"
15 #include "base/message_loop.h"
16 #include "base/metrics/field_trial.h"
17 #include "base/metrics/histogram.h"
18 #include "base/string_number_conversions.h"
19 #include "base/utf_string_conversions.h"
20 #include "content/browser/gpu/gpu_process_host.h"
21 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
22 #include "content/browser/gpu/gpu_surface_tracker.h"
23 #include "content/browser/renderer_host/backing_store.h"
24 #include "content/browser/renderer_host/backing_store_manager.h"
25 #include "content/browser/renderer_host/gesture_event_filter.h"
26 #include "content/browser/renderer_host/overscroll_controller.h"
27 #include "content/browser/renderer_host/render_process_host_impl.h"
28 #include "content/browser/renderer_host/render_view_host_impl.h"
29 #include "content/browser/renderer_host/render_widget_helper.h"
30 #include "content/browser/renderer_host/render_widget_host_delegate.h"
31 #include "content/browser/renderer_host/tap_suppression_controller.h"
32 #include "content/browser/renderer_host/touch_event_queue.h"
33 #include "content/common/accessibility_messages.h"
34 #include "content/common/gpu/gpu_messages.h"
35 #include "content/common/view_messages.h"
36 #include "content/port/browser/render_widget_host_view_port.h"
37 #include "content/port/browser/smooth_scroll_gesture.h"
38 #include "content/public/browser/compositor_util.h"
39 #include "content/public/browser/native_web_keyboard_event.h"
40 #include "content/public/browser/notification_service.h"
41 #include "content/public/browser/notification_types.h"
42 #include "content/public/browser/user_metrics.h"
43 #include "content/public/common/content_constants.h"
44 #include "content/public/common/content_switches.h"
45 #include "content/public/common/result_codes.h"
46 #include "skia/ext/image_operations.h"
47 #include "skia/ext/platform_canvas.h"
48 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h"
49 #if defined(OS_WIN)
50 #include "third_party/WebKit/Source/WebKit/chromium/public/win/WebScreenInfoFactory.h"
51 #endif
52 #include "ui/base/events/event.h"
53 #include "ui/base/keycodes/keyboard_codes.h"
54 #include "ui/gfx/size_conversions.h"
55 #include "ui/gfx/skbitmap_operations.h"
56 #include "webkit/glue/webcursor.h"
57 #include "webkit/glue/webpreferences.h"
58 #include "webkit/plugins/npapi/webplugin.h"
59 #include "webkit/plugins/npapi/webplugin_delegate_impl.h"
61 #if defined(TOOLKIT_GTK)
62 #include "content/browser/renderer_host/backing_store_gtk.h"
63 #elif defined(OS_MACOSX)
64 #include "content/browser/renderer_host/backing_store_mac.h"
65 #endif
67 using base::Time;
68 using base::TimeDelta;
69 using base::TimeTicks;
70 using webkit::npapi::WebPluginDelegateImpl;
71 using WebKit::WebGestureEvent;
72 using WebKit::WebInputEvent;
73 using WebKit::WebKeyboardEvent;
74 using WebKit::WebMouseEvent;
75 using WebKit::WebMouseWheelEvent;
76 using WebKit::WebTextDirection;
78 namespace content {
79 namespace {
81 // How long to (synchronously) wait for the renderer to respond with a
82 // PaintRect message, when our backing-store is invalid, before giving up and
83 // returning a null or incorrectly sized backing-store from GetBackingStore.
84 // This timeout impacts the "choppiness" of our window resize perf.
85 const int kPaintMsgTimeoutMS = 50;
87 // How long to wait before we consider a renderer hung.
88 const int kHungRendererDelayMs = 30000;
90 // How many milliseconds apart synthetic scroll messages should be sent.
91 static const int kSyntheticScrollMessageIntervalMs = 8;
93 // Returns |true| if the two wheel events should be coalesced.
94 bool ShouldCoalesceMouseWheelEvents(const WebMouseWheelEvent& last_event,
95 const WebMouseWheelEvent& new_event) {
96 return last_event.modifiers == new_event.modifiers &&
97 last_event.scrollByPage == new_event.scrollByPage &&
98 last_event.hasPreciseScrollingDeltas
99 == new_event.hasPreciseScrollingDeltas &&
100 last_event.phase == new_event.phase &&
101 last_event.momentumPhase == new_event.momentumPhase;
104 } // namespace
107 // static
108 void RenderWidgetHost::RemoveAllBackingStores() {
109 BackingStoreManager::RemoveAllBackingStores();
112 // static
113 size_t RenderWidgetHost::BackingStoreMemorySize() {
114 return BackingStoreManager::MemorySize();
117 ///////////////////////////////////////////////////////////////////////////////
118 // RenderWidgetHostImpl
120 RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
121 RenderProcessHost* process,
122 int routing_id)
123 : view_(NULL),
124 renderer_initialized_(false),
125 hung_renderer_delay_ms_(kHungRendererDelayMs),
126 delegate_(delegate),
127 process_(process),
128 routing_id_(routing_id),
129 surface_id_(0),
130 is_loading_(false),
131 is_hidden_(false),
132 is_fullscreen_(false),
133 is_accelerated_compositing_active_(false),
134 repaint_ack_pending_(false),
135 resize_ack_pending_(false),
136 should_auto_resize_(false),
137 waiting_for_screen_rects_ack_(false),
138 mouse_move_pending_(false),
139 mouse_wheel_pending_(false),
140 select_range_pending_(false),
141 needs_repainting_on_restore_(false),
142 is_unresponsive_(false),
143 in_flight_event_count_(0),
144 in_get_backing_store_(false),
145 abort_get_backing_store_(false),
146 view_being_painted_(false),
147 ignore_input_events_(false),
148 text_direction_updated_(false),
149 text_direction_(WebKit::WebTextDirectionLeftToRight),
150 text_direction_canceled_(false),
151 suppress_next_char_events_(false),
152 pending_mouse_lock_request_(false),
153 allow_privileged_mouse_lock_(false),
154 has_touch_handler_(false),
155 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
156 tick_active_smooth_scroll_gestures_task_posted_(false),
157 touch_event_queue_(new TouchEventQueue(this)),
158 gesture_event_filter_(new GestureEventFilter(this)) {
159 CHECK(delegate_);
160 if (routing_id_ == MSG_ROUTING_NONE) {
161 routing_id_ = process_->GetNextRoutingID();
162 surface_id_ = GpuSurfaceTracker::Get()->AddSurfaceForRenderer(
163 process_->GetID(),
164 routing_id_);
165 } else {
166 // TODO(piman): This is a O(N) lookup, where we could forward the
167 // information from the RenderWidgetHelper. The problem is that doing so
168 // currently leaks outside of content all the way to chrome classes, and
169 // would be a layering violation. Since we don't expect more than a few
170 // hundreds of RWH, this seems acceptable. Revisit if performance become a
171 // problem, for example by tracking in the RenderWidgetHelper the routing id
172 // (and surface id) that have been created, but whose RWH haven't yet.
173 surface_id_ = GpuSurfaceTracker::Get()->LookupSurfaceForRenderer(
174 process_->GetID(),
175 routing_id_);
176 DCHECK(surface_id_);
179 is_threaded_compositing_enabled_ = IsThreadedCompositingEnabled();
181 process_->Attach(this, routing_id_);
182 // Because the widget initializes as is_hidden_ == false,
183 // tell the process host that we're alive.
184 process_->WidgetRestored();
186 #if defined(USE_AURA)
187 bool overscroll_enabled = CommandLine::ForCurrentProcess()->
188 HasSwitch(switches::kEnableOverscrollHistoryNavigation);
189 if (overscroll_enabled)
190 InitializeOverscrollController();
191 #endif
194 RenderWidgetHostImpl::~RenderWidgetHostImpl() {
195 SetView(NULL);
197 // Clear our current or cached backing store if either remains.
198 BackingStoreManager::RemoveBackingStore(this);
200 GpuSurfaceTracker::Get()->RemoveSurface(surface_id_);
201 surface_id_ = 0;
203 process_->Release(routing_id_);
205 if (delegate_)
206 delegate_->RenderWidgetDeleted(this);
209 // static
210 RenderWidgetHostImpl* RenderWidgetHostImpl::From(RenderWidgetHost* rwh) {
211 return rwh->AsRenderWidgetHostImpl();
214 void RenderWidgetHostImpl::SetView(RenderWidgetHostView* view) {
215 view_ = RenderWidgetHostViewPort::FromRWHV(view);
217 if (!view_) {
218 GpuSurfaceTracker::Get()->SetSurfaceHandle(
219 surface_id_, gfx::GLSurfaceHandle());
223 RenderProcessHost* RenderWidgetHostImpl::GetProcess() const {
224 return process_;
227 int RenderWidgetHostImpl::GetRoutingID() const {
228 return routing_id_;
231 RenderWidgetHostView* RenderWidgetHostImpl::GetView() const {
232 return view_;
235 RenderWidgetHostImpl* RenderWidgetHostImpl::AsRenderWidgetHostImpl() {
236 return this;
239 gfx::NativeViewId RenderWidgetHostImpl::GetNativeViewId() const {
240 if (view_)
241 return view_->GetNativeViewId();
242 return 0;
245 gfx::GLSurfaceHandle RenderWidgetHostImpl::GetCompositingSurface() {
246 if (view_)
247 return view_->GetCompositingSurface();
248 return gfx::GLSurfaceHandle();
251 void RenderWidgetHostImpl::CompositingSurfaceUpdated() {
252 GpuSurfaceTracker::Get()->SetSurfaceHandle(
253 surface_id_, GetCompositingSurface());
254 process_->SurfaceUpdated(surface_id_);
257 void RenderWidgetHostImpl::ResetSizeAndRepaintPendingFlags() {
258 resize_ack_pending_ = false;
259 repaint_ack_pending_ = false;
260 in_flight_size_.SetSize(0, 0);
263 void RenderWidgetHostImpl::SendScreenRects() {
264 if (!renderer_initialized_ || waiting_for_screen_rects_ack_)
265 return;
267 if (is_hidden_) {
268 // On GTK, this comes in for backgrounded tabs. Ignore, to match what
269 // happens on Win & Mac, and when the view is shown it'll call this again.
270 return;
273 if (!view_)
274 return;
276 last_view_screen_rect_ = view_->GetViewBounds();
277 last_window_screen_rect_ = view_->GetBoundsInRootWindow();
278 Send(new ViewMsg_UpdateScreenRects(
279 GetRoutingID(), last_view_screen_rect_, last_window_screen_rect_));
280 waiting_for_screen_rects_ack_ = true;
283 void RenderWidgetHostImpl::Init() {
284 DCHECK(process_->HasConnection());
286 renderer_initialized_ = true;
288 GpuSurfaceTracker::Get()->SetSurfaceHandle(
289 surface_id_, GetCompositingSurface());
291 // Send the ack along with the information on placement.
292 Send(new ViewMsg_CreatingNew_ACK(routing_id_));
293 GetProcess()->ResumeRequestsForView(routing_id_);
295 WasResized();
298 void RenderWidgetHostImpl::Shutdown() {
299 RejectMouseLockOrUnlockIfNecessary();
301 if (process_->HasConnection()) {
302 // Tell the renderer object to close.
303 bool rv = Send(new ViewMsg_Close(routing_id_));
304 DCHECK(rv);
307 Destroy();
310 bool RenderWidgetHostImpl::IsLoading() const {
311 return is_loading_;
314 bool RenderWidgetHostImpl::IsRenderView() const {
315 return false;
318 bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) {
319 bool handled = true;
320 bool msg_is_ok = true;
321 IPC_BEGIN_MESSAGE_MAP_EX(RenderWidgetHostImpl, msg, msg_is_ok)
322 IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnMsgRenderViewReady)
323 IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewGone, OnMsgRenderViewGone)
324 IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnMsgClose)
325 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateScreenRects_ACK,
326 OnMsgUpdateScreenRectsAck)
327 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove)
328 IPC_MESSAGE_HANDLER(ViewHostMsg_SetTooltipText, OnMsgSetTooltipText)
329 IPC_MESSAGE_HANDLER(ViewHostMsg_PaintAtSize_ACK, OnMsgPaintAtSizeAck)
330 IPC_MESSAGE_HANDLER(ViewHostMsg_CompositorSurfaceBuffersSwapped,
331 OnCompositorSurfaceBuffersSwapped)
332 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnMsgUpdateRect)
333 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateIsDelayed, OnMsgUpdateIsDelayed)
334 IPC_MESSAGE_HANDLER(ViewHostMsg_HandleInputEvent_ACK, OnMsgInputEventAck)
335 IPC_MESSAGE_HANDLER(ViewHostMsg_BeginSmoothScroll, OnMsgBeginSmoothScroll)
336 IPC_MESSAGE_HANDLER(ViewHostMsg_SelectRange_ACK, OnMsgSelectRangeAck)
337 IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnMsgFocus)
338 IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnMsgBlur)
339 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
340 OnMsgHasTouchEventHandlers)
341 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnMsgSetCursor)
342 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
343 OnMsgTextInputStateChanged)
344 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged,
345 OnMsgImeCompositionRangeChanged)
346 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition,
347 OnMsgImeCancelComposition)
348 IPC_MESSAGE_HANDLER(ViewHostMsg_DidActivateAcceleratedCompositing,
349 OnMsgDidActivateAcceleratedCompositing)
350 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnMsgLockMouse)
351 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnMsgUnlockMouse)
352 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowDisambiguationPopup,
353 OnMsgShowDisambiguationPopup)
354 #if defined(OS_MACOSX)
355 IPC_MESSAGE_HANDLER(ViewHostMsg_PluginFocusChanged,
356 OnMsgPluginFocusChanged)
357 IPC_MESSAGE_HANDLER(ViewHostMsg_StartPluginIme,
358 OnMsgStartPluginIme)
359 IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateFakePluginWindowHandle,
360 OnAllocateFakePluginWindowHandle)
361 IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyFakePluginWindowHandle,
362 OnDestroyFakePluginWindowHandle)
363 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceSetIOSurface,
364 OnAcceleratedSurfaceSetIOSurface)
365 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceSetTransportDIB,
366 OnAcceleratedSurfaceSetTransportDIB)
367 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceBuffersSwapped,
368 OnAcceleratedSurfaceBuffersSwapped)
369 #endif
370 #if defined(OS_ANDROID)
371 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFrameInfo,
372 OnMsgUpdateFrameInfo)
373 #endif
374 #if defined(TOOLKIT_GTK)
375 IPC_MESSAGE_HANDLER(ViewHostMsg_CreatePluginContainer,
376 OnMsgCreatePluginContainer)
377 IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyPluginContainer,
378 OnMsgDestroyPluginContainer)
379 #endif
380 #if defined(OS_WIN)
381 IPC_MESSAGE_HANDLER(ViewHostMsg_WindowlessPluginDummyWindowCreated,
382 OnWindowlessPluginDummyWindowCreated)
383 IPC_MESSAGE_HANDLER(ViewHostMsg_WindowlessPluginDummyWindowDestroyed,
384 OnWindowlessPluginDummyWindowDestroyed)
385 #endif
386 IPC_MESSAGE_UNHANDLED(handled = false)
387 IPC_END_MESSAGE_MAP_EX()
389 if (!msg_is_ok) {
390 // The message de-serialization failed. Kill the renderer process.
391 RecordAction(UserMetricsAction("BadMessageTerminate_RWH"));
392 GetProcess()->ReceivedBadMessage();
394 return handled;
397 bool RenderWidgetHostImpl::Send(IPC::Message* msg) {
398 return process_->Send(msg);
401 void RenderWidgetHostImpl::WasHidden() {
402 is_hidden_ = true;
404 // Don't bother reporting hung state when we aren't active.
405 StopHangMonitorTimeout();
407 // If we have a renderer, then inform it that we are being hidden so it can
408 // reduce its resource utilization.
409 Send(new ViewMsg_WasHidden(routing_id_));
411 // Tell the RenderProcessHost we were hidden.
412 process_->WidgetHidden();
414 bool is_visible = false;
415 NotificationService::current()->Notify(
416 NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
417 Source<RenderWidgetHost>(this),
418 Details<bool>(&is_visible));
421 void RenderWidgetHostImpl::WasShown() {
422 // When we create the widget, it is created as *not* hidden.
423 if (!is_hidden_)
424 return;
425 is_hidden_ = false;
427 SendScreenRects();
429 BackingStore* backing_store = BackingStoreManager::Lookup(this);
430 // If we already have a backing store for this widget, then we don't need to
431 // repaint on restore _unless_ we know that our backing store is invalid.
432 // When accelerated compositing is on, we must always repaint, even when
433 // the backing store exists.
434 bool needs_repainting;
435 if (needs_repainting_on_restore_ || !backing_store ||
436 is_accelerated_compositing_active()) {
437 needs_repainting = true;
438 needs_repainting_on_restore_ = false;
439 } else {
440 needs_repainting = false;
442 Send(new ViewMsg_WasShown(routing_id_, needs_repainting));
444 process_->WidgetRestored();
446 bool is_visible = true;
447 NotificationService::current()->Notify(
448 NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
449 Source<RenderWidgetHost>(this),
450 Details<bool>(&is_visible));
452 // It's possible for our size to be out of sync with the renderer. The
453 // following is one case that leads to this:
454 // 1. WasResized -> Send ViewMsg_Resize to render
455 // 2. WasResized -> do nothing as resize_ack_pending_ is true
456 // 3. WasHidden
457 // 4. OnMsgUpdateRect from (1) processed. Does NOT invoke WasResized as view
458 // is hidden. Now renderer/browser out of sync with what they think size
459 // is.
460 // By invoking WasResized the renderer is updated as necessary. WasResized
461 // does nothing if the sizes are already in sync.
463 // TODO: ideally ViewMsg_WasShown would take a size. This way, the renderer
464 // could handle both the restore and resize at once. This isn't that big a
465 // deal as RenderWidget::WasShown delays updating, so that the resize from
466 // WasResized is usually processed before the renderer is painted.
467 WasResized();
470 void RenderWidgetHostImpl::WasResized() {
471 if (resize_ack_pending_ || !process_->HasConnection() || !view_ ||
472 !renderer_initialized_ || should_auto_resize_) {
473 return;
476 gfx::Rect view_bounds = view_->GetViewBounds();
477 gfx::Size new_size(view_bounds.size());
479 bool was_fullscreen = is_fullscreen_;
480 is_fullscreen_ = IsFullscreen();
481 bool fullscreen_changed = was_fullscreen != is_fullscreen_;
482 bool size_changed = new_size != current_size_;
484 // Avoid asking the RenderWidget to resize to its current size, since it
485 // won't send us a PaintRect message in that case.
486 if (!size_changed && !fullscreen_changed)
487 return;
489 if (in_flight_size_ != gfx::Size() && new_size == in_flight_size_ &&
490 !fullscreen_changed)
491 return;
493 // We don't expect to receive an ACK when the requested size is empty.
494 if (!new_size.IsEmpty() && size_changed)
495 resize_ack_pending_ = true;
497 if (!Send(new ViewMsg_Resize(routing_id_, new_size,
498 GetRootWindowResizerRect(), is_fullscreen_))) {
499 resize_ack_pending_ = false;
500 } else {
501 in_flight_size_ = new_size;
505 void RenderWidgetHostImpl::ResizeRectChanged(const gfx::Rect& new_rect) {
506 Send(new ViewMsg_ChangeResizeRect(routing_id_, new_rect));
509 void RenderWidgetHostImpl::GotFocus() {
510 Focus();
513 void RenderWidgetHostImpl::Focus() {
514 Send(new ViewMsg_SetFocus(routing_id_, true));
517 void RenderWidgetHostImpl::Blur() {
518 // If there is a pending mouse lock request, we don't want to reject it at
519 // this point. The user can switch focus back to this view and approve the
520 // request later.
521 if (IsMouseLocked())
522 view_->UnlockMouse();
524 Send(new ViewMsg_SetFocus(routing_id_, false));
527 void RenderWidgetHostImpl::LostCapture() {
528 Send(new ViewMsg_MouseCaptureLost(routing_id_));
531 void RenderWidgetHostImpl::SetActive(bool active) {
532 Send(new ViewMsg_SetActive(routing_id_, active));
535 void RenderWidgetHostImpl::LostMouseLock() {
536 Send(new ViewMsg_MouseLockLost(routing_id_));
539 void RenderWidgetHostImpl::ViewDestroyed() {
540 RejectMouseLockOrUnlockIfNecessary();
542 // TODO(evanm): tracking this may no longer be necessary;
543 // eliminate this function if so.
544 SetView(NULL);
547 void RenderWidgetHostImpl::SetIsLoading(bool is_loading) {
548 is_loading_ = is_loading;
549 gesture_event_filter_->FlingHasBeenHalted();
550 if (!view_)
551 return;
552 view_->SetIsLoading(is_loading);
555 void RenderWidgetHostImpl::CopyFromBackingStore(
556 const gfx::Rect& src_subrect,
557 const gfx::Size& accelerated_dst_size,
558 const base::Callback<void(bool)>& callback,
559 skia::PlatformBitmap* output) {
560 if (view_ && is_accelerated_compositing_active_) {
561 TRACE_EVENT0("browser",
562 "RenderWidgetHostImpl::CopyFromBackingStore::FromCompositingSurface");
563 gfx::Rect copy_rect = src_subrect.IsEmpty() ?
564 gfx::Rect(view_->GetViewBounds().size()) : src_subrect;
565 view_->CopyFromCompositingSurface(copy_rect,
566 accelerated_dst_size,
567 callback,
568 output);
569 return;
572 BackingStore* backing_store = GetBackingStore(false);
573 if (!backing_store) {
574 callback.Run(false);
575 return;
578 TRACE_EVENT0("browser",
579 "RenderWidgetHostImpl::CopyFromBackingStore::FromBackingStore");
580 gfx::Rect copy_rect = src_subrect.IsEmpty() ?
581 gfx::Rect(backing_store->size()) : src_subrect;
582 // When the result size is equal to the backing store size, copy from the
583 // backing store directly to the output canvas.
584 bool result = backing_store->CopyFromBackingStore(copy_rect, output);
585 callback.Run(result);
588 #if defined(TOOLKIT_GTK)
589 bool RenderWidgetHostImpl::CopyFromBackingStoreToGtkWindow(
590 const gfx::Rect& dest_rect, GdkWindow* target) {
591 BackingStore* backing_store = GetBackingStore(false);
592 if (!backing_store)
593 return false;
594 (static_cast<BackingStoreGtk*>(backing_store))->PaintToRect(
595 dest_rect, target);
596 return true;
598 #elif defined(OS_MACOSX)
599 gfx::Size RenderWidgetHostImpl::GetBackingStoreSize() {
600 BackingStore* backing_store = GetBackingStore(false);
601 return backing_store ? backing_store->size() : gfx::Size();
604 bool RenderWidgetHostImpl::CopyFromBackingStoreToCGContext(
605 const CGRect& dest_rect, CGContextRef target) {
606 BackingStore* backing_store = GetBackingStore(false);
607 if (!backing_store)
608 return false;
609 (static_cast<BackingStoreMac*>(backing_store))->
610 CopyFromBackingStoreToCGContext(dest_rect, target);
611 return true;
613 #endif
615 void RenderWidgetHostImpl::PaintAtSize(TransportDIB::Handle dib_handle,
616 int tag,
617 const gfx::Size& page_size,
618 const gfx::Size& desired_size) {
619 // Ask the renderer to create a bitmap regardless of whether it's
620 // hidden, being resized, redrawn, etc. It resizes the web widget
621 // to the page_size and then scales it to the desired_size.
622 Send(new ViewMsg_PaintAtSize(routing_id_, dib_handle, tag,
623 page_size, desired_size));
626 bool RenderWidgetHostImpl::TryGetBackingStore(const gfx::Size& desired_size,
627 BackingStore** backing_store) {
628 // Check if the view has an accelerated surface of the desired size.
629 if (view_->HasAcceleratedSurface(desired_size)) {
630 *backing_store = NULL;
631 return true;
634 // Check for a software backing store of the desired size.
635 *backing_store = BackingStoreManager::GetBackingStore(this, desired_size);
636 return !!*backing_store;
639 BackingStore* RenderWidgetHostImpl::GetBackingStore(bool force_create) {
640 if (!view_)
641 return NULL;
643 // The view_size will be current_size_ for auto-sized views and otherwise the
644 // size of the view_. (For auto-sized views, current_size_ is updated during
645 // UpdateRect messages.)
646 gfx::Size view_size = current_size_;
647 if (!should_auto_resize_) {
648 // Get the desired size from the current view bounds.
649 gfx::Rect view_rect = view_->GetViewBounds();
650 if (view_rect.IsEmpty())
651 return NULL;
652 view_size = view_rect.size();
655 TRACE_EVENT2("renderer_host", "RenderWidgetHostImpl::GetBackingStore",
656 "width", base::IntToString(view_size.width()),
657 "height", base::IntToString(view_size.height()));
659 // We should not be asked to paint while we are hidden. If we are hidden,
660 // then it means that our consumer failed to call WasShown. If we're not
661 // force creating the backing store, it's OK since we can feel free to give
662 // out our cached one if we have it.
663 DCHECK(!is_hidden_ || !force_create) <<
664 "GetBackingStore called while hidden!";
666 // We should never be called recursively; this can theoretically lead to
667 // infinite recursion and almost certainly leads to lower performance.
668 DCHECK(!in_get_backing_store_) << "GetBackingStore called recursively!";
669 base::AutoReset<bool> auto_reset_in_get_backing_store(
670 &in_get_backing_store_, true);
672 // We might have a cached backing store that we can reuse!
673 BackingStore* backing_store = NULL;
674 if (TryGetBackingStore(view_size, &backing_store) || !force_create)
675 return backing_store;
677 // We do not have a suitable backing store in the cache, so send out a
678 // request to the renderer to paint the view if required.
679 if (!repaint_ack_pending_ && !resize_ack_pending_ && !view_being_painted_) {
680 repaint_start_time_ = TimeTicks::Now();
681 repaint_ack_pending_ = true;
682 Send(new ViewMsg_Repaint(routing_id_, view_size));
685 TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS);
686 TimeTicks end_time = TimeTicks::Now() + max_delay;
687 do {
688 TRACE_EVENT0("renderer_host", "GetBackingStore::WaitForUpdate");
690 #if defined(OS_MACOSX)
691 view_->AboutToWaitForBackingStoreMsg();
692 #endif
694 // When we have asked the RenderWidget to resize, and we are still waiting
695 // on a response, block for a little while to see if we can't get a response
696 // before returning the old (incorrectly sized) backing store.
697 IPC::Message msg;
698 if (process_->WaitForBackingStoreMsg(routing_id_, max_delay, &msg)) {
699 OnMessageReceived(msg);
701 // For auto-resized views, current_size_ determines the view_size and it
702 // may have changed during the handling of an UpdateRect message.
703 if (should_auto_resize_)
704 view_size = current_size_;
706 // Break now if we got a backing store or accelerated surface of the
707 // correct size.
708 if (TryGetBackingStore(view_size, &backing_store) ||
709 abort_get_backing_store_) {
710 abort_get_backing_store_ = false;
711 return backing_store;
713 } else {
714 TRACE_EVENT0("renderer_host", "GetBackingStore::Timeout");
715 break;
718 // Loop if we still have time left and haven't gotten a properly sized
719 // BackingStore yet. This is necessary to support the GPU path which
720 // typically has multiple frames pipelined -- we may need to skip one or two
721 // BackingStore messages to get to the latest.
722 max_delay = end_time - TimeTicks::Now();
723 } while (max_delay > TimeDelta::FromSeconds(0));
725 // We have failed to get a backing store of view_size. Fall back on
726 // current_size_ to avoid a white flash while resizing slow pages.
727 if (view_size != current_size_)
728 TryGetBackingStore(current_size_, &backing_store);
729 return backing_store;
732 BackingStore* RenderWidgetHostImpl::AllocBackingStore(const gfx::Size& size) {
733 if (!view_)
734 return NULL;
735 return view_->AllocBackingStore(size);
738 void RenderWidgetHostImpl::DonePaintingToBackingStore() {
739 Send(new ViewMsg_UpdateRect_ACK(GetRoutingID()));
742 void RenderWidgetHostImpl::ScheduleComposite() {
743 if (is_hidden_ || !is_accelerated_compositing_active_) {
744 return;
747 // Send out a request to the renderer to paint the view if required.
748 if (!repaint_ack_pending_ && !resize_ack_pending_ && !view_being_painted_) {
749 repaint_start_time_ = TimeTicks::Now();
750 repaint_ack_pending_ = true;
751 Send(new ViewMsg_Repaint(routing_id_, current_size_));
755 void RenderWidgetHostImpl::StartHangMonitorTimeout(TimeDelta delay) {
756 if (CommandLine::ForCurrentProcess()->HasSwitch(
757 switches::kDisableHangMonitor)) {
758 return;
761 // Set time_when_considered_hung_ if it's null. Also, update
762 // time_when_considered_hung_ if the caller's request is sooner than the
763 // existing one. This will have the side effect that the existing timeout will
764 // be forgotten.
765 Time requested_end_time = Time::Now() + delay;
766 if (time_when_considered_hung_.is_null() ||
767 time_when_considered_hung_ > requested_end_time)
768 time_when_considered_hung_ = requested_end_time;
770 // If we already have a timer with the same or shorter duration, then we can
771 // wait for it to finish.
772 if (hung_renderer_timer_.IsRunning() &&
773 hung_renderer_timer_.GetCurrentDelay() <= delay) {
774 // If time_when_considered_hung_ was null, this timer may fire early.
775 // CheckRendererIsUnresponsive handles that by calling
776 // StartHangMonitorTimeout with the remaining time.
777 // If time_when_considered_hung_ was non-null, it means we still haven't
778 // heard from the renderer so we leave time_when_considered_hung_ as is.
779 return;
782 // Either the timer is not yet running, or we need to adjust the timer to
783 // fire sooner.
784 time_when_considered_hung_ = requested_end_time;
785 hung_renderer_timer_.Stop();
786 hung_renderer_timer_.Start(FROM_HERE, delay, this,
787 &RenderWidgetHostImpl::CheckRendererIsUnresponsive);
790 void RenderWidgetHostImpl::RestartHangMonitorTimeout() {
791 // Setting to null will cause StartHangMonitorTimeout to restart the timer.
792 time_when_considered_hung_ = Time();
793 StartHangMonitorTimeout(
794 TimeDelta::FromMilliseconds(hung_renderer_delay_ms_));
797 void RenderWidgetHostImpl::StopHangMonitorTimeout() {
798 time_when_considered_hung_ = Time();
799 RendererIsResponsive();
800 // We do not bother to stop the hung_renderer_timer_ here in case it will be
801 // started again shortly, which happens to be the common use case.
804 void RenderWidgetHostImpl::EnableFullAccessibilityMode() {
805 SetAccessibilityMode(AccessibilityModeComplete);
808 static WebGestureEvent MakeGestureEvent(WebInputEvent::Type type,
809 double timestamp_seconds,
810 int x,
811 int y,
812 int modifiers) {
813 WebGestureEvent result;
815 result.type = type;
816 result.x = x;
817 result.y = y;
818 result.timeStampSeconds = timestamp_seconds;
819 result.modifiers = modifiers;
821 return result;
824 void RenderWidgetHostImpl::SimulateTouchGestureWithMouse(
825 const WebMouseEvent& mouse_event) {
826 int x = mouse_event.x, y = mouse_event.y;
827 float dx = mouse_event.movementX, dy = mouse_event.movementY;
828 static int startX = 0, startY = 0;
830 switch (mouse_event.button) {
831 case WebMouseEvent::ButtonLeft:
832 if (mouse_event.type == WebInputEvent::MouseDown) {
833 startX = x;
834 startY = y;
835 ForwardGestureEvent(MakeGestureEvent(
836 WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
837 x, y, 0));
839 if (dx != 0 || dy != 0) {
840 WebGestureEvent event = MakeGestureEvent(
841 WebInputEvent::GestureScrollUpdate, mouse_event.timeStampSeconds,
842 x, y, 0);
843 event.data.scrollUpdate.deltaX = dx;
844 event.data.scrollUpdate.deltaY = dy;
845 ForwardGestureEvent(event);
847 if (mouse_event.type == WebInputEvent::MouseUp) {
848 ForwardGestureEvent(MakeGestureEvent(
849 WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
850 x, y, 0));
852 break;
853 case WebMouseEvent::ButtonMiddle:
854 if (mouse_event.type == WebInputEvent::MouseDown) {
855 startX = x;
856 startY = y;
857 ForwardGestureEvent(MakeGestureEvent(
858 WebInputEvent::GestureTapDown, mouse_event.timeStampSeconds,
859 x, y, 0));
861 if (mouse_event.type == WebInputEvent::MouseUp) {
862 ForwardGestureEvent(MakeGestureEvent(
863 WebInputEvent::GestureTap, mouse_event.timeStampSeconds,
864 x, y, 0));
866 break;
867 case WebMouseEvent::ButtonRight:
868 if (mouse_event.type == WebInputEvent::MouseDown) {
869 startX = x;
870 startY = y;
871 ForwardGestureEvent(MakeGestureEvent(
872 WebInputEvent::GesturePinchBegin, mouse_event.timeStampSeconds,
873 x, y, 0));
875 if (dx != 0 || dy != 0) {
876 dx = pow(dy < 0 ? 0.998f : 1.002f, fabs(dy));
877 WebGestureEvent event = MakeGestureEvent(
878 WebInputEvent::GesturePinchUpdate, mouse_event.timeStampSeconds,
879 startX, startY, 0);
880 event.data.pinchUpdate.scale = dx;
881 ForwardGestureEvent(event);
883 if (mouse_event.type == WebInputEvent::MouseUp) {
884 ForwardGestureEvent(MakeGestureEvent(
885 WebInputEvent::GesturePinchEnd, mouse_event.timeStampSeconds,
886 x, y, 0));
888 break;
889 case WebMouseEvent::ButtonNone:
890 break;
894 void RenderWidgetHostImpl::ForwardMouseEvent(const WebMouseEvent& mouse_event) {
895 TRACE_EVENT2("renderer_host", "RenderWidgetHostImpl::ForwardMouseEvent",
896 "x", mouse_event.x, "y", mouse_event.y);
897 if (ignore_input_events_ || process_->IgnoreInputEvents())
898 return;
900 if (CommandLine::ForCurrentProcess()->HasSwitch(
901 switches::kSimulateTouchScreenWithMouse)) {
902 SimulateTouchGestureWithMouse(mouse_event);
903 return;
906 if (mouse_event.type == WebInputEvent::MouseDown &&
907 gesture_event_filter_->GetTapSuppressionController()->
908 ShouldDeferMouseDown(mouse_event))
909 return;
910 if (mouse_event.type == WebInputEvent::MouseUp &&
911 gesture_event_filter_->GetTapSuppressionController()->
912 ShouldSuppressMouseUp())
913 return;
915 ForwardMouseEventImmediately(mouse_event);
918 void RenderWidgetHostImpl::OnPointerEventActivate() {
921 void RenderWidgetHostImpl::ForwardWheelEvent(
922 const WebMouseWheelEvent& wheel_event) {
923 TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::ForwardWheelEvent");
924 if (ignore_input_events_ || process_->IgnoreInputEvents())
925 return;
927 // If there's already a mouse wheel event waiting to be sent to the renderer,
928 // add the new deltas to that event. Not doing so (e.g., by dropping the old
929 // event, as for mouse moves) results in very slow scrolling on the Mac (on
930 // which many, very small wheel events are sent).
931 if (mouse_wheel_pending_) {
932 if (coalesced_mouse_wheel_events_.empty() ||
933 !ShouldCoalesceMouseWheelEvents(coalesced_mouse_wheel_events_.back(),
934 wheel_event)) {
935 coalesced_mouse_wheel_events_.push_back(wheel_event);
936 } else {
937 WebMouseWheelEvent* last_wheel_event =
938 &coalesced_mouse_wheel_events_.back();
939 last_wheel_event->deltaX += wheel_event.deltaX;
940 last_wheel_event->deltaY += wheel_event.deltaY;
941 last_wheel_event->wheelTicksX += wheel_event.wheelTicksX;
942 last_wheel_event->wheelTicksY += wheel_event.wheelTicksY;
943 DCHECK_GE(wheel_event.timeStampSeconds,
944 last_wheel_event->timeStampSeconds);
945 last_wheel_event->timeStampSeconds = wheel_event.timeStampSeconds;
947 return;
949 mouse_wheel_pending_ = true;
950 current_wheel_event_ = wheel_event;
952 HISTOGRAM_COUNTS_100("MPArch.RWH_WheelQueueSize",
953 coalesced_mouse_wheel_events_.size());
955 ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent), false);
958 void RenderWidgetHostImpl::ForwardGestureEvent(
959 const WebKit::WebGestureEvent& gesture_event) {
960 TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::ForwardGestureEvent");
961 if (ignore_input_events_ || process_->IgnoreInputEvents())
962 return;
964 if (!IsInOverscrollGesture() &&
965 !gesture_event_filter_->ShouldForward(gesture_event))
966 return;
968 ForwardInputEvent(gesture_event, sizeof(WebGestureEvent), false);
971 // Forwards MouseEvent without passing it through TapSuppressionController
972 void RenderWidgetHostImpl::ForwardMouseEventImmediately(
973 const WebMouseEvent& mouse_event) {
974 TRACE_EVENT2("renderer_host",
975 "RenderWidgetHostImpl::ForwardMouseEventImmediately",
976 "x", mouse_event.x, "y", mouse_event.y);
977 if (ignore_input_events_ || process_->IgnoreInputEvents())
978 return;
980 if (CommandLine::ForCurrentProcess()->HasSwitch(
981 switches::kSimulateTouchScreenWithMouse)) {
982 SimulateTouchGestureWithMouse(mouse_event);
983 return;
986 // Avoid spamming the renderer with mouse move events. It is important
987 // to note that WM_MOUSEMOVE events are anyways synthetic, but since our
988 // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way
989 // more WM_MOUSEMOVE events than we wish to send to the renderer.
990 if (mouse_event.type == WebInputEvent::MouseMove) {
991 if (mouse_move_pending_) {
992 if (!next_mouse_move_.get()) {
993 next_mouse_move_.reset(new WebMouseEvent(mouse_event));
994 } else {
995 // Accumulate movement deltas.
996 int x = next_mouse_move_->movementX;
997 int y = next_mouse_move_->movementY;
998 *next_mouse_move_ = mouse_event;
999 next_mouse_move_->movementX += x;
1000 next_mouse_move_->movementY += y;
1002 return;
1004 mouse_move_pending_ = true;
1005 } else if (mouse_event.type == WebInputEvent::MouseDown) {
1006 OnUserGesture();
1009 ForwardInputEvent(mouse_event, sizeof(WebMouseEvent), false);
1012 void RenderWidgetHostImpl::ForwardTouchEventImmediately(
1013 const WebKit::WebTouchEvent& touch_event) {
1014 TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::ForwardTouchEvent");
1015 if (ignore_input_events_ || process_->IgnoreInputEvents())
1016 return;
1018 ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent), false);
1021 void RenderWidgetHostImpl::ForwardGestureEventImmediately(
1022 const WebKit::WebGestureEvent& gesture_event) {
1023 if (ignore_input_events_ || process_->IgnoreInputEvents())
1024 return;
1025 ForwardInputEvent(gesture_event, sizeof(WebGestureEvent), false);
1028 void RenderWidgetHostImpl::ForwardKeyboardEvent(
1029 const NativeWebKeyboardEvent& key_event) {
1030 TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::ForwardKeyboardEvent");
1031 if (ignore_input_events_ || process_->IgnoreInputEvents())
1032 return;
1034 if (key_event.type == WebKeyboardEvent::Char &&
1035 (key_event.windowsKeyCode == ui::VKEY_RETURN ||
1036 key_event.windowsKeyCode == ui::VKEY_SPACE)) {
1037 OnUserGesture();
1040 // Double check the type to make sure caller hasn't sent us nonsense that
1041 // will mess up our key queue.
1042 if (WebInputEvent::isKeyboardEventType(key_event.type)) {
1043 if (suppress_next_char_events_) {
1044 // If preceding RawKeyDown event was handled by the browser, then we need
1045 // suppress all Char events generated by it. Please note that, one
1046 // RawKeyDown event may generate multiple Char events, so we can't reset
1047 // |suppress_next_char_events_| until we get a KeyUp or a RawKeyDown.
1048 if (key_event.type == WebKeyboardEvent::Char)
1049 return;
1050 // We get a KeyUp or a RawKeyDown event.
1051 suppress_next_char_events_ = false;
1054 bool is_keyboard_shortcut = false;
1055 // Only pre-handle the key event if it's not handled by the input method.
1056 if (delegate_ && !key_event.skip_in_browser) {
1057 // We need to set |suppress_next_char_events_| to true if
1058 // PreHandleKeyboardEvent() returns true, but |this| may already be
1059 // destroyed at that time. So set |suppress_next_char_events_| true here,
1060 // then revert it afterwards when necessary.
1061 if (key_event.type == WebKeyboardEvent::RawKeyDown)
1062 suppress_next_char_events_ = true;
1064 // Tab switching/closing accelerators aren't sent to the renderer to avoid
1065 // a hung/malicious renderer from interfering.
1066 if (delegate_->PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut))
1067 return;
1069 if (key_event.type == WebKeyboardEvent::RawKeyDown)
1070 suppress_next_char_events_ = false;
1073 // Don't add this key to the queue if we have no way to send the message...
1074 if (!process_->HasConnection())
1075 return;
1077 // Put all WebKeyboardEvent objects in a queue since we can't trust the
1078 // renderer and we need to give something to the HandleKeyboardEvent
1079 // handler.
1080 key_queue_.push_back(key_event);
1081 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
1083 gesture_event_filter_->FlingHasBeenHalted();
1085 // Only forward the non-native portions of our event.
1086 ForwardInputEvent(key_event, sizeof(WebKeyboardEvent),
1087 is_keyboard_shortcut);
1091 void RenderWidgetHostImpl::SendInputEvent(const WebInputEvent& input_event,
1092 int event_size,
1093 bool is_keyboard_shortcut) {
1094 IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_);
1095 message->WriteData(
1096 reinterpret_cast<const char*>(&input_event), event_size);
1097 // |is_keyboard_shortcut| only makes sense for RawKeyDown events.
1098 if (input_event.type == WebInputEvent::RawKeyDown)
1099 message->WriteBool(is_keyboard_shortcut);
1100 input_event_start_time_ = TimeTicks::Now();
1101 Send(message);
1102 increment_in_flight_event_count();
1105 void RenderWidgetHostImpl::ForwardInputEvent(const WebInputEvent& input_event,
1106 int event_size,
1107 bool is_keyboard_shortcut) {
1108 TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::ForwardInputEvent");
1110 if (!process_->HasConnection())
1111 return;
1113 DCHECK(!process_->IgnoreInputEvents());
1115 if (overscroll_controller_.get() &&
1116 !overscroll_controller_->WillDispatchEvent(input_event)) {
1117 // Reset the wheel-event state when appropriate.
1118 if (input_event.type == WebKit::WebInputEvent::MouseWheel) {
1119 mouse_wheel_pending_ = false;
1120 } else if (WebInputEvent::isGestureEventType(input_event.type) &&
1121 gesture_event_filter_->HasQueuedGestureEvents()) {
1122 // If the gesture-event filter has queued gesture events, that implies it
1123 // is awaiting an ack for the event. Since the event is being consumed by
1124 // the over scroll here, it is never sent to the renderer, and so it won't
1125 // receive any ACKs. So send the ACK to the gesture event filter
1126 // immediately, and mark it as having been processed.
1127 gesture_event_filter_->ProcessGestureAck(true, input_event.type);
1128 } else if (WebInputEvent::isTouchEventType(input_event.type)) {
1129 // During an overscroll gesture initiated by touch-scrolling, the
1130 // touch-events do not reset or contribute to the overscroll gesture.
1131 // However, the touch-events are not sent to the renderer. So send and ACK
1132 // to the touch-event queue immediately. Mark the event as not processed,
1133 // to make sure that the touch-scroll gesture that initiated the
1134 // overscroll is updated properly.
1135 touch_event_queue_->ProcessTouchAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
1137 return;
1140 in_process_event_types_.push(input_event.type);
1142 // Transmit any pending wheel events on a non-wheel event. This ensures that
1143 // the renderer receives the final PhaseEnded wheel event, which is necessary
1144 // to terminate rubber-banding, for example.
1145 if (input_event.type != WebInputEvent::MouseWheel) {
1146 for (size_t i = 0; i < coalesced_mouse_wheel_events_.size(); ++i) {
1147 SendInputEvent(coalesced_mouse_wheel_events_[i],
1148 sizeof(WebMouseWheelEvent), false);
1150 coalesced_mouse_wheel_events_.clear();
1153 SendInputEvent(input_event, event_size, is_keyboard_shortcut);
1155 // Any input event cancels a pending mouse move event. Note that
1156 // |next_mouse_move_| possibly owns |input_event|, so don't use |input_event|
1157 // after this line.
1158 next_mouse_move_.reset();
1160 StartHangMonitorTimeout(
1161 TimeDelta::FromMilliseconds(hung_renderer_delay_ms_));
1164 void RenderWidgetHostImpl::ForwardTouchEvent(
1165 const WebKit::WebTouchEvent& touch_event) {
1166 touch_event_queue_->QueueEvent(touch_event);
1169 #if defined(TOOLKIT_GTK)
1170 bool RenderWidgetHostImpl::KeyPressListenersHandleEvent(GdkEventKey* event) {
1171 if (event->type != GDK_KEY_PRESS)
1172 return false;
1174 for (std::list<KeyboardListener*>::iterator it = keyboard_listeners_.begin();
1175 it != keyboard_listeners_.end(); ++it) {
1176 if ((*it)->HandleKeyPressEvent(event))
1177 return true;
1180 return false;
1182 #endif // defined(TOOLKIT_GTK)
1184 #if defined(TOOLKIT_VIEWS)
1185 bool RenderWidgetHostImpl::KeyPressListenersHandleEvent(ui::KeyEvent* event) {
1186 if (event->type() != ui::ET_KEY_PRESSED)
1187 return false;
1189 for (std::list<KeyboardListener*>::iterator it = keyboard_listeners_.begin();
1190 it != keyboard_listeners_.end(); ++it) {
1191 if ((*it)->HandleKeyPressEvent(event))
1192 return true;
1195 return false;
1197 #endif // defined(TOOLKIT_VIEWS)
1199 void RenderWidgetHostImpl::AddKeyboardListener(KeyboardListener* listener) {
1200 keyboard_listeners_.push_back(listener);
1203 void RenderWidgetHostImpl::RemoveKeyboardListener(
1204 KeyboardListener* listener) {
1205 keyboard_listeners_.remove(listener);
1208 void RenderWidgetHostImpl::NotifyScreenInfoChanged() {
1209 WebKit::WebScreenInfo screen_info;
1210 GetWebScreenInfo(&screen_info);
1211 Send(new ViewMsg_ScreenInfoChanged(GetRoutingID(), screen_info));
1214 void RenderWidgetHostImpl::UpdateVSyncParameters(base::TimeTicks timebase,
1215 base::TimeDelta interval) {
1216 Send(new ViewMsg_UpdateVSyncParameters(GetRoutingID(), timebase, interval));
1219 void RenderWidgetHostImpl::RendererExited(base::TerminationStatus status,
1220 int exit_code) {
1221 // Clearing this flag causes us to re-create the renderer when recovering
1222 // from a crashed renderer.
1223 renderer_initialized_ = false;
1225 waiting_for_screen_rects_ack_ = false;
1227 // Must reset these to ensure that mouse move/wheel events work with a new
1228 // renderer.
1229 mouse_move_pending_ = false;
1230 next_mouse_move_.reset();
1231 mouse_wheel_pending_ = false;
1232 coalesced_mouse_wheel_events_.clear();
1234 // Must reset these to ensure that SelectRange works with a new renderer.
1235 select_range_pending_ = false;
1236 next_selection_range_.reset();
1238 touch_event_queue_->Reset();
1240 // Must reset these to ensure that gesture events work with a new renderer.
1241 gesture_event_filter_->Reset();
1243 if (overscroll_controller_.get())
1244 overscroll_controller_->Reset();
1246 // Must reset these to ensure that keyboard events work with a new renderer.
1247 key_queue_.clear();
1248 suppress_next_char_events_ = false;
1250 // Reset some fields in preparation for recovering from a crash.
1251 ResetSizeAndRepaintPendingFlags();
1252 current_size_.SetSize(0, 0);
1253 is_hidden_ = false;
1254 is_accelerated_compositing_active_ = false;
1256 // Reset this to ensure the hung renderer mechanism is working properly.
1257 in_flight_event_count_ = 0;
1259 if (view_) {
1260 GpuSurfaceTracker::Get()->SetSurfaceHandle(surface_id_,
1261 gfx::GLSurfaceHandle());
1262 view_->RenderViewGone(status, exit_code);
1263 view_ = NULL; // The View should be deleted by RenderViewGone.
1266 BackingStoreManager::RemoveBackingStore(this);
1269 void RenderWidgetHostImpl::UpdateTextDirection(WebTextDirection direction) {
1270 text_direction_updated_ = true;
1271 text_direction_ = direction;
1274 void RenderWidgetHostImpl::CancelUpdateTextDirection() {
1275 if (text_direction_updated_)
1276 text_direction_canceled_ = true;
1279 void RenderWidgetHostImpl::NotifyTextDirection() {
1280 if (text_direction_updated_) {
1281 if (!text_direction_canceled_)
1282 Send(new ViewMsg_SetTextDirection(GetRoutingID(), text_direction_));
1283 text_direction_updated_ = false;
1284 text_direction_canceled_ = false;
1288 void RenderWidgetHostImpl::SetInputMethodActive(bool activate) {
1289 Send(new ViewMsg_SetInputMethodActive(GetRoutingID(), activate));
1292 void RenderWidgetHostImpl::ImeSetComposition(
1293 const string16& text,
1294 const std::vector<WebKit::WebCompositionUnderline>& underlines,
1295 int selection_start,
1296 int selection_end) {
1297 Send(new ViewMsg_ImeSetComposition(
1298 GetRoutingID(), text, underlines, selection_start, selection_end));
1301 void RenderWidgetHostImpl::ImeConfirmComposition(const string16& text) {
1302 ImeConfirmComposition(text, ui::Range::InvalidRange());
1305 void RenderWidgetHostImpl::ImeConfirmComposition(
1306 const string16& text, const ui::Range& replacement_range) {
1307 Send(new ViewMsg_ImeConfirmComposition(
1308 GetRoutingID(), text, replacement_range));
1311 void RenderWidgetHostImpl::ImeConfirmComposition() {
1312 ImeConfirmComposition(string16());
1315 void RenderWidgetHostImpl::ImeCancelComposition() {
1316 Send(new ViewMsg_ImeSetComposition(GetRoutingID(), string16(),
1317 std::vector<WebKit::WebCompositionUnderline>(), 0, 0));
1320 void RenderWidgetHostImpl::ExtendSelectionAndDelete(
1321 size_t before,
1322 size_t after) {
1323 Send(new ViewMsg_ExtendSelectionAndDelete(GetRoutingID(), before, after));
1326 gfx::Rect RenderWidgetHostImpl::GetRootWindowResizerRect() const {
1327 return gfx::Rect();
1330 void RenderWidgetHostImpl::RequestToLockMouse(bool user_gesture,
1331 bool last_unlocked_by_target) {
1332 // Directly reject to lock the mouse. Subclass can override this method to
1333 // decide whether to allow mouse lock or not.
1334 GotResponseToLockMouseRequest(false);
1337 void RenderWidgetHostImpl::RejectMouseLockOrUnlockIfNecessary() {
1338 DCHECK(!pending_mouse_lock_request_ || !IsMouseLocked());
1339 if (pending_mouse_lock_request_) {
1340 pending_mouse_lock_request_ = false;
1341 Send(new ViewMsg_LockMouse_ACK(routing_id_, false));
1342 } else if (IsMouseLocked()) {
1343 view_->UnlockMouse();
1347 bool RenderWidgetHostImpl::IsMouseLocked() const {
1348 return view_ ? view_->IsMouseLocked() : false;
1351 bool RenderWidgetHostImpl::IsFullscreen() const {
1352 return false;
1355 void RenderWidgetHostImpl::SetShouldAutoResize(bool enable) {
1356 should_auto_resize_ = enable;
1359 void RenderWidgetHostImpl::InitializeOverscrollController() {
1360 overscroll_controller_.reset(new OverscrollController(this));
1363 bool RenderWidgetHostImpl::IsInOverscrollGesture() const {
1364 return overscroll_controller_.get() &&
1365 overscroll_controller_->overscroll_mode() != OVERSCROLL_NONE;
1368 void RenderWidgetHostImpl::GetWebScreenInfo(WebKit::WebScreenInfo* result) {
1369 #if defined(OS_POSIX) || defined(USE_AURA)
1370 if (GetView()) {
1371 static_cast<RenderWidgetHostViewPort*>(GetView())->GetScreenInfo(result);
1372 } else {
1373 RenderWidgetHostViewPort::GetDefaultScreenInfo(result);
1375 #else
1376 *result = WebKit::WebScreenInfoFactory::screenInfo(
1377 gfx::NativeViewFromId(GetNativeViewId()));
1378 #endif
1381 void RenderWidgetHostImpl::Destroy() {
1382 NotificationService::current()->Notify(
1383 NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
1384 Source<RenderWidgetHost>(this),
1385 NotificationService::NoDetails());
1387 // Tell the view to die.
1388 // Note that in the process of the view shutting down, it can call a ton
1389 // of other messages on us. So if you do any other deinitialization here,
1390 // do it after this call to view_->Destroy().
1391 if (view_)
1392 view_->Destroy();
1394 delete this;
1397 void RenderWidgetHostImpl::CheckRendererIsUnresponsive() {
1398 // If we received a call to StopHangMonitorTimeout.
1399 if (time_when_considered_hung_.is_null())
1400 return;
1402 // If we have not waited long enough, then wait some more.
1403 Time now = Time::Now();
1404 if (now < time_when_considered_hung_) {
1405 StartHangMonitorTimeout(time_when_considered_hung_ - now);
1406 return;
1409 // OK, looks like we have a hung renderer!
1410 NotificationService::current()->Notify(
1411 NOTIFICATION_RENDERER_PROCESS_HANG,
1412 Source<RenderWidgetHost>(this),
1413 NotificationService::NoDetails());
1414 is_unresponsive_ = true;
1415 NotifyRendererUnresponsive();
1418 void RenderWidgetHostImpl::RendererIsResponsive() {
1419 if (is_unresponsive_) {
1420 is_unresponsive_ = false;
1421 NotifyRendererResponsive();
1425 void RenderWidgetHostImpl::OnMsgRenderViewReady() {
1426 SendScreenRects();
1427 WasResized();
1430 void RenderWidgetHostImpl::OnMsgRenderViewGone(int status, int exit_code) {
1431 // TODO(evanm): This synchronously ends up calling "delete this".
1432 // Is that really what we want in response to this message? I'm matching
1433 // previous behavior of the code here.
1434 Destroy();
1437 void RenderWidgetHostImpl::OnMsgClose() {
1438 Shutdown();
1441 void RenderWidgetHostImpl::OnMsgSetTooltipText(
1442 const string16& tooltip_text,
1443 WebTextDirection text_direction_hint) {
1444 // First, add directionality marks around tooltip text if necessary.
1445 // A naive solution would be to simply always wrap the text. However, on
1446 // windows, Unicode directional embedding characters can't be displayed on
1447 // systems that lack RTL fonts and are instead displayed as empty squares.
1449 // To get around this we only wrap the string when we deem it necessary i.e.
1450 // when the locale direction is different than the tooltip direction hint.
1452 // Currently, we use element's directionality as the tooltip direction hint.
1453 // An alternate solution would be to set the overall directionality based on
1454 // trying to detect the directionality from the tooltip text rather than the
1455 // element direction. One could argue that would be a preferable solution
1456 // but we use the current approach to match Fx & IE's behavior.
1457 string16 wrapped_tooltip_text = tooltip_text;
1458 if (!tooltip_text.empty()) {
1459 if (text_direction_hint == WebKit::WebTextDirectionLeftToRight) {
1460 // Force the tooltip to have LTR directionality.
1461 wrapped_tooltip_text =
1462 base::i18n::GetDisplayStringInLTRDirectionality(wrapped_tooltip_text);
1463 } else if (text_direction_hint == WebKit::WebTextDirectionRightToLeft &&
1464 !base::i18n::IsRTL()) {
1465 // Force the tooltip to have RTL directionality.
1466 base::i18n::WrapStringWithRTLFormatting(&wrapped_tooltip_text);
1469 if (GetView())
1470 view_->SetTooltipText(wrapped_tooltip_text);
1473 void RenderWidgetHostImpl::OnMsgUpdateScreenRectsAck() {
1474 waiting_for_screen_rects_ack_ = false;
1475 if (!view_)
1476 return;
1478 if (view_->GetViewBounds() == last_view_screen_rect_ &&
1479 view_->GetBoundsInRootWindow() == last_window_screen_rect_) {
1480 return;
1483 SendScreenRects();
1486 void RenderWidgetHostImpl::OnMsgRequestMove(const gfx::Rect& pos) {
1487 // Note that we ignore the position.
1488 if (view_) {
1489 view_->SetBounds(pos);
1490 Send(new ViewMsg_Move_ACK(routing_id_));
1494 void RenderWidgetHostImpl::OnMsgPaintAtSizeAck(int tag, const gfx::Size& size) {
1495 std::pair<int, gfx::Size> details = std::make_pair(tag, size);
1496 NotificationService::current()->Notify(
1497 NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_PAINT_AT_SIZE_ACK,
1498 Source<RenderWidgetHost>(this),
1499 Details<std::pair<int, gfx::Size> >(&details));
1502 void RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwapped(
1503 int32 surface_id,
1504 uint64 surface_handle,
1505 int32 route_id,
1506 const gfx::Size& size,
1507 int32 gpu_process_host_id) {
1508 TRACE_EVENT0("renderer_host",
1509 "RenderWidgetHostImpl::OnCompositorSurfaceBuffersSwapped");
1510 if (!view_) {
1511 RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id,
1512 gpu_process_host_id,
1513 false,
1515 return;
1517 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params gpu_params;
1518 gpu_params.surface_id = surface_id;
1519 gpu_params.surface_handle = surface_handle;
1520 gpu_params.route_id = route_id;
1521 gpu_params.size = size;
1522 #if defined(OS_MACOSX)
1523 // Compositor window is always gfx::kNullPluginWindow.
1524 // TODO(jbates) http://crbug.com/105344 This will be removed when there are no
1525 // plugin windows.
1526 gpu_params.window = gfx::kNullPluginWindow;
1527 #endif
1528 view_->AcceleratedSurfaceBuffersSwapped(gpu_params,
1529 gpu_process_host_id);
1532 void RenderWidgetHostImpl::OnMsgUpdateRect(
1533 const ViewHostMsg_UpdateRect_Params& params) {
1534 TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::OnMsgUpdateRect");
1535 TimeTicks paint_start = TimeTicks::Now();
1537 // Update our knowledge of the RenderWidget's size.
1538 current_size_ = params.view_size;
1539 // Update our knowledge of the RenderWidget's scroll offset.
1540 last_scroll_offset_ = params.scroll_offset;
1542 bool is_resize_ack =
1543 ViewHostMsg_UpdateRect_Flags::is_resize_ack(params.flags);
1545 // resize_ack_pending_ needs to be cleared before we call DidPaintRect, since
1546 // that will end up reaching GetBackingStore.
1547 if (is_resize_ack) {
1548 DCHECK(resize_ack_pending_);
1549 resize_ack_pending_ = false;
1550 in_flight_size_.SetSize(0, 0);
1553 bool is_repaint_ack =
1554 ViewHostMsg_UpdateRect_Flags::is_repaint_ack(params.flags);
1555 if (is_repaint_ack) {
1556 repaint_ack_pending_ = false;
1557 TimeDelta delta = TimeTicks::Now() - repaint_start_time_;
1558 UMA_HISTOGRAM_TIMES("MPArch.RWH_RepaintDelta", delta);
1561 DCHECK(!params.view_size.IsEmpty());
1563 bool was_async = false;
1565 // If this is a GPU UpdateRect, params.bitmap is invalid and dib will be NULL.
1566 TransportDIB* dib = process_->GetTransportDIB(params.bitmap);
1568 // If gpu process does painting, scroll_rect and copy_rects are always empty
1569 // and backing store is never used.
1570 if (dib) {
1571 DCHECK(!params.bitmap_rect.IsEmpty());
1572 gfx::Size pixel_size = gfx::ToFlooredSize(
1573 gfx::ScaleSize(params.bitmap_rect.size(), params.scale_factor));
1574 const size_t size = pixel_size.height() * pixel_size.width() * 4;
1575 if (dib->size() < size) {
1576 DLOG(WARNING) << "Transport DIB too small for given rectangle";
1577 RecordAction(UserMetricsAction("BadMessageTerminate_RWH1"));
1578 GetProcess()->ReceivedBadMessage();
1579 } else {
1580 UNSHIPPED_TRACE_EVENT_INSTANT2("test_latency", "UpdateRect",
1581 "x+y", params.bitmap_rect.x() + params.bitmap_rect.y(),
1582 "color", 0xffffff & *static_cast<uint32*>(dib->memory()));
1583 UNSHIPPED_TRACE_EVENT_INSTANT1("test_latency", "UpdateRectWidth",
1584 "width", params.bitmap_rect.width());
1586 // Scroll the backing store.
1587 if (!params.scroll_rect.IsEmpty()) {
1588 ScrollBackingStoreRect(params.scroll_delta,
1589 params.scroll_rect,
1590 params.view_size);
1593 // Paint the backing store. This will update it with the
1594 // renderer-supplied bits. The view will read out of the backing store
1595 // later to actually draw to the screen.
1596 was_async = PaintBackingStoreRect(
1597 params.bitmap,
1598 params.bitmap_rect,
1599 params.copy_rects,
1600 params.view_size,
1601 params.scale_factor,
1602 base::Bind(&RenderWidgetHostImpl::DidUpdateBackingStore,
1603 weak_factory_.GetWeakPtr(), params, paint_start));
1607 if (!was_async) {
1608 DidUpdateBackingStore(params, paint_start);
1611 if (should_auto_resize_) {
1612 bool post_callback = new_auto_size_.IsEmpty();
1613 new_auto_size_ = params.view_size;
1614 if (post_callback) {
1615 MessageLoop::current()->PostTask(
1616 FROM_HERE,
1617 base::Bind(&RenderWidgetHostImpl::DelayedAutoResized,
1618 weak_factory_.GetWeakPtr()));
1622 // Log the time delta for processing a paint message. On platforms that don't
1623 // support asynchronous painting, this is equivalent to
1624 // MPArch.RWH_TotalPaintTime.
1625 TimeDelta delta = TimeTicks::Now() - paint_start;
1626 UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgUpdateRect", delta);
1629 void RenderWidgetHostImpl::OnMsgUpdateIsDelayed() {
1630 if (in_get_backing_store_)
1631 abort_get_backing_store_ = true;
1634 void RenderWidgetHostImpl::DidUpdateBackingStore(
1635 const ViewHostMsg_UpdateRect_Params& params,
1636 const TimeTicks& paint_start) {
1637 TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::DidUpdateBackingStore");
1638 TimeTicks update_start = TimeTicks::Now();
1640 if (params.needs_ack) {
1641 // ACK early so we can prefetch the next PaintRect if there is a next one.
1642 // This must be done AFTER we're done painting with the bitmap supplied by
1643 // the renderer. This ACK is a signal to the renderer that the backing store
1644 // can be re-used, so the bitmap may be invalid after this call.
1645 Send(new ViewMsg_UpdateRect_ACK(routing_id_));
1648 // Move the plugins if the view hasn't already been destroyed. Plugin moves
1649 // will not be re-issued, so must move them now, regardless of whether we
1650 // paint or not. MovePluginWindows attempts to move the plugin windows and
1651 // in the process could dispatch other window messages which could cause the
1652 // view to be destroyed.
1653 if (view_)
1654 view_->MovePluginWindows(params.scroll_offset, params.plugin_window_moves);
1656 NotificationService::current()->Notify(
1657 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
1658 Source<RenderWidgetHost>(this),
1659 NotificationService::NoDetails());
1661 // We don't need to update the view if the view is hidden. We must do this
1662 // early return after the ACK is sent, however, or the renderer will not send
1663 // us more data.
1664 if (is_hidden_)
1665 return;
1667 // Now paint the view. Watch out: it might be destroyed already.
1668 if (view_ && !is_accelerated_compositing_active_) {
1669 view_being_painted_ = true;
1670 view_->DidUpdateBackingStore(params.scroll_rect, params.scroll_delta,
1671 params.copy_rects);
1672 view_being_painted_ = false;
1675 // If we got a resize ack, then perhaps we have another resize to send?
1676 bool is_resize_ack =
1677 ViewHostMsg_UpdateRect_Flags::is_resize_ack(params.flags);
1678 if (is_resize_ack)
1679 WasResized();
1681 // Log the time delta for processing a paint message.
1682 TimeTicks now = TimeTicks::Now();
1683 TimeDelta delta = now - update_start;
1684 UMA_HISTOGRAM_TIMES("MPArch.RWH_DidUpdateBackingStore", delta);
1686 // Measures the time from receiving the MsgUpdateRect IPC to completing the
1687 // DidUpdateBackingStore() method. On platforms which have asynchronous
1688 // painting, such as Linux, this is the sum of MPArch.RWH_OnMsgUpdateRect,
1689 // MPArch.RWH_DidUpdateBackingStore, and the time spent asynchronously
1690 // waiting for the paint to complete.
1692 // On other platforms, this will be equivalent to MPArch.RWH_OnMsgUpdateRect.
1693 delta = now - paint_start;
1694 UMA_HISTOGRAM_TIMES("MPArch.RWH_TotalPaintTime", delta);
1695 UNSHIPPED_TRACE_EVENT_INSTANT1("test_latency", "UpdateRectComplete",
1696 "x+y", params.bitmap_rect.x() + params.bitmap_rect.y());
1699 void RenderWidgetHostImpl::OnMsgInputEventAck(
1700 WebInputEvent::Type event_type, InputEventAckState ack_result) {
1701 TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::OnMsgInputEventAck");
1702 bool processed = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
1704 if (!in_process_event_types_.empty() &&
1705 in_process_event_types_.front() == event_type)
1706 in_process_event_types_.pop();
1708 // Log the time delta for processing an input event.
1709 TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
1710 UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta);
1712 // Cancel pending hung renderer checks since the renderer is responsive.
1713 if (decrement_in_flight_event_count() == 0)
1714 StopHangMonitorTimeout();
1716 // If an input ack is pending, then hold off ticking the gesture
1717 // until we get an input ack.
1718 if (in_process_event_types_.empty() &&
1719 !active_smooth_scroll_gestures_.empty())
1720 TickActiveSmoothScrollGesture();
1722 int type = static_cast<int>(event_type);
1723 if (type < WebInputEvent::Undefined) {
1724 RecordAction(UserMetricsAction("BadMessageTerminate_RWH2"));
1725 process_->ReceivedBadMessage();
1726 } else if (type == WebInputEvent::MouseMove) {
1727 mouse_move_pending_ = false;
1729 // now, we can send the next mouse move event
1730 if (next_mouse_move_.get()) {
1731 DCHECK(next_mouse_move_->type == WebInputEvent::MouseMove);
1732 ForwardMouseEvent(*next_mouse_move_);
1734 } else if (WebInputEvent::isKeyboardEventType(type)) {
1735 ProcessKeyboardEventAck(type, processed);
1736 } else if (type == WebInputEvent::MouseWheel) {
1737 ProcessWheelAck(processed);
1738 } else if (WebInputEvent::isTouchEventType(type)) {
1739 ProcessTouchAck(ack_result);
1740 } else if (WebInputEvent::isGestureEventType(type)) {
1741 ProcessGestureAck(processed, type);
1744 // WARNING: |this| may be deleted at this point.
1746 // This is used only for testing, and the other end does not use the
1747 // source object. On linux, specifying
1748 // Source<RenderWidgetHost> results in a very strange
1749 // runtime error in the epilogue of the enclosing
1750 // (OnMsgInputEventAck) method, but not on other platforms; using
1751 // 'void' instead is just as safe (since NotificationSource
1752 // is not actually typesafe) and avoids this error.
1753 NotificationService::current()->Notify(
1754 NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
1755 Source<void>(this),
1756 Details<int>(&type));
1759 void RenderWidgetHostImpl::OnMsgBeginSmoothScroll(
1760 int gesture_id, const ViewHostMsg_BeginSmoothScroll_Params &params) {
1761 if (!view_)
1762 return;
1763 active_smooth_scroll_gestures_.insert(
1764 std::make_pair(gesture_id,
1765 view_->CreateSmoothScrollGesture(
1766 params.scroll_down, params.pixels_to_scroll,
1767 params.mouse_event_x, params.mouse_event_y)));
1769 // If an input ack is pending, then hold off ticking the gesture
1770 // until we get an input ack.
1771 if (!in_process_event_types_.empty())
1772 return;
1773 if (tick_active_smooth_scroll_gestures_task_posted_)
1774 return;
1775 TickActiveSmoothScrollGesture();
1778 void RenderWidgetHostImpl::TickActiveSmoothScrollGesture() {
1779 TRACE_EVENT0("input", "RenderWidgetHostImpl::TickActiveSmoothScrollGesture");
1780 tick_active_smooth_scroll_gestures_task_posted_ = false;
1781 if (active_smooth_scroll_gestures_.empty()) {
1782 TRACE_EVENT_INSTANT0("input", "EarlyOut_NoActiveScrollGesture");
1783 return;
1786 base::TimeTicks now = TimeTicks::HighResNow();
1787 base::TimeDelta preferred_interval =
1788 base::TimeDelta::FromMilliseconds(kSyntheticScrollMessageIntervalMs);
1789 base::TimeDelta time_until_next_ideal_interval =
1790 (last_smooth_scroll_gestures_tick_time_ + preferred_interval) -
1791 now;
1792 if (time_until_next_ideal_interval.InMilliseconds() > 0) {
1793 TRACE_EVENT_INSTANT1(
1794 "input", "EarlyOut_TickedTooRecently",
1795 "delay", time_until_next_ideal_interval.InMilliseconds());
1796 // Post a task.
1797 tick_active_smooth_scroll_gestures_task_posted_ = true;
1798 MessageLoop::current()->PostDelayedTask(
1799 FROM_HERE,
1800 base::Bind(&RenderWidgetHostImpl::TickActiveSmoothScrollGesture,
1801 weak_factory_.GetWeakPtr()),
1802 time_until_next_ideal_interval);
1803 return;
1806 last_smooth_scroll_gestures_tick_time_ = now;
1808 // Separate ticking of gestures from sending their completion messages.
1809 std::vector<int> ids_that_are_done;
1810 for (SmoothScrollGestureMap::iterator it =
1811 active_smooth_scroll_gestures_.begin();
1812 it != active_smooth_scroll_gestures_.end();
1813 ++it) {
1815 bool active = it->second->ForwardInputEvents(now, this);
1816 if (!active)
1817 ids_that_are_done.push_back(it->first);
1820 // Delete completed gestures and send their completion event.
1821 for(size_t i = 0; i < ids_that_are_done.size(); i++) {
1822 int id = ids_that_are_done[i];
1823 SmoothScrollGestureMap::iterator it =
1824 active_smooth_scroll_gestures_.find(id);
1825 DCHECK(it != active_smooth_scroll_gestures_.end());
1826 active_smooth_scroll_gestures_.erase(it);
1828 Send(new ViewMsg_SmoothScrollCompleted(routing_id_, id));
1831 // No need to post the next tick if an input is in flight.
1832 if (!in_process_event_types_.empty())
1833 return;
1835 TRACE_EVENT_INSTANT1("input", "PostTickTask",
1836 "delay", preferred_interval.InMilliseconds());
1837 tick_active_smooth_scroll_gestures_task_posted_ = true;
1838 MessageLoop::current()->PostDelayedTask(
1839 FROM_HERE,
1840 base::Bind(&RenderWidgetHostImpl::TickActiveSmoothScrollGesture,
1841 weak_factory_.GetWeakPtr()),
1842 preferred_interval);
1845 void RenderWidgetHostImpl::OnMsgSelectRangeAck() {
1846 select_range_pending_ = false;
1847 if (next_selection_range_.get()) {
1848 scoped_ptr<SelectionRange> next(next_selection_range_.Pass());
1849 SelectRange(next->start, next->end);
1853 void RenderWidgetHostImpl::ProcessWheelAck(bool processed) {
1854 mouse_wheel_pending_ = false;
1856 if (overscroll_controller_.get())
1857 overscroll_controller_->ReceivedEventACK(current_wheel_event_, processed);
1859 // Now send the next (coalesced) mouse wheel event.
1860 if (!coalesced_mouse_wheel_events_.empty()) {
1861 WebMouseWheelEvent next_wheel_event =
1862 coalesced_mouse_wheel_events_.front();
1863 coalesced_mouse_wheel_events_.pop_front();
1864 ForwardWheelEvent(next_wheel_event);
1867 if (!processed && !is_hidden_ && view_)
1868 view_->UnhandledWheelEvent(current_wheel_event_);
1871 void RenderWidgetHostImpl::ProcessGestureAck(bool processed, int type) {
1872 if (overscroll_controller_.get()) {
1873 overscroll_controller_->ReceivedEventACK(
1874 gesture_event_filter_->GetGestureEventAwaitingAck(), processed);
1876 gesture_event_filter_->ProcessGestureAck(processed, type);
1879 void RenderWidgetHostImpl::ProcessTouchAck(InputEventAckState ack_result) {
1880 touch_event_queue_->ProcessTouchAck(ack_result);
1883 void RenderWidgetHostImpl::OnMsgFocus() {
1884 // Only RenderViewHost can deal with that message.
1885 RecordAction(UserMetricsAction("BadMessageTerminate_RWH4"));
1886 GetProcess()->ReceivedBadMessage();
1889 void RenderWidgetHostImpl::OnMsgBlur() {
1890 // Only RenderViewHost can deal with that message.
1891 RecordAction(UserMetricsAction("BadMessageTerminate_RWH5"));
1892 GetProcess()->ReceivedBadMessage();
1895 void RenderWidgetHostImpl::OnMsgHasTouchEventHandlers(bool has_handlers) {
1896 if (has_touch_handler_ == has_handlers)
1897 return;
1898 has_touch_handler_ = has_handlers;
1899 if (!has_touch_handler_)
1900 touch_event_queue_->FlushQueue();
1901 #if defined(OS_ANDROID)
1902 if (view_)
1903 view_->HasTouchEventHandlers(has_touch_handler_);
1904 #endif
1907 void RenderWidgetHostImpl::OnMsgSetCursor(const WebCursor& cursor) {
1908 if (!view_) {
1909 return;
1911 view_->UpdateCursor(cursor);
1914 void RenderWidgetHostImpl::OnMsgTextInputStateChanged(
1915 const ViewHostMsg_TextInputState_Params& params) {
1916 if (view_)
1917 view_->TextInputStateChanged(params);
1920 void RenderWidgetHostImpl::OnMsgImeCompositionRangeChanged(
1921 const ui::Range& range,
1922 const std::vector<gfx::Rect>& character_bounds) {
1923 if (view_)
1924 view_->ImeCompositionRangeChanged(range, character_bounds);
1927 void RenderWidgetHostImpl::OnMsgImeCancelComposition() {
1928 if (view_)
1929 view_->ImeCancelComposition();
1932 void RenderWidgetHostImpl::OnMsgDidActivateAcceleratedCompositing(
1933 bool activated) {
1934 TRACE_EVENT1("renderer_host",
1935 "RenderWidgetHostImpl::OnMsgDidActivateAcceleratedCompositing",
1936 "activated", activated);
1937 is_accelerated_compositing_active_ = activated;
1938 if (view_)
1939 view_->OnAcceleratedCompositingStateChange();
1942 void RenderWidgetHostImpl::OnMsgLockMouse(bool user_gesture,
1943 bool last_unlocked_by_target,
1944 bool privileged) {
1946 if (pending_mouse_lock_request_) {
1947 Send(new ViewMsg_LockMouse_ACK(routing_id_, false));
1948 return;
1949 } else if (IsMouseLocked()) {
1950 Send(new ViewMsg_LockMouse_ACK(routing_id_, true));
1951 return;
1954 pending_mouse_lock_request_ = true;
1955 if (privileged && allow_privileged_mouse_lock_) {
1956 // Directly approve to lock the mouse.
1957 GotResponseToLockMouseRequest(true);
1958 } else {
1959 RequestToLockMouse(user_gesture, last_unlocked_by_target);
1963 void RenderWidgetHostImpl::OnMsgUnlockMouse() {
1964 RejectMouseLockOrUnlockIfNecessary();
1967 void RenderWidgetHostImpl::OnMsgShowDisambiguationPopup(
1968 const gfx::Rect& rect,
1969 const gfx::Size& size,
1970 const TransportDIB::Id& id) {
1971 DCHECK(!rect.IsEmpty());
1972 DCHECK(!size.IsEmpty());
1974 TransportDIB* dib = process_->GetTransportDIB(id);
1975 DCHECK(dib->memory());
1976 DCHECK(dib->size() == SkBitmap::ComputeSize(SkBitmap::kARGB_8888_Config,
1977 size.width(), size.height()));
1979 SkBitmap zoomed_bitmap;
1980 zoomed_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
1981 size.width(), size.height());
1982 zoomed_bitmap.setPixels(dib->memory());
1984 #if defined(OS_ANDROID)
1985 if (view_)
1986 view_->ShowDisambiguationPopup(rect, zoomed_bitmap);
1987 #else
1988 NOTIMPLEMENTED();
1989 #endif
1991 zoomed_bitmap.setPixels(0);
1992 Send(new ViewMsg_ReleaseDisambiguationPopupDIB(GetRoutingID(),
1993 dib->handle()));
1996 #if defined(OS_WIN)
1997 void RenderWidgetHostImpl::OnWindowlessPluginDummyWindowCreated(
1998 gfx::NativeViewId dummy_activation_window) {
1999 HWND hwnd = reinterpret_cast<HWND>(dummy_activation_window);
2000 if (!IsWindow(hwnd) ||
2001 !WebPluginDelegateImpl::IsDummyActivationWindow(hwnd)) {
2002 // This may happen as a result of a race condition when the plugin is going
2003 // away.
2004 return;
2007 SetParent(hwnd, reinterpret_cast<HWND>(GetNativeViewId()));
2008 dummy_windows_for_activation_.push_back(hwnd);
2011 void RenderWidgetHostImpl::OnWindowlessPluginDummyWindowDestroyed(
2012 gfx::NativeViewId dummy_activation_window) {
2013 HWND hwnd = reinterpret_cast<HWND>(dummy_activation_window);
2014 std::list<HWND>::iterator i = dummy_windows_for_activation_.begin();
2015 for (; i != dummy_windows_for_activation_.end(); ++i) {
2016 if ((*i) == hwnd) {
2017 dummy_windows_for_activation_.erase(i);
2018 return;
2021 NOTREACHED() << "Unknown dummy window";
2023 #endif
2025 bool RenderWidgetHostImpl::PaintBackingStoreRect(
2026 TransportDIB::Id bitmap,
2027 const gfx::Rect& bitmap_rect,
2028 const std::vector<gfx::Rect>& copy_rects,
2029 const gfx::Size& view_size,
2030 float scale_factor,
2031 const base::Closure& completion_callback) {
2032 // The view may be destroyed already.
2033 if (!view_)
2034 return false;
2036 if (is_hidden_) {
2037 // Don't bother updating the backing store when we're hidden. Just mark it
2038 // as being totally invalid. This will cause a complete repaint when the
2039 // view is restored.
2040 needs_repainting_on_restore_ = true;
2041 return false;
2044 bool needs_full_paint = false;
2045 bool scheduled_completion_callback = false;
2046 BackingStoreManager::PrepareBackingStore(this, view_size, bitmap, bitmap_rect,
2047 copy_rects, scale_factor,
2048 completion_callback,
2049 &needs_full_paint,
2050 &scheduled_completion_callback);
2051 if (needs_full_paint) {
2052 repaint_start_time_ = TimeTicks::Now();
2053 repaint_ack_pending_ = true;
2054 Send(new ViewMsg_Repaint(routing_id_, view_size));
2057 return scheduled_completion_callback;
2060 void RenderWidgetHostImpl::ScrollBackingStoreRect(const gfx::Vector2d& delta,
2061 const gfx::Rect& clip_rect,
2062 const gfx::Size& view_size) {
2063 if (is_hidden_) {
2064 // Don't bother updating the backing store when we're hidden. Just mark it
2065 // as being totally invalid. This will cause a complete repaint when the
2066 // view is restored.
2067 needs_repainting_on_restore_ = true;
2068 return;
2071 // TODO(darin): do we need to do something else if our backing store is not
2072 // the same size as the advertised view? maybe we just assume there is a
2073 // full paint on its way?
2074 BackingStore* backing_store = BackingStoreManager::Lookup(this);
2075 if (!backing_store || (backing_store->size() != view_size))
2076 return;
2077 backing_store->ScrollBackingStore(delta, clip_rect, view_size);
2080 void RenderWidgetHostImpl::Replace(const string16& word) {
2081 Send(new ViewMsg_Replace(routing_id_, word));
2084 void RenderWidgetHostImpl::SetIgnoreInputEvents(bool ignore_input_events) {
2085 ignore_input_events_ = ignore_input_events;
2088 void RenderWidgetHostImpl::ProcessKeyboardEventAck(int type, bool processed) {
2089 if (key_queue_.empty()) {
2090 LOG(ERROR) << "Got a KeyEvent back from the renderer but we "
2091 << "don't seem to have sent it to the renderer!";
2092 } else if (key_queue_.front().type != type) {
2093 LOG(ERROR) << "We seem to have a different key type sent from "
2094 << "the renderer. (" << key_queue_.front().type << " vs. "
2095 << type << "). Ignoring event.";
2097 // Something must be wrong. Clear the |key_queue_| and
2098 // |suppress_next_char_events_| so that we can resume from the error.
2099 key_queue_.clear();
2100 suppress_next_char_events_ = false;
2101 } else {
2102 NativeWebKeyboardEvent front_item = key_queue_.front();
2103 key_queue_.pop_front();
2105 #if defined(OS_MACOSX)
2106 if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item))
2107 return;
2108 #endif
2110 // We only send unprocessed key event upwards if we are not hidden,
2111 // because the user has moved away from us and no longer expect any effect
2112 // of this key event.
2113 if (delegate_ && !processed && !is_hidden_ && !front_item.skip_in_browser) {
2114 delegate_->HandleKeyboardEvent(front_item);
2116 // WARNING: This RenderWidgetHostImpl can be deallocated at this point
2117 // (i.e. in the case of Ctrl+W, where the call to
2118 // HandleKeyboardEvent destroys this RenderWidgetHostImpl).
2123 void RenderWidgetHostImpl::ActivateDeferredPluginHandles() {
2124 #if !defined(USE_AURA)
2125 if (view_ == NULL)
2126 return;
2128 for (int i = 0; i < static_cast<int>(deferred_plugin_handles_.size()); i++) {
2129 #if defined(TOOLKIT_GTK)
2130 view_->CreatePluginContainer(deferred_plugin_handles_[i]);
2131 #endif
2134 deferred_plugin_handles_.clear();
2135 #endif
2138 const gfx::Vector2d& RenderWidgetHostImpl::GetLastScrollOffset() const {
2139 return last_scroll_offset_;
2142 bool RenderWidgetHostImpl::ShouldForwardTouchEvent() const {
2143 // Always send a touch event if the renderer has a touch-event handler. It is
2144 // possible that a renderer stops listening to touch-events while there are
2145 // still events in the touch-queue. In such cases, the new events should still
2146 // get into the queue.
2147 return has_touch_handler_ || !touch_event_queue_->empty();
2150 void RenderWidgetHostImpl::StartUserGesture() {
2151 OnUserGesture();
2154 void RenderWidgetHostImpl::Stop() {
2155 Send(new ViewMsg_Stop(GetRoutingID()));
2158 void RenderWidgetHostImpl::SetBackground(const SkBitmap& background) {
2159 Send(new ViewMsg_SetBackground(GetRoutingID(), background));
2162 void RenderWidgetHostImpl::SetEditCommandsForNextKeyEvent(
2163 const std::vector<EditCommand>& commands) {
2164 Send(new ViewMsg_SetEditCommandsForNextKeyEvent(GetRoutingID(), commands));
2167 void RenderWidgetHostImpl::SetAccessibilityMode(AccessibilityMode mode) {
2168 Send(new ViewMsg_SetAccessibilityMode(routing_id_, mode));
2171 void RenderWidgetHostImpl::AccessibilityDoDefaultAction(int object_id) {
2172 Send(new AccessibilityMsg_DoDefaultAction(GetRoutingID(), object_id));
2175 void RenderWidgetHostImpl::AccessibilitySetFocus(int object_id) {
2176 Send(new AccessibilityMsg_SetFocus(GetRoutingID(), object_id));
2179 void RenderWidgetHostImpl::AccessibilityScrollToMakeVisible(
2180 int acc_obj_id, gfx::Rect subfocus) {
2181 Send(new AccessibilityMsg_ScrollToMakeVisible(
2182 GetRoutingID(), acc_obj_id, subfocus));
2185 void RenderWidgetHostImpl::AccessibilityScrollToPoint(
2186 int acc_obj_id, gfx::Point point) {
2187 Send(new AccessibilityMsg_ScrollToPoint(
2188 GetRoutingID(), acc_obj_id, point));
2191 void RenderWidgetHostImpl::AccessibilitySetTextSelection(
2192 int object_id, int start_offset, int end_offset) {
2193 Send(new AccessibilityMsg_SetTextSelection(
2194 GetRoutingID(), object_id, start_offset, end_offset));
2197 void RenderWidgetHostImpl::ExecuteEditCommand(const std::string& command,
2198 const std::string& value) {
2199 Send(new ViewMsg_ExecuteEditCommand(GetRoutingID(), command, value));
2202 void RenderWidgetHostImpl::ScrollFocusedEditableNodeIntoRect(
2203 const gfx::Rect& rect) {
2204 Send(new ViewMsg_ScrollFocusedEditableNodeIntoRect(GetRoutingID(), rect));
2207 void RenderWidgetHostImpl::SelectRange(const gfx::Point& start,
2208 const gfx::Point& end) {
2209 if (select_range_pending_) {
2210 if (!next_selection_range_.get()) {
2211 next_selection_range_.reset(new SelectionRange());
2213 next_selection_range_->start = start;
2214 next_selection_range_->end = end;
2215 return;
2218 select_range_pending_ = true;
2219 Send(new ViewMsg_SelectRange(GetRoutingID(), start, end));
2222 void RenderWidgetHostImpl::Undo() {
2223 Send(new ViewMsg_Undo(GetRoutingID()));
2224 RecordAction(UserMetricsAction("Undo"));
2227 void RenderWidgetHostImpl::Redo() {
2228 Send(new ViewMsg_Redo(GetRoutingID()));
2229 RecordAction(UserMetricsAction("Redo"));
2232 void RenderWidgetHostImpl::Cut() {
2233 Send(new ViewMsg_Cut(GetRoutingID()));
2234 RecordAction(UserMetricsAction("Cut"));
2237 void RenderWidgetHostImpl::Copy() {
2238 Send(new ViewMsg_Copy(GetRoutingID()));
2239 RecordAction(UserMetricsAction("Copy"));
2242 void RenderWidgetHostImpl::CopyToFindPboard() {
2243 #if defined(OS_MACOSX)
2244 // Windows/Linux don't have the concept of a find pasteboard.
2245 Send(new ViewMsg_CopyToFindPboard(GetRoutingID()));
2246 RecordAction(UserMetricsAction("CopyToFindPboard"));
2247 #endif
2250 void RenderWidgetHostImpl::Paste() {
2251 Send(new ViewMsg_Paste(GetRoutingID()));
2252 RecordAction(UserMetricsAction("Paste"));
2255 void RenderWidgetHostImpl::PasteAndMatchStyle() {
2256 Send(new ViewMsg_PasteAndMatchStyle(GetRoutingID()));
2257 RecordAction(UserMetricsAction("PasteAndMatchStyle"));
2260 void RenderWidgetHostImpl::Delete() {
2261 Send(new ViewMsg_Delete(GetRoutingID()));
2262 RecordAction(UserMetricsAction("DeleteSelection"));
2265 void RenderWidgetHostImpl::SelectAll() {
2266 Send(new ViewMsg_SelectAll(GetRoutingID()));
2267 RecordAction(UserMetricsAction("SelectAll"));
2269 bool RenderWidgetHostImpl::GotResponseToLockMouseRequest(bool allowed) {
2270 if (!allowed) {
2271 RejectMouseLockOrUnlockIfNecessary();
2272 return false;
2273 } else {
2274 if (!pending_mouse_lock_request_) {
2275 // This is possible, e.g., the plugin sends us an unlock request before
2276 // the user allows to lock to mouse.
2277 return false;
2280 pending_mouse_lock_request_ = false;
2281 if (!view_ || !view_->HasFocus()|| !view_->LockMouse()) {
2282 Send(new ViewMsg_LockMouse_ACK(routing_id_, false));
2283 return false;
2284 } else {
2285 Send(new ViewMsg_LockMouse_ACK(routing_id_, true));
2286 return true;
2291 // static
2292 void RenderWidgetHostImpl::AcknowledgeBufferPresent(
2293 int32 route_id, int gpu_host_id, bool presented, uint32 sync_point) {
2294 GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(gpu_host_id);
2295 if (ui_shim)
2296 ui_shim->Send(new AcceleratedSurfaceMsg_BufferPresented(route_id,
2297 presented,
2298 sync_point));
2301 void RenderWidgetHostImpl::AcknowledgeSwapBuffersToRenderer() {
2302 if (!is_threaded_compositing_enabled_)
2303 Send(new ViewMsg_SwapBuffers_ACK(routing_id_));
2306 #if defined(USE_AURA)
2308 void RenderWidgetHostImpl::ParentChanged(gfx::NativeViewId new_parent) {
2309 #if defined(OS_WIN)
2310 HWND hwnd = reinterpret_cast<HWND>(new_parent);
2311 if (!hwnd)
2312 hwnd = WebPluginDelegateImpl::GetDefaultWindowParent();
2313 for (std::list<HWND>::iterator i = dummy_windows_for_activation_.begin();
2314 i != dummy_windows_for_activation_.end(); ++i) {
2315 SetParent(*i, hwnd);
2317 #endif
2320 // static
2321 void RenderWidgetHostImpl::SendFrontSurfaceIsProtected(
2322 bool is_protected,
2323 uint32 protection_state_id,
2324 int32 route_id,
2325 int gpu_host_id) {
2326 GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(gpu_host_id);
2327 if (ui_shim) {
2328 ui_shim->Send(new AcceleratedSurfaceMsg_SetFrontSurfaceIsProtected(
2329 route_id, is_protected, protection_state_id));
2332 #endif
2334 void RenderWidgetHostImpl::DelayedAutoResized() {
2335 gfx::Size new_size = new_auto_size_;
2336 // Clear the new_auto_size_ since the empty value is used as a flag to
2337 // indicate that no callback is in progress (i.e. without this line
2338 // DelayedAutoResized will not get called again).
2339 new_auto_size_.SetSize(0, 0);
2340 if (!should_auto_resize_)
2341 return;
2343 OnRenderAutoResized(new_size);
2346 void RenderWidgetHostImpl::DetachDelegate() {
2347 delegate_ = NULL;
2350 } // namespace content