1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/render_widget.h" 6 7 #include "base/bind.h" 8 #include "base/command_line.h" 9 #include "base/debug/trace_event.h" 10 #include "base/logging.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/singleton.h" 13 #include "base/message_loop/message_loop.h" 14 #include "base/metrics/histogram.h" 15 #include "base/stl_util.h" 16 #include "base/strings/utf_string_conversions.h" 17 #include "build/build_config.h" 18 #include "cc/base/switches.h" 19 #include "cc/output/output_surface.h" 20 #include "cc/trees/layer_tree_host.h" 21 #include "content/child/npapi/webplugin.h" 22 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 23 #include "content/common/input_messages.h" 24 #include "content/common/swapped_out_messages.h" 25 #include "content/common/view_messages.h" 26 #include "content/public/common/content_switches.h" 27 #include "content/renderer/cursor_utils.h" 28 #include "content/renderer/gpu/compositor_output_surface.h" 29 #include "content/renderer/gpu/compositor_software_output_device.h" 30 #include "content/renderer/gpu/delegated_compositor_output_surface.h" 31 #include "content/renderer/gpu/input_handler_manager.h" 32 #include "content/renderer/gpu/mailbox_output_surface.h" 33 #include "content/renderer/gpu/render_widget_compositor.h" 34 #include "content/renderer/ime_event_guard.h" 35 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 36 #include "content/renderer/render_process.h" 37 #include "content/renderer/render_process_visibility_manager.h" 38 #include "content/renderer/render_thread_impl.h" 39 #include "content/renderer/renderer_webkitplatformsupport_impl.h" 40 #include "ipc/ipc_sync_message.h" 41 #include "skia/ext/platform_canvas.h" 42 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" 43 #include "third_party/WebKit/public/platform/WebPoint.h" 44 #include "third_party/WebKit/public/platform/WebRect.h" 45 #include "third_party/WebKit/public/platform/WebSize.h" 46 #include "third_party/WebKit/public/platform/WebString.h" 47 #include "third_party/WebKit/public/web/WebCursorInfo.h" 48 #include "third_party/WebKit/public/web/WebHelperPlugin.h" 49 #include "third_party/WebKit/public/web/WebPagePopup.h" 50 #include "third_party/WebKit/public/web/WebPopupMenu.h" 51 #include "third_party/WebKit/public/web/WebPopupMenuInfo.h" 52 #include "third_party/WebKit/public/web/WebRange.h" 53 #include "third_party/WebKit/public/web/WebScreenInfo.h" 54 #include "third_party/skia/include/core/SkShader.h" 55 #include "ui/base/ui_base_switches.h" 56 #include "ui/gfx/point.h" 57 #include "ui/gfx/rect_conversions.h" 58 #include "ui/gfx/size_conversions.h" 59 #include "ui/gfx/skia_util.h" 60 #include "ui/gl/gl_switches.h" 61 #include "ui/surface/transport_dib.h" 62 #include "webkit/renderer/compositor_bindings/web_rendering_stats_impl.h" 63 64 #if defined(OS_ANDROID) 65 #include "content/renderer/android/synchronous_compositor_factory.h" 66 #endif 67 68 #if defined(OS_POSIX) 69 #include "ipc/ipc_channel_posix.h" 70 #include "third_party/skia/include/core/SkMallocPixelRef.h" 71 #include "third_party/skia/include/core/SkPixelRef.h" 72 #endif // defined(OS_POSIX) 73 74 #include "third_party/WebKit/public/web/WebWidget.h" 75 76 using WebKit::WebCompositionUnderline; 77 using WebKit::WebCursorInfo; 78 using WebKit::WebGestureEvent; 79 using WebKit::WebInputEvent; 80 using WebKit::WebKeyboardEvent; 81 using WebKit::WebMouseEvent; 82 using WebKit::WebNavigationPolicy; 83 using WebKit::WebPagePopup; 84 using WebKit::WebPoint; 85 using WebKit::WebPopupMenu; 86 using WebKit::WebPopupMenuInfo; 87 using WebKit::WebPopupType; 88 using WebKit::WebRange; 89 using WebKit::WebRect; 90 using WebKit::WebScreenInfo; 91 using WebKit::WebSize; 92 using WebKit::WebTextDirection; 93 using WebKit::WebTouchEvent; 94 using WebKit::WebVector; 95 using WebKit::WebWidget; 96 97 namespace { 98 const char* GetEventName(WebInputEvent::Type type) { 99 #define CASE_TYPE(t) case WebInputEvent::t: return #t 100 switch(type) { 101 CASE_TYPE(Undefined); 102 CASE_TYPE(MouseDown); 103 CASE_TYPE(MouseUp); 104 CASE_TYPE(MouseMove); 105 CASE_TYPE(MouseEnter); 106 CASE_TYPE(MouseLeave); 107 CASE_TYPE(ContextMenu); 108 CASE_TYPE(MouseWheel); 109 CASE_TYPE(RawKeyDown); 110 CASE_TYPE(KeyDown); 111 CASE_TYPE(KeyUp); 112 CASE_TYPE(Char); 113 CASE_TYPE(GestureScrollBegin); 114 CASE_TYPE(GestureScrollEnd); 115 CASE_TYPE(GestureScrollUpdate); 116 CASE_TYPE(GestureFlingStart); 117 CASE_TYPE(GestureFlingCancel); 118 CASE_TYPE(GestureTap); 119 CASE_TYPE(GestureTapUnconfirmed); 120 CASE_TYPE(GestureTapDown); 121 CASE_TYPE(GestureTapCancel); 122 CASE_TYPE(GestureDoubleTap); 123 CASE_TYPE(GestureTwoFingerTap); 124 CASE_TYPE(GestureLongPress); 125 CASE_TYPE(GestureLongTap); 126 CASE_TYPE(GesturePinchBegin); 127 CASE_TYPE(GesturePinchEnd); 128 CASE_TYPE(GesturePinchUpdate); 129 CASE_TYPE(TouchStart); 130 CASE_TYPE(TouchMove); 131 CASE_TYPE(TouchEnd); 132 CASE_TYPE(TouchCancel); 133 default: 134 // Must include default to let WebKit::WebInputEvent add new event types 135 // before they're added here. 136 DLOG(WARNING) << "Unhandled WebInputEvent type in GetEventName.\n"; 137 break; 138 } 139 #undef CASE_TYPE 140 return ""; 141 } 142 143 typedef std::map<std::string, ui::TextInputMode> TextInputModeMap; 144 145 class TextInputModeMapSingleton { 146 public: 147 static TextInputModeMapSingleton* GetInstance() { 148 return Singleton<TextInputModeMapSingleton>::get(); 149 } 150 TextInputModeMapSingleton() 151 : map() { 152 map["verbatim"] = ui::TEXT_INPUT_MODE_VERBATIM; 153 map["latin"] = ui::TEXT_INPUT_MODE_LATIN; 154 map["latin-name"] = ui::TEXT_INPUT_MODE_LATIN_NAME; 155 map["latin-prose"] = ui::TEXT_INPUT_MODE_LATIN_PROSE; 156 map["full-width-latin"] = ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN; 157 map["kana"] = ui::TEXT_INPUT_MODE_KANA; 158 map["katakana"] = ui::TEXT_INPUT_MODE_KATAKANA; 159 map["numeric"] = ui::TEXT_INPUT_MODE_NUMERIC; 160 map["tel"] = ui::TEXT_INPUT_MODE_TEL; 161 map["email"] = ui::TEXT_INPUT_MODE_EMAIL; 162 map["url"] = ui::TEXT_INPUT_MODE_URL; 163 } 164 TextInputModeMap& Map() { 165 return map; 166 } 167 private: 168 TextInputModeMap map; 169 170 friend struct DefaultSingletonTraits<TextInputModeMapSingleton>; 171 172 DISALLOW_COPY_AND_ASSIGN(TextInputModeMapSingleton); 173 }; 174 175 ui::TextInputMode ConvertInputMode( 176 const WebKit::WebString& input_mode) { 177 static TextInputModeMapSingleton* singleton = 178 TextInputModeMapSingleton::GetInstance(); 179 TextInputModeMap::iterator it = singleton->Map().find(input_mode.utf8()); 180 if (it == singleton->Map().end()) 181 return ui::TEXT_INPUT_MODE_DEFAULT; 182 return it->second; 183 } 184 185 } // namespace 186 187 namespace content { 188 189 RenderWidget::RenderWidget(WebKit::WebPopupType popup_type, 190 const WebKit::WebScreenInfo& screen_info, 191 bool swapped_out) 192 : routing_id_(MSG_ROUTING_NONE), 193 surface_id_(0), 194 webwidget_(NULL), 195 opener_id_(MSG_ROUTING_NONE), 196 init_complete_(false), 197 current_paint_buf_(NULL), 198 overdraw_bottom_height_(0.f), 199 next_paint_flags_(0), 200 filtered_time_per_frame_(0.0f), 201 update_reply_pending_(false), 202 auto_resize_mode_(false), 203 need_update_rect_for_auto_resize_(false), 204 using_asynchronous_swapbuffers_(false), 205 num_swapbuffers_complete_pending_(0), 206 did_show_(false), 207 is_hidden_(false), 208 is_fullscreen_(false), 209 needs_repainting_on_restore_(false), 210 has_focus_(false), 211 handling_input_event_(false), 212 handling_ime_event_(false), 213 closing_(false), 214 is_swapped_out_(swapped_out), 215 input_method_is_active_(false), 216 text_input_type_(ui::TEXT_INPUT_TYPE_NONE), 217 can_compose_inline_(true), 218 text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT), 219 popup_type_(popup_type), 220 pending_window_rect_count_(0), 221 suppress_next_char_events_(false), 222 is_accelerated_compositing_active_(false), 223 animation_update_pending_(false), 224 invalidation_task_posted_(false), 225 screen_info_(screen_info), 226 device_scale_factor_(screen_info_.deviceScaleFactor), 227 is_threaded_compositing_enabled_(false), 228 next_output_surface_id_(0), 229 #if defined(OS_ANDROID) 230 outstanding_ime_acks_(0), 231 #endif 232 weak_ptr_factory_(this) { 233 if (!swapped_out) 234 RenderProcess::current()->AddRefProcess(); 235 DCHECK(RenderThread::Get()); 236 has_disable_gpu_vsync_switch_ = CommandLine::ForCurrentProcess()->HasSwitch( 237 switches::kDisableGpuVsync); 238 is_threaded_compositing_enabled_ = 239 CommandLine::ForCurrentProcess()->HasSwitch( 240 switches::kEnableThreadedCompositing); 241 242 RenderProcessVisibilityManager::GetInstance()->WidgetVisibilityChanged(true); 243 } 244 245 RenderWidget::~RenderWidget() { 246 DCHECK(!webwidget_) << "Leaking our WebWidget!"; 247 STLDeleteElements(&updates_pending_swap_); 248 if (current_paint_buf_) { 249 if (RenderProcess::current()) { 250 // If the RenderProcess is already gone, it will have released all DIBs 251 // in its destructor anyway. 252 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); 253 } 254 current_paint_buf_ = NULL; 255 } 256 // If we are swapped out, we have released already. 257 if (!is_swapped_out_) 258 RenderProcess::current()->ReleaseProcess(); 259 } 260 261 // static 262 RenderWidget* RenderWidget::Create(int32 opener_id, 263 WebKit::WebPopupType popup_type, 264 const WebKit::WebScreenInfo& screen_info) { 265 DCHECK(opener_id != MSG_ROUTING_NONE); 266 scoped_refptr<RenderWidget> widget( 267 new RenderWidget(popup_type, screen_info, false)); 268 if (widget->Init(opener_id)) { // adds reference on success. 269 return widget.get(); 270 } 271 return NULL; 272 } 273 274 // static 275 WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) { 276 switch (render_widget->popup_type_) { 277 case WebKit::WebPopupTypeNone: // Nothing to create. 278 break; 279 case WebKit::WebPopupTypeSelect: 280 case WebKit::WebPopupTypeSuggestion: 281 return WebPopupMenu::create(render_widget); 282 case WebKit::WebPopupTypePage: 283 return WebPagePopup::create(render_widget); 284 case WebKit::WebPopupTypeHelperPlugin: 285 return WebKit::WebHelperPlugin::create(render_widget); 286 default: 287 NOTREACHED(); 288 } 289 return NULL; 290 } 291 292 bool RenderWidget::Init(int32 opener_id) { 293 return DoInit(opener_id, 294 RenderWidget::CreateWebWidget(this), 295 new ViewHostMsg_CreateWidget(opener_id, popup_type_, 296 &routing_id_, &surface_id_)); 297 } 298 299 bool RenderWidget::DoInit(int32 opener_id, 300 WebWidget* web_widget, 301 IPC::SyncMessage* create_widget_message) { 302 DCHECK(!webwidget_); 303 304 if (opener_id != MSG_ROUTING_NONE) 305 opener_id_ = opener_id; 306 307 webwidget_ = web_widget; 308 309 bool result = RenderThread::Get()->Send(create_widget_message); 310 if (result) { 311 RenderThread::Get()->AddRoute(routing_id_, this); 312 // Take a reference on behalf of the RenderThread. This will be balanced 313 // when we receive ViewMsg_Close. 314 AddRef(); 315 return true; 316 } else { 317 // The above Send can fail when the tab is closing. 318 return false; 319 } 320 } 321 322 // This is used to complete pending inits and non-pending inits. 323 void RenderWidget::CompleteInit() { 324 DCHECK(routing_id_ != MSG_ROUTING_NONE); 325 326 init_complete_ = true; 327 328 if (webwidget_ && is_threaded_compositing_enabled_) { 329 webwidget_->enterForceCompositingMode(true); 330 } 331 if (compositor_) { 332 compositor_->setSurfaceReady(); 333 } 334 DoDeferredUpdate(); 335 336 Send(new ViewHostMsg_RenderViewReady(routing_id_)); 337 } 338 339 void RenderWidget::SetSwappedOut(bool is_swapped_out) { 340 // We should only toggle between states. 341 DCHECK(is_swapped_out_ != is_swapped_out); 342 is_swapped_out_ = is_swapped_out; 343 344 // If we are swapping out, we will call ReleaseProcess, allowing the process 345 // to exit if all of its RenderViews are swapped out. We wait until the 346 // WasSwappedOut call to do this, to avoid showing the sad tab. 347 // If we are swapping in, we call AddRefProcess to prevent the process from 348 // exiting. 349 if (!is_swapped_out) 350 RenderProcess::current()->AddRefProcess(); 351 } 352 353 bool RenderWidget::AllowPartialSwap() const { 354 return true; 355 } 356 357 bool RenderWidget::UsingSynchronousRendererCompositor() const { 358 #if defined(OS_ANDROID) 359 return SynchronousCompositorFactory::GetInstance() != NULL; 360 #else 361 return false; 362 #endif 363 } 364 365 bool RenderWidget::OnMessageReceived(const IPC::Message& message) { 366 bool handled = true; 367 IPC_BEGIN_MESSAGE_MAP(RenderWidget, message) 368 IPC_MESSAGE_HANDLER(InputMsg_HandleInputEvent, OnHandleInputEvent) 369 IPC_MESSAGE_HANDLER(InputMsg_CursorVisibilityChange, 370 OnCursorVisibilityChange) 371 IPC_MESSAGE_HANDLER(InputMsg_MouseCaptureLost, OnMouseCaptureLost) 372 IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetFocus) 373 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose) 374 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck) 375 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize) 376 IPC_MESSAGE_HANDLER(ViewMsg_ChangeResizeRect, OnChangeResizeRect) 377 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden) 378 IPC_MESSAGE_HANDLER(ViewMsg_WasShown, OnWasShown) 379 IPC_MESSAGE_HANDLER(ViewMsg_WasSwappedOut, OnWasSwappedOut) 380 IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck) 381 IPC_MESSAGE_HANDLER(ViewMsg_SwapBuffers_ACK, 382 OnViewContextSwapBuffersComplete) 383 IPC_MESSAGE_HANDLER(ViewMsg_SetInputMethodActive, OnSetInputMethodActive) 384 IPC_MESSAGE_HANDLER(ViewMsg_ImeSetComposition, OnImeSetComposition) 385 IPC_MESSAGE_HANDLER(ViewMsg_ImeConfirmComposition, OnImeConfirmComposition) 386 IPC_MESSAGE_HANDLER(ViewMsg_PaintAtSize, OnPaintAtSize) 387 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnRepaint) 388 IPC_MESSAGE_HANDLER(ViewMsg_SmoothScrollCompleted, OnSmoothScrollCompleted) 389 IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection) 390 IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck) 391 IPC_MESSAGE_HANDLER(ViewMsg_UpdateScreenRects, OnUpdateScreenRects) 392 #if defined(OS_ANDROID) 393 IPC_MESSAGE_HANDLER(ViewMsg_ImeBatchStateChanged, OnImeBatchStateChanged) 394 IPC_MESSAGE_HANDLER(ViewMsg_ShowImeIfNeeded, OnShowImeIfNeeded) 395 IPC_MESSAGE_HANDLER(ViewMsg_ImeEventAck, OnImeEventAck) 396 #endif 397 IPC_MESSAGE_HANDLER(ViewMsg_Snapshot, OnSnapshot) 398 IPC_MESSAGE_HANDLER(ViewMsg_SetBrowserRenderingStats, 399 OnSetBrowserRenderingStats) 400 IPC_MESSAGE_UNHANDLED(handled = false) 401 IPC_END_MESSAGE_MAP() 402 return handled; 403 } 404 405 bool RenderWidget::Send(IPC::Message* message) { 406 // Don't send any messages after the browser has told us to close, and filter 407 // most outgoing messages while swapped out. 408 if ((is_swapped_out_ && 409 !SwappedOutMessages::CanSendWhileSwappedOut(message)) || 410 closing_) { 411 delete message; 412 return false; 413 } 414 415 // If given a messsage without a routing ID, then assign our routing ID. 416 if (message->routing_id() == MSG_ROUTING_NONE) 417 message->set_routing_id(routing_id_); 418 419 return RenderThread::Get()->Send(message); 420 } 421 422 void RenderWidget::Resize(const gfx::Size& new_size, 423 const gfx::Size& physical_backing_size, 424 float overdraw_bottom_height, 425 const gfx::Rect& resizer_rect, 426 bool is_fullscreen, 427 ResizeAck resize_ack) { 428 if (!RenderThreadImpl::current() || // Will be NULL during unit tests. 429 !RenderThreadImpl::current()->layout_test_mode()) { 430 // A resize ack shouldn't be requested if we have not ACK'd the previous 431 // one. 432 DCHECK(resize_ack != SEND_RESIZE_ACK || !next_paint_is_resize_ack()); 433 DCHECK(resize_ack == SEND_RESIZE_ACK || resize_ack == NO_RESIZE_ACK); 434 } 435 436 // Ignore this during shutdown. 437 if (!webwidget_) 438 return; 439 440 if (compositor_) { 441 compositor_->setViewportSize(new_size, physical_backing_size); 442 compositor_->SetOverdrawBottomHeight(overdraw_bottom_height); 443 } 444 445 physical_backing_size_ = physical_backing_size; 446 overdraw_bottom_height_ = overdraw_bottom_height; 447 resizer_rect_ = resizer_rect; 448 449 // NOTE: We may have entered fullscreen mode without changing our size. 450 bool fullscreen_change = is_fullscreen_ != is_fullscreen; 451 if (fullscreen_change) 452 WillToggleFullscreen(); 453 is_fullscreen_ = is_fullscreen; 454 455 if (size_ != new_size) { 456 // TODO(darin): We should not need to reset this here. 457 needs_repainting_on_restore_ = false; 458 459 size_ = new_size; 460 461 paint_aggregator_.ClearPendingUpdate(); 462 463 // When resizing, we want to wait to paint before ACK'ing the resize. This 464 // ensures that we only resize as fast as we can paint. We only need to 465 // send an ACK if we are resized to a non-empty rect. 466 webwidget_->resize(new_size); 467 468 if (!RenderThreadImpl::current() || // Will be NULL during unit tests. 469 !RenderThreadImpl::current()->layout_test_mode()) { 470 // Resize should have caused an invalidation of the entire view. 471 DCHECK(new_size.IsEmpty() || is_accelerated_compositing_active_ || 472 paint_aggregator_.HasPendingUpdate()); 473 } 474 } else if (!RenderThreadImpl::current() || // Will be NULL during unit tests. 475 !RenderThreadImpl::current()->layout_test_mode()) { 476 resize_ack = NO_RESIZE_ACK; 477 } 478 479 if (new_size.IsEmpty() || physical_backing_size.IsEmpty()) { 480 // For empty size or empty physical_backing_size, there is no next paint 481 // (along with which to send the ack) until they are set to non-empty. 482 resize_ack = NO_RESIZE_ACK; 483 } 484 485 // Send the Resize_ACK flag once we paint again if requested. 486 if (resize_ack == SEND_RESIZE_ACK) 487 set_next_paint_is_resize_ack(); 488 489 if (fullscreen_change) 490 DidToggleFullscreen(); 491 492 // If a resize ack is requested and it isn't set-up, then no more resizes will 493 // come in and in general things will go wrong. 494 DCHECK(resize_ack != SEND_RESIZE_ACK || next_paint_is_resize_ack()); 495 } 496 497 void RenderWidget::OnClose() { 498 if (closing_) 499 return; 500 closing_ = true; 501 502 // Browser correspondence is no longer needed at this point. 503 if (routing_id_ != MSG_ROUTING_NONE) { 504 RenderThread::Get()->RemoveRoute(routing_id_); 505 SetHidden(false); 506 } 507 508 // If there is a Send call on the stack, then it could be dangerous to close 509 // now. Post a task that only gets invoked when there are no nested message 510 // loops. 511 base::MessageLoop::current()->PostNonNestableTask( 512 FROM_HERE, base::Bind(&RenderWidget::Close, this)); 513 514 // Balances the AddRef taken when we called AddRoute. 515 Release(); 516 } 517 518 // Got a response from the browser after the renderer decided to create a new 519 // view. 520 void RenderWidget::OnCreatingNewAck() { 521 DCHECK(routing_id_ != MSG_ROUTING_NONE); 522 523 CompleteInit(); 524 } 525 526 void RenderWidget::OnResize(const ViewMsg_Resize_Params& params) { 527 screen_info_ = params.screen_info; 528 SetDeviceScaleFactor(screen_info_.deviceScaleFactor); 529 Resize(params.new_size, params.physical_backing_size, 530 params.overdraw_bottom_height, params.resizer_rect, 531 params.is_fullscreen, SEND_RESIZE_ACK); 532 } 533 534 void RenderWidget::OnChangeResizeRect(const gfx::Rect& resizer_rect) { 535 if (resizer_rect_ != resizer_rect) { 536 gfx::Rect view_rect(size_); 537 538 gfx::Rect old_damage_rect = gfx::IntersectRects(view_rect, resizer_rect_); 539 if (!old_damage_rect.IsEmpty()) 540 paint_aggregator_.InvalidateRect(old_damage_rect); 541 542 gfx::Rect new_damage_rect = gfx::IntersectRects(view_rect, resizer_rect); 543 if (!new_damage_rect.IsEmpty()) 544 paint_aggregator_.InvalidateRect(new_damage_rect); 545 546 resizer_rect_ = resizer_rect; 547 548 if (webwidget_) 549 webwidget_->didChangeWindowResizerRect(); 550 } 551 } 552 553 void RenderWidget::OnWasHidden() { 554 TRACE_EVENT0("renderer", "RenderWidget::OnWasHidden"); 555 // Go into a mode where we stop generating paint and scrolling events. 556 SetHidden(true); 557 } 558 559 void RenderWidget::OnWasShown(bool needs_repainting) { 560 TRACE_EVENT0("renderer", "RenderWidget::OnWasShown"); 561 // During shutdown we can just ignore this message. 562 if (!webwidget_) 563 return; 564 565 // See OnWasHidden 566 SetHidden(false); 567 568 if (!needs_repainting && !needs_repainting_on_restore_) 569 return; 570 needs_repainting_on_restore_ = false; 571 572 // Tag the next paint as a restore ack, which is picked up by 573 // DoDeferredUpdate when it sends out the next PaintRect message. 574 set_next_paint_is_restore_ack(); 575 576 // Generate a full repaint. 577 if (!is_accelerated_compositing_active_) { 578 didInvalidateRect(gfx::Rect(size_.width(), size_.height())); 579 } else { 580 scheduleComposite(); 581 } 582 } 583 584 void RenderWidget::OnWasSwappedOut() { 585 // If we have been swapped out and no one else is using this process, 586 // it's safe to exit now. If we get swapped back in, we will call 587 // AddRefProcess in SetSwappedOut. 588 if (is_swapped_out_) 589 RenderProcess::current()->ReleaseProcess(); 590 } 591 592 void RenderWidget::OnRequestMoveAck() { 593 DCHECK(pending_window_rect_count_); 594 pending_window_rect_count_--; 595 } 596 597 void RenderWidget::OnUpdateRectAck() { 598 TRACE_EVENT0("renderer", "RenderWidget::OnUpdateRectAck"); 599 DCHECK(update_reply_pending_); 600 update_reply_pending_ = false; 601 602 // If we sent an UpdateRect message with a zero-sized bitmap, then we should 603 // have no current paint buffer. 604 if (current_paint_buf_) { 605 RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); 606 current_paint_buf_ = NULL; 607 } 608 609 // If swapbuffers is still pending, then defer the update until the 610 // swapbuffers occurs. 611 if (num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) { 612 TRACE_EVENT0("renderer", "EarlyOut_SwapStillPending"); 613 return; 614 } 615 616 // Notify subclasses that software rendering was flushed to the screen. 617 if (!is_accelerated_compositing_active_) { 618 DidFlushPaint(); 619 } 620 621 // Continue painting if necessary... 622 DoDeferredUpdateAndSendInputAck(); 623 } 624 625 bool RenderWidget::SupportsAsynchronousSwapBuffers() { 626 // Contexts using the command buffer support asynchronous swapbuffers. 627 // See RenderWidget::CreateOutputSurface(). 628 if (RenderThreadImpl::current()->compositor_message_loop_proxy().get()) 629 return false; 630 631 return true; 632 } 633 634 GURL RenderWidget::GetURLForGraphicsContext3D() { 635 return GURL(); 636 } 637 638 bool RenderWidget::ForceCompositingModeEnabled() { 639 return false; 640 } 641 642 scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) { 643 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 644 645 #if defined(OS_ANDROID) 646 if (SynchronousCompositorFactory* factory = 647 SynchronousCompositorFactory::GetInstance()) { 648 return factory->CreateOutputSurface(routing_id()); 649 } 650 #endif 651 652 uint32 output_surface_id = next_output_surface_id_++; 653 654 // Explicitly disable antialiasing for the compositor. As of the time of 655 // this writing, the only platform that supported antialiasing for the 656 // compositor was Mac OS X, because the on-screen OpenGL context creation 657 // code paths on Windows and Linux didn't yet have multisampling support. 658 // Mac OS X essentially always behaves as though it's rendering offscreen. 659 // Multisampling has a heavy cost especially on devices with relatively low 660 // fill rate like most notebooks, and the Mac implementation would need to 661 // be optimized to resolve directly into the IOSurface shared between the 662 // GPU and browser processes. For these reasons and to avoid platform 663 // disparities we explicitly disable antialiasing. 664 WebKit::WebGraphicsContext3D::Attributes attributes; 665 attributes.antialias = false; 666 attributes.shareResources = true; 667 attributes.noAutomaticFlushes = true; 668 attributes.depth = false; 669 attributes.stencil = false; 670 if (command_line.HasSwitch(cc::switches::kForceDirectLayerDrawing)) 671 attributes.stencil = true; 672 WebGraphicsContext3DCommandBufferImpl* context = NULL; 673 if (!fallback) 674 context = CreateGraphicsContext3D(attributes); 675 676 if (!context) { 677 if (!command_line.HasSwitch(switches::kEnableSoftwareCompositing)) 678 return scoped_ptr<cc::OutputSurface>(); 679 return scoped_ptr<cc::OutputSurface>( 680 new CompositorOutputSurface(routing_id(), 681 output_surface_id, 682 NULL, 683 new CompositorSoftwareOutputDevice(), 684 true)); 685 } 686 687 if (command_line.HasSwitch(switches::kEnableDelegatedRenderer) && 688 !command_line.HasSwitch(switches::kDisableDelegatedRenderer)) { 689 DCHECK(is_threaded_compositing_enabled_); 690 return scoped_ptr<cc::OutputSurface>( 691 new DelegatedCompositorOutputSurface(routing_id(), output_surface_id, 692 context, NULL)); 693 } 694 if (command_line.HasSwitch(cc::switches::kCompositeToMailbox)) { 695 DCHECK(is_threaded_compositing_enabled_); 696 return scoped_ptr<cc::OutputSurface>( 697 new MailboxOutputSurface(routing_id(), output_surface_id, 698 context, NULL)); 699 } 700 return scoped_ptr<cc::OutputSurface>( 701 new CompositorOutputSurface(routing_id(), output_surface_id, 702 context, NULL, false)); 703 } 704 705 void RenderWidget::OnViewContextSwapBuffersAborted() { 706 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersAborted"); 707 while (!updates_pending_swap_.empty()) { 708 ViewHostMsg_UpdateRect* msg = updates_pending_swap_.front(); 709 updates_pending_swap_.pop_front(); 710 // msg can be NULL if the swap doesn't correspond to an DoDeferredUpdate 711 // compositing pass, hence doesn't require an UpdateRect message. 712 if (msg) 713 Send(msg); 714 } 715 num_swapbuffers_complete_pending_ = 0; 716 using_asynchronous_swapbuffers_ = false; 717 // Schedule another frame so the compositor learns about it. 718 scheduleComposite(); 719 } 720 721 void RenderWidget::OnViewContextSwapBuffersPosted() { 722 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersPosted"); 723 724 if (using_asynchronous_swapbuffers_) { 725 ViewHostMsg_UpdateRect* msg = NULL; 726 // pending_update_params_ can be NULL if the swap doesn't correspond to an 727 // DoDeferredUpdate compositing pass, hence doesn't require an UpdateRect 728 // message. 729 if (pending_update_params_) { 730 msg = new ViewHostMsg_UpdateRect(routing_id_, *pending_update_params_); 731 pending_update_params_.reset(); 732 } 733 updates_pending_swap_.push_back(msg); 734 num_swapbuffers_complete_pending_++; 735 } 736 } 737 738 void RenderWidget::OnViewContextSwapBuffersComplete() { 739 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersComplete"); 740 741 // Notify subclasses that composited rendering was flushed to the screen. 742 DidFlushPaint(); 743 744 // When compositing deactivates, we reset the swapbuffers pending count. The 745 // swapbuffers acks may still arrive, however. 746 if (num_swapbuffers_complete_pending_ == 0) { 747 TRACE_EVENT0("renderer", "EarlyOut_ZeroSwapbuffersPending"); 748 return; 749 } 750 DCHECK(!updates_pending_swap_.empty()); 751 ViewHostMsg_UpdateRect* msg = updates_pending_swap_.front(); 752 updates_pending_swap_.pop_front(); 753 // msg can be NULL if the swap doesn't correspond to an DoDeferredUpdate 754 // compositing pass, hence doesn't require an UpdateRect message. 755 if (msg) 756 Send(msg); 757 num_swapbuffers_complete_pending_--; 758 759 // If update reply is still pending, then defer the update until that reply 760 // occurs. 761 if (update_reply_pending_) { 762 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending"); 763 return; 764 } 765 766 // If we are not accelerated rendering, then this is a stale swapbuffers from 767 // when we were previously rendering. However, if an invalidation task is not 768 // posted, there may be software rendering work pending. In that case, don't 769 // early out. 770 if (!is_accelerated_compositing_active_ && invalidation_task_posted_) { 771 TRACE_EVENT0("renderer", "EarlyOut_AcceleratedCompositingOff"); 772 return; 773 } 774 775 // Do not call DoDeferredUpdate unless there's animation work to be done or 776 // a real invalidation. This prevents rendering in response to a swapbuffers 777 // callback coming back after we've navigated away from the page that 778 // generated it. 779 if (!animation_update_pending_ && !paint_aggregator_.HasPendingUpdate()) { 780 TRACE_EVENT0("renderer", "EarlyOut_NoPendingUpdate"); 781 return; 782 } 783 784 // Continue painting if necessary... 785 DoDeferredUpdateAndSendInputAck(); 786 } 787 788 void RenderWidget::OnHandleInputEvent(const WebKit::WebInputEvent* input_event, 789 const ui::LatencyInfo& latency_info, 790 bool is_keyboard_shortcut) { 791 handling_input_event_ = true; 792 if (!input_event) { 793 handling_input_event_ = false; 794 return; 795 } 796 797 const char* const event_name = GetEventName(input_event->type); 798 TRACE_EVENT1("renderer", "RenderWidget::OnHandleInputEvent", 799 "event", event_name); 800 801 if (compositor_) 802 compositor_->SetLatencyInfo(latency_info); 803 else 804 latency_info_.MergeWith(latency_info); 805 806 base::TimeDelta now = base::TimeDelta::FromInternalValue( 807 base::TimeTicks::Now().ToInternalValue()); 808 809 int64 delta = static_cast<int64>( 810 (now.InSecondsF() - input_event->timeStampSeconds) * 811 base::Time::kMicrosecondsPerSecond); 812 UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.Renderer", delta, 0, 1000000, 100); 813 base::HistogramBase* counter_for_type = 814 base::Histogram::FactoryGet( 815 base::StringPrintf("Event.Latency.Renderer.%s", event_name), 816 0, 817 1000000, 818 100, 819 base::HistogramBase::kUmaTargetedHistogramFlag); 820 counter_for_type->Add(delta); 821 822 bool prevent_default = false; 823 if (WebInputEvent::isMouseEventType(input_event->type)) { 824 const WebMouseEvent& mouse_event = 825 *static_cast<const WebMouseEvent*>(input_event); 826 TRACE_EVENT2("renderer", "HandleMouseMove", 827 "x", mouse_event.x, "y", mouse_event.y); 828 prevent_default = WillHandleMouseEvent(mouse_event); 829 } 830 831 if (WebInputEvent::isKeyboardEventType(input_event->type)) { 832 const WebKeyboardEvent& key_event = 833 *static_cast<const WebKeyboardEvent*>(input_event); 834 prevent_default = WillHandleKeyEvent(key_event); 835 } 836 837 if (WebInputEvent::isGestureEventType(input_event->type)) { 838 const WebGestureEvent& gesture_event = 839 *static_cast<const WebGestureEvent*>(input_event); 840 prevent_default = prevent_default || WillHandleGestureEvent(gesture_event); 841 } 842 843 if (input_event->type == WebInputEvent::GestureTap || 844 input_event->type == WebInputEvent::GestureLongPress) 845 resetInputMethod(); 846 847 bool processed = prevent_default; 848 if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) { 849 suppress_next_char_events_ = false; 850 if (!processed && webwidget_) 851 processed = webwidget_->handleInputEvent(*input_event); 852 } 853 854 // If this RawKeyDown event corresponds to a browser keyboard shortcut and 855 // it's not processed by webkit, then we need to suppress the upcoming Char 856 // events. 857 if (!processed && is_keyboard_shortcut) 858 suppress_next_char_events_ = true; 859 860 InputEventAckState ack_result = processed ? 861 INPUT_EVENT_ACK_STATE_CONSUMED : INPUT_EVENT_ACK_STATE_NOT_CONSUMED; 862 if (!processed && input_event->type == WebInputEvent::TouchStart) { 863 const WebTouchEvent& touch_event = 864 *static_cast<const WebTouchEvent*>(input_event); 865 ack_result = HasTouchEventHandlersAt(touch_event.touches[0].position) ? 866 INPUT_EVENT_ACK_STATE_NOT_CONSUMED : 867 INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; 868 } 869 870 IPC::Message* response = 871 new InputHostMsg_HandleInputEvent_ACK(routing_id_, 872 input_event->type, 873 ack_result, 874 latency_info); 875 bool event_type_gets_rate_limited = 876 input_event->type == WebInputEvent::MouseMove || 877 input_event->type == WebInputEvent::MouseWheel || 878 WebInputEvent::isTouchEventType(input_event->type); 879 880 bool frame_pending = paint_aggregator_.HasPendingUpdate(); 881 if (is_accelerated_compositing_active_) { 882 frame_pending = compositor_ && 883 compositor_->commitRequested(); 884 } 885 886 if (event_type_gets_rate_limited && frame_pending && !is_hidden_) { 887 // We want to rate limit the input events in this case, so we'll wait for 888 // painting to finish before ACKing this message. 889 if (pending_input_event_ack_) { 890 // As two different kinds of events could cause us to postpone an ack 891 // we send it now, if we have one pending. The Browser should never 892 // send us the same kind of event we are delaying the ack for. 893 Send(pending_input_event_ack_.release()); 894 } 895 pending_input_event_ack_.reset(response); 896 if (compositor_) 897 compositor_->NotifyInputThrottledUntilCommit(); 898 } else { 899 Send(response); 900 } 901 902 #if defined(OS_ANDROID) 903 // Allow the IME to be shown when the focus changes as a consequence 904 // of a processed touch end event. 905 if (input_event->type == WebInputEvent::TouchEnd && processed) 906 UpdateTextInputState(true, true); 907 #endif 908 909 handling_input_event_ = false; 910 911 if (!prevent_default) { 912 if (WebInputEvent::isKeyboardEventType(input_event->type)) 913 DidHandleKeyEvent(); 914 if (WebInputEvent::isMouseEventType(input_event->type)) 915 DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event))); 916 if (WebInputEvent::isTouchEventType(input_event->type)) 917 DidHandleTouchEvent(*(static_cast<const WebTouchEvent*>(input_event))); 918 } 919 } 920 921 void RenderWidget::OnCursorVisibilityChange(bool is_visible) { 922 if (webwidget_) 923 webwidget_->setCursorVisibilityState(is_visible); 924 } 925 926 void RenderWidget::OnMouseCaptureLost() { 927 if (webwidget_) 928 webwidget_->mouseCaptureLost(); 929 } 930 931 void RenderWidget::OnSetFocus(bool enable) { 932 has_focus_ = enable; 933 if (webwidget_) 934 webwidget_->setFocus(enable); 935 } 936 937 void RenderWidget::ClearFocus() { 938 // We may have got the focus from the browser before this gets processed, in 939 // which case we do not want to unfocus ourself. 940 if (!has_focus_ && webwidget_) 941 webwidget_->setFocus(false); 942 } 943 944 void RenderWidget::PaintRect(const gfx::Rect& rect, 945 const gfx::Point& canvas_origin, 946 skia::PlatformCanvas* canvas) { 947 TRACE_EVENT2("renderer", "PaintRect", 948 "width", rect.width(), "height", rect.height()); 949 950 const bool kEnableGpuBenchmarking = 951 CommandLine::ForCurrentProcess()->HasSwitch( 952 switches::kEnableGpuBenchmarking); 953 canvas->save(); 954 955 // Bring the canvas into the coordinate system of the paint rect. 956 canvas->translate(static_cast<SkScalar>(-canvas_origin.x()), 957 static_cast<SkScalar>(-canvas_origin.y())); 958 959 // If there is a custom background, tile it. 960 if (!background_.empty()) { 961 SkPaint paint; 962 skia::RefPtr<SkShader> shader = skia::AdoptRef( 963 SkShader::CreateBitmapShader(background_, 964 SkShader::kRepeat_TileMode, 965 SkShader::kRepeat_TileMode)); 966 paint.setShader(shader.get()); 967 968 // Use kSrc_Mode to handle background_ transparency properly. 969 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 970 971 // Canvas could contain multiple update rects. Clip to given rect so that 972 // we don't accidentally clear other update rects. 973 canvas->save(); 974 canvas->scale(device_scale_factor_, device_scale_factor_); 975 canvas->clipRect(gfx::RectToSkRect(rect)); 976 canvas->drawPaint(paint); 977 canvas->restore(); 978 } 979 980 // First see if this rect is a plugin that can paint itself faster. 981 TransportDIB* optimized_dib = NULL; 982 gfx::Rect optimized_copy_rect, optimized_copy_location; 983 float dib_scale_factor; 984 PepperPluginInstanceImpl* optimized_instance = 985 GetBitmapForOptimizedPluginPaint(rect, &optimized_dib, 986 &optimized_copy_location, 987 &optimized_copy_rect, 988 &dib_scale_factor); 989 if (optimized_instance) { 990 #if defined(ENABLE_PLUGINS) 991 // This plugin can be optimize-painted and we can just ask it to paint 992 // itself. We don't actually need the TransportDIB in this case. 993 // 994 // This is an optimization for PPAPI plugins that know they're on top of 995 // the page content. If this rect is inside such a plugin, we can save some 996 // time and avoid re-rendering the page content which we know will be 997 // covered by the plugin later (this time can be significant, especially 998 // for a playing movie that is invalidating a lot). 999 // 1000 // In the plugin movie case, hopefully the similar call to 1001 // GetBitmapForOptimizedPluginPaint in DoDeferredUpdate handles the 1002 // painting, because that avoids copying the plugin image to a different 1003 // paint rect. Unfortunately, if anything on the page is animating other 1004 // than the movie, it break this optimization since the union of the 1005 // invalid regions will be larger than the plugin. 1006 // 1007 // This code optimizes that case, where we can still avoid painting in 1008 // WebKit and filling the background (which can be slow) and just painting 1009 // the plugin. Unlike the DoDeferredUpdate case, an extra copy is still 1010 // required. 1011 base::TimeTicks paint_begin_ticks; 1012 if (kEnableGpuBenchmarking) 1013 paint_begin_ticks = base::TimeTicks::HighResNow(); 1014 1015 SkAutoCanvasRestore auto_restore(canvas, true); 1016 canvas->scale(device_scale_factor_, device_scale_factor_); 1017 optimized_instance->Paint(canvas, optimized_copy_location, rect); 1018 canvas->restore(); 1019 if (kEnableGpuBenchmarking) { 1020 base::TimeDelta paint_time = 1021 base::TimeTicks::HighResNow() - paint_begin_ticks; 1022 if (!is_accelerated_compositing_active_) 1023 software_stats_.total_paint_time += paint_time; 1024 } 1025 #endif 1026 } else { 1027 // Normal painting case. 1028 base::TimeTicks paint_begin_ticks; 1029 if (kEnableGpuBenchmarking) 1030 paint_begin_ticks = base::TimeTicks::HighResNow(); 1031 1032 webwidget_->paint(canvas, rect); 1033 1034 if (kEnableGpuBenchmarking) { 1035 base::TimeDelta paint_time = 1036 base::TimeTicks::HighResNow() - paint_begin_ticks; 1037 if (!is_accelerated_compositing_active_) 1038 software_stats_.total_paint_time += paint_time; 1039 } 1040 1041 // Flush to underlying bitmap. TODO(darin): is this needed? 1042 skia::GetTopDevice(*canvas)->accessBitmap(false); 1043 } 1044 1045 PaintDebugBorder(rect, canvas); 1046 canvas->restore(); 1047 1048 if (kEnableGpuBenchmarking) { 1049 int64 num_pixels_processed = rect.width() * rect.height(); 1050 software_stats_.total_pixels_painted += num_pixels_processed; 1051 } 1052 } 1053 1054 void RenderWidget::PaintDebugBorder(const gfx::Rect& rect, 1055 skia::PlatformCanvas* canvas) { 1056 static bool kPaintBorder = 1057 CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowPaintRects); 1058 if (!kPaintBorder) 1059 return; 1060 1061 // Cycle through these colors to help distinguish new paint rects. 1062 const SkColor colors[] = { 1063 SkColorSetARGB(0x3F, 0xFF, 0, 0), 1064 SkColorSetARGB(0x3F, 0xFF, 0, 0xFF), 1065 SkColorSetARGB(0x3F, 0, 0, 0xFF), 1066 }; 1067 static int color_selector = 0; 1068 1069 SkPaint paint; 1070 paint.setStyle(SkPaint::kStroke_Style); 1071 paint.setColor(colors[color_selector++ % arraysize(colors)]); 1072 paint.setStrokeWidth(1); 1073 1074 SkIRect irect; 1075 irect.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1); 1076 canvas->drawIRect(irect, paint); 1077 } 1078 1079 void RenderWidget::AnimationCallback() { 1080 TRACE_EVENT0("renderer", "RenderWidget::AnimationCallback"); 1081 if (!animation_update_pending_) { 1082 TRACE_EVENT0("renderer", "EarlyOut_NoAnimationUpdatePending"); 1083 return; 1084 } 1085 if (!animation_floor_time_.is_null() && IsRenderingVSynced()) { 1086 // Record when we fired (according to base::Time::Now()) relative to when 1087 // we posted the task to quantify how much the base::Time/base::TimeTicks 1088 // skew is affecting animations. 1089 base::TimeDelta animation_callback_delay = base::Time::Now() - 1090 (animation_floor_time_ - base::TimeDelta::FromMilliseconds(16)); 1091 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AnimationCallbackDelayTime", 1092 animation_callback_delay, 1093 base::TimeDelta::FromMilliseconds(0), 1094 base::TimeDelta::FromMilliseconds(30), 1095 25); 1096 } 1097 DoDeferredUpdateAndSendInputAck(); 1098 } 1099 1100 void RenderWidget::AnimateIfNeeded() { 1101 if (!animation_update_pending_) 1102 return; 1103 1104 // Target 60FPS if vsync is on. Go as fast as we can if vsync is off. 1105 base::TimeDelta animationInterval = IsRenderingVSynced() ? 1106 base::TimeDelta::FromMilliseconds(16) : base::TimeDelta(); 1107 1108 base::Time now = base::Time::Now(); 1109 1110 // animation_floor_time_ is the earliest time that we should animate when 1111 // using the dead reckoning software scheduler. If we're using swapbuffers 1112 // complete callbacks to rate limit, we can ignore this floor. 1113 if (now >= animation_floor_time_ || num_swapbuffers_complete_pending_ > 0) { 1114 TRACE_EVENT0("renderer", "RenderWidget::AnimateIfNeeded") 1115 animation_floor_time_ = now + animationInterval; 1116 // Set a timer to call us back after animationInterval before 1117 // running animation callbacks so that if a callback requests another 1118 // we'll be sure to run it at the proper time. 1119 animation_timer_.Stop(); 1120 animation_timer_.Start(FROM_HERE, animationInterval, this, 1121 &RenderWidget::AnimationCallback); 1122 animation_update_pending_ = false; 1123 if (is_accelerated_compositing_active_ && compositor_) { 1124 compositor_->Animate(base::TimeTicks::Now()); 1125 } else { 1126 double frame_begin_time = 1127 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); 1128 webwidget_->animate(frame_begin_time); 1129 } 1130 return; 1131 } 1132 TRACE_EVENT0("renderer", "EarlyOut_AnimatedTooRecently"); 1133 if (!animation_timer_.IsRunning()) { 1134 // This code uses base::Time::Now() to calculate the floor and next fire 1135 // time because javascript's Date object uses base::Time::Now(). The 1136 // message loop uses base::TimeTicks, which on windows can have a 1137 // different granularity than base::Time. 1138 // The upshot of all this is that this function might be called before 1139 // base::Time::Now() has advanced past the animation_floor_time_. To 1140 // avoid exposing this delay to javascript, we keep posting delayed 1141 // tasks until base::Time::Now() has advanced far enough. 1142 base::TimeDelta delay = animation_floor_time_ - now; 1143 animation_timer_.Start(FROM_HERE, delay, this, 1144 &RenderWidget::AnimationCallback); 1145 } 1146 } 1147 1148 bool RenderWidget::IsRenderingVSynced() { 1149 // TODO(nduca): Forcing a driver to disable vsync (e.g. in a control panel) is 1150 // not caught by this check. This will lead to artificially low frame rates 1151 // for people who force vsync off at a driver level and expect Chrome to speed 1152 // up. 1153 return !has_disable_gpu_vsync_switch_; 1154 } 1155 1156 void RenderWidget::InvalidationCallback() { 1157 TRACE_EVENT0("renderer", "RenderWidget::InvalidationCallback"); 1158 invalidation_task_posted_ = false; 1159 DoDeferredUpdateAndSendInputAck(); 1160 } 1161 1162 void RenderWidget::DoDeferredUpdateAndSendInputAck() { 1163 DoDeferredUpdate(); 1164 1165 if (pending_input_event_ack_) 1166 Send(pending_input_event_ack_.release()); 1167 } 1168 1169 void RenderWidget::DoDeferredUpdate() { 1170 TRACE_EVENT0("renderer", "RenderWidget::DoDeferredUpdate"); 1171 TRACE_EVENT_SCOPED_SAMPLING_STATE("Chrome", "Paint"); 1172 1173 if (!webwidget_) 1174 return; 1175 1176 if (!init_complete_) { 1177 TRACE_EVENT0("renderer", "EarlyOut_InitNotComplete"); 1178 return; 1179 } 1180 if (update_reply_pending_) { 1181 TRACE_EVENT0("renderer", "EarlyOut_UpdateReplyPending"); 1182 return; 1183 } 1184 if (is_accelerated_compositing_active_ && 1185 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) { 1186 TRACE_EVENT0("renderer", "EarlyOut_MaxSwapBuffersPending"); 1187 return; 1188 } 1189 1190 // Suppress updating when we are hidden. 1191 if (is_hidden_ || size_.IsEmpty() || is_swapped_out_) { 1192 paint_aggregator_.ClearPendingUpdate(); 1193 needs_repainting_on_restore_ = true; 1194 TRACE_EVENT0("renderer", "EarlyOut_NotVisible"); 1195 return; 1196 } 1197 1198 // Tracking of frame rate jitter 1199 base::TimeTicks frame_begin_ticks = base::TimeTicks::Now(); 1200 InstrumentWillBeginFrame(); 1201 AnimateIfNeeded(); 1202 1203 // Layout may generate more invalidation. It may also enable the 1204 // GPU acceleration, so make sure to run layout before we send the 1205 // GpuRenderingActivated message. 1206 webwidget_->layout(); 1207 1208 // Check for whether we need to track swap buffers. We need to do that after 1209 // layout() because it may have switched us to accelerated compositing. 1210 if (is_accelerated_compositing_active_) 1211 using_asynchronous_swapbuffers_ = SupportsAsynchronousSwapBuffers(); 1212 1213 // The following two can result in further layout and possibly 1214 // enable GPU acceleration so they need to be called before any painting 1215 // is done. 1216 UpdateTextInputType(); 1217 UpdateSelectionBounds(); 1218 1219 // Suppress painting if nothing is dirty. This has to be done after updating 1220 // animations running layout as these may generate further invalidations. 1221 if (!paint_aggregator_.HasPendingUpdate()) { 1222 TRACE_EVENT0("renderer", "EarlyOut_NoPendingUpdate"); 1223 InstrumentDidCancelFrame(); 1224 return; 1225 } 1226 1227 if (!is_accelerated_compositing_active_ && 1228 !is_threaded_compositing_enabled_ && 1229 ForceCompositingModeEnabled()) { 1230 webwidget_->enterForceCompositingMode(true); 1231 } 1232 1233 if (!last_do_deferred_update_time_.is_null()) { 1234 base::TimeDelta delay = frame_begin_ticks - last_do_deferred_update_time_; 1235 if (is_accelerated_compositing_active_) { 1236 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.AccelDoDeferredUpdateDelay", 1237 delay, 1238 base::TimeDelta::FromMilliseconds(1), 1239 base::TimeDelta::FromMilliseconds(120), 1240 60); 1241 } else { 1242 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer4.SoftwareDoDeferredUpdateDelay", 1243 delay, 1244 base::TimeDelta::FromMilliseconds(1), 1245 base::TimeDelta::FromMilliseconds(120), 1246 60); 1247 } 1248 1249 // Calculate filtered time per frame: 1250 float frame_time_elapsed = static_cast<float>(delay.InSecondsF()); 1251 filtered_time_per_frame_ = 1252 0.9f * filtered_time_per_frame_ + 0.1f * frame_time_elapsed; 1253 } 1254 last_do_deferred_update_time_ = frame_begin_ticks; 1255 1256 if (!is_accelerated_compositing_active_) { 1257 software_stats_.animation_frame_count++; 1258 software_stats_.screen_frame_count++; 1259 } 1260 1261 // OK, save the pending update to a local since painting may cause more 1262 // invalidation. Some WebCore rendering objects only layout when painted. 1263 PaintAggregator::PendingUpdate update; 1264 paint_aggregator_.PopPendingUpdate(&update); 1265 1266 gfx::Rect scroll_damage = update.GetScrollDamage(); 1267 gfx::Rect bounds = gfx::UnionRects(update.GetPaintBounds(), scroll_damage); 1268 1269 // Notify derived classes that we're about to initiate a paint. 1270 WillInitiatePaint(); 1271 1272 // A plugin may be able to do an optimized paint. First check this, in which 1273 // case we can skip all of the bitmap generation and regular paint code. 1274 // This optimization allows PPAPI plugins that declare themselves on top of 1275 // the page (like a traditional windowed plugin) to be able to animate (think 1276 // movie playing) without repeatedly re-painting the page underneath, or 1277 // copying the plugin backing store (since we can send the plugin's backing 1278 // store directly to the browser). 1279 // 1280 // This optimization only works when the entire invalid region is contained 1281 // within the plugin. There is a related optimization in PaintRect for the 1282 // case where there may be multiple invalid regions. 1283 TransportDIB* dib = NULL; 1284 gfx::Rect optimized_copy_rect, optimized_copy_location; 1285 float dib_scale_factor = 1; 1286 DCHECK(!pending_update_params_.get()); 1287 pending_update_params_.reset(new ViewHostMsg_UpdateRect_Params); 1288 pending_update_params_->scroll_delta = update.scroll_delta; 1289 pending_update_params_->scroll_rect = update.scroll_rect; 1290 pending_update_params_->view_size = size_; 1291 pending_update_params_->plugin_window_moves.swap(plugin_window_moves_); 1292 pending_update_params_->flags = next_paint_flags_; 1293 pending_update_params_->scroll_offset = GetScrollOffset(); 1294 pending_update_params_->needs_ack = true; 1295 pending_update_params_->scale_factor = device_scale_factor_; 1296 next_paint_flags_ = 0; 1297 need_update_rect_for_auto_resize_ = false; 1298 1299 if (!is_accelerated_compositing_active_) 1300 pending_update_params_->latency_info = latency_info_; 1301 1302 latency_info_.Clear(); 1303 1304 if (update.scroll_rect.IsEmpty() && 1305 !is_accelerated_compositing_active_ && 1306 GetBitmapForOptimizedPluginPaint(bounds, &dib, &optimized_copy_location, 1307 &optimized_copy_rect, 1308 &dib_scale_factor)) { 1309 // Only update the part of the plugin that actually changed. 1310 optimized_copy_rect.Intersect(bounds); 1311 pending_update_params_->bitmap = dib->id(); 1312 pending_update_params_->bitmap_rect = optimized_copy_location; 1313 pending_update_params_->copy_rects.push_back(optimized_copy_rect); 1314 pending_update_params_->scale_factor = dib_scale_factor; 1315 } else if (!is_accelerated_compositing_active_) { 1316 // Compute a buffer for painting and cache it. 1317 1318 bool fractional_scale = device_scale_factor_ - 1319 static_cast<int>(device_scale_factor_) != 0; 1320 if (fractional_scale) { 1321 // Damage might not be DIP aligned. Inflate damage to compensate. 1322 bounds.Inset(-1, -1); 1323 bounds.Intersect(gfx::Rect(size_)); 1324 } 1325 1326 gfx::Rect pixel_bounds = gfx::ToEnclosingRect( 1327 gfx::ScaleRect(bounds, device_scale_factor_)); 1328 1329 scoped_ptr<skia::PlatformCanvas> canvas( 1330 RenderProcess::current()->GetDrawingCanvas(¤t_paint_buf_, 1331 pixel_bounds)); 1332 if (!canvas) { 1333 NOTREACHED(); 1334 return; 1335 } 1336 1337 // We may get back a smaller canvas than we asked for. 1338 // TODO(darin): This seems like it could cause painting problems! 1339 DCHECK_EQ(pixel_bounds.width(), canvas->getDevice()->width()); 1340 DCHECK_EQ(pixel_bounds.height(), canvas->getDevice()->height()); 1341 pixel_bounds.set_width(canvas->getDevice()->width()); 1342 pixel_bounds.set_height(canvas->getDevice()->height()); 1343 bounds.set_width(pixel_bounds.width() / device_scale_factor_); 1344 bounds.set_height(pixel_bounds.height() / device_scale_factor_); 1345 1346 HISTOGRAM_COUNTS_100("MPArch.RW_PaintRectCount", update.paint_rects.size()); 1347 1348 pending_update_params_->bitmap = current_paint_buf_->id(); 1349 pending_update_params_->bitmap_rect = bounds; 1350 1351 std::vector<gfx::Rect>& copy_rects = pending_update_params_->copy_rects; 1352 // The scroll damage is just another rectangle to paint and copy. 1353 copy_rects.swap(update.paint_rects); 1354 if (!scroll_damage.IsEmpty()) 1355 copy_rects.push_back(scroll_damage); 1356 1357 for (size_t i = 0; i < copy_rects.size(); ++i) { 1358 gfx::Rect rect = copy_rects[i]; 1359 if (fractional_scale) { 1360 // Damage might not be DPI aligned. Inflate rect to compensate. 1361 rect.Inset(-1, -1); 1362 } 1363 PaintRect(rect, pixel_bounds.origin(), canvas.get()); 1364 } 1365 1366 // Software FPS tick for performance tests. The accelerated path traces the 1367 // frame events in didCommitAndDrawCompositorFrame. See throughput_tests.cc. 1368 // NOTE: Tests may break if this event is renamed or moved. 1369 UNSHIPPED_TRACE_EVENT_INSTANT0("test_fps", "TestFrameTickSW", 1370 TRACE_EVENT_SCOPE_THREAD); 1371 } else { // Accelerated compositing path 1372 // Begin painting. 1373 // If painting is done via the gpu process then we don't set any damage 1374 // rects to save the browser process from doing unecessary work. 1375 pending_update_params_->bitmap_rect = bounds; 1376 pending_update_params_->scroll_rect = gfx::Rect(); 1377 // We don't need an ack, because we're not sharing a DIB with the browser. 1378 // If it needs to (e.g. composited UI), the GPU process does its own ACK 1379 // with the browser for the GPU surface. 1380 pending_update_params_->needs_ack = false; 1381 Composite(frame_begin_ticks); 1382 } 1383 1384 // If we're holding a pending input event ACK, send the ACK before sending the 1385 // UpdateReply message so we can receive another input event before the 1386 // UpdateRect_ACK on platforms where the UpdateRect_ACK is sent from within 1387 // the UpdateRect IPC message handler. 1388 if (pending_input_event_ack_) 1389 Send(pending_input_event_ack_.release()); 1390 1391 // If Composite() called SwapBuffers, pending_update_params_ will be reset (in 1392 // OnSwapBuffersPosted), meaning a message has been added to the 1393 // updates_pending_swap_ queue, that will be sent later. Otherwise, we send 1394 // the message now. 1395 if (pending_update_params_) { 1396 // sending an ack to browser process that the paint is complete... 1397 update_reply_pending_ = pending_update_params_->needs_ack; 1398 Send(new ViewHostMsg_UpdateRect(routing_id_, *pending_update_params_)); 1399 pending_update_params_.reset(); 1400 } 1401 1402 // If we're software rendering then we're done initiating the paint. 1403 if (!is_accelerated_compositing_active_) 1404 DidInitiatePaint(); 1405 } 1406 1407 void RenderWidget::Composite(base::TimeTicks frame_begin_time) { 1408 DCHECK(is_accelerated_compositing_active_); 1409 if (compositor_) // TODO(jamesr): Figure out how this can be null. 1410 compositor_->Composite(frame_begin_time); 1411 } 1412 1413 /////////////////////////////////////////////////////////////////////////////// 1414 // WebWidgetClient 1415 1416 void RenderWidget::didInvalidateRect(const WebRect& rect) { 1417 // The invalidated rect might be outside the bounds of the view. 1418 gfx::Rect view_rect(size_); 1419 gfx::Rect damaged_rect = gfx::IntersectRects(view_rect, rect); 1420 if (damaged_rect.IsEmpty()) 1421 return; 1422 1423 paint_aggregator_.InvalidateRect(damaged_rect); 1424 1425 // We may not need to schedule another call to DoDeferredUpdate. 1426 if (invalidation_task_posted_) 1427 return; 1428 if (!paint_aggregator_.HasPendingUpdate()) 1429 return; 1430 if (update_reply_pending_ || 1431 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) 1432 return; 1433 1434 // When GPU rendering, combine pending animations and invalidations into 1435 // a single update. 1436 if (is_accelerated_compositing_active_ && 1437 animation_update_pending_ && 1438 animation_timer_.IsRunning()) 1439 return; 1440 1441 // Perform updating asynchronously. This serves two purposes: 1442 // 1) Ensures that we call WebView::Paint without a bunch of other junk 1443 // on the call stack. 1444 // 2) Allows us to collect more damage rects before painting to help coalesce 1445 // the work that we will need to do. 1446 invalidation_task_posted_ = true; 1447 base::MessageLoop::current()->PostTask( 1448 FROM_HERE, base::Bind(&RenderWidget::InvalidationCallback, this)); 1449 } 1450 1451 void RenderWidget::didScrollRect(int dx, int dy, 1452 const WebRect& clip_rect) { 1453 // Drop scrolls on the floor when we are in compositing mode. 1454 // TODO(nduca): stop WebViewImpl from sending scrolls in the first place. 1455 if (is_accelerated_compositing_active_) 1456 return; 1457 1458 // The scrolled rect might be outside the bounds of the view. 1459 gfx::Rect view_rect(size_); 1460 gfx::Rect damaged_rect = gfx::IntersectRects(view_rect, clip_rect); 1461 if (damaged_rect.IsEmpty()) 1462 return; 1463 1464 paint_aggregator_.ScrollRect(gfx::Vector2d(dx, dy), damaged_rect); 1465 1466 // We may not need to schedule another call to DoDeferredUpdate. 1467 if (invalidation_task_posted_) 1468 return; 1469 if (!paint_aggregator_.HasPendingUpdate()) 1470 return; 1471 if (update_reply_pending_ || 1472 num_swapbuffers_complete_pending_ >= kMaxSwapBuffersPending) 1473 return; 1474 1475 // When GPU rendering, combine pending animations and invalidations into 1476 // a single update. 1477 if (is_accelerated_compositing_active_ && 1478 animation_update_pending_ && 1479 animation_timer_.IsRunning()) 1480 return; 1481 1482 // Perform updating asynchronously. This serves two purposes: 1483 // 1) Ensures that we call WebView::Paint without a bunch of other junk 1484 // on the call stack. 1485 // 2) Allows us to collect more damage rects before painting to help coalesce 1486 // the work that we will need to do. 1487 invalidation_task_posted_ = true; 1488 base::MessageLoop::current()->PostTask( 1489 FROM_HERE, base::Bind(&RenderWidget::InvalidationCallback, this)); 1490 } 1491 1492 void RenderWidget::didAutoResize(const WebSize& new_size) { 1493 if (size_.width() != new_size.width || size_.height() != new_size.height) { 1494 size_ = new_size; 1495 1496 // If we don't clear PaintAggregator after changing autoResize state, then 1497 // we might end up in a situation where bitmap_rect is larger than the 1498 // view_size. By clearing PaintAggregator, we ensure that we don't end up 1499 // with invalid damage rects. 1500 paint_aggregator_.ClearPendingUpdate(); 1501 1502 if (RenderThreadImpl::current()->layout_test_mode()) { 1503 WebRect new_pos(rootWindowRect().x, 1504 rootWindowRect().y, 1505 new_size.width, 1506 new_size.height); 1507 view_screen_rect_ = new_pos; 1508 window_screen_rect_ = new_pos; 1509 } 1510 1511 AutoResizeCompositor(); 1512 1513 if (!RenderThreadImpl::current()->layout_test_mode()) 1514 need_update_rect_for_auto_resize_ = true; 1515 } 1516 } 1517 1518 void RenderWidget::AutoResizeCompositor() { 1519 physical_backing_size_ = gfx::ToCeiledSize(gfx::ScaleSize(size_, 1520 device_scale_factor_)); 1521 if (compositor_) 1522 compositor_->setViewportSize(size_, physical_backing_size_); 1523 } 1524 1525 void RenderWidget::didActivateCompositor(int input_handler_identifier) { 1526 TRACE_EVENT0("gpu", "RenderWidget::didActivateCompositor"); 1527 1528 #if !defined(OS_MACOSX) 1529 if (!is_accelerated_compositing_active_) { 1530 // When not in accelerated compositing mode, in certain cases (e.g. waiting 1531 // for a resize or if no backing store) the RenderWidgetHost is blocking the 1532 // browser's UI thread for some time, waiting for an UpdateRect. If we are 1533 // going to switch to accelerated compositing, the GPU process may need 1534 // round-trips to the browser's UI thread before finishing the frame, 1535 // causing deadlocks if we delay the UpdateRect until we receive the 1536 // OnSwapBuffersComplete. So send a dummy message that will unblock the 1537 // browser's UI thread. This is not necessary on Mac, because SwapBuffers 1538 // now unblocks GetBackingStore on Mac. 1539 Send(new ViewHostMsg_UpdateIsDelayed(routing_id_)); 1540 } 1541 #endif 1542 1543 is_accelerated_compositing_active_ = true; 1544 Send(new ViewHostMsg_DidActivateAcceleratedCompositing( 1545 routing_id_, is_accelerated_compositing_active_)); 1546 } 1547 1548 void RenderWidget::didDeactivateCompositor() { 1549 TRACE_EVENT0("gpu", "RenderWidget::didDeactivateCompositor"); 1550 1551 is_accelerated_compositing_active_ = false; 1552 Send(new ViewHostMsg_DidActivateAcceleratedCompositing( 1553 routing_id_, is_accelerated_compositing_active_)); 1554 1555 if (using_asynchronous_swapbuffers_) 1556 using_asynchronous_swapbuffers_ = false; 1557 1558 // In single-threaded mode, we exit force compositing mode and re-enter in 1559 // DoDeferredUpdate() if appropriate. In threaded compositing mode, 1560 // DoDeferredUpdate() is bypassed and WebKit is responsible for exiting and 1561 // entering force compositing mode at the appropriate times. 1562 if (!is_threaded_compositing_enabled_) 1563 webwidget_->enterForceCompositingMode(false); 1564 } 1565 1566 void RenderWidget::initializeLayerTreeView() { 1567 compositor_ = RenderWidgetCompositor::Create( 1568 this, is_threaded_compositing_enabled_); 1569 if (!compositor_) 1570 return; 1571 1572 compositor_->setViewportSize(size_, physical_backing_size_); 1573 if (init_complete_) 1574 compositor_->setSurfaceReady(); 1575 } 1576 1577 WebKit::WebLayerTreeView* RenderWidget::layerTreeView() { 1578 return compositor_.get(); 1579 } 1580 1581 void RenderWidget::suppressCompositorScheduling(bool enable) { 1582 if (compositor_) 1583 compositor_->SetSuppressScheduleComposite(enable); 1584 } 1585 1586 void RenderWidget::willBeginCompositorFrame() { 1587 TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame"); 1588 1589 DCHECK(RenderThreadImpl::current()->compositor_message_loop_proxy().get()); 1590 1591 // The following two can result in further layout and possibly 1592 // enable GPU acceleration so they need to be called before any painting 1593 // is done. 1594 UpdateTextInputType(); 1595 #if defined(OS_ANDROID) 1596 UpdateTextInputState(false, true); 1597 #endif 1598 UpdateSelectionBounds(); 1599 1600 WillInitiatePaint(); 1601 } 1602 1603 void RenderWidget::didBecomeReadyForAdditionalInput() { 1604 TRACE_EVENT0("renderer", "RenderWidget::didBecomeReadyForAdditionalInput"); 1605 if (pending_input_event_ack_) 1606 Send(pending_input_event_ack_.release()); 1607 } 1608 1609 void RenderWidget::DidCommitCompositorFrame() { 1610 } 1611 1612 void RenderWidget::didCommitAndDrawCompositorFrame() { 1613 TRACE_EVENT0("gpu", "RenderWidget::didCommitAndDrawCompositorFrame"); 1614 // Accelerated FPS tick for performance tests. See throughput_tests.cc. 1615 // NOTE: Tests may break if this event is renamed or moved. 1616 UNSHIPPED_TRACE_EVENT_INSTANT0("test_fps", "TestFrameTickGPU", 1617 TRACE_EVENT_SCOPE_THREAD); 1618 // Notify subclasses that we initiated the paint operation. 1619 DidInitiatePaint(); 1620 } 1621 1622 void RenderWidget::didCompleteSwapBuffers() { 1623 TRACE_EVENT0("renderer", "RenderWidget::didCompleteSwapBuffers"); 1624 1625 // Notify subclasses threaded composited rendering was flushed to the screen. 1626 DidFlushPaint(); 1627 1628 if (update_reply_pending_) 1629 return; 1630 1631 if (!next_paint_flags_ && 1632 !need_update_rect_for_auto_resize_ && 1633 !plugin_window_moves_.size()) { 1634 return; 1635 } 1636 1637 ViewHostMsg_UpdateRect_Params params; 1638 params.view_size = size_; 1639 params.plugin_window_moves.swap(plugin_window_moves_); 1640 params.flags = next_paint_flags_; 1641 params.scroll_offset = GetScrollOffset(); 1642 params.needs_ack = false; 1643 params.scale_factor = device_scale_factor_; 1644 1645 Send(new ViewHostMsg_UpdateRect(routing_id_, params)); 1646 next_paint_flags_ = 0; 1647 need_update_rect_for_auto_resize_ = false; 1648 } 1649 1650 void RenderWidget::scheduleComposite() { 1651 if (RenderThreadImpl::current()->compositor_message_loop_proxy().get() && 1652 compositor_) { 1653 compositor_->setNeedsRedraw(); 1654 } else { 1655 // TODO(nduca): replace with something a little less hacky. The reason this 1656 // hack is still used is because the Invalidate-DoDeferredUpdate loop 1657 // contains a lot of host-renderer synchronization logic that is still 1658 // important for the accelerated compositing case. The option of simply 1659 // duplicating all that code is less desirable than "faking out" the 1660 // invalidation path using a magical damage rect. 1661 didInvalidateRect(WebRect(0, 0, 1, 1)); 1662 } 1663 } 1664 1665 void RenderWidget::scheduleAnimation() { 1666 if (animation_update_pending_) 1667 return; 1668 1669 TRACE_EVENT0("gpu", "RenderWidget::scheduleAnimation"); 1670 animation_update_pending_ = true; 1671 if (!animation_timer_.IsRunning()) { 1672 animation_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(0), this, 1673 &RenderWidget::AnimationCallback); 1674 } 1675 } 1676 1677 void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) { 1678 // TODO(darin): Eliminate this temporary. 1679 WebCursor cursor; 1680 InitializeCursorFromWebKitCursorInfo(&cursor, cursor_info); 1681 // Only send a SetCursor message if we need to make a change. 1682 if (!current_cursor_.IsEqual(cursor)) { 1683 current_cursor_ = cursor; 1684 Send(new ViewHostMsg_SetCursor(routing_id_, cursor)); 1685 } 1686 } 1687 1688 // We are supposed to get a single call to Show for a newly created RenderWidget 1689 // that was created via RenderWidget::CreateWebView. So, we wait until this 1690 // point to dispatch the ShowWidget message. 1691 // 1692 // This method provides us with the information about how to display the newly 1693 // created RenderWidget (i.e., as a blocked popup or as a new tab). 1694 // 1695 void RenderWidget::show(WebNavigationPolicy) { 1696 DCHECK(!did_show_) << "received extraneous Show call"; 1697 DCHECK(routing_id_ != MSG_ROUTING_NONE); 1698 DCHECK(opener_id_ != MSG_ROUTING_NONE); 1699 1700 if (did_show_) 1701 return; 1702 1703 did_show_ = true; 1704 // NOTE: initial_pos_ may still have its default values at this point, but 1705 // that's okay. It'll be ignored if as_popup is false, or the browser 1706 // process will impose a default position otherwise. 1707 Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_)); 1708 SetPendingWindowRect(initial_pos_); 1709 } 1710 1711 void RenderWidget::didProgrammaticallyScroll( 1712 const WebKit::WebPoint& scroll_point) { 1713 if (!compositor_) 1714 return; 1715 Send(new ViewHostMsg_DidProgrammaticallyScroll( 1716 routing_id_, gfx::Vector2d(scroll_point.x, scroll_point.y))); 1717 } 1718 1719 void RenderWidget::didFocus() { 1720 } 1721 1722 void RenderWidget::didBlur() { 1723 } 1724 1725 void RenderWidget::DoDeferredClose() { 1726 Send(new ViewHostMsg_Close(routing_id_)); 1727 } 1728 1729 void RenderWidget::closeWidgetSoon() { 1730 if (is_swapped_out_) { 1731 // This widget is currently swapped out, and the active widget is in a 1732 // different process. Have the browser route the close request to the 1733 // active widget instead, so that the correct unload handlers are run. 1734 Send(new ViewHostMsg_RouteCloseEvent(routing_id_)); 1735 return; 1736 } 1737 1738 // If a page calls window.close() twice, we'll end up here twice, but that's 1739 // OK. It is safe to send multiple Close messages. 1740 1741 // Ask the RenderWidgetHost to initiate close. We could be called from deep 1742 // in Javascript. If we ask the RendwerWidgetHost to close now, the window 1743 // could be closed before the JS finishes executing. So instead, post a 1744 // message back to the message loop, which won't run until the JS is 1745 // complete, and then the Close message can be sent. 1746 base::MessageLoop::current()->PostTask( 1747 FROM_HERE, base::Bind(&RenderWidget::DoDeferredClose, this)); 1748 } 1749 1750 void RenderWidget::Close() { 1751 if (webwidget_) { 1752 webwidget_->willCloseLayerTreeView(); 1753 compositor_.reset(); 1754 webwidget_->close(); 1755 webwidget_ = NULL; 1756 } 1757 } 1758 1759 WebRect RenderWidget::windowRect() { 1760 if (pending_window_rect_count_) 1761 return pending_window_rect_; 1762 1763 return view_screen_rect_; 1764 } 1765 1766 void RenderWidget::setToolTipText(const WebKit::WebString& text, 1767 WebTextDirection hint) { 1768 Send(new ViewHostMsg_SetTooltipText(routing_id_, text, hint)); 1769 } 1770 1771 void RenderWidget::setWindowRect(const WebRect& pos) { 1772 if (did_show_) { 1773 if (!RenderThreadImpl::current()->layout_test_mode()) { 1774 Send(new ViewHostMsg_RequestMove(routing_id_, pos)); 1775 SetPendingWindowRect(pos); 1776 } else { 1777 WebSize new_size(pos.width, pos.height); 1778 Resize(new_size, new_size, overdraw_bottom_height_, 1779 WebRect(), is_fullscreen_, NO_RESIZE_ACK); 1780 view_screen_rect_ = pos; 1781 window_screen_rect_ = pos; 1782 } 1783 } else { 1784 initial_pos_ = pos; 1785 } 1786 } 1787 1788 void RenderWidget::SetPendingWindowRect(const WebRect& rect) { 1789 pending_window_rect_ = rect; 1790 pending_window_rect_count_++; 1791 } 1792 1793 WebRect RenderWidget::rootWindowRect() { 1794 if (pending_window_rect_count_) { 1795 // NOTE(mbelshe): If there is a pending_window_rect_, then getting 1796 // the RootWindowRect is probably going to return wrong results since the 1797 // browser may not have processed the Move yet. There isn't really anything 1798 // good to do in this case, and it shouldn't happen - since this size is 1799 // only really needed for windowToScreen, which is only used for Popups. 1800 return pending_window_rect_; 1801 } 1802 1803 return window_screen_rect_; 1804 } 1805 1806 WebRect RenderWidget::windowResizerRect() { 1807 return resizer_rect_; 1808 } 1809 1810 void RenderWidget::OnSetInputMethodActive(bool is_active) { 1811 // To prevent this renderer process from sending unnecessary IPC messages to 1812 // a browser process, we permit the renderer process to send IPC messages 1813 // only during the input method attached to the browser process is active. 1814 input_method_is_active_ = is_active; 1815 } 1816 1817 void RenderWidget::OnImeSetComposition( 1818 const string16& text, 1819 const std::vector<WebCompositionUnderline>& underlines, 1820 int selection_start, int selection_end) { 1821 if (!ShouldHandleImeEvent()) 1822 return; 1823 ImeEventGuard guard(this); 1824 if (!webwidget_->setComposition( 1825 text, WebVector<WebCompositionUnderline>(underlines), 1826 selection_start, selection_end)) { 1827 // If we failed to set the composition text, then we need to let the browser 1828 // process to cancel the input method's ongoing composition session, to make 1829 // sure we are in a consistent state. 1830 Send(new ViewHostMsg_ImeCancelComposition(routing_id())); 1831 } 1832 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA) 1833 UpdateCompositionInfo(true); 1834 #endif 1835 } 1836 1837 void RenderWidget::OnImeConfirmComposition(const string16& text, 1838 const ui::Range& replacement_range, 1839 bool keep_selection) { 1840 if (!ShouldHandleImeEvent()) 1841 return; 1842 ImeEventGuard guard(this); 1843 handling_input_event_ = true; 1844 if (text.length()) 1845 webwidget_->confirmComposition(text); 1846 else if (keep_selection) 1847 webwidget_->confirmComposition(WebWidget::KeepSelection); 1848 else 1849 webwidget_->confirmComposition(WebWidget::DoNotKeepSelection); 1850 handling_input_event_ = false; 1851 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA) 1852 UpdateCompositionInfo(true); 1853 #endif 1854 } 1855 1856 // This message causes the renderer to render an image of the 1857 // desired_size, regardless of whether the tab is hidden or not. 1858 void RenderWidget::OnPaintAtSize(const TransportDIB::Handle& dib_handle, 1859 int tag, 1860 const gfx::Size& page_size, 1861 const gfx::Size& desired_size) { 1862 if (!webwidget_ || !TransportDIB::is_valid_handle(dib_handle)) { 1863 if (TransportDIB::is_valid_handle(dib_handle)) { 1864 // Close our unused handle. 1865 #if defined(OS_WIN) 1866 ::CloseHandle(dib_handle); 1867 #elif defined(OS_MACOSX) 1868 base::SharedMemory::CloseHandle(dib_handle); 1869 #endif 1870 } 1871 return; 1872 } 1873 1874 if (page_size.IsEmpty() || desired_size.IsEmpty()) { 1875 // If one of these is empty, then we just return the dib we were 1876 // given, to avoid leaking it. 1877 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, desired_size)); 1878 return; 1879 } 1880 1881 // Map the given DIB ID into this process, and unmap it at the end 1882 // of this function. 1883 scoped_ptr<TransportDIB> paint_at_size_buffer( 1884 TransportDIB::CreateWithHandle(dib_handle)); 1885 1886 gfx::Size page_size_in_pixel = gfx::ToFlooredSize( 1887 gfx::ScaleSize(page_size, device_scale_factor_)); 1888 gfx::Size desired_size_in_pixel = gfx::ToFlooredSize( 1889 gfx::ScaleSize(desired_size, device_scale_factor_)); 1890 gfx::Size canvas_size = page_size_in_pixel; 1891 float x_scale = static_cast<float>(desired_size_in_pixel.width()) / 1892 static_cast<float>(canvas_size.width()); 1893 float y_scale = static_cast<float>(desired_size_in_pixel.height()) / 1894 static_cast<float>(canvas_size.height()); 1895 1896 gfx::Rect orig_bounds(canvas_size); 1897 canvas_size.set_width(static_cast<int>(canvas_size.width() * x_scale)); 1898 canvas_size.set_height(static_cast<int>(canvas_size.height() * y_scale)); 1899 gfx::Rect bounds(canvas_size); 1900 1901 scoped_ptr<skia::PlatformCanvas> canvas( 1902 paint_at_size_buffer->GetPlatformCanvas(canvas_size.width(), 1903 canvas_size.height())); 1904 if (!canvas) { 1905 NOTREACHED(); 1906 return; 1907 } 1908 1909 // Reset bounds to what we actually received, but they should be the 1910 // same. 1911 DCHECK_EQ(bounds.width(), canvas->getDevice()->width()); 1912 DCHECK_EQ(bounds.height(), canvas->getDevice()->height()); 1913 bounds.set_width(canvas->getDevice()->width()); 1914 bounds.set_height(canvas->getDevice()->height()); 1915 1916 canvas->save(); 1917 // Add the scale factor to the canvas, so that we'll get the desired size. 1918 canvas->scale(SkFloatToScalar(x_scale), SkFloatToScalar(y_scale)); 1919 1920 // Have to make sure we're laid out at the right size before 1921 // rendering. 1922 gfx::Size old_size = webwidget_->size(); 1923 webwidget_->resize(page_size); 1924 webwidget_->layout(); 1925 1926 // Paint the entire thing (using original bounds, not scaled bounds). 1927 PaintRect(orig_bounds, orig_bounds.origin(), canvas.get()); 1928 canvas->restore(); 1929 1930 // Return the widget to its previous size. 1931 webwidget_->resize(old_size); 1932 1933 Send(new ViewHostMsg_PaintAtSize_ACK(routing_id_, tag, bounds.size())); 1934 } 1935 1936 void RenderWidget::OnSnapshot(const gfx::Rect& src_subrect) { 1937 SkBitmap snapshot; 1938 1939 if (OnSnapshotHelper(src_subrect, &snapshot)) { 1940 Send(new ViewHostMsg_Snapshot(routing_id(), true, snapshot)); 1941 } else { 1942 Send(new ViewHostMsg_Snapshot(routing_id(), false, SkBitmap())); 1943 } 1944 } 1945 1946 bool RenderWidget::OnSnapshotHelper(const gfx::Rect& src_subrect, 1947 SkBitmap* snapshot) { 1948 base::TimeTicks beginning_time = base::TimeTicks::Now(); 1949 1950 if (!webwidget_ || src_subrect.IsEmpty()) 1951 return false; 1952 1953 gfx::Rect viewport_size = gfx::IntersectRects( 1954 src_subrect, gfx::Rect(physical_backing_size_)); 1955 1956 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef( 1957 skia::CreatePlatformCanvas(viewport_size.width(), 1958 viewport_size.height(), 1959 true, 1960 NULL, 1961 skia::RETURN_NULL_ON_FAILURE)); 1962 if (!canvas) 1963 return false; 1964 1965 canvas->save(); 1966 webwidget_->layout(); 1967 1968 PaintRect(viewport_size, viewport_size.origin(), canvas.get()); 1969 canvas->restore(); 1970 1971 const SkBitmap& bitmap = skia::GetTopDevice(*canvas)->accessBitmap(false); 1972 if (!bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config)) 1973 return false; 1974 1975 UMA_HISTOGRAM_TIMES("Renderer4.Snapshot", 1976 base::TimeTicks::Now() - beginning_time); 1977 return true; 1978 } 1979 1980 void RenderWidget::OnRepaint(gfx::Size size_to_paint) { 1981 // During shutdown we can just ignore this message. 1982 if (!webwidget_) 1983 return; 1984 1985 // Even if the browser provides an empty damage rect, it's still expecting to 1986 // receive a repaint ack so just damage the entire widget bounds. 1987 if (size_to_paint.IsEmpty()) { 1988 size_to_paint = size_; 1989 } 1990 1991 set_next_paint_is_repaint_ack(); 1992 if (is_accelerated_compositing_active_ && compositor_) { 1993 compositor_->SetNeedsRedrawRect(gfx::Rect(size_to_paint)); 1994 } else { 1995 gfx::Rect repaint_rect(size_to_paint.width(), size_to_paint.height()); 1996 didInvalidateRect(repaint_rect); 1997 } 1998 } 1999 2000 void RenderWidget::OnSmoothScrollCompleted() { 2001 pending_smooth_scroll_gesture_.Run(); 2002 } 2003 2004 void RenderWidget::OnSetTextDirection(WebTextDirection direction) { 2005 if (!webwidget_) 2006 return; 2007 webwidget_->setTextDirection(direction); 2008 } 2009 2010 void RenderWidget::OnUpdateScreenRects(const gfx::Rect& view_screen_rect, 2011 const gfx::Rect& window_screen_rect) { 2012 view_screen_rect_ = view_screen_rect; 2013 window_screen_rect_ = window_screen_rect; 2014 Send(new ViewHostMsg_UpdateScreenRects_ACK(routing_id())); 2015 } 2016 2017 #if defined(OS_ANDROID) 2018 void RenderWidget::OnImeBatchStateChanged(bool is_begin) { 2019 Send(new ViewHostMsg_ImeBatchStateChanged_ACK(routing_id(), is_begin)); 2020 } 2021 2022 void RenderWidget::OnShowImeIfNeeded() { 2023 UpdateTextInputState(true, true); 2024 } 2025 2026 void RenderWidget::IncrementOutstandingImeEventAcks() { 2027 ++outstanding_ime_acks_; 2028 } 2029 2030 void RenderWidget::OnImeEventAck() { 2031 --outstanding_ime_acks_; 2032 DCHECK(outstanding_ime_acks_ >= 0); 2033 } 2034 #endif 2035 2036 bool RenderWidget::ShouldHandleImeEvent() { 2037 #if defined(OS_ANDROID) 2038 return !!webwidget_ && outstanding_ime_acks_ == 0; 2039 #else 2040 return !!webwidget_; 2041 #endif 2042 } 2043 2044 void RenderWidget::SetDeviceScaleFactor(float device_scale_factor) { 2045 if (device_scale_factor_ == device_scale_factor) 2046 return; 2047 2048 device_scale_factor_ = device_scale_factor; 2049 2050 if (!is_accelerated_compositing_active_) { 2051 didInvalidateRect(gfx::Rect(size_.width(), size_.height())); 2052 } else { 2053 scheduleComposite(); 2054 } 2055 } 2056 2057 PepperPluginInstanceImpl* RenderWidget::GetBitmapForOptimizedPluginPaint( 2058 const gfx::Rect& paint_bounds, 2059 TransportDIB** dib, 2060 gfx::Rect* location, 2061 gfx::Rect* clip, 2062 float* scale_factor) { 2063 // Bare RenderWidgets don't support optimized plugin painting. 2064 return NULL; 2065 } 2066 2067 gfx::Vector2d RenderWidget::GetScrollOffset() { 2068 // Bare RenderWidgets don't support scroll offset. 2069 return gfx::Vector2d(); 2070 } 2071 2072 void RenderWidget::SetHidden(bool hidden) { 2073 if (is_hidden_ == hidden) 2074 return; 2075 2076 // The status has changed. Tell the RenderThread about it. 2077 is_hidden_ = hidden; 2078 if (is_hidden_) 2079 RenderThread::Get()->WidgetHidden(); 2080 else 2081 RenderThread::Get()->WidgetRestored(); 2082 } 2083 2084 void RenderWidget::WillToggleFullscreen() { 2085 if (!webwidget_) 2086 return; 2087 2088 if (is_fullscreen_) { 2089 webwidget_->willExitFullScreen(); 2090 } else { 2091 webwidget_->willEnterFullScreen(); 2092 } 2093 } 2094 2095 void RenderWidget::DidToggleFullscreen() { 2096 if (!webwidget_) 2097 return; 2098 2099 if (is_fullscreen_) { 2100 webwidget_->didEnterFullScreen(); 2101 } else { 2102 webwidget_->didExitFullScreen(); 2103 } 2104 } 2105 2106 void RenderWidget::SetBackground(const SkBitmap& background) { 2107 background_ = background; 2108 2109 // Generate a full repaint. 2110 didInvalidateRect(gfx::Rect(size_.width(), size_.height())); 2111 } 2112 2113 bool RenderWidget::next_paint_is_resize_ack() const { 2114 return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_); 2115 } 2116 2117 bool RenderWidget::next_paint_is_restore_ack() const { 2118 return ViewHostMsg_UpdateRect_Flags::is_restore_ack(next_paint_flags_); 2119 } 2120 2121 void RenderWidget::set_next_paint_is_resize_ack() { 2122 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK; 2123 } 2124 2125 void RenderWidget::set_next_paint_is_restore_ack() { 2126 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESTORE_ACK; 2127 } 2128 2129 void RenderWidget::set_next_paint_is_repaint_ack() { 2130 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK; 2131 } 2132 2133 static bool IsDateTimeInput(ui::TextInputType type) { 2134 return type == ui::TEXT_INPUT_TYPE_DATE || 2135 type == ui::TEXT_INPUT_TYPE_DATE_TIME || 2136 type == ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL || 2137 type == ui::TEXT_INPUT_TYPE_MONTH || 2138 type == ui::TEXT_INPUT_TYPE_TIME || 2139 type == ui::TEXT_INPUT_TYPE_WEEK; 2140 } 2141 2142 2143 void RenderWidget::StartHandlingImeEvent() { 2144 DCHECK(!handling_ime_event_); 2145 handling_ime_event_ = true; 2146 } 2147 2148 void RenderWidget::FinishHandlingImeEvent() { 2149 DCHECK(handling_ime_event_); 2150 handling_ime_event_ = false; 2151 // While handling an ime event, text input state and selection bounds updates 2152 // are ignored. These must explicitly be updated once finished handling the 2153 // ime event. 2154 UpdateSelectionBounds(); 2155 #if defined(OS_ANDROID) 2156 UpdateTextInputState(false, false); 2157 #endif 2158 } 2159 2160 void RenderWidget::UpdateTextInputType() { 2161 if (!input_method_is_active_) 2162 return; 2163 2164 ui::TextInputType new_type = GetTextInputType(); 2165 if (IsDateTimeInput(new_type)) 2166 return; // Not considered as a text input field in WebKit/Chromium. 2167 2168 bool new_can_compose_inline = CanComposeInline(); 2169 2170 WebKit::WebTextInputInfo new_info; 2171 if (webwidget_) 2172 new_info = webwidget_->textInputInfo(); 2173 const ui::TextInputMode new_mode = ConvertInputMode(new_info.inputMode); 2174 2175 if (text_input_type_ != new_type 2176 || can_compose_inline_ != new_can_compose_inline 2177 || text_input_mode_ != new_mode) { 2178 Send(new ViewHostMsg_TextInputTypeChanged(routing_id(), 2179 new_type, 2180 new_can_compose_inline, 2181 new_mode)); 2182 text_input_type_ = new_type; 2183 can_compose_inline_ = new_can_compose_inline; 2184 text_input_mode_ = new_mode; 2185 } 2186 } 2187 2188 #if defined(OS_ANDROID) 2189 void RenderWidget::UpdateTextInputState(bool show_ime_if_needed, 2190 bool send_ime_ack) { 2191 if (handling_ime_event_) 2192 return; 2193 if (!show_ime_if_needed && !input_method_is_active_) 2194 return; 2195 ui::TextInputType new_type = GetTextInputType(); 2196 if (IsDateTimeInput(new_type)) 2197 return; // Not considered as a text input field in WebKit/Chromium. 2198 2199 WebKit::WebTextInputInfo new_info; 2200 if (webwidget_) 2201 new_info = webwidget_->textInputInfo(); 2202 2203 bool new_can_compose_inline = CanComposeInline(); 2204 2205 // Only sends text input params if they are changed or if the ime should be 2206 // shown. 2207 if (show_ime_if_needed || (text_input_type_ != new_type 2208 || text_input_info_ != new_info 2209 || can_compose_inline_ != new_can_compose_inline)) { 2210 ViewHostMsg_TextInputState_Params p; 2211 p.type = new_type; 2212 p.value = new_info.value.utf8(); 2213 p.selection_start = new_info.selectionStart; 2214 p.selection_end = new_info.selectionEnd; 2215 p.composition_start = new_info.compositionStart; 2216 p.composition_end = new_info.compositionEnd; 2217 p.can_compose_inline = new_can_compose_inline; 2218 p.show_ime_if_needed = show_ime_if_needed; 2219 p.require_ack = send_ime_ack; 2220 if (p.require_ack) 2221 IncrementOutstandingImeEventAcks(); 2222 Send(new ViewHostMsg_TextInputStateChanged(routing_id(), p)); 2223 2224 text_input_info_ = new_info; 2225 text_input_type_ = new_type; 2226 can_compose_inline_ = new_can_compose_inline; 2227 } 2228 } 2229 #endif 2230 2231 void RenderWidget::GetSelectionBounds(gfx::Rect* focus, gfx::Rect* anchor) { 2232 WebRect focus_webrect; 2233 WebRect anchor_webrect; 2234 webwidget_->selectionBounds(focus_webrect, anchor_webrect); 2235 *focus = focus_webrect; 2236 *anchor = anchor_webrect; 2237 } 2238 2239 void RenderWidget::UpdateSelectionBounds() { 2240 if (!webwidget_) 2241 return; 2242 if (handling_ime_event_) 2243 return; 2244 2245 ViewHostMsg_SelectionBounds_Params params; 2246 GetSelectionBounds(¶ms.anchor_rect, ¶ms.focus_rect); 2247 if (selection_anchor_rect_ != params.anchor_rect || 2248 selection_focus_rect_ != params.focus_rect) { 2249 selection_anchor_rect_ = params.anchor_rect; 2250 selection_focus_rect_ = params.focus_rect; 2251 webwidget_->selectionTextDirection(params.focus_dir, params.anchor_dir); 2252 params.is_anchor_first = webwidget_->isSelectionAnchorFirst(); 2253 Send(new ViewHostMsg_SelectionBoundsChanged(routing_id_, params)); 2254 } 2255 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA) 2256 UpdateCompositionInfo(false); 2257 #endif 2258 } 2259 2260 // Check WebKit::WebTextInputType and ui::TextInputType is kept in sync. 2261 COMPILE_ASSERT(int(WebKit::WebTextInputTypeNone) == \ 2262 int(ui::TEXT_INPUT_TYPE_NONE), mismatching_enums); 2263 COMPILE_ASSERT(int(WebKit::WebTextInputTypeText) == \ 2264 int(ui::TEXT_INPUT_TYPE_TEXT), mismatching_enums); 2265 COMPILE_ASSERT(int(WebKit::WebTextInputTypePassword) == \ 2266 int(ui::TEXT_INPUT_TYPE_PASSWORD), mismatching_enums); 2267 COMPILE_ASSERT(int(WebKit::WebTextInputTypeSearch) == \ 2268 int(ui::TEXT_INPUT_TYPE_SEARCH), mismatching_enums); 2269 COMPILE_ASSERT(int(WebKit::WebTextInputTypeEmail) == \ 2270 int(ui::TEXT_INPUT_TYPE_EMAIL), mismatching_enums); 2271 COMPILE_ASSERT(int(WebKit::WebTextInputTypeNumber) == \ 2272 int(ui::TEXT_INPUT_TYPE_NUMBER), mismatching_enums); 2273 COMPILE_ASSERT(int(WebKit::WebTextInputTypeTelephone) == \ 2274 int(ui::TEXT_INPUT_TYPE_TELEPHONE), mismatching_enums); 2275 COMPILE_ASSERT(int(WebKit::WebTextInputTypeURL) == \ 2276 int(ui::TEXT_INPUT_TYPE_URL), mismatching_enums); 2277 COMPILE_ASSERT(int(WebKit::WebTextInputTypeDate) == \ 2278 int(ui::TEXT_INPUT_TYPE_DATE), mismatching_enum); 2279 COMPILE_ASSERT(int(WebKit::WebTextInputTypeDateTime) == \ 2280 int(ui::TEXT_INPUT_TYPE_DATE_TIME), mismatching_enum); 2281 COMPILE_ASSERT(int(WebKit::WebTextInputTypeDateTimeLocal) == \ 2282 int(ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL), mismatching_enum); 2283 COMPILE_ASSERT(int(WebKit::WebTextInputTypeMonth) == \ 2284 int(ui::TEXT_INPUT_TYPE_MONTH), mismatching_enum); 2285 COMPILE_ASSERT(int(WebKit::WebTextInputTypeTime) == \ 2286 int(ui::TEXT_INPUT_TYPE_TIME), mismatching_enum); 2287 COMPILE_ASSERT(int(WebKit::WebTextInputTypeWeek) == \ 2288 int(ui::TEXT_INPUT_TYPE_WEEK), mismatching_enum); 2289 COMPILE_ASSERT(int(WebKit::WebTextInputTypeTextArea) == \ 2290 int(ui::TEXT_INPUT_TYPE_TEXT_AREA), mismatching_enums); 2291 COMPILE_ASSERT(int(WebKit::WebTextInputTypeContentEditable) == \ 2292 int(ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE), mismatching_enums); 2293 COMPILE_ASSERT(int(WebKit::WebTextInputTypeDateTimeField) == \ 2294 int(ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD), mismatching_enums); 2295 2296 ui::TextInputType RenderWidget::WebKitToUiTextInputType( 2297 WebKit::WebTextInputType type) { 2298 // Check the type is in the range representable by ui::TextInputType. 2299 DCHECK_LE(type, static_cast<int>(ui::TEXT_INPUT_TYPE_MAX)) << 2300 "WebKit::WebTextInputType and ui::TextInputType not synchronized"; 2301 return static_cast<ui::TextInputType>(type); 2302 } 2303 2304 ui::TextInputType RenderWidget::GetTextInputType() { 2305 if (webwidget_) 2306 return WebKitToUiTextInputType(webwidget_->textInputInfo().type); 2307 return ui::TEXT_INPUT_TYPE_NONE; 2308 } 2309 2310 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA) 2311 void RenderWidget::UpdateCompositionInfo(bool should_update_range) { 2312 ui::Range range = ui::Range(); 2313 if (should_update_range) { 2314 GetCompositionRange(&range); 2315 } else { 2316 range = composition_range_; 2317 } 2318 std::vector<gfx::Rect> character_bounds; 2319 GetCompositionCharacterBounds(&character_bounds); 2320 2321 if (!ShouldUpdateCompositionInfo(range, character_bounds)) 2322 return; 2323 composition_character_bounds_ = character_bounds; 2324 composition_range_ = range; 2325 Send(new ViewHostMsg_ImeCompositionRangeChanged( 2326 routing_id(), composition_range_, composition_character_bounds_)); 2327 } 2328 2329 void RenderWidget::GetCompositionCharacterBounds( 2330 std::vector<gfx::Rect>* bounds) { 2331 DCHECK(bounds); 2332 bounds->clear(); 2333 } 2334 2335 void RenderWidget::GetCompositionRange(ui::Range* range) { 2336 size_t location, length; 2337 if (webwidget_->compositionRange(&location, &length)) { 2338 range->set_start(location); 2339 range->set_end(location + length); 2340 } else if (webwidget_->caretOrSelectionRange(&location, &length)) { 2341 range->set_start(location); 2342 range->set_end(location + length); 2343 } else { 2344 *range = ui::Range::InvalidRange(); 2345 } 2346 } 2347 2348 bool RenderWidget::ShouldUpdateCompositionInfo( 2349 const ui::Range& range, 2350 const std::vector<gfx::Rect>& bounds) { 2351 if (composition_range_ != range) 2352 return true; 2353 if (bounds.size() != composition_character_bounds_.size()) 2354 return true; 2355 for (size_t i = 0; i < bounds.size(); ++i) { 2356 if (bounds[i] != composition_character_bounds_[i]) 2357 return true; 2358 } 2359 return false; 2360 } 2361 #endif 2362 2363 bool RenderWidget::CanComposeInline() { 2364 return true; 2365 } 2366 2367 WebScreenInfo RenderWidget::screenInfo() { 2368 return screen_info_; 2369 } 2370 2371 float RenderWidget::deviceScaleFactor() { 2372 return device_scale_factor_; 2373 } 2374 2375 void RenderWidget::resetInputMethod() { 2376 if (!input_method_is_active_) 2377 return; 2378 2379 ImeEventGuard guard(this); 2380 // If the last text input type is not None, then we should finish any 2381 // ongoing composition regardless of the new text input type. 2382 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) { 2383 // If a composition text exists, then we need to let the browser process 2384 // to cancel the input method's ongoing composition session. 2385 if (webwidget_->confirmComposition()) 2386 Send(new ViewHostMsg_ImeCancelComposition(routing_id())); 2387 } 2388 2389 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA) 2390 UpdateCompositionInfo(true); 2391 #endif 2392 } 2393 2394 void RenderWidget::didHandleGestureEvent( 2395 const WebGestureEvent& event, 2396 bool event_cancelled) { 2397 #if defined(OS_ANDROID) 2398 if (event_cancelled) 2399 return; 2400 if (event.type == WebInputEvent::GestureTap || 2401 event.type == WebInputEvent::GestureLongPress) { 2402 UpdateTextInputState(true, true); 2403 } 2404 #endif 2405 } 2406 2407 void RenderWidget::SchedulePluginMove(const WebPluginGeometry& move) { 2408 size_t i = 0; 2409 for (; i < plugin_window_moves_.size(); ++i) { 2410 if (plugin_window_moves_[i].window == move.window) { 2411 if (move.rects_valid) { 2412 plugin_window_moves_[i] = move; 2413 } else { 2414 plugin_window_moves_[i].visible = move.visible; 2415 } 2416 break; 2417 } 2418 } 2419 2420 if (i == plugin_window_moves_.size()) 2421 plugin_window_moves_.push_back(move); 2422 } 2423 2424 void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) { 2425 for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin(); 2426 i != plugin_window_moves_.end(); ++i) { 2427 if (i->window == window) { 2428 plugin_window_moves_.erase(i); 2429 break; 2430 } 2431 } 2432 } 2433 2434 void RenderWidget::GetRenderingStats( 2435 WebKit::WebRenderingStatsImpl& stats) const { 2436 if (compositor_) 2437 compositor_->GetRenderingStats(&stats.rendering_stats); 2438 2439 stats.rendering_stats.animation_frame_count += 2440 software_stats_.animation_frame_count; 2441 stats.rendering_stats.screen_frame_count += 2442 software_stats_.screen_frame_count; 2443 stats.rendering_stats.total_paint_time += 2444 software_stats_.total_paint_time; 2445 stats.rendering_stats.total_pixels_painted += 2446 software_stats_.total_pixels_painted; 2447 } 2448 2449 bool RenderWidget::GetGpuRenderingStats(GpuRenderingStats* stats) const { 2450 GpuChannelHost* gpu_channel = RenderThreadImpl::current()->GetGpuChannel(); 2451 if (!gpu_channel) 2452 return false; 2453 2454 return gpu_channel->CollectRenderingStatsForSurface(surface_id(), stats); 2455 } 2456 2457 RenderWidgetCompositor* RenderWidget::compositor() const { 2458 return compositor_.get(); 2459 } 2460 2461 void RenderWidget::OnSetBrowserRenderingStats( 2462 const BrowserRenderingStats& stats) { 2463 browser_rendering_stats_ = stats; 2464 } 2465 2466 void RenderWidget::GetBrowserRenderingStats(BrowserRenderingStats* stats) { 2467 *stats = browser_rendering_stats_; 2468 } 2469 2470 void RenderWidget::BeginSmoothScroll( 2471 bool down, 2472 const SmoothScrollCompletionCallback& callback, 2473 int pixels_to_scroll, 2474 int mouse_event_x, 2475 int mouse_event_y) { 2476 DCHECK(!callback.is_null()); 2477 2478 ViewHostMsg_BeginSmoothScroll_Params params; 2479 params.scroll_down = down; 2480 params.pixels_to_scroll = pixels_to_scroll; 2481 params.mouse_event_x = mouse_event_x; 2482 params.mouse_event_y = mouse_event_y; 2483 2484 Send(new ViewHostMsg_BeginSmoothScroll(routing_id_, params)); 2485 pending_smooth_scroll_gesture_ = callback; 2486 } 2487 2488 bool RenderWidget::WillHandleMouseEvent(const WebKit::WebMouseEvent& event) { 2489 return false; 2490 } 2491 2492 bool RenderWidget::WillHandleKeyEvent(const WebKit::WebKeyboardEvent& event) { 2493 return false; 2494 } 2495 2496 bool RenderWidget::WillHandleGestureEvent( 2497 const WebKit::WebGestureEvent& event) { 2498 return false; 2499 } 2500 2501 void RenderWidget::hasTouchEventHandlers(bool has_handlers) { 2502 Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers)); 2503 } 2504 2505 bool RenderWidget::HasTouchEventHandlersAt(const gfx::Point& point) const { 2506 return true; 2507 } 2508 2509 WebGraphicsContext3DCommandBufferImpl* RenderWidget::CreateGraphicsContext3D( 2510 const WebKit::WebGraphicsContext3D::Attributes& attributes) { 2511 if (!webwidget_) 2512 return NULL; 2513 if (CommandLine::ForCurrentProcess()->HasSwitch( 2514 switches::kDisableGpuCompositing)) 2515 return NULL; 2516 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context( 2517 new WebGraphicsContext3DCommandBufferImpl( 2518 surface_id(), 2519 GetURLForGraphicsContext3D(), 2520 RenderThreadImpl::current(), 2521 weak_ptr_factory_.GetWeakPtr())); 2522 2523 if (!context->InitializeWithDefaultBufferSizes( 2524 attributes, 2525 false /* bind generates resources */, 2526 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)) 2527 return NULL; 2528 return context.release(); 2529 } 2530 2531 } // namespace content 2532