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