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