render_widget.cc revision 1675a649fd7a8b3cb80ffddae2dc181f122353c5
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/auto_reset.h" 8#include "base/bind.h" 9#include "base/command_line.h" 10#include "base/debug/trace_event.h" 11#include "base/debug/trace_event_synthetic_delay.h" 12#include "base/logging.h" 13#include "base/memory/scoped_ptr.h" 14#include "base/memory/singleton.h" 15#include "base/message_loop/message_loop.h" 16#include "base/metrics/histogram.h" 17#include "base/stl_util.h" 18#include "base/strings/utf_string_conversions.h" 19#include "base/sys_info.h" 20#include "build/build_config.h" 21#include "cc/base/switches.h" 22#include "cc/debug/benchmark_instrumentation.h" 23#include "cc/output/output_surface.h" 24#include "cc/trees/layer_tree_host.h" 25#include "content/child/npapi/webplugin.h" 26#include "content/common/gpu/client/context_provider_command_buffer.h" 27#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 28#include "content/common/gpu/gpu_process_launch_causes.h" 29#include "content/common/input/synthetic_gesture_packet.h" 30#include "content/common/input/web_input_event_traits.h" 31#include "content/common/input_messages.h" 32#include "content/common/swapped_out_messages.h" 33#include "content/common/view_messages.h" 34#include "content/public/common/content_switches.h" 35#include "content/public/common/context_menu_params.h" 36#include "content/renderer/cursor_utils.h" 37#include "content/renderer/external_popup_menu.h" 38#include "content/renderer/gpu/compositor_output_surface.h" 39#include "content/renderer/gpu/compositor_software_output_device.h" 40#include "content/renderer/gpu/delegated_compositor_output_surface.h" 41#include "content/renderer/gpu/frame_swap_message_queue.h" 42#include "content/renderer/gpu/mailbox_output_surface.h" 43#include "content/renderer/gpu/queue_message_swap_promise.h" 44#include "content/renderer/gpu/render_widget_compositor.h" 45#include "content/renderer/ime_event_guard.h" 46#include "content/renderer/input/input_handler_manager.h" 47#include "content/renderer/pepper/pepper_plugin_instance_impl.h" 48#include "content/renderer/render_frame_impl.h" 49#include "content/renderer/render_frame_proxy.h" 50#include "content/renderer/render_process.h" 51#include "content/renderer/render_thread_impl.h" 52#include "content/renderer/renderer_webkitplatformsupport_impl.h" 53#include "content/renderer/resizing_mode_selector.h" 54#include "ipc/ipc_sync_message.h" 55#include "skia/ext/platform_canvas.h" 56#include "third_party/WebKit/public/platform/WebCursorInfo.h" 57#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" 58#include "third_party/WebKit/public/platform/WebRect.h" 59#include "third_party/WebKit/public/platform/WebScreenInfo.h" 60#include "third_party/WebKit/public/platform/WebSize.h" 61#include "third_party/WebKit/public/platform/WebString.h" 62#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h" 63#include "third_party/WebKit/public/web/WebPagePopup.h" 64#include "third_party/WebKit/public/web/WebPopupMenu.h" 65#include "third_party/WebKit/public/web/WebPopupMenuInfo.h" 66#include "third_party/WebKit/public/web/WebRange.h" 67#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" 68#include "third_party/skia/include/core/SkShader.h" 69#include "ui/base/ui_base_switches.h" 70#include "ui/gfx/frame_time.h" 71#include "ui/gfx/point_conversions.h" 72#include "ui/gfx/rect_conversions.h" 73#include "ui/gfx/size_conversions.h" 74#include "ui/gfx/skia_util.h" 75#include "ui/gl/gl_switches.h" 76#include "ui/surface/transport_dib.h" 77 78#if defined(OS_ANDROID) 79#include <android/keycodes.h> 80#include "content/renderer/android/synchronous_compositor_factory.h" 81#endif 82 83#if defined(OS_POSIX) 84#include "ipc/ipc_channel_posix.h" 85#include "third_party/skia/include/core/SkMallocPixelRef.h" 86#include "third_party/skia/include/core/SkPixelRef.h" 87#endif // defined(OS_POSIX) 88 89#include "third_party/WebKit/public/web/WebWidget.h" 90 91using blink::WebCompositionUnderline; 92using blink::WebCursorInfo; 93using blink::WebDeviceEmulationParams; 94using blink::WebGestureEvent; 95using blink::WebInputEvent; 96using blink::WebKeyboardEvent; 97using blink::WebMouseEvent; 98using blink::WebMouseWheelEvent; 99using blink::WebNavigationPolicy; 100using blink::WebPagePopup; 101using blink::WebPopupMenu; 102using blink::WebPopupMenuInfo; 103using blink::WebPopupType; 104using blink::WebRange; 105using blink::WebRect; 106using blink::WebScreenInfo; 107using blink::WebSize; 108using blink::WebTextDirection; 109using blink::WebTouchEvent; 110using blink::WebTouchPoint; 111using blink::WebVector; 112using blink::WebWidget; 113 114namespace { 115 116typedef std::map<std::string, ui::TextInputMode> TextInputModeMap; 117 118class TextInputModeMapSingleton { 119 public: 120 static TextInputModeMapSingleton* GetInstance() { 121 return Singleton<TextInputModeMapSingleton>::get(); 122 } 123 TextInputModeMapSingleton() { 124 map_["verbatim"] = ui::TEXT_INPUT_MODE_VERBATIM; 125 map_["latin"] = ui::TEXT_INPUT_MODE_LATIN; 126 map_["latin-name"] = ui::TEXT_INPUT_MODE_LATIN_NAME; 127 map_["latin-prose"] = ui::TEXT_INPUT_MODE_LATIN_PROSE; 128 map_["full-width-latin"] = ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN; 129 map_["kana"] = ui::TEXT_INPUT_MODE_KANA; 130 map_["katakana"] = ui::TEXT_INPUT_MODE_KATAKANA; 131 map_["numeric"] = ui::TEXT_INPUT_MODE_NUMERIC; 132 map_["tel"] = ui::TEXT_INPUT_MODE_TEL; 133 map_["email"] = ui::TEXT_INPUT_MODE_EMAIL; 134 map_["url"] = ui::TEXT_INPUT_MODE_URL; 135 } 136 const TextInputModeMap& map() const { return map_; } 137 private: 138 TextInputModeMap map_; 139 140 friend struct DefaultSingletonTraits<TextInputModeMapSingleton>; 141 142 DISALLOW_COPY_AND_ASSIGN(TextInputModeMapSingleton); 143}; 144 145ui::TextInputMode ConvertInputMode(const blink::WebString& input_mode) { 146 static TextInputModeMapSingleton* singleton = 147 TextInputModeMapSingleton::GetInstance(); 148 TextInputModeMap::const_iterator it = 149 singleton->map().find(input_mode.utf8()); 150 if (it == singleton->map().end()) 151 return ui::TEXT_INPUT_MODE_DEFAULT; 152 return it->second; 153} 154 155bool IsThreadedCompositingEnabled() { 156 content::RenderThreadImpl* impl = content::RenderThreadImpl::current(); 157 return impl && !!impl->compositor_message_loop_proxy().get(); 158} 159 160// TODO(brianderson): Replace the hard-coded threshold with a fraction of 161// the BeginMainFrame interval. 162// 4166us will allow 1/4 of a 60Hz interval or 1/2 of a 120Hz interval to 163// be spent in input hanlders before input starts getting throttled. 164const int kInputHandlingTimeThrottlingThresholdMicroseconds = 4166; 165 166} // namespace 167 168namespace content { 169 170// RenderWidget::ScreenMetricsEmulator ---------------------------------------- 171 172class RenderWidget::ScreenMetricsEmulator { 173 public: 174 ScreenMetricsEmulator( 175 RenderWidget* widget, 176 const WebDeviceEmulationParams& params); 177 virtual ~ScreenMetricsEmulator(); 178 179 // Scale and offset used to convert between host coordinates 180 // and webwidget coordinates. 181 float scale() { return scale_; } 182 gfx::Point offset() { return offset_; } 183 gfx::Rect applied_widget_rect() const { return applied_widget_rect_; } 184 gfx::Rect original_screen_rect() const { return original_view_screen_rect_; } 185 const WebScreenInfo& original_screen_info() { return original_screen_info_; } 186 187 void ChangeEmulationParams( 188 const WebDeviceEmulationParams& params); 189 190 // The following methods alter handlers' behavior for messages related to 191 // widget size and position. 192 void OnResizeMessage(const ViewMsg_Resize_Params& params); 193 void OnUpdateScreenRectsMessage(const gfx::Rect& view_screen_rect, 194 const gfx::Rect& window_screen_rect); 195 void OnShowContextMenu(ContextMenuParams* params); 196 gfx::Rect AdjustValidationMessageAnchor(const gfx::Rect& anchor); 197 198 private: 199 void Reapply(); 200 void Apply(float top_controls_layout_height, 201 gfx::Rect resizer_rect, 202 bool is_fullscreen); 203 204 RenderWidget* widget_; 205 206 // Parameters as passed by RenderWidget::EnableScreenMetricsEmulation. 207 WebDeviceEmulationParams params_; 208 209 // The computed scale and offset used to fit widget into browser window. 210 float scale_; 211 gfx::Point offset_; 212 213 // Widget rect as passed to webwidget. 214 gfx::Rect applied_widget_rect_; 215 216 // Original values to restore back after emulation ends. 217 gfx::Size original_size_; 218 gfx::Size original_physical_backing_size_; 219 gfx::Size original_visible_viewport_size_; 220 blink::WebScreenInfo original_screen_info_; 221 gfx::Rect original_view_screen_rect_; 222 gfx::Rect original_window_screen_rect_; 223}; 224 225RenderWidget::ScreenMetricsEmulator::ScreenMetricsEmulator( 226 RenderWidget* widget, 227 const WebDeviceEmulationParams& params) 228 : widget_(widget), 229 params_(params), 230 scale_(1.f) { 231 original_size_ = widget_->size_; 232 original_physical_backing_size_ = widget_->physical_backing_size_; 233 original_visible_viewport_size_ = widget_->visible_viewport_size_; 234 original_screen_info_ = widget_->screen_info_; 235 original_view_screen_rect_ = widget_->view_screen_rect_; 236 original_window_screen_rect_ = widget_->window_screen_rect_; 237 Apply(widget_->top_controls_layout_height_, widget_->resizer_rect_, 238 widget_->is_fullscreen_); 239} 240 241RenderWidget::ScreenMetricsEmulator::~ScreenMetricsEmulator() { 242 widget_->screen_info_ = original_screen_info_; 243 244 widget_->SetDeviceScaleFactor(original_screen_info_.deviceScaleFactor); 245 widget_->SetScreenMetricsEmulationParameters(0.f, gfx::Point(), 1.f); 246 widget_->view_screen_rect_ = original_view_screen_rect_; 247 widget_->window_screen_rect_ = original_window_screen_rect_; 248 widget_->Resize(original_size_, 249 original_physical_backing_size_, 250 widget_->top_controls_layout_height_, 251 original_visible_viewport_size_, 252 widget_->resizer_rect_, 253 widget_->is_fullscreen_, 254 NO_RESIZE_ACK); 255} 256 257void RenderWidget::ScreenMetricsEmulator::ChangeEmulationParams( 258 const WebDeviceEmulationParams& params) { 259 params_ = params; 260 Reapply(); 261} 262 263void RenderWidget::ScreenMetricsEmulator::Reapply() { 264 Apply(widget_->top_controls_layout_height_, widget_->resizer_rect_, 265 widget_->is_fullscreen_); 266} 267 268void RenderWidget::ScreenMetricsEmulator::Apply( 269 float top_controls_layout_height, 270 gfx::Rect resizer_rect, 271 bool is_fullscreen) { 272 applied_widget_rect_.set_size(gfx::Size(params_.viewSize)); 273 if (!applied_widget_rect_.width()) 274 applied_widget_rect_.set_width(original_size_.width()); 275 if (!applied_widget_rect_.height()) 276 applied_widget_rect_.set_height(original_size_.height()); 277 278 if (params_.fitToView && !original_size_.IsEmpty()) { 279 int original_width = std::max(original_size_.width(), 1); 280 int original_height = std::max(original_size_.height(), 1); 281 float width_ratio = 282 static_cast<float>(applied_widget_rect_.width()) / original_width; 283 float height_ratio = 284 static_cast<float>(applied_widget_rect_.height()) / original_height; 285 float ratio = std::max(1.0f, std::max(width_ratio, height_ratio)); 286 scale_ = 1.f / ratio; 287 288 // Center emulated view inside available view space. 289 offset_.set_x( 290 (original_size_.width() - scale_ * applied_widget_rect_.width()) / 2); 291 offset_.set_y( 292 (original_size_.height() - scale_ * applied_widget_rect_.height()) / 2); 293 } else { 294 scale_ = params_.scale; 295 offset_.SetPoint(params_.offset.x, params_.offset.y); 296 } 297 298 if (params_.screenPosition == WebDeviceEmulationParams::Desktop) { 299 applied_widget_rect_.set_origin(original_view_screen_rect_.origin()); 300 widget_->screen_info_.rect = original_screen_info_.rect; 301 widget_->screen_info_.availableRect = original_screen_info_.availableRect; 302 widget_->window_screen_rect_ = original_window_screen_rect_; 303 } else { 304 applied_widget_rect_.set_origin(gfx::Point(0, 0)); 305 widget_->screen_info_.rect = applied_widget_rect_; 306 widget_->screen_info_.availableRect = applied_widget_rect_; 307 widget_->window_screen_rect_ = applied_widget_rect_; 308 } 309 310 float applied_device_scale_factor = params_.deviceScaleFactor ? 311 params_.deviceScaleFactor : original_screen_info_.deviceScaleFactor; 312 widget_->screen_info_.deviceScaleFactor = applied_device_scale_factor; 313 314 // Pass three emulation parameters to the blink side: 315 // - we keep the real device scale factor in compositor to produce sharp image 316 // even when emulating different scale factor; 317 // - in order to fit into view, WebView applies offset and scale to the 318 // root layer. 319 widget_->SetScreenMetricsEmulationParameters( 320 original_screen_info_.deviceScaleFactor, offset_, scale_); 321 322 widget_->SetDeviceScaleFactor(applied_device_scale_factor); 323 widget_->view_screen_rect_ = applied_widget_rect_; 324 325 gfx::Size physical_backing_size = gfx::ToCeiledSize(gfx::ScaleSize( 326 original_size_, original_screen_info_.deviceScaleFactor)); 327 widget_->Resize(applied_widget_rect_.size(), physical_backing_size, 328 top_controls_layout_height, applied_widget_rect_.size(), resizer_rect, 329 is_fullscreen, NO_RESIZE_ACK); 330} 331 332void RenderWidget::ScreenMetricsEmulator::OnResizeMessage( 333 const ViewMsg_Resize_Params& params) { 334 bool need_ack = params.new_size != original_size_ && 335 !params.new_size.IsEmpty() && !params.physical_backing_size.IsEmpty(); 336 original_size_ = params.new_size; 337 original_physical_backing_size_ = params.physical_backing_size; 338 original_screen_info_ = params.screen_info; 339 original_visible_viewport_size_ = params.visible_viewport_size; 340 Apply(params.top_controls_layout_height, params.resizer_rect, 341 params.is_fullscreen); 342 343 if (need_ack) { 344 widget_->set_next_paint_is_resize_ack(); 345 if (widget_->compositor_) 346 widget_->compositor_->SetNeedsRedrawRect(gfx::Rect(widget_->size_)); 347 } 348} 349 350void RenderWidget::ScreenMetricsEmulator::OnUpdateScreenRectsMessage( 351 const gfx::Rect& view_screen_rect, 352 const gfx::Rect& window_screen_rect) { 353 original_view_screen_rect_ = view_screen_rect; 354 original_window_screen_rect_ = window_screen_rect; 355 if (params_.screenPosition == WebDeviceEmulationParams::Desktop) 356 Reapply(); 357} 358 359void RenderWidget::ScreenMetricsEmulator::OnShowContextMenu( 360 ContextMenuParams* params) { 361 params->x *= scale_; 362 params->x += offset_.x(); 363 params->y *= scale_; 364 params->y += offset_.y(); 365} 366 367gfx::Rect RenderWidget::ScreenMetricsEmulator::AdjustValidationMessageAnchor( 368 const gfx::Rect& anchor) { 369 gfx::Rect scaled = gfx::ToEnclosedRect(gfx::ScaleRect(anchor, scale_)); 370 scaled.set_x(scaled.x() + offset_.x()); 371 scaled.set_y(scaled.y() + offset_.y()); 372 return scaled; 373} 374 375// RenderWidget --------------------------------------------------------------- 376 377RenderWidget::RenderWidget(blink::WebPopupType popup_type, 378 const blink::WebScreenInfo& screen_info, 379 bool swapped_out, 380 bool hidden, 381 bool never_visible) 382 : routing_id_(MSG_ROUTING_NONE), 383 surface_id_(0), 384 webwidget_(NULL), 385 opener_id_(MSG_ROUTING_NONE), 386 init_complete_(false), 387 top_controls_layout_height_(0.f), 388 next_paint_flags_(0), 389 auto_resize_mode_(false), 390 need_update_rect_for_auto_resize_(false), 391 did_show_(false), 392 is_hidden_(hidden), 393 never_visible_(never_visible), 394 is_fullscreen_(false), 395 has_focus_(false), 396 handling_input_event_(false), 397 handling_ime_event_(false), 398 handling_event_type_(WebInputEvent::Undefined), 399 ignore_ack_for_mouse_move_from_debugger_(false), 400 closing_(false), 401 host_closing_(false), 402 is_swapped_out_(swapped_out), 403 input_method_is_active_(false), 404 text_input_type_(ui::TEXT_INPUT_TYPE_NONE), 405 text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT), 406 can_compose_inline_(true), 407 popup_type_(popup_type), 408 pending_window_rect_count_(0), 409 suppress_next_char_events_(false), 410 screen_info_(screen_info), 411 device_scale_factor_(screen_info_.deviceScaleFactor), 412 current_event_latency_info_(NULL), 413 next_output_surface_id_(0), 414#if defined(OS_ANDROID) 415 text_field_is_dirty_(false), 416 outstanding_ime_acks_(0), 417 body_background_color_(SK_ColorWHITE), 418#endif 419 popup_origin_scale_for_emulation_(0.f), 420 frame_swap_message_queue_(new FrameSwapMessageQueue()), 421 resizing_mode_selector_(new ResizingModeSelector()), 422 context_menu_source_type_(ui::MENU_SOURCE_MOUSE), 423 has_host_context_menu_location_(false) { 424 if (!swapped_out) 425 RenderProcess::current()->AddRefProcess(); 426 DCHECK(RenderThread::Get()); 427 device_color_profile_.push_back('0'); 428} 429 430RenderWidget::~RenderWidget() { 431 DCHECK(!webwidget_) << "Leaking our WebWidget!"; 432 433 // If we are swapped out, we have released already. 434 if (!is_swapped_out_ && RenderProcess::current()) 435 RenderProcess::current()->ReleaseProcess(); 436} 437 438// static 439RenderWidget* RenderWidget::Create(int32 opener_id, 440 blink::WebPopupType popup_type, 441 const blink::WebScreenInfo& screen_info) { 442 DCHECK(opener_id != MSG_ROUTING_NONE); 443 scoped_refptr<RenderWidget> widget( 444 new RenderWidget(popup_type, screen_info, false, false, false)); 445 if (widget->Init(opener_id)) { // adds reference on success. 446 return widget.get(); 447 } 448 return NULL; 449} 450 451// static 452WebWidget* RenderWidget::CreateWebWidget(RenderWidget* render_widget) { 453 switch (render_widget->popup_type_) { 454 case blink::WebPopupTypeNone: // Nothing to create. 455 break; 456 case blink::WebPopupTypeSelect: 457 case blink::WebPopupTypeSuggestion: 458 return WebPopupMenu::create(render_widget); 459 case blink::WebPopupTypePage: 460 return WebPagePopup::create(render_widget); 461 default: 462 NOTREACHED(); 463 } 464 return NULL; 465} 466 467bool RenderWidget::Init(int32 opener_id) { 468 return DoInit(opener_id, 469 RenderWidget::CreateWebWidget(this), 470 new ViewHostMsg_CreateWidget(opener_id, popup_type_, 471 &routing_id_, &surface_id_)); 472} 473 474bool RenderWidget::DoInit(int32 opener_id, 475 WebWidget* web_widget, 476 IPC::SyncMessage* create_widget_message) { 477 DCHECK(!webwidget_); 478 479 if (opener_id != MSG_ROUTING_NONE) 480 opener_id_ = opener_id; 481 482 webwidget_ = web_widget; 483 484 bool result = RenderThread::Get()->Send(create_widget_message); 485 if (result) { 486 RenderThread::Get()->AddRoute(routing_id_, this); 487 // Take a reference on behalf of the RenderThread. This will be balanced 488 // when we receive ViewMsg_Close. 489 AddRef(); 490 if (RenderThreadImpl::current()) { 491 RenderThreadImpl::current()->WidgetCreated(); 492 if (is_hidden_) 493 RenderThreadImpl::current()->WidgetHidden(); 494 } 495 return true; 496 } else { 497 // The above Send can fail when the tab is closing. 498 return false; 499 } 500} 501 502// This is used to complete pending inits and non-pending inits. 503void RenderWidget::CompleteInit() { 504 DCHECK(routing_id_ != MSG_ROUTING_NONE); 505 506 init_complete_ = true; 507 508 if (compositor_) 509 StartCompositor(); 510 511 Send(new ViewHostMsg_RenderViewReady(routing_id_)); 512} 513 514void RenderWidget::SetSwappedOut(bool is_swapped_out) { 515 // We should only toggle between states. 516 DCHECK(is_swapped_out_ != is_swapped_out); 517 is_swapped_out_ = is_swapped_out; 518 519 // If we are swapping out, we will call ReleaseProcess, allowing the process 520 // to exit if all of its RenderViews are swapped out. We wait until the 521 // WasSwappedOut call to do this, to allow the unload handler to finish. 522 // If we are swapping in, we call AddRefProcess to prevent the process from 523 // exiting. 524 if (!is_swapped_out_) 525 RenderProcess::current()->AddRefProcess(); 526} 527 528void RenderWidget::WasSwappedOut() { 529 // If we have been swapped out and no one else is using this process, 530 // it's safe to exit now. 531 CHECK(is_swapped_out_); 532 RenderProcess::current()->ReleaseProcess(); 533} 534 535void RenderWidget::EnableScreenMetricsEmulation( 536 const WebDeviceEmulationParams& params) { 537 if (!screen_metrics_emulator_) 538 screen_metrics_emulator_.reset(new ScreenMetricsEmulator(this, params)); 539 else 540 screen_metrics_emulator_->ChangeEmulationParams(params); 541} 542 543void RenderWidget::DisableScreenMetricsEmulation() { 544 screen_metrics_emulator_.reset(); 545} 546 547void RenderWidget::SetPopupOriginAdjustmentsForEmulation( 548 ScreenMetricsEmulator* emulator) { 549 popup_origin_scale_for_emulation_ = emulator->scale(); 550 popup_view_origin_for_emulation_ = emulator->applied_widget_rect().origin(); 551 popup_screen_origin_for_emulation_ = gfx::Point( 552 emulator->original_screen_rect().origin().x() + emulator->offset().x(), 553 emulator->original_screen_rect().origin().y() + emulator->offset().y()); 554 screen_info_ = emulator->original_screen_info(); 555 device_scale_factor_ = screen_info_.deviceScaleFactor; 556} 557 558gfx::Rect RenderWidget::AdjustValidationMessageAnchor(const gfx::Rect& anchor) { 559 if (screen_metrics_emulator_) 560 return screen_metrics_emulator_->AdjustValidationMessageAnchor(anchor); 561 return anchor; 562} 563 564void RenderWidget::SetScreenMetricsEmulationParameters( 565 float device_scale_factor, 566 const gfx::Point& root_layer_offset, 567 float root_layer_scale) { 568 // This is only supported in RenderView. 569 NOTREACHED(); 570} 571 572#if defined(OS_MACOSX) || defined(OS_ANDROID) 573void RenderWidget::SetExternalPopupOriginAdjustmentsForEmulation( 574 ExternalPopupMenu* popup, ScreenMetricsEmulator* emulator) { 575 popup->SetOriginScaleAndOffsetForEmulation( 576 emulator->scale(), emulator->offset()); 577} 578#endif 579 580void RenderWidget::OnShowHostContextMenu(ContextMenuParams* params) { 581 if (screen_metrics_emulator_) 582 screen_metrics_emulator_->OnShowContextMenu(params); 583} 584 585void RenderWidget::ScheduleCompositeWithForcedRedraw() { 586 if (compositor_) { 587 // Regardless of whether threaded compositing is enabled, always 588 // use this mechanism to force the compositor to redraw. However, 589 // the invalidation code path below is still needed for the 590 // non-threaded case. 591 compositor_->SetNeedsForcedRedraw(); 592 } 593 scheduleComposite(); 594} 595 596bool RenderWidget::OnMessageReceived(const IPC::Message& message) { 597 bool handled = true; 598 IPC_BEGIN_MESSAGE_MAP(RenderWidget, message) 599 IPC_MESSAGE_HANDLER(InputMsg_HandleInputEvent, OnHandleInputEvent) 600 IPC_MESSAGE_HANDLER(InputMsg_CursorVisibilityChange, 601 OnCursorVisibilityChange) 602 IPC_MESSAGE_HANDLER(InputMsg_ImeSetComposition, OnImeSetComposition) 603 IPC_MESSAGE_HANDLER(InputMsg_ImeConfirmComposition, OnImeConfirmComposition) 604 IPC_MESSAGE_HANDLER(InputMsg_MouseCaptureLost, OnMouseCaptureLost) 605 IPC_MESSAGE_HANDLER(InputMsg_SetFocus, OnSetFocus) 606 IPC_MESSAGE_HANDLER(InputMsg_SyntheticGestureCompleted, 607 OnSyntheticGestureCompleted) 608 IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose) 609 IPC_MESSAGE_HANDLER(ViewMsg_CreatingNew_ACK, OnCreatingNewAck) 610 IPC_MESSAGE_HANDLER(ViewMsg_Resize, OnResize) 611 IPC_MESSAGE_HANDLER(ViewMsg_ChangeResizeRect, OnChangeResizeRect) 612 IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden) 613 IPC_MESSAGE_HANDLER(ViewMsg_WasShown, OnWasShown) 614 IPC_MESSAGE_HANDLER(ViewMsg_SetInputMethodActive, OnSetInputMethodActive) 615 IPC_MESSAGE_HANDLER(ViewMsg_CandidateWindowShown, OnCandidateWindowShown) 616 IPC_MESSAGE_HANDLER(ViewMsg_CandidateWindowUpdated, 617 OnCandidateWindowUpdated) 618 IPC_MESSAGE_HANDLER(ViewMsg_CandidateWindowHidden, OnCandidateWindowHidden) 619 IPC_MESSAGE_HANDLER(ViewMsg_Repaint, OnRepaint) 620 IPC_MESSAGE_HANDLER(ViewMsg_SetTextDirection, OnSetTextDirection) 621 IPC_MESSAGE_HANDLER(ViewMsg_Move_ACK, OnRequestMoveAck) 622 IPC_MESSAGE_HANDLER(ViewMsg_UpdateScreenRects, OnUpdateScreenRects) 623#if defined(OS_ANDROID) 624 IPC_MESSAGE_HANDLER(ViewMsg_ShowImeIfNeeded, OnShowImeIfNeeded) 625 IPC_MESSAGE_HANDLER(ViewMsg_ImeEventAck, OnImeEventAck) 626#endif 627 IPC_MESSAGE_UNHANDLED(handled = false) 628 IPC_END_MESSAGE_MAP() 629 return handled; 630} 631 632bool RenderWidget::Send(IPC::Message* message) { 633 // Don't send any messages after the browser has told us to close, and filter 634 // most outgoing messages while swapped out. 635 if ((is_swapped_out_ && 636 !SwappedOutMessages::CanSendWhileSwappedOut(message)) || 637 closing_) { 638 delete message; 639 return false; 640 } 641 642 // If given a messsage without a routing ID, then assign our routing ID. 643 if (message->routing_id() == MSG_ROUTING_NONE) 644 message->set_routing_id(routing_id_); 645 646 return RenderThread::Get()->Send(message); 647} 648 649void RenderWidget::Resize(const gfx::Size& new_size, 650 const gfx::Size& physical_backing_size, 651 float top_controls_layout_height, 652 const gfx::Size& visible_viewport_size, 653 const gfx::Rect& resizer_rect, 654 bool is_fullscreen, 655 ResizeAck resize_ack) { 656 if (resizing_mode_selector_->NeverUsesSynchronousResize()) { 657 // A resize ack shouldn't be requested if we have not ACK'd the previous 658 // one. 659 DCHECK(resize_ack != SEND_RESIZE_ACK || !next_paint_is_resize_ack()); 660 DCHECK(resize_ack == SEND_RESIZE_ACK || resize_ack == NO_RESIZE_ACK); 661 } 662 663 // Ignore this during shutdown. 664 if (!webwidget_) 665 return; 666 667 if (compositor_) { 668 compositor_->setViewportSize(new_size, physical_backing_size); 669 compositor_->SetTopControlsLayoutHeight(top_controls_layout_height); 670 } 671 672 physical_backing_size_ = physical_backing_size; 673 top_controls_layout_height_ = top_controls_layout_height; 674 visible_viewport_size_ = visible_viewport_size; 675 resizer_rect_ = resizer_rect; 676 677 // NOTE: We may have entered fullscreen mode without changing our size. 678 bool fullscreen_change = is_fullscreen_ != is_fullscreen; 679 if (fullscreen_change) 680 WillToggleFullscreen(); 681 is_fullscreen_ = is_fullscreen; 682 683 if (size_ != new_size) { 684 size_ = new_size; 685 686 // When resizing, we want to wait to paint before ACK'ing the resize. This 687 // ensures that we only resize as fast as we can paint. We only need to 688 // send an ACK if we are resized to a non-empty rect. 689 webwidget_->resize(new_size); 690 } else if (!resizing_mode_selector_->is_synchronous_mode()) { 691 resize_ack = NO_RESIZE_ACK; 692 } 693 694 webwidget()->resizePinchViewport(gfx::Size( 695 visible_viewport_size.width(), 696 visible_viewport_size.height())); 697 698 if (new_size.IsEmpty() || physical_backing_size.IsEmpty()) { 699 // For empty size or empty physical_backing_size, there is no next paint 700 // (along with which to send the ack) until they are set to non-empty. 701 resize_ack = NO_RESIZE_ACK; 702 } 703 704 // Send the Resize_ACK flag once we paint again if requested. 705 if (resize_ack == SEND_RESIZE_ACK) 706 set_next_paint_is_resize_ack(); 707 708 if (fullscreen_change) 709 DidToggleFullscreen(); 710 711 // If a resize ack is requested and it isn't set-up, then no more resizes will 712 // come in and in general things will go wrong. 713 DCHECK(resize_ack != SEND_RESIZE_ACK || next_paint_is_resize_ack()); 714} 715 716void RenderWidget::ResizeSynchronously(const gfx::Rect& new_position) { 717 Resize(new_position.size(), 718 new_position.size(), 719 top_controls_layout_height_, 720 visible_viewport_size_, 721 gfx::Rect(), 722 is_fullscreen_, 723 NO_RESIZE_ACK); 724 view_screen_rect_ = new_position; 725 window_screen_rect_ = new_position; 726 if (!did_show_) 727 initial_pos_ = new_position; 728} 729 730void RenderWidget::OnClose() { 731 if (closing_) 732 return; 733 closing_ = true; 734 735 // Browser correspondence is no longer needed at this point. 736 if (routing_id_ != MSG_ROUTING_NONE) { 737 if (RenderThreadImpl::current()) 738 RenderThreadImpl::current()->WidgetDestroyed(); 739 RenderThread::Get()->RemoveRoute(routing_id_); 740 SetHidden(false); 741 } 742 743 // If there is a Send call on the stack, then it could be dangerous to close 744 // now. Post a task that only gets invoked when there are no nested message 745 // loops. 746 base::MessageLoop::current()->PostNonNestableTask( 747 FROM_HERE, base::Bind(&RenderWidget::Close, this)); 748 749 // Balances the AddRef taken when we called AddRoute. 750 Release(); 751} 752 753// Got a response from the browser after the renderer decided to create a new 754// view. 755void RenderWidget::OnCreatingNewAck() { 756 DCHECK(routing_id_ != MSG_ROUTING_NONE); 757 758 CompleteInit(); 759} 760 761void RenderWidget::OnResize(const ViewMsg_Resize_Params& params) { 762 if (resizing_mode_selector_->ShouldAbortOnResize(this, params)) 763 return; 764 765 if (screen_metrics_emulator_) { 766 screen_metrics_emulator_->OnResizeMessage(params); 767 return; 768 } 769 770 bool orientation_changed = 771 screen_info_.orientationAngle != params.screen_info.orientationAngle; 772 773 screen_info_ = params.screen_info; 774 SetDeviceScaleFactor(screen_info_.deviceScaleFactor); 775 Resize(params.new_size, params.physical_backing_size, 776 params.top_controls_layout_height, 777 params.visible_viewport_size, params.resizer_rect, 778 params.is_fullscreen, SEND_RESIZE_ACK); 779 780 if (orientation_changed) 781 OnOrientationChange(); 782} 783 784void RenderWidget::OnChangeResizeRect(const gfx::Rect& resizer_rect) { 785 if (resizer_rect_ == resizer_rect) 786 return; 787 resizer_rect_ = resizer_rect; 788 if (webwidget_) 789 webwidget_->didChangeWindowResizerRect(); 790} 791 792void RenderWidget::OnWasHidden() { 793 TRACE_EVENT0("renderer", "RenderWidget::OnWasHidden"); 794 // Go into a mode where we stop generating paint and scrolling events. 795 SetHidden(true); 796 FOR_EACH_OBSERVER(RenderFrameImpl, render_frames_, 797 WasHidden()); 798} 799 800void RenderWidget::OnWasShown(bool needs_repainting, 801 const ui::LatencyInfo& latency_info) { 802 TRACE_EVENT0("renderer", "RenderWidget::OnWasShown"); 803 // During shutdown we can just ignore this message. 804 if (!webwidget_) 805 return; 806 807 // See OnWasHidden 808 SetHidden(false); 809 FOR_EACH_OBSERVER(RenderFrameImpl, render_frames_, 810 WasShown()); 811 812 if (!needs_repainting) 813 return; 814 815 // Generate a full repaint. 816 if (compositor_) { 817 ui::LatencyInfo swap_latency_info(latency_info); 818 scoped_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor( 819 compositor_->CreateLatencyInfoSwapPromiseMonitor(&swap_latency_info)); 820 compositor_->SetNeedsForcedRedraw(); 821 } 822 scheduleComposite(); 823} 824 825void RenderWidget::OnRequestMoveAck() { 826 DCHECK(pending_window_rect_count_); 827 pending_window_rect_count_--; 828} 829 830GURL RenderWidget::GetURLForGraphicsContext3D() { 831 return GURL(); 832} 833 834scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) { 835 // For widgets that are never visible, we don't start the compositor, so we 836 // never get a request for a cc::OutputSurface. 837 DCHECK(!never_visible_); 838 839#if defined(OS_ANDROID) 840 if (SynchronousCompositorFactory* factory = 841 SynchronousCompositorFactory::GetInstance()) { 842 return factory->CreateOutputSurface(routing_id(), 843 frame_swap_message_queue_); 844 } 845#endif 846 847 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 848 bool use_software = fallback; 849 if (command_line.HasSwitch(switches::kDisableGpuCompositing)) 850 use_software = true; 851 852 scoped_refptr<ContextProviderCommandBuffer> context_provider; 853 if (!use_software) { 854 context_provider = ContextProviderCommandBuffer::Create( 855 CreateGraphicsContext3D(), "RenderCompositor"); 856 if (!context_provider.get()) { 857 // Cause the compositor to wait and try again. 858 return scoped_ptr<cc::OutputSurface>(); 859 } 860 } 861 862 uint32 output_surface_id = next_output_surface_id_++; 863 if (command_line.HasSwitch(switches::kEnableDelegatedRenderer)) { 864 DCHECK(IsThreadedCompositingEnabled()); 865 return scoped_ptr<cc::OutputSurface>( 866 new DelegatedCompositorOutputSurface(routing_id(), 867 output_surface_id, 868 context_provider, 869 frame_swap_message_queue_)); 870 } 871 if (!context_provider.get()) { 872 scoped_ptr<cc::SoftwareOutputDevice> software_device( 873 new CompositorSoftwareOutputDevice()); 874 875 return scoped_ptr<cc::OutputSurface>( 876 new CompositorOutputSurface(routing_id(), 877 output_surface_id, 878 NULL, 879 software_device.Pass(), 880 frame_swap_message_queue_, 881 true)); 882 } 883 884 if (command_line.HasSwitch(cc::switches::kCompositeToMailbox)) { 885 // Composite-to-mailbox is currently used for layout tests in order to cause 886 // them to draw inside in the renderer to do the readback there. This should 887 // no longer be the case when crbug.com/311404 is fixed. 888 DCHECK(IsThreadedCompositingEnabled() || 889 RenderThreadImpl::current()->layout_test_mode()); 890 cc::ResourceFormat format = cc::RGBA_8888; 891 if (base::SysInfo::IsLowEndDevice()) 892 format = cc::RGB_565; 893 return scoped_ptr<cc::OutputSurface>( 894 new MailboxOutputSurface(routing_id(), 895 output_surface_id, 896 context_provider, 897 scoped_ptr<cc::SoftwareOutputDevice>(), 898 frame_swap_message_queue_, 899 format)); 900 } 901 bool use_swap_compositor_frame_message = false; 902 return scoped_ptr<cc::OutputSurface>( 903 new CompositorOutputSurface(routing_id(), 904 output_surface_id, 905 context_provider, 906 scoped_ptr<cc::SoftwareOutputDevice>(), 907 frame_swap_message_queue_, 908 use_swap_compositor_frame_message)); 909} 910 911void RenderWidget::OnSwapBuffersAborted() { 912 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersAborted"); 913 // Schedule another frame so the compositor learns about it. 914 scheduleComposite(); 915} 916 917void RenderWidget::OnSwapBuffersPosted() { 918 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersPosted"); 919} 920 921void RenderWidget::OnSwapBuffersComplete() { 922 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersComplete"); 923 924 // Notify subclasses that composited rendering was flushed to the screen. 925 DidFlushPaint(); 926} 927 928void RenderWidget::OnHandleInputEvent(const blink::WebInputEvent* input_event, 929 const ui::LatencyInfo& latency_info, 930 bool is_keyboard_shortcut) { 931 base::AutoReset<bool> handling_input_event_resetter( 932 &handling_input_event_, true); 933 if (!input_event) 934 return; 935 base::AutoReset<WebInputEvent::Type> handling_event_type_resetter( 936 &handling_event_type_, input_event->type); 937#if defined(OS_ANDROID) 938 // On Android, when a key is pressed or sent from the Keyboard using IME, 939 // |AdapterInputConnection| generates input key events to make sure all JS 940 // listeners that monitor KeyUp and KeyDown events receive the proper key 941 // code. Since this input key event comes from IME, we need to set the 942 // IME event guard here to make sure it does not interfere with other IME 943 // events. 944 scoped_ptr<ImeEventGuard> ime_event_guard_maybe; 945 if (WebInputEvent::isKeyboardEventType(input_event->type)) { 946 const WebKeyboardEvent& key_event = 947 *static_cast<const WebKeyboardEvent*>(input_event); 948 // Some keys are special and it's essential that no events get blocked. 949 if (key_event.nativeKeyCode != AKEYCODE_TAB) 950 ime_event_guard_maybe.reset(new ImeEventGuard(this)); 951 } 952#endif 953 954 base::AutoReset<const ui::LatencyInfo*> resetter(¤t_event_latency_info_, 955 &latency_info); 956 957 base::TimeTicks start_time; 958 if (base::TimeTicks::IsHighResNowFastAndReliable()) 959 start_time = base::TimeTicks::HighResNow(); 960 961 const char* const event_name = 962 WebInputEventTraits::GetName(input_event->type); 963 TRACE_EVENT1("renderer", "RenderWidget::OnHandleInputEvent", 964 "event", event_name); 965 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("blink.HandleInputEvent"); 966 TRACE_EVENT_FLOW_STEP0( 967 "input", 968 "LatencyInfo.Flow", 969 TRACE_ID_DONT_MANGLE(latency_info.trace_id), 970 "HanldeInputEventMain"); 971 972 scoped_ptr<cc::SwapPromiseMonitor> latency_info_swap_promise_monitor; 973 ui::LatencyInfo swap_latency_info(latency_info); 974 if (compositor_) { 975 latency_info_swap_promise_monitor = 976 compositor_->CreateLatencyInfoSwapPromiseMonitor(&swap_latency_info) 977 .Pass(); 978 } 979 980 if (base::TimeTicks::IsHighResNowFastAndReliable()) { 981 // If we don't have a high res timer, these metrics won't be accurate enough 982 // to be worth collecting. Note that this does introduce some sampling bias. 983 984 base::TimeDelta now = base::TimeDelta::FromInternalValue( 985 base::TimeTicks::HighResNow().ToInternalValue()); 986 987 int64 delta = 988 static_cast<int64>((now.InSecondsF() - input_event->timeStampSeconds) * 989 base::Time::kMicrosecondsPerSecond); 990 991 UMA_HISTOGRAM_CUSTOM_COUNTS( 992 "Event.AggregatedLatency.Renderer2", delta, 1, 10000000, 100); 993 base::HistogramBase* counter_for_type = base::Histogram::FactoryGet( 994 base::StringPrintf("Event.Latency.Renderer2.%s", event_name), 995 1, 996 10000000, 997 100, 998 base::HistogramBase::kUmaTargetedHistogramFlag); 999 counter_for_type->Add(delta); 1000 } 1001 1002 bool prevent_default = false; 1003 if (WebInputEvent::isMouseEventType(input_event->type)) { 1004 const WebMouseEvent& mouse_event = 1005 *static_cast<const WebMouseEvent*>(input_event); 1006 TRACE_EVENT2("renderer", "HandleMouseMove", 1007 "x", mouse_event.x, "y", mouse_event.y); 1008 context_menu_source_type_ = ui::MENU_SOURCE_MOUSE; 1009 prevent_default = WillHandleMouseEvent(mouse_event); 1010 } 1011 1012 if (WebInputEvent::isKeyboardEventType(input_event->type)) { 1013 context_menu_source_type_ = ui::MENU_SOURCE_KEYBOARD; 1014#if defined(OS_ANDROID) 1015 // The DPAD_CENTER key on Android has a dual semantic: (1) in the general 1016 // case it should behave like a select key (i.e. causing a click if a button 1017 // is focused). However, if a text field is focused (2), its intended 1018 // behavior is to just show the IME and don't propagate the key. 1019 // A typical use case is a web form: the DPAD_CENTER should bring up the IME 1020 // when clicked on an input text field and cause the form submit if clicked 1021 // when the submit button is focused, but not vice-versa. 1022 // The UI layer takes care of translating DPAD_CENTER into a RETURN key, 1023 // but at this point we have to swallow the event for the scenario (2). 1024 const WebKeyboardEvent& key_event = 1025 *static_cast<const WebKeyboardEvent*>(input_event); 1026 if (key_event.nativeKeyCode == AKEYCODE_DPAD_CENTER && 1027 GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) { 1028 OnShowImeIfNeeded(); 1029 prevent_default = true; 1030 } 1031#endif 1032 } 1033 1034 if (WebInputEvent::isGestureEventType(input_event->type)) { 1035 const WebGestureEvent& gesture_event = 1036 *static_cast<const WebGestureEvent*>(input_event); 1037 context_menu_source_type_ = ui::MENU_SOURCE_TOUCH; 1038 prevent_default = prevent_default || WillHandleGestureEvent(gesture_event); 1039 } 1040 1041 bool processed = prevent_default; 1042 if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) { 1043 suppress_next_char_events_ = false; 1044 if (!processed && webwidget_) 1045 processed = webwidget_->handleInputEvent(*input_event); 1046 } 1047 1048 // If this RawKeyDown event corresponds to a browser keyboard shortcut and 1049 // it's not processed by webkit, then we need to suppress the upcoming Char 1050 // events. 1051 if (!processed && is_keyboard_shortcut) 1052 suppress_next_char_events_ = true; 1053 1054 InputEventAckState ack_result = processed ? 1055 INPUT_EVENT_ACK_STATE_CONSUMED : INPUT_EVENT_ACK_STATE_NOT_CONSUMED; 1056 if (!processed && input_event->type == WebInputEvent::TouchStart) { 1057 const WebTouchEvent& touch_event = 1058 *static_cast<const WebTouchEvent*>(input_event); 1059 // Hit-test for all the pressed touch points. If there is a touch-handler 1060 // for any of the touch points, then the renderer should continue to receive 1061 // touch events. 1062 ack_result = INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; 1063 for (size_t i = 0; i < touch_event.touchesLength; ++i) { 1064 if (touch_event.touches[i].state == WebTouchPoint::StatePressed && 1065 HasTouchEventHandlersAt( 1066 gfx::ToFlooredPoint(touch_event.touches[i].position))) { 1067 ack_result = INPUT_EVENT_ACK_STATE_NOT_CONSUMED; 1068 break; 1069 } 1070 } 1071 } 1072 1073 // Unconsumed touchmove acks should never be throttled as they're required to 1074 // dispatch compositor-handled scroll gestures. 1075 bool event_type_can_be_rate_limited = 1076 input_event->type == WebInputEvent::MouseMove || 1077 input_event->type == WebInputEvent::MouseWheel || 1078 (input_event->type == WebInputEvent::TouchMove && 1079 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); 1080 1081 bool frame_pending = compositor_ && compositor_->BeginMainFrameRequested(); 1082 1083 // If we don't have a fast and accurate HighResNow, we assume the input 1084 // handlers are heavy and rate limit them. 1085 bool rate_limiting_wanted = true; 1086 if (base::TimeTicks::IsHighResNowFastAndReliable()) { 1087 base::TimeTicks end_time = base::TimeTicks::HighResNow(); 1088 total_input_handling_time_this_frame_ += (end_time - start_time); 1089 rate_limiting_wanted = 1090 total_input_handling_time_this_frame_.InMicroseconds() > 1091 kInputHandlingTimeThrottlingThresholdMicroseconds; 1092 } 1093 1094 TRACE_EVENT_SYNTHETIC_DELAY_END("blink.HandleInputEvent"); 1095 1096 // Note that we can't use handling_event_type_ here since it will be overriden 1097 // by reentrant calls for events after the paused one. 1098 bool no_ack = ignore_ack_for_mouse_move_from_debugger_ && 1099 input_event->type == WebInputEvent::MouseMove; 1100 if (!WebInputEventTraits::IgnoresAckDisposition(*input_event) && !no_ack) { 1101 InputHostMsg_HandleInputEvent_ACK_Params ack; 1102 ack.type = input_event->type; 1103 ack.state = ack_result; 1104 ack.latency = swap_latency_info; 1105 scoped_ptr<IPC::Message> response( 1106 new InputHostMsg_HandleInputEvent_ACK(routing_id_, ack)); 1107 if (rate_limiting_wanted && event_type_can_be_rate_limited && 1108 frame_pending && !is_hidden_) { 1109 // We want to rate limit the input events in this case, so we'll wait for 1110 // painting to finish before ACKing this message. 1111 TRACE_EVENT_INSTANT0("renderer", 1112 "RenderWidget::OnHandleInputEvent ack throttled", 1113 TRACE_EVENT_SCOPE_THREAD); 1114 if (pending_input_event_ack_) { 1115 // As two different kinds of events could cause us to postpone an ack 1116 // we send it now, if we have one pending. The Browser should never 1117 // send us the same kind of event we are delaying the ack for. 1118 Send(pending_input_event_ack_.release()); 1119 } 1120 pending_input_event_ack_ = response.Pass(); 1121 if (compositor_) 1122 compositor_->NotifyInputThrottledUntilCommit(); 1123 } else { 1124 Send(response.release()); 1125 } 1126 } 1127 if (input_event->type == WebInputEvent::MouseMove) 1128 ignore_ack_for_mouse_move_from_debugger_ = false; 1129 1130#if defined(OS_ANDROID) 1131 // Allow the IME to be shown when the focus changes as a consequence 1132 // of a processed touch end event. 1133 if (input_event->type == WebInputEvent::TouchEnd && processed) 1134 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME); 1135#elif defined(USE_AURA) 1136 // Show the virtual keyboard if enabled and a user gesture triggers a focus 1137 // change. 1138 if (processed && (input_event->type == WebInputEvent::TouchEnd || 1139 input_event->type == WebInputEvent::MouseUp)) 1140 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_IME); 1141#endif 1142 1143 if (!prevent_default) { 1144 if (WebInputEvent::isKeyboardEventType(input_event->type)) 1145 DidHandleKeyEvent(); 1146 if (WebInputEvent::isMouseEventType(input_event->type)) 1147 DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event))); 1148 if (WebInputEvent::isTouchEventType(input_event->type)) 1149 DidHandleTouchEvent(*(static_cast<const WebTouchEvent*>(input_event))); 1150 } 1151} 1152 1153void RenderWidget::OnCursorVisibilityChange(bool is_visible) { 1154 if (webwidget_) 1155 webwidget_->setCursorVisibilityState(is_visible); 1156} 1157 1158void RenderWidget::OnMouseCaptureLost() { 1159 if (webwidget_) 1160 webwidget_->mouseCaptureLost(); 1161} 1162 1163void RenderWidget::OnSetFocus(bool enable) { 1164 has_focus_ = enable; 1165 if (webwidget_) 1166 webwidget_->setFocus(enable); 1167} 1168 1169void RenderWidget::ClearFocus() { 1170 // We may have got the focus from the browser before this gets processed, in 1171 // which case we do not want to unfocus ourself. 1172 if (!has_focus_ && webwidget_) 1173 webwidget_->setFocus(false); 1174} 1175 1176void RenderWidget::FlushPendingInputEventAck() { 1177 if (pending_input_event_ack_) 1178 Send(pending_input_event_ack_.release()); 1179 total_input_handling_time_this_frame_ = base::TimeDelta(); 1180} 1181 1182/////////////////////////////////////////////////////////////////////////////// 1183// WebWidgetClient 1184 1185void RenderWidget::didAutoResize(const WebSize& new_size) { 1186 if (size_.width() != new_size.width || size_.height() != new_size.height) { 1187 size_ = new_size; 1188 1189 if (resizing_mode_selector_->is_synchronous_mode()) { 1190 WebRect new_pos(rootWindowRect().x, 1191 rootWindowRect().y, 1192 new_size.width, 1193 new_size.height); 1194 view_screen_rect_ = new_pos; 1195 window_screen_rect_ = new_pos; 1196 } 1197 1198 AutoResizeCompositor(); 1199 1200 if (!resizing_mode_selector_->is_synchronous_mode()) 1201 need_update_rect_for_auto_resize_ = true; 1202 } 1203} 1204 1205void RenderWidget::AutoResizeCompositor() { 1206 physical_backing_size_ = gfx::ToCeiledSize(gfx::ScaleSize(size_, 1207 device_scale_factor_)); 1208 if (compositor_) 1209 compositor_->setViewportSize(size_, physical_backing_size_); 1210} 1211 1212void RenderWidget::initializeLayerTreeView() { 1213 DCHECK(!host_closing_); 1214 1215 compositor_ = 1216 RenderWidgetCompositor::Create(this, IsThreadedCompositingEnabled()); 1217 compositor_->setViewportSize(size_, physical_backing_size_); 1218 if (init_complete_) 1219 StartCompositor(); 1220} 1221 1222void RenderWidget::DestroyLayerTreeView() { 1223 // Always send this notification to prevent new layer tree views from 1224 // being created, even if one hasn't been created yet. 1225 if (webwidget_) 1226 webwidget_->willCloseLayerTreeView(); 1227 compositor_.reset(); 1228} 1229 1230blink::WebLayerTreeView* RenderWidget::layerTreeView() { 1231 return compositor_.get(); 1232} 1233 1234void RenderWidget::willBeginCompositorFrame() { 1235 TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame"); 1236 1237 // The following two can result in further layout and possibly 1238 // enable GPU acceleration so they need to be called before any painting 1239 // is done. 1240 UpdateTextInputType(); 1241#if defined(OS_ANDROID) 1242 UpdateTextInputState(NO_SHOW_IME, FROM_NON_IME); 1243#endif 1244 UpdateSelectionBounds(); 1245} 1246 1247void RenderWidget::didBecomeReadyForAdditionalInput() { 1248 TRACE_EVENT0("renderer", "RenderWidget::didBecomeReadyForAdditionalInput"); 1249 FlushPendingInputEventAck(); 1250} 1251 1252void RenderWidget::DidCommitCompositorFrame() { 1253 FOR_EACH_OBSERVER(RenderFrameProxy, render_frame_proxies_, 1254 DidCommitCompositorFrame()); 1255#if defined(VIDEO_HOLE) 1256 FOR_EACH_OBSERVER(RenderFrameImpl, video_hole_frames_, 1257 DidCommitCompositorFrame()); 1258#endif // defined(VIDEO_HOLE) 1259} 1260 1261// static 1262scoped_ptr<cc::SwapPromise> RenderWidget::QueueMessageImpl( 1263 IPC::Message* msg, 1264 MessageDeliveryPolicy policy, 1265 FrameSwapMessageQueue* frame_swap_message_queue, 1266 scoped_refptr<IPC::SyncMessageFilter> sync_message_filter, 1267 bool commit_requested, 1268 int source_frame_number) { 1269 if (policy == MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE && 1270 // No need for lock: this gets changed only on this thread. 1271 !commit_requested && 1272 // No need for lock: Messages are only enqueued from this thread, if we 1273 // don't have any now, no other thread will add any. 1274 frame_swap_message_queue->Empty()) { 1275 sync_message_filter->Send(msg); 1276 return scoped_ptr<cc::SwapPromise>(); 1277 } 1278 1279 bool first_message_for_frame = false; 1280 frame_swap_message_queue->QueueMessageForFrame(policy, 1281 source_frame_number, 1282 make_scoped_ptr(msg), 1283 &first_message_for_frame); 1284 if (first_message_for_frame) { 1285 scoped_ptr<cc::SwapPromise> promise(new QueueMessageSwapPromise( 1286 sync_message_filter, frame_swap_message_queue, source_frame_number)); 1287 return promise.PassAs<cc::SwapPromise>(); 1288 } 1289 return scoped_ptr<cc::SwapPromise>(); 1290} 1291 1292void RenderWidget::QueueMessage(IPC::Message* msg, 1293 MessageDeliveryPolicy policy) { 1294 // RenderThreadImpl::current() is NULL in some tests. 1295 if (!compositor_ || !RenderThreadImpl::current()) { 1296 Send(msg); 1297 return; 1298 } 1299 1300 scoped_ptr<cc::SwapPromise> swap_promise = 1301 QueueMessageImpl(msg, 1302 policy, 1303 frame_swap_message_queue_.get(), 1304 RenderThreadImpl::current()->sync_message_filter(), 1305 compositor_->commitRequested(), 1306 compositor_->GetSourceFrameNumber()); 1307 1308 if (swap_promise) { 1309 compositor_->QueueSwapPromise(swap_promise.Pass()); 1310 compositor_->SetNeedsCommit(); 1311 } 1312} 1313 1314void RenderWidget::didCommitAndDrawCompositorFrame() { 1315 // NOTE: Tests may break if this event is renamed or moved. See 1316 // tab_capture_performancetest.cc. 1317 TRACE_EVENT0("gpu", "RenderWidget::didCommitAndDrawCompositorFrame"); 1318 // Notify subclasses that we initiated the paint operation. 1319 DidInitiatePaint(); 1320} 1321 1322void RenderWidget::didCompleteSwapBuffers() { 1323 TRACE_EVENT0("renderer", "RenderWidget::didCompleteSwapBuffers"); 1324 1325 // Notify subclasses threaded composited rendering was flushed to the screen. 1326 DidFlushPaint(); 1327 1328 if (!next_paint_flags_ && 1329 !need_update_rect_for_auto_resize_ && 1330 !plugin_window_moves_.size()) { 1331 return; 1332 } 1333 1334 ViewHostMsg_UpdateRect_Params params; 1335 params.view_size = size_; 1336 params.plugin_window_moves.swap(plugin_window_moves_); 1337 params.flags = next_paint_flags_; 1338 1339 Send(new ViewHostMsg_UpdateRect(routing_id_, params)); 1340 next_paint_flags_ = 0; 1341 need_update_rect_for_auto_resize_ = false; 1342} 1343 1344void RenderWidget::scheduleComposite() { 1345 RenderThreadImpl* render_thread = RenderThreadImpl::current(); 1346 // render_thread may be NULL in tests. 1347 if (render_thread && render_thread->compositor_message_loop_proxy().get() && 1348 compositor_) { 1349 compositor_->setNeedsAnimate(); 1350 } 1351} 1352 1353void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) { 1354 // TODO(darin): Eliminate this temporary. 1355 WebCursor cursor; 1356 InitializeCursorFromWebKitCursorInfo(&cursor, cursor_info); 1357 // Only send a SetCursor message if we need to make a change. 1358 if (!current_cursor_.IsEqual(cursor)) { 1359 current_cursor_ = cursor; 1360 Send(new ViewHostMsg_SetCursor(routing_id_, cursor)); 1361 } 1362} 1363 1364// We are supposed to get a single call to Show for a newly created RenderWidget 1365// that was created via RenderWidget::CreateWebView. So, we wait until this 1366// point to dispatch the ShowWidget message. 1367// 1368// This method provides us with the information about how to display the newly 1369// created RenderWidget (i.e., as a blocked popup or as a new tab). 1370// 1371void RenderWidget::show(WebNavigationPolicy) { 1372 DCHECK(!did_show_) << "received extraneous Show call"; 1373 DCHECK(routing_id_ != MSG_ROUTING_NONE); 1374 DCHECK(opener_id_ != MSG_ROUTING_NONE); 1375 1376 if (did_show_) 1377 return; 1378 1379 did_show_ = true; 1380 // NOTE: initial_pos_ may still have its default values at this point, but 1381 // that's okay. It'll be ignored if as_popup is false, or the browser 1382 // process will impose a default position otherwise. 1383 Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_)); 1384 SetPendingWindowRect(initial_pos_); 1385} 1386 1387void RenderWidget::didFocus() { 1388} 1389 1390void RenderWidget::didBlur() { 1391} 1392 1393void RenderWidget::DoDeferredClose() { 1394 // No more compositing is possible. This prevents shutdown races between 1395 // previously posted CreateOutputSurface tasks and the host being unable to 1396 // create them because the close message was handled. 1397 DestroyLayerTreeView(); 1398 // Also prevent new compositors from being created. 1399 host_closing_ = true; 1400 Send(new ViewHostMsg_Close(routing_id_)); 1401} 1402 1403void RenderWidget::closeWidgetSoon() { 1404 if (is_swapped_out_) { 1405 // This widget is currently swapped out, and the active widget is in a 1406 // different process. Have the browser route the close request to the 1407 // active widget instead, so that the correct unload handlers are run. 1408 Send(new ViewHostMsg_RouteCloseEvent(routing_id_)); 1409 return; 1410 } 1411 1412 // If a page calls window.close() twice, we'll end up here twice, but that's 1413 // OK. It is safe to send multiple Close messages. 1414 1415 // Ask the RenderWidgetHost to initiate close. We could be called from deep 1416 // in Javascript. If we ask the RendwerWidgetHost to close now, the window 1417 // could be closed before the JS finishes executing. So instead, post a 1418 // message back to the message loop, which won't run until the JS is 1419 // complete, and then the Close message can be sent. 1420 base::MessageLoop::current()->PostNonNestableTask( 1421 FROM_HERE, base::Bind(&RenderWidget::DoDeferredClose, this)); 1422} 1423 1424void RenderWidget::QueueSyntheticGesture( 1425 scoped_ptr<SyntheticGestureParams> gesture_params, 1426 const SyntheticGestureCompletionCallback& callback) { 1427 DCHECK(!callback.is_null()); 1428 1429 pending_synthetic_gesture_callbacks_.push(callback); 1430 1431 SyntheticGesturePacket gesture_packet; 1432 gesture_packet.set_gesture_params(gesture_params.Pass()); 1433 1434 Send(new InputHostMsg_QueueSyntheticGesture(routing_id_, gesture_packet)); 1435} 1436 1437void RenderWidget::Close() { 1438 screen_metrics_emulator_.reset(); 1439 DestroyLayerTreeView(); 1440 if (webwidget_) { 1441 webwidget_->close(); 1442 webwidget_ = NULL; 1443 } 1444} 1445 1446WebRect RenderWidget::windowRect() { 1447 if (pending_window_rect_count_) 1448 return pending_window_rect_; 1449 1450 return view_screen_rect_; 1451} 1452 1453void RenderWidget::setToolTipText(const blink::WebString& text, 1454 WebTextDirection hint) { 1455 Send(new ViewHostMsg_SetTooltipText(routing_id_, text, hint)); 1456} 1457 1458void RenderWidget::setWindowRect(const WebRect& rect) { 1459 WebRect pos = rect; 1460 if (popup_origin_scale_for_emulation_) { 1461 float scale = popup_origin_scale_for_emulation_; 1462 pos.x = popup_screen_origin_for_emulation_.x() + 1463 (pos.x - popup_view_origin_for_emulation_.x()) * scale; 1464 pos.y = popup_screen_origin_for_emulation_.y() + 1465 (pos.y - popup_view_origin_for_emulation_.y()) * scale; 1466 } 1467 1468 if (!resizing_mode_selector_->is_synchronous_mode()) { 1469 if (did_show_) { 1470 Send(new ViewHostMsg_RequestMove(routing_id_, pos)); 1471 SetPendingWindowRect(pos); 1472 } else { 1473 initial_pos_ = pos; 1474 } 1475 } else { 1476 ResizeSynchronously(pos); 1477 } 1478} 1479 1480void RenderWidget::SetPendingWindowRect(const WebRect& rect) { 1481 pending_window_rect_ = rect; 1482 pending_window_rect_count_++; 1483} 1484 1485WebRect RenderWidget::rootWindowRect() { 1486 if (pending_window_rect_count_) { 1487 // NOTE(mbelshe): If there is a pending_window_rect_, then getting 1488 // the RootWindowRect is probably going to return wrong results since the 1489 // browser may not have processed the Move yet. There isn't really anything 1490 // good to do in this case, and it shouldn't happen - since this size is 1491 // only really needed for windowToScreen, which is only used for Popups. 1492 return pending_window_rect_; 1493 } 1494 1495 return window_screen_rect_; 1496} 1497 1498WebRect RenderWidget::windowResizerRect() { 1499 return resizer_rect_; 1500} 1501 1502void RenderWidget::OnSetInputMethodActive(bool is_active) { 1503 // To prevent this renderer process from sending unnecessary IPC messages to 1504 // a browser process, we permit the renderer process to send IPC messages 1505 // only during the input method attached to the browser process is active. 1506 input_method_is_active_ = is_active; 1507} 1508 1509void RenderWidget::OnCandidateWindowShown() { 1510 webwidget_->didShowCandidateWindow(); 1511} 1512 1513void RenderWidget::OnCandidateWindowUpdated() { 1514 webwidget_->didUpdateCandidateWindow(); 1515} 1516 1517void RenderWidget::OnCandidateWindowHidden() { 1518 webwidget_->didHideCandidateWindow(); 1519} 1520 1521void RenderWidget::OnImeSetComposition( 1522 const base::string16& text, 1523 const std::vector<WebCompositionUnderline>& underlines, 1524 int selection_start, int selection_end) { 1525 if (!ShouldHandleImeEvent()) 1526 return; 1527 ImeEventGuard guard(this); 1528 if (!webwidget_->setComposition( 1529 text, WebVector<WebCompositionUnderline>(underlines), 1530 selection_start, selection_end)) { 1531 // If we failed to set the composition text, then we need to let the browser 1532 // process to cancel the input method's ongoing composition session, to make 1533 // sure we are in a consistent state. 1534 Send(new InputHostMsg_ImeCancelComposition(routing_id())); 1535 } 1536#if defined(OS_MACOSX) || defined(USE_AURA) 1537 UpdateCompositionInfo(true); 1538#endif 1539} 1540 1541void RenderWidget::OnImeConfirmComposition(const base::string16& text, 1542 const gfx::Range& replacement_range, 1543 bool keep_selection) { 1544 if (!ShouldHandleImeEvent()) 1545 return; 1546 ImeEventGuard guard(this); 1547 handling_input_event_ = true; 1548 if (text.length()) 1549 webwidget_->confirmComposition(text); 1550 else if (keep_selection) 1551 webwidget_->confirmComposition(WebWidget::KeepSelection); 1552 else 1553 webwidget_->confirmComposition(WebWidget::DoNotKeepSelection); 1554 handling_input_event_ = false; 1555#if defined(OS_MACOSX) || defined(USE_AURA) 1556 UpdateCompositionInfo(true); 1557#endif 1558} 1559 1560void RenderWidget::OnRepaint(gfx::Size size_to_paint) { 1561 // During shutdown we can just ignore this message. 1562 if (!webwidget_) 1563 return; 1564 1565 // Even if the browser provides an empty damage rect, it's still expecting to 1566 // receive a repaint ack so just damage the entire widget bounds. 1567 if (size_to_paint.IsEmpty()) { 1568 size_to_paint = size_; 1569 } 1570 1571 set_next_paint_is_repaint_ack(); 1572 if (compositor_) 1573 compositor_->SetNeedsRedrawRect(gfx::Rect(size_to_paint)); 1574} 1575 1576void RenderWidget::OnSyntheticGestureCompleted() { 1577 DCHECK(!pending_synthetic_gesture_callbacks_.empty()); 1578 1579 pending_synthetic_gesture_callbacks_.front().Run(); 1580 pending_synthetic_gesture_callbacks_.pop(); 1581} 1582 1583void RenderWidget::OnSetTextDirection(WebTextDirection direction) { 1584 if (!webwidget_) 1585 return; 1586 webwidget_->setTextDirection(direction); 1587} 1588 1589void RenderWidget::OnUpdateScreenRects(const gfx::Rect& view_screen_rect, 1590 const gfx::Rect& window_screen_rect) { 1591 if (screen_metrics_emulator_) { 1592 screen_metrics_emulator_->OnUpdateScreenRectsMessage( 1593 view_screen_rect, window_screen_rect); 1594 } else { 1595 view_screen_rect_ = view_screen_rect; 1596 window_screen_rect_ = window_screen_rect; 1597 } 1598 Send(new ViewHostMsg_UpdateScreenRects_ACK(routing_id())); 1599} 1600 1601void RenderWidget::showImeIfNeeded() { 1602 OnShowImeIfNeeded(); 1603} 1604 1605void RenderWidget::OnShowImeIfNeeded() { 1606#if defined(OS_ANDROID) || defined(USE_AURA) 1607 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME); 1608#endif 1609} 1610 1611#if defined(OS_ANDROID) 1612void RenderWidget::IncrementOutstandingImeEventAcks() { 1613 ++outstanding_ime_acks_; 1614} 1615 1616void RenderWidget::OnImeEventAck() { 1617 --outstanding_ime_acks_; 1618 DCHECK(outstanding_ime_acks_ >= 0); 1619} 1620#endif 1621 1622bool RenderWidget::ShouldHandleImeEvent() { 1623#if defined(OS_ANDROID) 1624 return !!webwidget_ && outstanding_ime_acks_ == 0; 1625#else 1626 return !!webwidget_; 1627#endif 1628} 1629 1630bool RenderWidget::SendAckForMouseMoveFromDebugger() { 1631 if (handling_event_type_ == WebInputEvent::MouseMove) { 1632 // If we pause multiple times during a single mouse move event, we should 1633 // only send ACK once. 1634 if (!ignore_ack_for_mouse_move_from_debugger_) { 1635 InputHostMsg_HandleInputEvent_ACK_Params ack; 1636 ack.type = handling_event_type_; 1637 ack.state = INPUT_EVENT_ACK_STATE_CONSUMED; 1638 Send(new InputHostMsg_HandleInputEvent_ACK(routing_id_, ack)); 1639 } 1640 return true; 1641 } 1642 return false; 1643} 1644 1645void RenderWidget::IgnoreAckForMouseMoveFromDebugger() { 1646 ignore_ack_for_mouse_move_from_debugger_ = true; 1647} 1648 1649void RenderWidget::SetDeviceScaleFactor(float device_scale_factor) { 1650 if (device_scale_factor_ == device_scale_factor) 1651 return; 1652 1653 device_scale_factor_ = device_scale_factor; 1654 scheduleComposite(); 1655} 1656 1657bool RenderWidget::SetDeviceColorProfile( 1658 const std::vector<char>& color_profile) { 1659 if (device_color_profile_ == color_profile) 1660 return false; 1661 1662 device_color_profile_ = color_profile; 1663 return true; 1664} 1665 1666void RenderWidget::ResetDeviceColorProfileForTesting() { 1667 if (!device_color_profile_.empty()) 1668 device_color_profile_.clear(); 1669 device_color_profile_.push_back('0'); 1670} 1671 1672void RenderWidget::OnOrientationChange() { 1673} 1674 1675gfx::Vector2d RenderWidget::GetScrollOffset() { 1676 // Bare RenderWidgets don't support scroll offset. 1677 return gfx::Vector2d(); 1678} 1679 1680void RenderWidget::SetHidden(bool hidden) { 1681 if (is_hidden_ == hidden) 1682 return; 1683 1684 // The status has changed. Tell the RenderThread about it. 1685 is_hidden_ = hidden; 1686 if (is_hidden_) 1687 RenderThreadImpl::current()->WidgetHidden(); 1688 else 1689 RenderThreadImpl::current()->WidgetRestored(); 1690} 1691 1692void RenderWidget::WillToggleFullscreen() { 1693 if (!webwidget_) 1694 return; 1695 1696 if (is_fullscreen_) { 1697 webwidget_->willExitFullScreen(); 1698 } else { 1699 webwidget_->willEnterFullScreen(); 1700 } 1701} 1702 1703void RenderWidget::DidToggleFullscreen() { 1704 if (!webwidget_) 1705 return; 1706 1707 if (is_fullscreen_) { 1708 webwidget_->didEnterFullScreen(); 1709 } else { 1710 webwidget_->didExitFullScreen(); 1711 } 1712} 1713 1714bool RenderWidget::next_paint_is_resize_ack() const { 1715 return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_); 1716} 1717 1718void RenderWidget::set_next_paint_is_resize_ack() { 1719 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK; 1720} 1721 1722void RenderWidget::set_next_paint_is_repaint_ack() { 1723 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK; 1724} 1725 1726static bool IsDateTimeInput(ui::TextInputType type) { 1727 return type == ui::TEXT_INPUT_TYPE_DATE || 1728 type == ui::TEXT_INPUT_TYPE_DATE_TIME || 1729 type == ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL || 1730 type == ui::TEXT_INPUT_TYPE_MONTH || 1731 type == ui::TEXT_INPUT_TYPE_TIME || 1732 type == ui::TEXT_INPUT_TYPE_WEEK; 1733} 1734 1735 1736void RenderWidget::StartHandlingImeEvent() { 1737 DCHECK(!handling_ime_event_); 1738 handling_ime_event_ = true; 1739} 1740 1741void RenderWidget::FinishHandlingImeEvent() { 1742 DCHECK(handling_ime_event_); 1743 handling_ime_event_ = false; 1744 // While handling an ime event, text input state and selection bounds updates 1745 // are ignored. These must explicitly be updated once finished handling the 1746 // ime event. 1747 UpdateSelectionBounds(); 1748#if defined(OS_ANDROID) 1749 UpdateTextInputState(NO_SHOW_IME, FROM_IME); 1750#endif 1751} 1752 1753void RenderWidget::UpdateTextInputType() { 1754 // On Windows, not only an IME but also an on-screen keyboard relies on the 1755 // latest TextInputType to optimize its layout and functionality. Thus 1756 // |input_method_is_active_| is no longer an appropriate condition to suppress 1757 // TextInputTypeChanged IPC on Windows. 1758 // TODO(yukawa, yoichio): Consider to stop checking |input_method_is_active_| 1759 // on other platforms as well as Windows if the overhead is acceptable. 1760#if !defined(OS_WIN) 1761 if (!input_method_is_active_) 1762 return; 1763#endif 1764 1765 ui::TextInputType new_type = GetTextInputType(); 1766 if (IsDateTimeInput(new_type)) 1767 return; // Not considered as a text input field in WebKit/Chromium. 1768 1769 bool new_can_compose_inline = CanComposeInline(); 1770 1771 blink::WebTextInputInfo new_info; 1772 if (webwidget_) 1773 new_info = webwidget_->textInputInfo(); 1774 const ui::TextInputMode new_mode = ConvertInputMode(new_info.inputMode); 1775 1776 if (text_input_type_ != new_type 1777 || can_compose_inline_ != new_can_compose_inline 1778 || text_input_mode_ != new_mode) { 1779 Send(new ViewHostMsg_TextInputTypeChanged(routing_id(), 1780 new_type, 1781 new_mode, 1782 new_can_compose_inline)); 1783 text_input_type_ = new_type; 1784 can_compose_inline_ = new_can_compose_inline; 1785 text_input_mode_ = new_mode; 1786 } 1787} 1788 1789#if defined(OS_ANDROID) || defined(USE_AURA) 1790void RenderWidget::UpdateTextInputState(ShowIme show_ime, 1791 ChangeSource change_source) { 1792 if (handling_ime_event_) 1793 return; 1794 if (show_ime == NO_SHOW_IME && !input_method_is_active_) 1795 return; 1796 ui::TextInputType new_type = GetTextInputType(); 1797 if (IsDateTimeInput(new_type)) 1798 return; // Not considered as a text input field in WebKit/Chromium. 1799 1800 blink::WebTextInputInfo new_info; 1801 if (webwidget_) 1802 new_info = webwidget_->textInputInfo(); 1803 1804 bool new_can_compose_inline = CanComposeInline(); 1805 1806 // Only sends text input params if they are changed or if the ime should be 1807 // shown. 1808 if (show_ime == SHOW_IME_IF_NEEDED || 1809 (text_input_type_ != new_type || 1810 text_input_info_ != new_info || 1811 can_compose_inline_ != new_can_compose_inline) 1812#if defined(OS_ANDROID) 1813 || text_field_is_dirty_ 1814#endif 1815 ) { 1816 ViewHostMsg_TextInputState_Params p; 1817 p.type = new_type; 1818 p.flags = new_info.flags; 1819 p.value = new_info.value.utf8(); 1820 p.selection_start = new_info.selectionStart; 1821 p.selection_end = new_info.selectionEnd; 1822 p.composition_start = new_info.compositionStart; 1823 p.composition_end = new_info.compositionEnd; 1824 p.can_compose_inline = new_can_compose_inline; 1825 p.show_ime_if_needed = (show_ime == SHOW_IME_IF_NEEDED); 1826#if defined(USE_AURA) 1827 p.is_non_ime_change = true; 1828#endif 1829#if defined(OS_ANDROID) 1830 p.is_non_ime_change = (change_source == FROM_NON_IME) || 1831 text_field_is_dirty_; 1832 if (p.is_non_ime_change) 1833 IncrementOutstandingImeEventAcks(); 1834 text_field_is_dirty_ = false; 1835#endif 1836#if defined(USE_AURA) 1837 Send(new ViewHostMsg_TextInputTypeChanged(routing_id(), 1838 new_type, 1839 text_input_mode_, 1840 new_can_compose_inline)); 1841#endif 1842 Send(new ViewHostMsg_TextInputStateChanged(routing_id(), p)); 1843 1844 text_input_info_ = new_info; 1845 text_input_type_ = new_type; 1846 can_compose_inline_ = new_can_compose_inline; 1847 } 1848} 1849#endif 1850 1851void RenderWidget::GetSelectionBounds(gfx::Rect* focus, gfx::Rect* anchor) { 1852 WebRect focus_webrect; 1853 WebRect anchor_webrect; 1854 webwidget_->selectionBounds(focus_webrect, anchor_webrect); 1855 *focus = focus_webrect; 1856 *anchor = anchor_webrect; 1857} 1858 1859void RenderWidget::UpdateSelectionBounds() { 1860 if (!webwidget_) 1861 return; 1862 if (handling_ime_event_) 1863 return; 1864 1865 // With composited selection updates, the selection bounds will be reported 1866 // directly by the compositor, in which case explicit IPC selection 1867 // notifications should be suppressed. 1868 if (!blink::WebRuntimeFeatures::isCompositedSelectionUpdateEnabled()) { 1869 ViewHostMsg_SelectionBounds_Params params; 1870 GetSelectionBounds(¶ms.anchor_rect, ¶ms.focus_rect); 1871 if (selection_anchor_rect_ != params.anchor_rect || 1872 selection_focus_rect_ != params.focus_rect) { 1873 selection_anchor_rect_ = params.anchor_rect; 1874 selection_focus_rect_ = params.focus_rect; 1875 webwidget_->selectionTextDirection(params.focus_dir, params.anchor_dir); 1876 params.is_anchor_first = webwidget_->isSelectionAnchorFirst(); 1877 Send(new ViewHostMsg_SelectionBoundsChanged(routing_id_, params)); 1878 } 1879 } 1880 1881#if defined(OS_MACOSX) || defined(USE_AURA) 1882 UpdateCompositionInfo(false); 1883#endif 1884} 1885 1886// Check blink::WebTextInputType and ui::TextInputType is kept in sync. 1887COMPILE_ASSERT(int(blink::WebTextInputTypeNone) == \ 1888 int(ui::TEXT_INPUT_TYPE_NONE), mismatching_enums); 1889COMPILE_ASSERT(int(blink::WebTextInputTypeText) == \ 1890 int(ui::TEXT_INPUT_TYPE_TEXT), mismatching_enums); 1891COMPILE_ASSERT(int(blink::WebTextInputTypePassword) == \ 1892 int(ui::TEXT_INPUT_TYPE_PASSWORD), mismatching_enums); 1893COMPILE_ASSERT(int(blink::WebTextInputTypeSearch) == \ 1894 int(ui::TEXT_INPUT_TYPE_SEARCH), mismatching_enums); 1895COMPILE_ASSERT(int(blink::WebTextInputTypeEmail) == \ 1896 int(ui::TEXT_INPUT_TYPE_EMAIL), mismatching_enums); 1897COMPILE_ASSERT(int(blink::WebTextInputTypeNumber) == \ 1898 int(ui::TEXT_INPUT_TYPE_NUMBER), mismatching_enums); 1899COMPILE_ASSERT(int(blink::WebTextInputTypeTelephone) == \ 1900 int(ui::TEXT_INPUT_TYPE_TELEPHONE), mismatching_enums); 1901COMPILE_ASSERT(int(blink::WebTextInputTypeURL) == \ 1902 int(ui::TEXT_INPUT_TYPE_URL), mismatching_enums); 1903COMPILE_ASSERT(int(blink::WebTextInputTypeDate) == \ 1904 int(ui::TEXT_INPUT_TYPE_DATE), mismatching_enum); 1905COMPILE_ASSERT(int(blink::WebTextInputTypeDateTime) == \ 1906 int(ui::TEXT_INPUT_TYPE_DATE_TIME), mismatching_enum); 1907COMPILE_ASSERT(int(blink::WebTextInputTypeDateTimeLocal) == \ 1908 int(ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL), mismatching_enum); 1909COMPILE_ASSERT(int(blink::WebTextInputTypeMonth) == \ 1910 int(ui::TEXT_INPUT_TYPE_MONTH), mismatching_enum); 1911COMPILE_ASSERT(int(blink::WebTextInputTypeTime) == \ 1912 int(ui::TEXT_INPUT_TYPE_TIME), mismatching_enum); 1913COMPILE_ASSERT(int(blink::WebTextInputTypeWeek) == \ 1914 int(ui::TEXT_INPUT_TYPE_WEEK), mismatching_enum); 1915COMPILE_ASSERT(int(blink::WebTextInputTypeTextArea) == \ 1916 int(ui::TEXT_INPUT_TYPE_TEXT_AREA), mismatching_enums); 1917COMPILE_ASSERT(int(blink::WebTextInputTypeContentEditable) == \ 1918 int(ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE), mismatching_enums); 1919COMPILE_ASSERT(int(blink::WebTextInputTypeDateTimeField) == \ 1920 int(ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD), mismatching_enums); 1921 1922ui::TextInputType RenderWidget::WebKitToUiTextInputType( 1923 blink::WebTextInputType type) { 1924 // Check the type is in the range representable by ui::TextInputType. 1925 DCHECK_LE(type, static_cast<int>(ui::TEXT_INPUT_TYPE_MAX)) << 1926 "blink::WebTextInputType and ui::TextInputType not synchronized"; 1927 return static_cast<ui::TextInputType>(type); 1928} 1929 1930ui::TextInputType RenderWidget::GetTextInputType() { 1931 if (webwidget_) 1932 return WebKitToUiTextInputType(webwidget_->textInputInfo().type); 1933 return ui::TEXT_INPUT_TYPE_NONE; 1934} 1935 1936#if defined(OS_MACOSX) || defined(USE_AURA) 1937void RenderWidget::UpdateCompositionInfo(bool should_update_range) { 1938 gfx::Range range = gfx::Range(); 1939 if (should_update_range) { 1940 GetCompositionRange(&range); 1941 } else { 1942 range = composition_range_; 1943 } 1944 std::vector<gfx::Rect> character_bounds; 1945 GetCompositionCharacterBounds(&character_bounds); 1946 1947 if (!ShouldUpdateCompositionInfo(range, character_bounds)) 1948 return; 1949 composition_character_bounds_ = character_bounds; 1950 composition_range_ = range; 1951 Send(new InputHostMsg_ImeCompositionRangeChanged( 1952 routing_id(), composition_range_, composition_character_bounds_)); 1953} 1954 1955void RenderWidget::GetCompositionCharacterBounds( 1956 std::vector<gfx::Rect>* bounds) { 1957 DCHECK(bounds); 1958 bounds->clear(); 1959} 1960 1961void RenderWidget::GetCompositionRange(gfx::Range* range) { 1962 size_t location, length; 1963 if (webwidget_->compositionRange(&location, &length)) { 1964 range->set_start(location); 1965 range->set_end(location + length); 1966 } else if (webwidget_->caretOrSelectionRange(&location, &length)) { 1967 range->set_start(location); 1968 range->set_end(location + length); 1969 } else { 1970 *range = gfx::Range::InvalidRange(); 1971 } 1972} 1973 1974bool RenderWidget::ShouldUpdateCompositionInfo( 1975 const gfx::Range& range, 1976 const std::vector<gfx::Rect>& bounds) { 1977 if (composition_range_ != range) 1978 return true; 1979 if (bounds.size() != composition_character_bounds_.size()) 1980 return true; 1981 for (size_t i = 0; i < bounds.size(); ++i) { 1982 if (bounds[i] != composition_character_bounds_[i]) 1983 return true; 1984 } 1985 return false; 1986} 1987#endif 1988 1989#if defined(OS_ANDROID) 1990void RenderWidget::DidChangeBodyBackgroundColor(SkColor bg_color) { 1991 // If not initialized, default to white. Note that 0 is different from black 1992 // as black still has alpha 0xFF. 1993 if (!bg_color) 1994 bg_color = SK_ColorWHITE; 1995 1996 if (bg_color != body_background_color_) { 1997 body_background_color_ = bg_color; 1998 Send(new ViewHostMsg_DidChangeBodyBackgroundColor(routing_id(), bg_color)); 1999 } 2000} 2001#endif 2002 2003bool RenderWidget::CanComposeInline() { 2004 return true; 2005} 2006 2007WebScreenInfo RenderWidget::screenInfo() { 2008 return screen_info_; 2009} 2010 2011float RenderWidget::deviceScaleFactor() { 2012 return device_scale_factor_; 2013} 2014 2015void RenderWidget::resetInputMethod() { 2016 if (!input_method_is_active_) 2017 return; 2018 2019 ImeEventGuard guard(this); 2020 // If the last text input type is not None, then we should finish any 2021 // ongoing composition regardless of the new text input type. 2022 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) { 2023 // If a composition text exists, then we need to let the browser process 2024 // to cancel the input method's ongoing composition session. 2025 if (webwidget_->confirmComposition()) 2026 Send(new InputHostMsg_ImeCancelComposition(routing_id())); 2027 } 2028 2029#if defined(OS_MACOSX) || defined(USE_AURA) 2030 UpdateCompositionInfo(true); 2031#endif 2032} 2033 2034void RenderWidget::didHandleGestureEvent( 2035 const WebGestureEvent& event, 2036 bool event_cancelled) { 2037#if defined(OS_ANDROID) || defined(USE_AURA) 2038 if (event_cancelled) 2039 return; 2040 if (event.type == WebInputEvent::GestureTap) { 2041 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME); 2042 } else if (event.type == WebInputEvent::GestureLongPress) { 2043 DCHECK(webwidget_); 2044 if (webwidget_->textInputInfo().value.isEmpty()) 2045 UpdateTextInputState(NO_SHOW_IME, FROM_NON_IME); 2046 else 2047 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME); 2048 } 2049#endif 2050} 2051 2052void RenderWidget::StartCompositor() { 2053 // For widgets that are never visible, we don't need the compositor to run 2054 // at all. 2055 if (never_visible_) 2056 return; 2057 compositor_->setSurfaceReady(); 2058} 2059 2060void RenderWidget::SchedulePluginMove(const WebPluginGeometry& move) { 2061 size_t i = 0; 2062 for (; i < plugin_window_moves_.size(); ++i) { 2063 if (plugin_window_moves_[i].window == move.window) { 2064 if (move.rects_valid) { 2065 plugin_window_moves_[i] = move; 2066 } else { 2067 plugin_window_moves_[i].visible = move.visible; 2068 } 2069 break; 2070 } 2071 } 2072 2073 if (i == plugin_window_moves_.size()) 2074 plugin_window_moves_.push_back(move); 2075} 2076 2077void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) { 2078 for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin(); 2079 i != plugin_window_moves_.end(); ++i) { 2080 if (i->window == window) { 2081 plugin_window_moves_.erase(i); 2082 break; 2083 } 2084 } 2085} 2086 2087 2088RenderWidgetCompositor* RenderWidget::compositor() const { 2089 return compositor_.get(); 2090} 2091 2092bool RenderWidget::WillHandleMouseEvent(const blink::WebMouseEvent& event) { 2093 return false; 2094} 2095 2096bool RenderWidget::WillHandleGestureEvent( 2097 const blink::WebGestureEvent& event) { 2098 return false; 2099} 2100 2101void RenderWidget::hasTouchEventHandlers(bool has_handlers) { 2102 Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers)); 2103} 2104 2105void RenderWidget::setTouchAction( 2106 blink::WebTouchAction web_touch_action) { 2107 2108 // Ignore setTouchAction calls that result from synthetic touch events (eg. 2109 // when blink is emulating touch with mouse). 2110 if (handling_event_type_ != WebInputEvent::TouchStart) 2111 return; 2112 2113 // Verify the same values are used by the types so we can cast between them. 2114 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_AUTO) == 2115 blink::WebTouchActionAuto, 2116 enum_values_must_match_for_touch_action); 2117 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_NONE) == 2118 blink::WebTouchActionNone, 2119 enum_values_must_match_for_touch_action); 2120 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_PAN_X) == 2121 blink::WebTouchActionPanX, 2122 enum_values_must_match_for_touch_action); 2123 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_PAN_Y) == 2124 blink::WebTouchActionPanY, 2125 enum_values_must_match_for_touch_action); 2126 COMPILE_ASSERT( 2127 static_cast<blink::WebTouchAction>(TOUCH_ACTION_PINCH_ZOOM) == 2128 blink::WebTouchActionPinchZoom, 2129 enum_values_must_match_for_touch_action); 2130 2131 content::TouchAction content_touch_action = 2132 static_cast<content::TouchAction>(web_touch_action); 2133 Send(new InputHostMsg_SetTouchAction(routing_id_, content_touch_action)); 2134} 2135 2136void RenderWidget::didUpdateTextOfFocusedElementByNonUserInput() { 2137#if defined(OS_ANDROID) 2138 text_field_is_dirty_ = true; 2139#endif 2140} 2141 2142bool RenderWidget::HasTouchEventHandlersAt(const gfx::Point& point) const { 2143 return true; 2144} 2145 2146scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 2147RenderWidget::CreateGraphicsContext3D() { 2148 if (!webwidget_) 2149 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 2150 if (CommandLine::ForCurrentProcess()->HasSwitch( 2151 switches::kDisableGpuCompositing)) 2152 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 2153 if (!RenderThreadImpl::current()) 2154 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 2155 CauseForGpuLaunch cause = 2156 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE; 2157 scoped_refptr<GpuChannelHost> gpu_channel_host( 2158 RenderThreadImpl::current()->EstablishGpuChannelSync(cause)); 2159 if (!gpu_channel_host.get()) 2160 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 2161 2162 // Explicitly disable antialiasing for the compositor. As of the time of 2163 // this writing, the only platform that supported antialiasing for the 2164 // compositor was Mac OS X, because the on-screen OpenGL context creation 2165 // code paths on Windows and Linux didn't yet have multisampling support. 2166 // Mac OS X essentially always behaves as though it's rendering offscreen. 2167 // Multisampling has a heavy cost especially on devices with relatively low 2168 // fill rate like most notebooks, and the Mac implementation would need to 2169 // be optimized to resolve directly into the IOSurface shared between the 2170 // GPU and browser processes. For these reasons and to avoid platform 2171 // disparities we explicitly disable antialiasing. 2172 blink::WebGraphicsContext3D::Attributes attributes; 2173 attributes.antialias = false; 2174 attributes.shareResources = true; 2175 attributes.noAutomaticFlushes = true; 2176 attributes.depth = false; 2177 attributes.stencil = false; 2178 bool lose_context_when_out_of_memory = true; 2179 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits; 2180#if defined(OS_ANDROID) 2181 // If we raster too fast we become upload bound, and pending 2182 // uploads consume memory. For maximum upload throughput, we would 2183 // want to allow for upload_throughput * pipeline_time of pending 2184 // uploads, after which we are just wasting memory. Since we don't 2185 // know our upload throughput yet, this just caps our memory usage. 2186 size_t divider = 1; 2187 if (base::SysInfo::IsLowEndDevice()) 2188 divider = 6; 2189 // For reference Nexus10 can upload 1MB in about 2.5ms. 2190 const double max_mb_uploaded_per_ms = 2.0 / (5 * divider); 2191 // Deadline to draw a frame to achieve 60 frames per second. 2192 const size_t kMillisecondsPerFrame = 16; 2193 // Assuming a two frame deep pipeline between the CPU and the GPU. 2194 size_t max_transfer_buffer_usage_mb = 2195 static_cast<size_t>(2 * kMillisecondsPerFrame * max_mb_uploaded_per_ms); 2196 static const size_t kBytesPerMegabyte = 1024 * 1024; 2197 // We keep the MappedMemoryReclaimLimit the same as the upload limit 2198 // to avoid unnecessarily stalling the compositor thread. 2199 limits.mapped_memory_reclaim_limit = 2200 max_transfer_buffer_usage_mb * kBytesPerMegabyte; 2201#endif 2202 2203 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context( 2204 new WebGraphicsContext3DCommandBufferImpl(surface_id(), 2205 GetURLForGraphicsContext3D(), 2206 gpu_channel_host.get(), 2207 attributes, 2208 lose_context_when_out_of_memory, 2209 limits, 2210 NULL)); 2211 return context.Pass(); 2212} 2213 2214void RenderWidget::RegisterRenderFrameProxy(RenderFrameProxy* proxy) { 2215 render_frame_proxies_.AddObserver(proxy); 2216} 2217 2218void RenderWidget::UnregisterRenderFrameProxy(RenderFrameProxy* proxy) { 2219 render_frame_proxies_.RemoveObserver(proxy); 2220} 2221 2222void RenderWidget::RegisterRenderFrame(RenderFrameImpl* frame) { 2223 render_frames_.AddObserver(frame); 2224} 2225 2226void RenderWidget::UnregisterRenderFrame(RenderFrameImpl* frame) { 2227 render_frames_.RemoveObserver(frame); 2228} 2229 2230#if defined(VIDEO_HOLE) 2231void RenderWidget::RegisterVideoHoleFrame(RenderFrameImpl* frame) { 2232 video_hole_frames_.AddObserver(frame); 2233} 2234 2235void RenderWidget::UnregisterVideoHoleFrame(RenderFrameImpl* frame) { 2236 video_hole_frames_.RemoveObserver(frame); 2237} 2238#endif // defined(VIDEO_HOLE) 2239 2240} // namespace content 2241