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