| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/renderer_host/render_widget_host.h" | |
| 6 | |
| 7 #include "base/auto_reset.h" | |
| 8 #include "base/command_line.h" | |
| 9 #include "base/message_loop.h" | |
| 10 #include "base/metrics/histogram.h" | |
| 11 #include "chrome/browser/accessibility/browser_accessibility_state.h" | |
| 12 #include "chrome/browser/metrics/user_metrics.h" | |
| 13 #include "chrome/browser/renderer_host/backing_store.h" | |
| 14 #include "chrome/browser/renderer_host/backing_store_manager.h" | |
| 15 #include "chrome/browser/renderer_host/render_process_host.h" | |
| 16 #include "chrome/browser/renderer_host/render_widget_helper.h" | |
| 17 #include "chrome/browser/renderer_host/render_widget_host_view.h" | |
| 18 #include "chrome/common/chrome_switches.h" | |
| 19 #include "chrome/common/result_codes.h" | |
| 20 #include "chrome/common/native_web_keyboard_event.h" | |
| 21 #include "chrome/common/notification_service.h" | |
| 22 #include "chrome/common/render_messages.h" | |
| 23 #include "chrome/common/render_messages_params.h" | |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderli
ne.h" | |
| 25 #include "ui/base/keycodes/keyboard_codes.h" | |
| 26 #include "webkit/glue/webcursor.h" | |
| 27 #include "webkit/plugins/npapi/webplugin.h" | |
| 28 | |
| 29 #if defined(TOOLKIT_VIEWS) | |
| 30 #include "views/view.h" | |
| 31 #endif | |
| 32 | |
| 33 #if defined (OS_MACOSX) | |
| 34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" | |
| 35 #include "third_party/WebKit/Source/WebKit/chromium/public/mac/WebScreenInfoFact
ory.h" | |
| 36 #endif | |
| 37 | |
| 38 using base::Time; | |
| 39 using base::TimeDelta; | |
| 40 using base::TimeTicks; | |
| 41 | |
| 42 using WebKit::WebInputEvent; | |
| 43 using WebKit::WebKeyboardEvent; | |
| 44 using WebKit::WebMouseEvent; | |
| 45 using WebKit::WebMouseWheelEvent; | |
| 46 using WebKit::WebTextDirection; | |
| 47 | |
| 48 #if defined (OS_MACOSX) | |
| 49 using WebKit::WebScreenInfo; | |
| 50 using WebKit::WebScreenInfoFactory; | |
| 51 #endif | |
| 52 | |
| 53 // How long to (synchronously) wait for the renderer to respond with a | |
| 54 // PaintRect message, when our backing-store is invalid, before giving up and | |
| 55 // returning a null or incorrectly sized backing-store from GetBackingStore. | |
| 56 // This timeout impacts the "choppiness" of our window resize perf. | |
| 57 static const int kPaintMsgTimeoutMS = 40; | |
| 58 | |
| 59 // How long to wait before we consider a renderer hung. | |
| 60 static const int kHungRendererDelayMs = 20000; | |
| 61 | |
| 62 // The maximum time between wheel messages while coalescing. This trades off | |
| 63 // smoothness of scrolling with a risk of falling behind the events, resulting | |
| 64 // in trailing scrolls after the user ends their input. | |
| 65 static const int kMaxTimeBetweenWheelMessagesMs = 250; | |
| 66 | |
| 67 /////////////////////////////////////////////////////////////////////////////// | |
| 68 // RenderWidgetHost | |
| 69 | |
| 70 RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process, | |
| 71 int routing_id) | |
| 72 : renderer_initialized_(false), | |
| 73 renderer_accessible_(false), | |
| 74 view_(NULL), | |
| 75 process_(process), | |
| 76 routing_id_(routing_id), | |
| 77 is_loading_(false), | |
| 78 is_hidden_(false), | |
| 79 is_accelerated_compositing_active_(false), | |
| 80 repaint_ack_pending_(false), | |
| 81 resize_ack_pending_(false), | |
| 82 mouse_move_pending_(false), | |
| 83 mouse_wheel_pending_(false), | |
| 84 needs_repainting_on_restore_(false), | |
| 85 is_unresponsive_(false), | |
| 86 in_get_backing_store_(false), | |
| 87 view_being_painted_(false), | |
| 88 ignore_input_events_(false), | |
| 89 text_direction_updated_(false), | |
| 90 text_direction_(WebKit::WebTextDirectionLeftToRight), | |
| 91 text_direction_canceled_(false), | |
| 92 suppress_next_char_events_(false) { | |
| 93 if (routing_id_ == MSG_ROUTING_NONE) | |
| 94 routing_id_ = process_->GetNextRoutingID(); | |
| 95 | |
| 96 process_->Attach(this, routing_id_); | |
| 97 // Because the widget initializes as is_hidden_ == false, | |
| 98 // tell the process host that we're alive. | |
| 99 process_->WidgetRestored(); | |
| 100 | |
| 101 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 102 switches::kForceRendererAccessibility) || | |
| 103 BrowserAccessibilityState::GetInstance()->IsAccessibleBrowser()) { | |
| 104 EnableRendererAccessibility(); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 RenderWidgetHost::~RenderWidgetHost() { | |
| 109 // Clear our current or cached backing store if either remains. | |
| 110 BackingStoreManager::RemoveBackingStore(this); | |
| 111 | |
| 112 process_->Release(routing_id_); | |
| 113 } | |
| 114 | |
| 115 gfx::NativeViewId RenderWidgetHost::GetNativeViewId() { | |
| 116 if (view_) | |
| 117 return gfx::IdFromNativeView(view_->GetNativeView()); | |
| 118 return 0; | |
| 119 } | |
| 120 | |
| 121 bool RenderWidgetHost::PreHandleKeyboardEvent( | |
| 122 const NativeWebKeyboardEvent& event, | |
| 123 bool* is_keyboard_shortcut) { | |
| 124 return false; | |
| 125 } | |
| 126 | |
| 127 void RenderWidgetHost::Init() { | |
| 128 DCHECK(process_->HasConnection()); | |
| 129 | |
| 130 renderer_initialized_ = true; | |
| 131 | |
| 132 // Send the ack along with the information on placement. | |
| 133 Send(new ViewMsg_CreatingNew_ACK(routing_id_, GetNativeViewId())); | |
| 134 WasResized(); | |
| 135 } | |
| 136 | |
| 137 void RenderWidgetHost::Shutdown() { | |
| 138 if (process_->HasConnection()) { | |
| 139 // Tell the renderer object to close. | |
| 140 process_->ReportExpectingClose(routing_id_); | |
| 141 bool rv = Send(new ViewMsg_Close(routing_id_)); | |
| 142 DCHECK(rv); | |
| 143 } | |
| 144 | |
| 145 Destroy(); | |
| 146 } | |
| 147 | |
| 148 bool RenderWidgetHost::IsRenderView() const { | |
| 149 return false; | |
| 150 } | |
| 151 | |
| 152 bool RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) { | |
| 153 bool handled = true; | |
| 154 bool msg_is_ok = true; | |
| 155 IPC_BEGIN_MESSAGE_MAP_EX(RenderWidgetHost, msg, msg_is_ok) | |
| 156 IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnMsgRenderViewReady) | |
| 157 IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewGone, OnMsgRenderViewGone) | |
| 158 IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnMsgClose) | |
| 159 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove) | |
| 160 IPC_MESSAGE_HANDLER(ViewHostMsg_PaintAtSize_ACK, OnMsgPaintAtSizeAck) | |
| 161 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnMsgUpdateRect) | |
| 162 IPC_MESSAGE_HANDLER(ViewHostMsg_HandleInputEvent_ACK, OnMsgInputEventAck) | |
| 163 IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnMsgFocus) | |
| 164 IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnMsgBlur) | |
| 165 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnMsgSetCursor) | |
| 166 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeUpdateTextInputState, | |
| 167 OnMsgImeUpdateTextInputState) | |
| 168 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition, | |
| 169 OnMsgImeCancelComposition) | |
| 170 IPC_MESSAGE_HANDLER(ViewHostMsg_DidActivateAcceleratedCompositing, | |
| 171 OnMsgDidActivateAcceleratedCompositing) | |
| 172 #if defined(OS_MACOSX) | |
| 173 IPC_MESSAGE_HANDLER(ViewHostMsg_GetScreenInfo, OnMsgGetScreenInfo) | |
| 174 IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnMsgGetWindowRect) | |
| 175 IPC_MESSAGE_HANDLER(ViewHostMsg_GetRootWindowRect, OnMsgGetRootWindowRect) | |
| 176 IPC_MESSAGE_HANDLER(ViewHostMsg_PluginFocusChanged, | |
| 177 OnMsgPluginFocusChanged) | |
| 178 IPC_MESSAGE_HANDLER(ViewHostMsg_StartPluginIme, | |
| 179 OnMsgStartPluginIme) | |
| 180 IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateFakePluginWindowHandle, | |
| 181 OnAllocateFakePluginWindowHandle) | |
| 182 IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyFakePluginWindowHandle, | |
| 183 OnDestroyFakePluginWindowHandle) | |
| 184 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceSetIOSurface, | |
| 185 OnAcceleratedSurfaceSetIOSurface) | |
| 186 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceSetTransportDIB, | |
| 187 OnAcceleratedSurfaceSetTransportDIB) | |
| 188 IPC_MESSAGE_HANDLER(ViewHostMsg_AcceleratedSurfaceBuffersSwapped, | |
| 189 OnAcceleratedSurfaceBuffersSwapped) | |
| 190 #elif defined(OS_POSIX) | |
| 191 IPC_MESSAGE_HANDLER(ViewHostMsg_CreatePluginContainer, | |
| 192 OnMsgCreatePluginContainer) | |
| 193 IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyPluginContainer, | |
| 194 OnMsgDestroyPluginContainer) | |
| 195 #endif | |
| 196 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 197 IPC_END_MESSAGE_MAP_EX() | |
| 198 | |
| 199 if (!msg_is_ok) { | |
| 200 // The message de-serialization failed. Kill the renderer process. | |
| 201 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH")); | |
| 202 process()->ReceivedBadMessage(); | |
| 203 } | |
| 204 return handled; | |
| 205 } | |
| 206 | |
| 207 bool RenderWidgetHost::Send(IPC::Message* msg) { | |
| 208 return process_->Send(msg); | |
| 209 } | |
| 210 | |
| 211 void RenderWidgetHost::WasHidden() { | |
| 212 is_hidden_ = true; | |
| 213 | |
| 214 // Don't bother reporting hung state when we aren't the active tab. | |
| 215 StopHangMonitorTimeout(); | |
| 216 | |
| 217 // If we have a renderer, then inform it that we are being hidden so it can | |
| 218 // reduce its resource utilization. | |
| 219 Send(new ViewMsg_WasHidden(routing_id_)); | |
| 220 | |
| 221 // TODO(darin): what about constrained windows? it doesn't look like they | |
| 222 // see a message when their parent is hidden. maybe there is something more | |
| 223 // generic we can do at the TabContents API level instead of relying on | |
| 224 // Windows messages. | |
| 225 | |
| 226 // Tell the RenderProcessHost we were hidden. | |
| 227 process_->WidgetHidden(); | |
| 228 | |
| 229 bool is_visible = false; | |
| 230 NotificationService::current()->Notify( | |
| 231 NotificationType::RENDER_WIDGET_VISIBILITY_CHANGED, | |
| 232 Source<RenderWidgetHost>(this), | |
| 233 Details<bool>(&is_visible)); | |
| 234 } | |
| 235 | |
| 236 void RenderWidgetHost::WasRestored() { | |
| 237 // When we create the widget, it is created as *not* hidden. | |
| 238 if (!is_hidden_) | |
| 239 return; | |
| 240 is_hidden_ = false; | |
| 241 | |
| 242 BackingStore* backing_store = BackingStoreManager::Lookup(this); | |
| 243 // If we already have a backing store for this widget, then we don't need to | |
| 244 // repaint on restore _unless_ we know that our backing store is invalid. | |
| 245 // When accelerated compositing is on, we must always repaint, even when | |
| 246 // the backing store exists. | |
| 247 bool needs_repainting; | |
| 248 if (needs_repainting_on_restore_ || !backing_store || | |
| 249 is_accelerated_compositing_active()) { | |
| 250 needs_repainting = true; | |
| 251 needs_repainting_on_restore_ = false; | |
| 252 } else { | |
| 253 needs_repainting = false; | |
| 254 } | |
| 255 Send(new ViewMsg_WasRestored(routing_id_, needs_repainting)); | |
| 256 | |
| 257 process_->WidgetRestored(); | |
| 258 | |
| 259 bool is_visible = true; | |
| 260 NotificationService::current()->Notify( | |
| 261 NotificationType::RENDER_WIDGET_VISIBILITY_CHANGED, | |
| 262 Source<RenderWidgetHost>(this), | |
| 263 Details<bool>(&is_visible)); | |
| 264 | |
| 265 // It's possible for our size to be out of sync with the renderer. The | |
| 266 // following is one case that leads to this: | |
| 267 // 1. WasResized -> Send ViewMsg_Resize to render | |
| 268 // 2. WasResized -> do nothing as resize_ack_pending_ is true | |
| 269 // 3. WasHidden | |
| 270 // 4. OnMsgUpdateRect from (1) processed. Does NOT invoke WasResized as view | |
| 271 // is hidden. Now renderer/browser out of sync with what they think size | |
| 272 // is. | |
| 273 // By invoking WasResized the renderer is updated as necessary. WasResized | |
| 274 // does nothing if the sizes are already in sync. | |
| 275 // | |
| 276 // TODO: ideally ViewMsg_WasRestored would take a size. This way, the renderer | |
| 277 // could handle both the restore and resize at once. This isn't that big a | |
| 278 // deal as RenderWidget::WasRestored delays updating, so that the resize from | |
| 279 // WasResized is usually processed before the renderer is painted. | |
| 280 WasResized(); | |
| 281 } | |
| 282 | |
| 283 void RenderWidgetHost::WasResized() { | |
| 284 if (resize_ack_pending_ || !process_->HasConnection() || !view_ || | |
| 285 !renderer_initialized_) { | |
| 286 return; | |
| 287 } | |
| 288 | |
| 289 #if !defined(OS_MACOSX) | |
| 290 gfx::Size new_size = view_->GetViewBounds().size(); | |
| 291 #else | |
| 292 // When UI scaling is enabled on OS X, allocate a smaller bitmap and | |
| 293 // pixel-scale it up. | |
| 294 // TODO(thakis): Use pixel size on mac and set UI scale in renderer. | |
| 295 // http://crbug.com/31960 | |
| 296 gfx::Size new_size(view_->GetViewCocoaBounds().size()); | |
| 297 #endif | |
| 298 gfx::Rect reserved_rect = view_->reserved_contents_rect(); | |
| 299 | |
| 300 // Avoid asking the RenderWidget to resize to its current size, since it | |
| 301 // won't send us a PaintRect message in that case, unless reserved area is | |
| 302 // changed, but even in this case PaintRect message won't be sent. | |
| 303 if (new_size == current_size_ && reserved_rect == current_reserved_rect_) | |
| 304 return; | |
| 305 | |
| 306 if (in_flight_size_ != gfx::Size() && new_size == in_flight_size_ && | |
| 307 in_flight_reserved_rect_ == reserved_rect) { | |
| 308 return; | |
| 309 } | |
| 310 | |
| 311 // We don't expect to receive an ACK when the requested size is empty or | |
| 312 // only reserved area is changed. | |
| 313 resize_ack_pending_ = !new_size.IsEmpty() && new_size != current_size_; | |
| 314 | |
| 315 if (!Send(new ViewMsg_Resize(routing_id_, new_size, reserved_rect))) { | |
| 316 resize_ack_pending_ = false; | |
| 317 } else { | |
| 318 if (resize_ack_pending_) { | |
| 319 in_flight_size_ = new_size; | |
| 320 in_flight_reserved_rect_ = reserved_rect; | |
| 321 } else { | |
| 322 // Message was sent successfully, but we do not expect to receive an ACK, | |
| 323 // so update current values right away. | |
| 324 current_size_ = new_size; | |
| 325 // TODO(alekseys): send a message from renderer to ack a reserved rect | |
| 326 // changes only. | |
| 327 current_reserved_rect_ = reserved_rect; | |
| 328 } | |
| 329 } | |
| 330 } | |
| 331 | |
| 332 void RenderWidgetHost::GotFocus() { | |
| 333 Focus(); | |
| 334 } | |
| 335 | |
| 336 void RenderWidgetHost::Focus() { | |
| 337 Send(new ViewMsg_SetFocus(routing_id_, true)); | |
| 338 } | |
| 339 | |
| 340 void RenderWidgetHost::Blur() { | |
| 341 Send(new ViewMsg_SetFocus(routing_id_, false)); | |
| 342 } | |
| 343 | |
| 344 void RenderWidgetHost::LostCapture() { | |
| 345 Send(new ViewMsg_MouseCaptureLost(routing_id_)); | |
| 346 } | |
| 347 | |
| 348 void RenderWidgetHost::ViewDestroyed() { | |
| 349 // TODO(evanm): tracking this may no longer be necessary; | |
| 350 // eliminate this function if so. | |
| 351 view_ = NULL; | |
| 352 } | |
| 353 | |
| 354 void RenderWidgetHost::SetIsLoading(bool is_loading) { | |
| 355 is_loading_ = is_loading; | |
| 356 if (!view_) | |
| 357 return; | |
| 358 view_->SetIsLoading(is_loading); | |
| 359 } | |
| 360 | |
| 361 void RenderWidgetHost::PaintAtSize(TransportDIB::Handle dib_handle, | |
| 362 int tag, | |
| 363 const gfx::Size& page_size, | |
| 364 const gfx::Size& desired_size) { | |
| 365 // Ask the renderer to create a bitmap regardless of whether it's | |
| 366 // hidden, being resized, redrawn, etc. It resizes the web widget | |
| 367 // to the page_size and then scales it to the desired_size. | |
| 368 Send(new ViewMsg_PaintAtSize(routing_id_, dib_handle, tag, | |
| 369 page_size, desired_size)); | |
| 370 } | |
| 371 | |
| 372 BackingStore* RenderWidgetHost::GetBackingStore(bool force_create) { | |
| 373 // We should not be asked to paint while we are hidden. If we are hidden, | |
| 374 // then it means that our consumer failed to call WasRestored. If we're not | |
| 375 // force creating the backing store, it's OK since we can feel free to give | |
| 376 // out our cached one if we have it. | |
| 377 DCHECK(!is_hidden_ || !force_create) << | |
| 378 "GetBackingStore called while hidden!"; | |
| 379 | |
| 380 // We should never be called recursively; this can theoretically lead to | |
| 381 // infinite recursion and almost certainly leads to lower performance. | |
| 382 DCHECK(!in_get_backing_store_) << "GetBackingStore called recursively!"; | |
| 383 AutoReset<bool> auto_reset_in_get_backing_store(&in_get_backing_store_, true); | |
| 384 | |
| 385 // We might have a cached backing store that we can reuse! | |
| 386 BackingStore* backing_store = | |
| 387 BackingStoreManager::GetBackingStore(this, current_size_); | |
| 388 if (!force_create) | |
| 389 return backing_store; | |
| 390 | |
| 391 // If we fail to find a backing store in the cache, send out a request | |
| 392 // to the renderer to paint the view if required. | |
| 393 if (!backing_store && !repaint_ack_pending_ && !resize_ack_pending_ && | |
| 394 !view_being_painted_) { | |
| 395 repaint_start_time_ = TimeTicks::Now(); | |
| 396 repaint_ack_pending_ = true; | |
| 397 Send(new ViewMsg_Repaint(routing_id_, current_size_)); | |
| 398 } | |
| 399 | |
| 400 // When we have asked the RenderWidget to resize, and we are still waiting on | |
| 401 // a response, block for a little while to see if we can't get a response | |
| 402 // before returning the old (incorrectly sized) backing store. | |
| 403 if (resize_ack_pending_ || !backing_store) { | |
| 404 IPC::Message msg; | |
| 405 TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); | |
| 406 if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg)) { | |
| 407 OnMessageReceived(msg); | |
| 408 backing_store = BackingStoreManager::GetBackingStore(this, current_size_); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 return backing_store; | |
| 413 } | |
| 414 | |
| 415 BackingStore* RenderWidgetHost::AllocBackingStore(const gfx::Size& size) { | |
| 416 if (!view_) | |
| 417 return NULL; | |
| 418 return view_->AllocBackingStore(size); | |
| 419 } | |
| 420 | |
| 421 void RenderWidgetHost::DonePaintingToBackingStore() { | |
| 422 Send(new ViewMsg_UpdateRect_ACK(routing_id())); | |
| 423 } | |
| 424 | |
| 425 void RenderWidgetHost::ScheduleComposite() { | |
| 426 if (is_hidden_ || !is_accelerated_compositing_active_) { | |
| 427 return; | |
| 428 } | |
| 429 | |
| 430 // Send out a request to the renderer to paint the view if required. | |
| 431 if (!repaint_ack_pending_ && !resize_ack_pending_ && !view_being_painted_) { | |
| 432 repaint_start_time_ = TimeTicks::Now(); | |
| 433 repaint_ack_pending_ = true; | |
| 434 Send(new ViewMsg_Repaint(routing_id_, current_size_)); | |
| 435 } | |
| 436 | |
| 437 // When we have asked the RenderWidget to resize, and we are still waiting on | |
| 438 // a response, block for a little while to see if we can't get a response. | |
| 439 // We always block on response because we do not have a backing store. | |
| 440 IPC::Message msg; | |
| 441 TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS); | |
| 442 if (process_->WaitForUpdateMsg(routing_id_, max_delay, &msg)) | |
| 443 OnMessageReceived(msg); | |
| 444 } | |
| 445 | |
| 446 void RenderWidgetHost::StartHangMonitorTimeout(TimeDelta delay) { | |
| 447 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 448 switches::kDisableHangMonitor)) { | |
| 449 return; | |
| 450 } | |
| 451 | |
| 452 // If we already have a timer that will expire at or before the given delay, | |
| 453 // then we have nothing more to do now. If we have set our end time to null | |
| 454 // by calling StopHangMonitorTimeout, though, we will need to restart the | |
| 455 // timer. | |
| 456 if (hung_renderer_timer_.IsRunning() && | |
| 457 hung_renderer_timer_.GetCurrentDelay() <= delay && | |
| 458 !time_when_considered_hung_.is_null()) { | |
| 459 return; | |
| 460 } | |
| 461 | |
| 462 // Either the timer is not yet running, or we need to adjust the timer to | |
| 463 // fire sooner. | |
| 464 time_when_considered_hung_ = Time::Now() + delay; | |
| 465 hung_renderer_timer_.Stop(); | |
| 466 hung_renderer_timer_.Start(delay, this, | |
| 467 &RenderWidgetHost::CheckRendererIsUnresponsive); | |
| 468 } | |
| 469 | |
| 470 void RenderWidgetHost::RestartHangMonitorTimeout() { | |
| 471 // Setting to null will cause StartHangMonitorTimeout to restart the timer. | |
| 472 time_when_considered_hung_ = Time(); | |
| 473 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs)); | |
| 474 } | |
| 475 | |
| 476 void RenderWidgetHost::StopHangMonitorTimeout() { | |
| 477 time_when_considered_hung_ = Time(); | |
| 478 RendererIsResponsive(); | |
| 479 | |
| 480 // We do not bother to stop the hung_renderer_timer_ here in case it will be | |
| 481 // started again shortly, which happens to be the common use case. | |
| 482 } | |
| 483 | |
| 484 void RenderWidgetHost::SystemThemeChanged() { | |
| 485 Send(new ViewMsg_ThemeChanged(routing_id_)); | |
| 486 } | |
| 487 | |
| 488 void RenderWidgetHost::ForwardMouseEvent(const WebMouseEvent& mouse_event) { | |
| 489 if (ignore_input_events_ || process_->ignore_input_events()) | |
| 490 return; | |
| 491 | |
| 492 // Avoid spamming the renderer with mouse move events. It is important | |
| 493 // to note that WM_MOUSEMOVE events are anyways synthetic, but since our | |
| 494 // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way | |
| 495 // more WM_MOUSEMOVE events than we wish to send to the renderer. | |
| 496 if (mouse_event.type == WebInputEvent::MouseMove) { | |
| 497 if (mouse_move_pending_) { | |
| 498 next_mouse_move_.reset(new WebMouseEvent(mouse_event)); | |
| 499 return; | |
| 500 } | |
| 501 mouse_move_pending_ = true; | |
| 502 } else if (mouse_event.type == WebInputEvent::MouseDown) { | |
| 503 OnUserGesture(); | |
| 504 } | |
| 505 | |
| 506 ForwardInputEvent(mouse_event, sizeof(WebMouseEvent), false); | |
| 507 } | |
| 508 | |
| 509 void RenderWidgetHost::OnMouseActivate() { | |
| 510 } | |
| 511 | |
| 512 void RenderWidgetHost::ForwardWheelEvent( | |
| 513 const WebMouseWheelEvent& wheel_event) { | |
| 514 if (ignore_input_events_ || process_->ignore_input_events()) | |
| 515 return; | |
| 516 | |
| 517 // If there's already a mouse wheel event waiting to be sent to the renderer, | |
| 518 // add the new deltas to that event. Not doing so (e.g., by dropping the old | |
| 519 // event, as for mouse moves) results in very slow scrolling on the Mac (on | |
| 520 // which many, very small wheel events are sent). | |
| 521 if (mouse_wheel_pending_) { | |
| 522 if (coalesced_mouse_wheel_events_.empty() || | |
| 523 coalesced_mouse_wheel_events_.back().modifiers | |
| 524 != wheel_event.modifiers || | |
| 525 coalesced_mouse_wheel_events_.back().scrollByPage | |
| 526 != wheel_event.scrollByPage) { | |
| 527 coalesced_mouse_wheel_events_.push_back(wheel_event); | |
| 528 } else { | |
| 529 WebMouseWheelEvent* last_wheel_event = | |
| 530 &coalesced_mouse_wheel_events_.back(); | |
| 531 last_wheel_event->deltaX += wheel_event.deltaX; | |
| 532 last_wheel_event->deltaY += wheel_event.deltaY; | |
| 533 DCHECK_GE(wheel_event.timeStampSeconds, | |
| 534 last_wheel_event->timeStampSeconds); | |
| 535 last_wheel_event->timeStampSeconds = wheel_event.timeStampSeconds; | |
| 536 } | |
| 537 return; | |
| 538 } | |
| 539 mouse_wheel_pending_ = true; | |
| 540 | |
| 541 HISTOGRAM_COUNTS_100("MPArch.RWH_WheelQueueSize", | |
| 542 coalesced_mouse_wheel_events_.size()); | |
| 543 | |
| 544 ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent), false); | |
| 545 } | |
| 546 | |
| 547 void RenderWidgetHost::ForwardKeyboardEvent( | |
| 548 const NativeWebKeyboardEvent& key_event) { | |
| 549 if (ignore_input_events_ || process_->ignore_input_events()) | |
| 550 return; | |
| 551 | |
| 552 if (key_event.type == WebKeyboardEvent::Char && | |
| 553 (key_event.windowsKeyCode == ui::VKEY_RETURN || | |
| 554 key_event.windowsKeyCode == ui::VKEY_SPACE)) { | |
| 555 OnUserGesture(); | |
| 556 } | |
| 557 | |
| 558 // Double check the type to make sure caller hasn't sent us nonsense that | |
| 559 // will mess up our key queue. | |
| 560 if (WebInputEvent::isKeyboardEventType(key_event.type)) { | |
| 561 if (suppress_next_char_events_) { | |
| 562 // If preceding RawKeyDown event was handled by the browser, then we need | |
| 563 // suppress all Char events generated by it. Please note that, one | |
| 564 // RawKeyDown event may generate multiple Char events, so we can't reset | |
| 565 // |suppress_next_char_events_| until we get a KeyUp or a RawKeyDown. | |
| 566 if (key_event.type == WebKeyboardEvent::Char) | |
| 567 return; | |
| 568 // We get a KeyUp or a RawKeyDown event. | |
| 569 suppress_next_char_events_ = false; | |
| 570 } | |
| 571 | |
| 572 bool is_keyboard_shortcut = false; | |
| 573 // Only pre-handle the key event if it's not handled by the input method. | |
| 574 if (!key_event.skip_in_browser) { | |
| 575 // We need to set |suppress_next_char_events_| to true if | |
| 576 // PreHandleKeyboardEvent() returns true, but |this| may already be | |
| 577 // destroyed at that time. So set |suppress_next_char_events_| true here, | |
| 578 // then revert it afterwards when necessary. | |
| 579 if (key_event.type == WebKeyboardEvent::RawKeyDown) | |
| 580 suppress_next_char_events_ = true; | |
| 581 | |
| 582 // Tab switching/closing accelerators aren't sent to the renderer to avoid | |
| 583 // a hung/malicious renderer from interfering. | |
| 584 if (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut)) | |
| 585 return; | |
| 586 | |
| 587 if (key_event.type == WebKeyboardEvent::RawKeyDown) | |
| 588 suppress_next_char_events_ = false; | |
| 589 } | |
| 590 | |
| 591 // Don't add this key to the queue if we have no way to send the message... | |
| 592 if (!process_->HasConnection()) | |
| 593 return; | |
| 594 | |
| 595 // Put all WebKeyboardEvent objects in a queue since we can't trust the | |
| 596 // renderer and we need to give something to the UnhandledInputEvent | |
| 597 // handler. | |
| 598 key_queue_.push_back(key_event); | |
| 599 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); | |
| 600 | |
| 601 // Only forward the non-native portions of our event. | |
| 602 ForwardInputEvent(key_event, sizeof(WebKeyboardEvent), | |
| 603 is_keyboard_shortcut); | |
| 604 } | |
| 605 } | |
| 606 | |
| 607 void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event, | |
| 608 int event_size, | |
| 609 bool is_keyboard_shortcut) { | |
| 610 if (!process_->HasConnection()) | |
| 611 return; | |
| 612 | |
| 613 DCHECK(!process_->ignore_input_events()); | |
| 614 | |
| 615 IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_); | |
| 616 message->WriteData( | |
| 617 reinterpret_cast<const char*>(&input_event), event_size); | |
| 618 // |is_keyboard_shortcut| only makes sense for RawKeyDown events. | |
| 619 if (input_event.type == WebInputEvent::RawKeyDown) | |
| 620 message->WriteBool(is_keyboard_shortcut); | |
| 621 input_event_start_time_ = TimeTicks::Now(); | |
| 622 Send(message); | |
| 623 | |
| 624 // Any non-wheel input event cancels pending wheel events. | |
| 625 if (input_event.type != WebInputEvent::MouseWheel) | |
| 626 coalesced_mouse_wheel_events_.clear(); | |
| 627 | |
| 628 // Any input event cancels a pending mouse move event. Note that | |
| 629 // |next_mouse_move_| possibly owns |input_event|, so don't use |input_event| | |
| 630 // after this line. | |
| 631 next_mouse_move_.reset(); | |
| 632 | |
| 633 StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs)); | |
| 634 } | |
| 635 | |
| 636 void RenderWidgetHost::ForwardEditCommand(const std::string& name, | |
| 637 const std::string& value) { | |
| 638 // We don't need an implementation of this function here since the | |
| 639 // only place we use this is for the case of dropdown menus and other | |
| 640 // edge cases for which edit commands don't make sense. | |
| 641 } | |
| 642 | |
| 643 void RenderWidgetHost::ForwardEditCommandsForNextKeyEvent( | |
| 644 const EditCommands& edit_commands) { | |
| 645 // We don't need an implementation of this function here since this message is | |
| 646 // only handled by RenderView. | |
| 647 } | |
| 648 | |
| 649 #if defined(TOUCH_UI) | |
| 650 void RenderWidgetHost::ForwardTouchEvent( | |
| 651 const WebKit::WebTouchEvent& touch_event) { | |
| 652 ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent), false); | |
| 653 } | |
| 654 #endif | |
| 655 | |
| 656 void RenderWidgetHost::RendererExited(base::TerminationStatus status, | |
| 657 int exit_code) { | |
| 658 // Clearing this flag causes us to re-create the renderer when recovering | |
| 659 // from a crashed renderer. | |
| 660 renderer_initialized_ = false; | |
| 661 | |
| 662 // Must reset these to ensure that mouse move/wheel events work with a new | |
| 663 // renderer. | |
| 664 mouse_move_pending_ = false; | |
| 665 next_mouse_move_.reset(); | |
| 666 mouse_wheel_pending_ = false; | |
| 667 coalesced_mouse_wheel_events_.clear(); | |
| 668 | |
| 669 // Must reset these to ensure that keyboard events work with a new renderer. | |
| 670 key_queue_.clear(); | |
| 671 suppress_next_char_events_ = false; | |
| 672 | |
| 673 // Reset some fields in preparation for recovering from a crash. | |
| 674 resize_ack_pending_ = false; | |
| 675 repaint_ack_pending_ = false; | |
| 676 | |
| 677 in_flight_size_.SetSize(0, 0); | |
| 678 in_flight_reserved_rect_.SetRect(0, 0, 0, 0); | |
| 679 current_size_.SetSize(0, 0); | |
| 680 current_reserved_rect_.SetRect(0, 0, 0, 0); | |
| 681 is_hidden_ = false; | |
| 682 is_accelerated_compositing_active_ = false; | |
| 683 | |
| 684 if (view_) { | |
| 685 view_->RenderViewGone(status, exit_code); | |
| 686 view_ = NULL; // The View should be deleted by RenderViewGone. | |
| 687 } | |
| 688 | |
| 689 BackingStoreManager::RemoveBackingStore(this); | |
| 690 } | |
| 691 | |
| 692 void RenderWidgetHost::UpdateTextDirection(WebTextDirection direction) { | |
| 693 text_direction_updated_ = true; | |
| 694 text_direction_ = direction; | |
| 695 } | |
| 696 | |
| 697 void RenderWidgetHost::CancelUpdateTextDirection() { | |
| 698 if (text_direction_updated_) | |
| 699 text_direction_canceled_ = true; | |
| 700 } | |
| 701 | |
| 702 void RenderWidgetHost::NotifyTextDirection() { | |
| 703 if (text_direction_updated_) { | |
| 704 if (!text_direction_canceled_) | |
| 705 Send(new ViewMsg_SetTextDirection(routing_id(), text_direction_)); | |
| 706 text_direction_updated_ = false; | |
| 707 text_direction_canceled_ = false; | |
| 708 } | |
| 709 } | |
| 710 | |
| 711 void RenderWidgetHost::SetInputMethodActive(bool activate) { | |
| 712 Send(new ViewMsg_SetInputMethodActive(routing_id(), activate)); | |
| 713 } | |
| 714 | |
| 715 void RenderWidgetHost::ImeSetComposition( | |
| 716 const string16& text, | |
| 717 const std::vector<WebKit::WebCompositionUnderline>& underlines, | |
| 718 int selection_start, | |
| 719 int selection_end) { | |
| 720 Send(new ViewMsg_ImeSetComposition( | |
| 721 routing_id(), text, underlines, selection_start, selection_end)); | |
| 722 } | |
| 723 | |
| 724 void RenderWidgetHost::ImeConfirmComposition(const string16& text) { | |
| 725 Send(new ViewMsg_ImeConfirmComposition(routing_id(), text)); | |
| 726 } | |
| 727 | |
| 728 void RenderWidgetHost::ImeConfirmComposition() { | |
| 729 Send(new ViewMsg_ImeConfirmComposition(routing_id(), string16())); | |
| 730 } | |
| 731 | |
| 732 void RenderWidgetHost::ImeCancelComposition() { | |
| 733 Send(new ViewMsg_ImeSetComposition(routing_id(), string16(), | |
| 734 std::vector<WebKit::WebCompositionUnderline>(), 0, 0)); | |
| 735 } | |
| 736 | |
| 737 void RenderWidgetHost::SetActive(bool active) { | |
| 738 Send(new ViewMsg_SetActive(routing_id(), active)); | |
| 739 } | |
| 740 | |
| 741 void RenderWidgetHost::Destroy() { | |
| 742 NotificationService::current()->Notify( | |
| 743 NotificationType::RENDER_WIDGET_HOST_DESTROYED, | |
| 744 Source<RenderWidgetHost>(this), | |
| 745 NotificationService::NoDetails()); | |
| 746 | |
| 747 // Tell the view to die. | |
| 748 // Note that in the process of the view shutting down, it can call a ton | |
| 749 // of other messages on us. So if you do any other deinitialization here, | |
| 750 // do it after this call to view_->Destroy(). | |
| 751 if (view_) | |
| 752 view_->Destroy(); | |
| 753 | |
| 754 delete this; | |
| 755 } | |
| 756 | |
| 757 void RenderWidgetHost::CheckRendererIsUnresponsive() { | |
| 758 // If we received a call to StopHangMonitorTimeout. | |
| 759 if (time_when_considered_hung_.is_null()) | |
| 760 return; | |
| 761 | |
| 762 // If we have not waited long enough, then wait some more. | |
| 763 Time now = Time::Now(); | |
| 764 if (now < time_when_considered_hung_) { | |
| 765 StartHangMonitorTimeout(time_when_considered_hung_ - now); | |
| 766 return; | |
| 767 } | |
| 768 | |
| 769 // OK, looks like we have a hung renderer! | |
| 770 NotificationService::current()->Notify( | |
| 771 NotificationType::RENDERER_PROCESS_HANG, | |
| 772 Source<RenderWidgetHost>(this), | |
| 773 NotificationService::NoDetails()); | |
| 774 is_unresponsive_ = true; | |
| 775 NotifyRendererUnresponsive(); | |
| 776 } | |
| 777 | |
| 778 void RenderWidgetHost::RendererIsResponsive() { | |
| 779 if (is_unresponsive_) { | |
| 780 is_unresponsive_ = false; | |
| 781 NotifyRendererResponsive(); | |
| 782 } | |
| 783 } | |
| 784 | |
| 785 void RenderWidgetHost::OnMsgRenderViewReady() { | |
| 786 WasResized(); | |
| 787 } | |
| 788 | |
| 789 void RenderWidgetHost::OnMsgRenderViewGone(int status, int exit_code) { | |
| 790 // TODO(evanm): This synchronously ends up calling "delete this". | |
| 791 // Is that really what we want in response to this message? I'm matching | |
| 792 // previous behavior of the code here. | |
| 793 Destroy(); | |
| 794 } | |
| 795 | |
| 796 void RenderWidgetHost::OnMsgClose() { | |
| 797 Shutdown(); | |
| 798 } | |
| 799 | |
| 800 void RenderWidgetHost::OnMsgRequestMove(const gfx::Rect& pos) { | |
| 801 // Note that we ignore the position. | |
| 802 if (view_) { | |
| 803 view_->SetSize(pos.size()); | |
| 804 Send(new ViewMsg_Move_ACK(routing_id_)); | |
| 805 } | |
| 806 } | |
| 807 | |
| 808 void RenderWidgetHost::OnMsgPaintAtSizeAck(int tag, const gfx::Size& size) { | |
| 809 PaintAtSizeAckDetails details = {tag, size}; | |
| 810 gfx::Size size_details = size; | |
| 811 NotificationService::current()->Notify( | |
| 812 NotificationType::RENDER_WIDGET_HOST_DID_RECEIVE_PAINT_AT_SIZE_ACK, | |
| 813 Source<RenderWidgetHost>(this), | |
| 814 Details<PaintAtSizeAckDetails>(&details)); | |
| 815 } | |
| 816 | |
| 817 void RenderWidgetHost::OnMsgUpdateRect( | |
| 818 const ViewHostMsg_UpdateRect_Params& params) { | |
| 819 TimeTicks paint_start = TimeTicks::Now(); | |
| 820 | |
| 821 NotificationService::current()->Notify( | |
| 822 NotificationType::RENDER_WIDGET_HOST_WILL_PAINT, | |
| 823 Source<RenderWidgetHost>(this), | |
| 824 NotificationService::NoDetails()); | |
| 825 | |
| 826 // Update our knowledge of the RenderWidget's size. | |
| 827 current_size_ = params.view_size; | |
| 828 // Update our knowledge of the RenderWidget's scroll offset. | |
| 829 last_scroll_offset_ = params.scroll_offset; | |
| 830 | |
| 831 bool is_resize_ack = | |
| 832 ViewHostMsg_UpdateRect_Flags::is_resize_ack(params.flags); | |
| 833 | |
| 834 // resize_ack_pending_ needs to be cleared before we call DidPaintRect, since | |
| 835 // that will end up reaching GetBackingStore. | |
| 836 if (is_resize_ack) { | |
| 837 DCHECK(resize_ack_pending_); | |
| 838 resize_ack_pending_ = false; | |
| 839 in_flight_size_.SetSize(0, 0); | |
| 840 in_flight_reserved_rect_.SetRect(0, 0, 0, 0); | |
| 841 // Update our knowledge of the RenderWidget's resizer rect. | |
| 842 // ViewMsg_Resize is acknowledged only when view size is actually changed, | |
| 843 // otherwise current_reserved_rect_ is updated immediately after sending | |
| 844 // ViewMsg_Resize to the RenderWidget and can be clobbered by | |
| 845 // OnMsgUpdateRect called for a paint that was initiated before the resize | |
| 846 // message was sent. | |
| 847 current_reserved_rect_ = params.resizer_rect; | |
| 848 } | |
| 849 | |
| 850 bool is_repaint_ack = | |
| 851 ViewHostMsg_UpdateRect_Flags::is_repaint_ack(params.flags); | |
| 852 if (is_repaint_ack) { | |
| 853 repaint_ack_pending_ = false; | |
| 854 TimeDelta delta = TimeTicks::Now() - repaint_start_time_; | |
| 855 UMA_HISTOGRAM_TIMES("MPArch.RWH_RepaintDelta", delta); | |
| 856 } | |
| 857 | |
| 858 DCHECK(!params.bitmap_rect.IsEmpty()); | |
| 859 DCHECK(!params.view_size.IsEmpty()); | |
| 860 | |
| 861 if (!is_accelerated_compositing_active_) { | |
| 862 const size_t size = params.bitmap_rect.height() * | |
| 863 params.bitmap_rect.width() * 4; | |
| 864 TransportDIB* dib = process_->GetTransportDIB(params.bitmap); | |
| 865 | |
| 866 // If gpu process does painting, scroll_rect and copy_rects are always empty | |
| 867 // and backing store is never used. | |
| 868 if (dib) { | |
| 869 if (dib->size() < size) { | |
| 870 DLOG(WARNING) << "Transport DIB too small for given rectangle"; | |
| 871 UserMetrics::RecordAction(UserMetricsAction( | |
| 872 "BadMessageTerminate_RWH1")); | |
| 873 process()->ReceivedBadMessage(); | |
| 874 } else { | |
| 875 // Scroll the backing store. | |
| 876 if (!params.scroll_rect.IsEmpty()) { | |
| 877 ScrollBackingStoreRect(params.dx, params.dy, | |
| 878 params.scroll_rect, | |
| 879 params.view_size); | |
| 880 } | |
| 881 | |
| 882 // Paint the backing store. This will update it with the | |
| 883 // renderer-supplied bits. The view will read out of the backing store | |
| 884 // later to actually draw to the screen. | |
| 885 PaintBackingStoreRect(params.bitmap, params.bitmap_rect, | |
| 886 params.copy_rects, params.view_size); | |
| 887 } | |
| 888 } | |
| 889 } | |
| 890 | |
| 891 // ACK early so we can prefetch the next PaintRect if there is a next one. | |
| 892 // This must be done AFTER we're done painting with the bitmap supplied by the | |
| 893 // renderer. This ACK is a signal to the renderer that the backing store can | |
| 894 // be re-used, so the bitmap may be invalid after this call. | |
| 895 Send(new ViewMsg_UpdateRect_ACK(routing_id_)); | |
| 896 | |
| 897 // We don't need to update the view if the view is hidden. We must do this | |
| 898 // early return after the ACK is sent, however, or the renderer will not send | |
| 899 // us more data. | |
| 900 if (is_hidden_) | |
| 901 return; | |
| 902 | |
| 903 // Now paint the view. Watch out: it might be destroyed already. | |
| 904 if (view_) { | |
| 905 view_->MovePluginWindows(params.plugin_window_moves); | |
| 906 // The view_ pointer could be destroyed in the context of MovePluginWindows | |
| 907 // which attempts to move the plugin windows and in the process could | |
| 908 // dispatch other window messages which could cause the view to be | |
| 909 // destroyed. | |
| 910 if (view_ && !is_accelerated_compositing_active_) { | |
| 911 view_being_painted_ = true; | |
| 912 view_->DidUpdateBackingStore(params.scroll_rect, params.dx, params.dy, | |
| 913 params.copy_rects); | |
| 914 view_being_painted_ = false; | |
| 915 } | |
| 916 } | |
| 917 | |
| 918 NotificationService::current()->Notify( | |
| 919 NotificationType::RENDER_WIDGET_HOST_DID_PAINT, | |
| 920 Source<RenderWidgetHost>(this), | |
| 921 NotificationService::NoDetails()); | |
| 922 | |
| 923 // If we got a resize ack, then perhaps we have another resize to send? | |
| 924 if (is_resize_ack && view_) { | |
| 925 // WasResized checks the current size and sends the resize update only | |
| 926 // when something was actually changed. | |
| 927 WasResized(); | |
| 928 } | |
| 929 | |
| 930 NotificationService::current()->Notify( | |
| 931 NotificationType::RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | |
| 932 Source<RenderWidgetHost>(this), | |
| 933 NotificationService::NoDetails()); | |
| 934 | |
| 935 // Log the time delta for processing a paint message. | |
| 936 TimeDelta delta = TimeTicks::Now() - paint_start; | |
| 937 UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgUpdateRect", delta); | |
| 938 } | |
| 939 | |
| 940 void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { | |
| 941 // Log the time delta for processing an input event. | |
| 942 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; | |
| 943 UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta); | |
| 944 | |
| 945 // Cancel pending hung renderer checks since the renderer is responsive. | |
| 946 StopHangMonitorTimeout(); | |
| 947 | |
| 948 void* iter = NULL; | |
| 949 int type = 0; | |
| 950 if (!message.ReadInt(&iter, &type) || (type < WebInputEvent::Undefined)) { | |
| 951 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH2")); | |
| 952 process()->ReceivedBadMessage(); | |
| 953 } else if (type == WebInputEvent::MouseMove) { | |
| 954 mouse_move_pending_ = false; | |
| 955 | |
| 956 // now, we can send the next mouse move event | |
| 957 if (next_mouse_move_.get()) { | |
| 958 DCHECK(next_mouse_move_->type == WebInputEvent::MouseMove); | |
| 959 ForwardMouseEvent(*next_mouse_move_); | |
| 960 } | |
| 961 } else if (type == WebInputEvent::MouseWheel) { | |
| 962 ProcessWheelAck(); | |
| 963 } else if (WebInputEvent::isKeyboardEventType(type)) { | |
| 964 bool processed = false; | |
| 965 if (!message.ReadBool(&iter, &processed)) { | |
| 966 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH3")); | |
| 967 process()->ReceivedBadMessage(); | |
| 968 } | |
| 969 | |
| 970 ProcessKeyboardEventAck(type, processed); | |
| 971 } | |
| 972 // This is used only for testing. | |
| 973 NotificationService::current()->Notify( | |
| 974 NotificationType::RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, | |
| 975 Source<RenderWidgetHost>(this), | |
| 976 Details<int>(&type)); | |
| 977 } | |
| 978 | |
| 979 void RenderWidgetHost::ProcessWheelAck() { | |
| 980 mouse_wheel_pending_ = false; | |
| 981 | |
| 982 // Now send the next (coalesced) mouse wheel event. | |
| 983 if (!coalesced_mouse_wheel_events_.empty()) { | |
| 984 WebMouseWheelEvent next_wheel_event = | |
| 985 coalesced_mouse_wheel_events_.front(); | |
| 986 coalesced_mouse_wheel_events_.pop_front(); | |
| 987 ForwardWheelEvent(next_wheel_event); | |
| 988 } | |
| 989 } | |
| 990 | |
| 991 void RenderWidgetHost::OnMsgFocus() { | |
| 992 // Only RenderViewHost can deal with that message. | |
| 993 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH4")); | |
| 994 process()->ReceivedBadMessage(); | |
| 995 } | |
| 996 | |
| 997 void RenderWidgetHost::OnMsgBlur() { | |
| 998 // Only RenderViewHost can deal with that message. | |
| 999 UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_RWH5")); | |
| 1000 process()->ReceivedBadMessage(); | |
| 1001 } | |
| 1002 | |
| 1003 void RenderWidgetHost::OnMsgSetCursor(const WebCursor& cursor) { | |
| 1004 if (!view_) { | |
| 1005 return; | |
| 1006 } | |
| 1007 view_->UpdateCursor(cursor); | |
| 1008 } | |
| 1009 | |
| 1010 void RenderWidgetHost::OnMsgImeUpdateTextInputState( | |
| 1011 WebKit::WebTextInputType type, | |
| 1012 const gfx::Rect& caret_rect) { | |
| 1013 if (view_) | |
| 1014 view_->ImeUpdateTextInputState(type, caret_rect); | |
| 1015 } | |
| 1016 | |
| 1017 void RenderWidgetHost::OnMsgImeCancelComposition() { | |
| 1018 if (view_) | |
| 1019 view_->ImeCancelComposition(); | |
| 1020 } | |
| 1021 | |
| 1022 void RenderWidgetHost::OnMsgDidActivateAcceleratedCompositing(bool activated) { | |
| 1023 #if defined(OS_MACOSX) | |
| 1024 bool old_state = is_accelerated_compositing_active_; | |
| 1025 #endif | |
| 1026 is_accelerated_compositing_active_ = activated; | |
| 1027 #if defined(OS_MACOSX) | |
| 1028 if (old_state != is_accelerated_compositing_active_ && view_) | |
| 1029 view_->GpuRenderingStateDidChange(); | |
| 1030 #elif defined(OS_WIN) | |
| 1031 if (view_) | |
| 1032 view_->ShowCompositorHostWindow(is_accelerated_compositing_active_); | |
| 1033 #elif defined(TOOLKIT_USES_GTK) | |
| 1034 if (view_) | |
| 1035 view_->AcceleratedCompositingActivated(activated); | |
| 1036 #endif | |
| 1037 } | |
| 1038 | |
| 1039 #if defined(OS_MACOSX) | |
| 1040 | |
| 1041 void RenderWidgetHost::OnMsgGetScreenInfo(gfx::NativeViewId view, | |
| 1042 WebScreenInfo* results) { | |
| 1043 gfx::NativeView native_view = view_ ? view_->GetNativeView() : NULL; | |
| 1044 *results = WebScreenInfoFactory::screenInfo(native_view); | |
| 1045 } | |
| 1046 | |
| 1047 void RenderWidgetHost::OnMsgGetWindowRect(gfx::NativeViewId window_id, | |
| 1048 gfx::Rect* results) { | |
| 1049 if (view_) { | |
| 1050 *results = view_->GetViewBounds(); | |
| 1051 } | |
| 1052 } | |
| 1053 | |
| 1054 void RenderWidgetHost::OnMsgGetRootWindowRect(gfx::NativeViewId window_id, | |
| 1055 gfx::Rect* results) { | |
| 1056 if (view_) { | |
| 1057 *results = view_->GetRootWindowRect(); | |
| 1058 } | |
| 1059 } | |
| 1060 | |
| 1061 void RenderWidgetHost::OnMsgPluginFocusChanged(bool focused, int plugin_id) { | |
| 1062 if (view_) | |
| 1063 view_->PluginFocusChanged(focused, plugin_id); | |
| 1064 } | |
| 1065 | |
| 1066 void RenderWidgetHost::OnMsgStartPluginIme() { | |
| 1067 if (view_) | |
| 1068 view_->StartPluginIme(); | |
| 1069 } | |
| 1070 | |
| 1071 void RenderWidgetHost::OnAllocateFakePluginWindowHandle( | |
| 1072 bool opaque, | |
| 1073 bool root, | |
| 1074 gfx::PluginWindowHandle* id) { | |
| 1075 // TODO(kbr): similar potential issue here as in OnMsgCreatePluginContainer. | |
| 1076 // Possibly less of an issue because this is only used for the GPU plugin. | |
| 1077 if (view_) { | |
| 1078 *id = view_->AllocateFakePluginWindowHandle(opaque, root); | |
| 1079 } else { | |
| 1080 NOTIMPLEMENTED(); | |
| 1081 } | |
| 1082 } | |
| 1083 | |
| 1084 void RenderWidgetHost::OnDestroyFakePluginWindowHandle( | |
| 1085 gfx::PluginWindowHandle id) { | |
| 1086 if (view_) { | |
| 1087 view_->DestroyFakePluginWindowHandle(id); | |
| 1088 } else { | |
| 1089 NOTIMPLEMENTED(); | |
| 1090 } | |
| 1091 } | |
| 1092 | |
| 1093 void RenderWidgetHost::OnAcceleratedSurfaceSetIOSurface( | |
| 1094 gfx::PluginWindowHandle window, | |
| 1095 int32 width, | |
| 1096 int32 height, | |
| 1097 uint64 mach_port) { | |
| 1098 if (view_) { | |
| 1099 view_->AcceleratedSurfaceSetIOSurface(window, width, height, mach_port); | |
| 1100 } | |
| 1101 } | |
| 1102 | |
| 1103 void RenderWidgetHost::OnAcceleratedSurfaceSetTransportDIB( | |
| 1104 gfx::PluginWindowHandle window, | |
| 1105 int32 width, | |
| 1106 int32 height, | |
| 1107 TransportDIB::Handle transport_dib) { | |
| 1108 if (view_) { | |
| 1109 view_->AcceleratedSurfaceSetTransportDIB(window, width, height, | |
| 1110 transport_dib); | |
| 1111 } | |
| 1112 } | |
| 1113 | |
| 1114 void RenderWidgetHost::OnAcceleratedSurfaceBuffersSwapped( | |
| 1115 gfx::PluginWindowHandle window, uint64 surface_id) { | |
| 1116 if (view_) { | |
| 1117 // This code path could be updated to implement flow control for | |
| 1118 // updating of accelerated plugins as well. However, if we add support | |
| 1119 // for composited plugins then this is not necessary. | |
| 1120 view_->AcceleratedSurfaceBuffersSwapped(window, surface_id, | |
| 1121 0, 0, 0); | |
| 1122 } | |
| 1123 } | |
| 1124 #elif defined(OS_POSIX) | |
| 1125 | |
| 1126 void RenderWidgetHost::OnMsgCreatePluginContainer(gfx::PluginWindowHandle id) { | |
| 1127 // TODO(piman): view_ can only be NULL with delayed view creation in | |
| 1128 // extensions (see ExtensionHost::CreateRenderViewSoon). Figure out how to | |
| 1129 // support plugins in that case. | |
| 1130 if (view_) { | |
| 1131 view_->CreatePluginContainer(id); | |
| 1132 } else { | |
| 1133 deferred_plugin_handles_.push_back(id); | |
| 1134 } | |
| 1135 } | |
| 1136 | |
| 1137 void RenderWidgetHost::OnMsgDestroyPluginContainer(gfx::PluginWindowHandle id) { | |
| 1138 if (view_) { | |
| 1139 view_->DestroyPluginContainer(id); | |
| 1140 } else { | |
| 1141 for (int i = 0; | |
| 1142 i < static_cast<int>(deferred_plugin_handles_.size()); | |
| 1143 i++) { | |
| 1144 if (deferred_plugin_handles_[i] == id) { | |
| 1145 deferred_plugin_handles_.erase(deferred_plugin_handles_.begin() + i); | |
| 1146 i--; | |
| 1147 } | |
| 1148 } | |
| 1149 } | |
| 1150 } | |
| 1151 #endif | |
| 1152 | |
| 1153 void RenderWidgetHost::PaintBackingStoreRect( | |
| 1154 TransportDIB::Id bitmap, | |
| 1155 const gfx::Rect& bitmap_rect, | |
| 1156 const std::vector<gfx::Rect>& copy_rects, | |
| 1157 const gfx::Size& view_size) { | |
| 1158 // The view may be destroyed already. | |
| 1159 if (!view_) | |
| 1160 return; | |
| 1161 | |
| 1162 if (is_hidden_) { | |
| 1163 // Don't bother updating the backing store when we're hidden. Just mark it | |
| 1164 // as being totally invalid. This will cause a complete repaint when the | |
| 1165 // view is restored. | |
| 1166 needs_repainting_on_restore_ = true; | |
| 1167 return; | |
| 1168 } | |
| 1169 | |
| 1170 bool needs_full_paint = false; | |
| 1171 BackingStoreManager::PrepareBackingStore(this, view_size, bitmap, bitmap_rect, | |
| 1172 copy_rects, &needs_full_paint); | |
| 1173 if (needs_full_paint) { | |
| 1174 repaint_start_time_ = TimeTicks::Now(); | |
| 1175 repaint_ack_pending_ = true; | |
| 1176 Send(new ViewMsg_Repaint(routing_id_, view_size)); | |
| 1177 } | |
| 1178 } | |
| 1179 | |
| 1180 void RenderWidgetHost::ScrollBackingStoreRect(int dx, int dy, | |
| 1181 const gfx::Rect& clip_rect, | |
| 1182 const gfx::Size& view_size) { | |
| 1183 if (is_hidden_) { | |
| 1184 // Don't bother updating the backing store when we're hidden. Just mark it | |
| 1185 // as being totally invalid. This will cause a complete repaint when the | |
| 1186 // view is restored. | |
| 1187 needs_repainting_on_restore_ = true; | |
| 1188 return; | |
| 1189 } | |
| 1190 | |
| 1191 // TODO(darin): do we need to do something else if our backing store is not | |
| 1192 // the same size as the advertised view? maybe we just assume there is a | |
| 1193 // full paint on its way? | |
| 1194 BackingStore* backing_store = BackingStoreManager::Lookup(this); | |
| 1195 if (!backing_store || (backing_store->size() != view_size)) | |
| 1196 return; | |
| 1197 backing_store->ScrollBackingStore(dx, dy, clip_rect, view_size); | |
| 1198 } | |
| 1199 | |
| 1200 void RenderWidgetHost::ToggleSpellPanel(bool is_currently_visible) { | |
| 1201 Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible)); | |
| 1202 } | |
| 1203 | |
| 1204 void RenderWidgetHost::Replace(const string16& word) { | |
| 1205 Send(new ViewMsg_Replace(routing_id_, word)); | |
| 1206 } | |
| 1207 | |
| 1208 void RenderWidgetHost::AdvanceToNextMisspelling() { | |
| 1209 Send(new ViewMsg_AdvanceToNextMisspelling(routing_id_)); | |
| 1210 } | |
| 1211 | |
| 1212 void RenderWidgetHost::EnableRendererAccessibility() { | |
| 1213 if (renderer_accessible_) | |
| 1214 return; | |
| 1215 | |
| 1216 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1217 switches::kDisableRendererAccessibility)) { | |
| 1218 return; | |
| 1219 } | |
| 1220 | |
| 1221 renderer_accessible_ = true; | |
| 1222 | |
| 1223 if (process_->HasConnection()) { | |
| 1224 // Renderer accessibility wasn't enabled on process launch. Enable it now. | |
| 1225 Send(new ViewMsg_EnableAccessibility(routing_id())); | |
| 1226 } | |
| 1227 } | |
| 1228 | |
| 1229 void RenderWidgetHost::SetAccessibilityFocus(int acc_obj_id) { | |
| 1230 Send(new ViewMsg_SetAccessibilityFocus(routing_id(), acc_obj_id)); | |
| 1231 } | |
| 1232 | |
| 1233 void RenderWidgetHost::AccessibilityDoDefaultAction(int acc_obj_id) { | |
| 1234 Send(new ViewMsg_AccessibilityDoDefaultAction(routing_id(), acc_obj_id)); | |
| 1235 } | |
| 1236 | |
| 1237 void RenderWidgetHost::AccessibilityNotificationsAck() { | |
| 1238 Send(new ViewMsg_AccessibilityNotifications_ACK(routing_id())); | |
| 1239 } | |
| 1240 | |
| 1241 void RenderWidgetHost::ProcessKeyboardEventAck(int type, bool processed) { | |
| 1242 if (key_queue_.size() == 0) { | |
| 1243 LOG(ERROR) << "Got a KeyEvent back from the renderer but we " | |
| 1244 << "don't seem to have sent it to the renderer!"; | |
| 1245 } else if (key_queue_.front().type != type) { | |
| 1246 LOG(ERROR) << "We seem to have a different key type sent from " | |
| 1247 << "the renderer. (" << key_queue_.front().type << " vs. " | |
| 1248 << type << "). Ignoring event."; | |
| 1249 | |
| 1250 // Something must be wrong. Clear the |key_queue_| and | |
| 1251 // |suppress_next_char_events_| so that we can resume from the error. | |
| 1252 key_queue_.clear(); | |
| 1253 suppress_next_char_events_ = false; | |
| 1254 } else { | |
| 1255 NativeWebKeyboardEvent front_item = key_queue_.front(); | |
| 1256 key_queue_.pop_front(); | |
| 1257 | |
| 1258 #if defined(OS_MACOSX) | |
| 1259 if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item)) | |
| 1260 return; | |
| 1261 #endif | |
| 1262 | |
| 1263 // We only send unprocessed key event upwards if we are not hidden, | |
| 1264 // because the user has moved away from us and no longer expect any effect | |
| 1265 // of this key event. | |
| 1266 if (!processed && !is_hidden_ && !front_item.skip_in_browser) { | |
| 1267 UnhandledKeyboardEvent(front_item); | |
| 1268 | |
| 1269 // WARNING: This RenderWidgetHost can be deallocated at this point | |
| 1270 // (i.e. in the case of Ctrl+W, where the call to | |
| 1271 // UnhandledKeyboardEvent destroys this RenderWidgetHost). | |
| 1272 } | |
| 1273 } | |
| 1274 } | |
| 1275 | |
| 1276 void RenderWidgetHost::ActivateDeferredPluginHandles() { | |
| 1277 if (view_ == NULL) | |
| 1278 return; | |
| 1279 | |
| 1280 for (int i = 0; i < static_cast<int>(deferred_plugin_handles_.size()); i++) { | |
| 1281 #if defined(TOOLKIT_USES_GTK) | |
| 1282 view_->CreatePluginContainer(deferred_plugin_handles_[i]); | |
| 1283 #endif | |
| 1284 } | |
| 1285 | |
| 1286 deferred_plugin_handles_.clear(); | |
| 1287 } | |
| OLD | NEW |