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 91 using blink::WebCompositionUnderline; 92 using blink::WebCursorInfo; 93 using blink::WebDeviceEmulationParams; 94 using blink::WebGestureEvent; 95 using blink::WebInputEvent; 96 using blink::WebKeyboardEvent; 97 using blink::WebMouseEvent; 98 using blink::WebMouseWheelEvent; 99 using blink::WebNavigationPolicy; 100 using blink::WebPagePopup; 101 using blink::WebPopupMenu; 102 using blink::WebPopupMenuInfo; 103 using blink::WebPopupType; 104 using blink::WebRange; 105 using blink::WebRect; 106 using blink::WebScreenInfo; 107 using blink::WebSize; 108 using blink::WebTextDirection; 109 using blink::WebTouchEvent; 110 using blink::WebTouchPoint; 111 using blink::WebVector; 112 using blink::WebWidget; 113 114 namespace { 115 116 typedef std::map<std::string, ui::TextInputMode> TextInputModeMap; 117 118 class 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 145 ui::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 155 bool 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. 164 const int kInputHandlingTimeThrottlingThresholdMicroseconds = 4166; 165 166 } // namespace 167 168 namespace content { 169 170 // RenderWidget::ScreenMetricsEmulator ---------------------------------------- 171 172 class 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 225 RenderWidget::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 241 RenderWidget::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 257 void RenderWidget::ScreenMetricsEmulator::ChangeEmulationParams( 258 const WebDeviceEmulationParams& params) { 259 params_ = params; 260 Reapply(); 261 } 262 263 void RenderWidget::ScreenMetricsEmulator::Reapply() { 264 Apply(widget_->top_controls_layout_height_, widget_->resizer_rect_, 265 widget_->is_fullscreen_); 266 } 267 268 void 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 332 void 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 350 void 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 359 void 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 367 gfx::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 377 RenderWidget::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 430 RenderWidget::~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 439 RenderWidget* 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 452 WebWidget* 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 467 bool 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 474 bool 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. 503 void 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 514 void 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 528 void 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 535 void 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 543 void RenderWidget::DisableScreenMetricsEmulation() { 544 screen_metrics_emulator_.reset(); 545 } 546 547 void 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 558 gfx::Rect RenderWidget::AdjustValidationMessageAnchor(const gfx::Rect& anchor) { 559 if (screen_metrics_emulator_) 560 return screen_metrics_emulator_->AdjustValidationMessageAnchor(anchor); 561 return anchor; 562 } 563 564 void 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) 573 void RenderWidget::SetExternalPopupOriginAdjustmentsForEmulation( 574 ExternalPopupMenu* popup, ScreenMetricsEmulator* emulator) { 575 popup->SetOriginScaleAndOffsetForEmulation( 576 emulator->scale(), emulator->offset()); 577 } 578 #endif 579 580 void RenderWidget::OnShowHostContextMenu(ContextMenuParams* params) { 581 if (screen_metrics_emulator_) 582 screen_metrics_emulator_->OnShowContextMenu(params); 583 } 584 585 void 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 596 bool 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 632 bool 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 649 void 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 716 void 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 730 void 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. 755 void RenderWidget::OnCreatingNewAck() { 756 DCHECK(routing_id_ != MSG_ROUTING_NONE); 757 758 CompleteInit(); 759 } 760 761 void 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 784 void 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 792 void 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 800 void 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 825 void RenderWidget::OnRequestMoveAck() { 826 DCHECK(pending_window_rect_count_); 827 pending_window_rect_count_--; 828 } 829 830 GURL RenderWidget::GetURLForGraphicsContext3D() { 831 return GURL(); 832 } 833 834 scoped_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 911 void RenderWidget::OnSwapBuffersAborted() { 912 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersAborted"); 913 // Schedule another frame so the compositor learns about it. 914 scheduleComposite(); 915 } 916 917 void RenderWidget::OnSwapBuffersPosted() { 918 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersPosted"); 919 } 920 921 void RenderWidget::OnSwapBuffersComplete() { 922 TRACE_EVENT0("renderer", "RenderWidget::OnSwapBuffersComplete"); 923 924 // Notify subclasses that composited rendering was flushed to the screen. 925 DidFlushPaint(); 926 } 927 928 void 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 bool event_type_can_be_rate_limited = 1074 input_event->type == WebInputEvent::MouseMove || 1075 input_event->type == WebInputEvent::MouseWheel; 1076 1077 bool frame_pending = compositor_ && compositor_->BeginMainFrameRequested(); 1078 1079 // If we don't have a fast and accurate HighResNow, we assume the input 1080 // handlers are heavy and rate limit them. 1081 bool rate_limiting_wanted = true; 1082 if (base::TimeTicks::IsHighResNowFastAndReliable()) { 1083 base::TimeTicks end_time = base::TimeTicks::HighResNow(); 1084 total_input_handling_time_this_frame_ += (end_time - start_time); 1085 rate_limiting_wanted = 1086 total_input_handling_time_this_frame_.InMicroseconds() > 1087 kInputHandlingTimeThrottlingThresholdMicroseconds; 1088 } 1089 1090 TRACE_EVENT_SYNTHETIC_DELAY_END("blink.HandleInputEvent"); 1091 1092 // Note that we can't use handling_event_type_ here since it will be overriden 1093 // by reentrant calls for events after the paused one. 1094 bool no_ack = ignore_ack_for_mouse_move_from_debugger_ && 1095 input_event->type == WebInputEvent::MouseMove; 1096 if (!WebInputEventTraits::IgnoresAckDisposition(*input_event) && !no_ack) { 1097 InputHostMsg_HandleInputEvent_ACK_Params ack; 1098 ack.type = input_event->type; 1099 ack.state = ack_result; 1100 ack.latency = swap_latency_info; 1101 scoped_ptr<IPC::Message> response( 1102 new InputHostMsg_HandleInputEvent_ACK(routing_id_, ack)); 1103 if (rate_limiting_wanted && event_type_can_be_rate_limited && 1104 frame_pending && !is_hidden_) { 1105 // We want to rate limit the input events in this case, so we'll wait for 1106 // painting to finish before ACKing this message. 1107 TRACE_EVENT_INSTANT0("renderer", 1108 "RenderWidget::OnHandleInputEvent ack throttled", 1109 TRACE_EVENT_SCOPE_THREAD); 1110 if (pending_input_event_ack_) { 1111 // As two different kinds of events could cause us to postpone an ack 1112 // we send it now, if we have one pending. The Browser should never 1113 // send us the same kind of event we are delaying the ack for. 1114 Send(pending_input_event_ack_.release()); 1115 } 1116 pending_input_event_ack_ = response.Pass(); 1117 if (compositor_) 1118 compositor_->NotifyInputThrottledUntilCommit(); 1119 } else { 1120 Send(response.release()); 1121 } 1122 } 1123 if (input_event->type == WebInputEvent::MouseMove) 1124 ignore_ack_for_mouse_move_from_debugger_ = false; 1125 1126 #if defined(OS_ANDROID) 1127 // Allow the IME to be shown when the focus changes as a consequence 1128 // of a processed touch end event. 1129 if (input_event->type == WebInputEvent::TouchEnd && processed) 1130 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME); 1131 #elif defined(USE_AURA) 1132 // Show the virtual keyboard if enabled and a user gesture triggers a focus 1133 // change. 1134 if (processed && (input_event->type == WebInputEvent::TouchEnd || 1135 input_event->type == WebInputEvent::MouseUp)) 1136 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_IME); 1137 #endif 1138 1139 if (!prevent_default) { 1140 if (WebInputEvent::isKeyboardEventType(input_event->type)) 1141 DidHandleKeyEvent(); 1142 if (WebInputEvent::isMouseEventType(input_event->type)) 1143 DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event))); 1144 if (WebInputEvent::isTouchEventType(input_event->type)) 1145 DidHandleTouchEvent(*(static_cast<const WebTouchEvent*>(input_event))); 1146 } 1147 } 1148 1149 void RenderWidget::OnCursorVisibilityChange(bool is_visible) { 1150 if (webwidget_) 1151 webwidget_->setCursorVisibilityState(is_visible); 1152 } 1153 1154 void RenderWidget::OnMouseCaptureLost() { 1155 if (webwidget_) 1156 webwidget_->mouseCaptureLost(); 1157 } 1158 1159 void RenderWidget::OnSetFocus(bool enable) { 1160 has_focus_ = enable; 1161 if (webwidget_) 1162 webwidget_->setFocus(enable); 1163 } 1164 1165 void RenderWidget::ClearFocus() { 1166 // We may have got the focus from the browser before this gets processed, in 1167 // which case we do not want to unfocus ourself. 1168 if (!has_focus_ && webwidget_) 1169 webwidget_->setFocus(false); 1170 } 1171 1172 void RenderWidget::FlushPendingInputEventAck() { 1173 if (pending_input_event_ack_) 1174 Send(pending_input_event_ack_.release()); 1175 total_input_handling_time_this_frame_ = base::TimeDelta(); 1176 } 1177 1178 /////////////////////////////////////////////////////////////////////////////// 1179 // WebWidgetClient 1180 1181 void RenderWidget::didAutoResize(const WebSize& new_size) { 1182 if (size_.width() != new_size.width || size_.height() != new_size.height) { 1183 size_ = new_size; 1184 1185 if (resizing_mode_selector_->is_synchronous_mode()) { 1186 WebRect new_pos(rootWindowRect().x, 1187 rootWindowRect().y, 1188 new_size.width, 1189 new_size.height); 1190 view_screen_rect_ = new_pos; 1191 window_screen_rect_ = new_pos; 1192 } 1193 1194 AutoResizeCompositor(); 1195 1196 if (!resizing_mode_selector_->is_synchronous_mode()) 1197 need_update_rect_for_auto_resize_ = true; 1198 } 1199 } 1200 1201 void RenderWidget::AutoResizeCompositor() { 1202 physical_backing_size_ = gfx::ToCeiledSize(gfx::ScaleSize(size_, 1203 device_scale_factor_)); 1204 if (compositor_) 1205 compositor_->setViewportSize(size_, physical_backing_size_); 1206 } 1207 1208 void RenderWidget::initializeLayerTreeView() { 1209 DCHECK(!host_closing_); 1210 1211 compositor_ = 1212 RenderWidgetCompositor::Create(this, IsThreadedCompositingEnabled()); 1213 compositor_->setViewportSize(size_, physical_backing_size_); 1214 if (init_complete_) 1215 StartCompositor(); 1216 } 1217 1218 void RenderWidget::DestroyLayerTreeView() { 1219 // Always send this notification to prevent new layer tree views from 1220 // being created, even if one hasn't been created yet. 1221 if (webwidget_) 1222 webwidget_->willCloseLayerTreeView(); 1223 compositor_.reset(); 1224 } 1225 1226 blink::WebLayerTreeView* RenderWidget::layerTreeView() { 1227 return compositor_.get(); 1228 } 1229 1230 void RenderWidget::willBeginCompositorFrame() { 1231 TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame"); 1232 1233 // The following two can result in further layout and possibly 1234 // enable GPU acceleration so they need to be called before any painting 1235 // is done. 1236 UpdateTextInputType(); 1237 #if defined(OS_ANDROID) 1238 UpdateTextInputState(NO_SHOW_IME, FROM_NON_IME); 1239 #endif 1240 UpdateSelectionBounds(); 1241 } 1242 1243 void RenderWidget::didBecomeReadyForAdditionalInput() { 1244 TRACE_EVENT0("renderer", "RenderWidget::didBecomeReadyForAdditionalInput"); 1245 FlushPendingInputEventAck(); 1246 } 1247 1248 void RenderWidget::DidCommitCompositorFrame() { 1249 FOR_EACH_OBSERVER(RenderFrameProxy, render_frame_proxies_, 1250 DidCommitCompositorFrame()); 1251 #if defined(VIDEO_HOLE) 1252 FOR_EACH_OBSERVER(RenderFrameImpl, video_hole_frames_, 1253 DidCommitCompositorFrame()); 1254 #endif // defined(VIDEO_HOLE) 1255 } 1256 1257 // static 1258 scoped_ptr<cc::SwapPromise> RenderWidget::QueueMessageImpl( 1259 IPC::Message* msg, 1260 MessageDeliveryPolicy policy, 1261 FrameSwapMessageQueue* frame_swap_message_queue, 1262 scoped_refptr<IPC::SyncMessageFilter> sync_message_filter, 1263 bool commit_requested, 1264 int source_frame_number) { 1265 if (policy == MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE && 1266 // No need for lock: this gets changed only on this thread. 1267 !commit_requested && 1268 // No need for lock: Messages are only enqueued from this thread, if we 1269 // don't have any now, no other thread will add any. 1270 frame_swap_message_queue->Empty()) { 1271 sync_message_filter->Send(msg); 1272 return scoped_ptr<cc::SwapPromise>(); 1273 } 1274 1275 bool first_message_for_frame = false; 1276 frame_swap_message_queue->QueueMessageForFrame(policy, 1277 source_frame_number, 1278 make_scoped_ptr(msg), 1279 &first_message_for_frame); 1280 if (first_message_for_frame) { 1281 scoped_ptr<cc::SwapPromise> promise(new QueueMessageSwapPromise( 1282 sync_message_filter, frame_swap_message_queue, source_frame_number)); 1283 return promise.PassAs<cc::SwapPromise>(); 1284 } 1285 return scoped_ptr<cc::SwapPromise>(); 1286 } 1287 1288 void RenderWidget::QueueMessage(IPC::Message* msg, 1289 MessageDeliveryPolicy policy) { 1290 // RenderThreadImpl::current() is NULL in some tests. 1291 if (!compositor_ || !RenderThreadImpl::current()) { 1292 Send(msg); 1293 return; 1294 } 1295 1296 scoped_ptr<cc::SwapPromise> swap_promise = 1297 QueueMessageImpl(msg, 1298 policy, 1299 frame_swap_message_queue_.get(), 1300 RenderThreadImpl::current()->sync_message_filter(), 1301 compositor_->commitRequested(), 1302 compositor_->GetSourceFrameNumber()); 1303 1304 if (swap_promise) { 1305 compositor_->QueueSwapPromise(swap_promise.Pass()); 1306 compositor_->SetNeedsCommit(); 1307 } 1308 } 1309 1310 void RenderWidget::didCommitAndDrawCompositorFrame() { 1311 // NOTE: Tests may break if this event is renamed or moved. See 1312 // tab_capture_performancetest.cc. 1313 TRACE_EVENT0("gpu", "RenderWidget::didCommitAndDrawCompositorFrame"); 1314 // Notify subclasses that we initiated the paint operation. 1315 DidInitiatePaint(); 1316 } 1317 1318 void RenderWidget::didCompleteSwapBuffers() { 1319 TRACE_EVENT0("renderer", "RenderWidget::didCompleteSwapBuffers"); 1320 1321 // Notify subclasses threaded composited rendering was flushed to the screen. 1322 DidFlushPaint(); 1323 1324 if (!next_paint_flags_ && 1325 !need_update_rect_for_auto_resize_ && 1326 !plugin_window_moves_.size()) { 1327 return; 1328 } 1329 1330 ViewHostMsg_UpdateRect_Params params; 1331 params.view_size = size_; 1332 params.plugin_window_moves.swap(plugin_window_moves_); 1333 params.flags = next_paint_flags_; 1334 1335 Send(new ViewHostMsg_UpdateRect(routing_id_, params)); 1336 next_paint_flags_ = 0; 1337 need_update_rect_for_auto_resize_ = false; 1338 } 1339 1340 void RenderWidget::scheduleComposite() { 1341 RenderThreadImpl* render_thread = RenderThreadImpl::current(); 1342 // render_thread may be NULL in tests. 1343 if (render_thread && render_thread->compositor_message_loop_proxy().get() && 1344 compositor_) { 1345 compositor_->setNeedsAnimate(); 1346 } 1347 } 1348 1349 void RenderWidget::didChangeCursor(const WebCursorInfo& cursor_info) { 1350 // TODO(darin): Eliminate this temporary. 1351 WebCursor cursor; 1352 InitializeCursorFromWebKitCursorInfo(&cursor, cursor_info); 1353 // Only send a SetCursor message if we need to make a change. 1354 if (!current_cursor_.IsEqual(cursor)) { 1355 current_cursor_ = cursor; 1356 Send(new ViewHostMsg_SetCursor(routing_id_, cursor)); 1357 } 1358 } 1359 1360 // We are supposed to get a single call to Show for a newly created RenderWidget 1361 // that was created via RenderWidget::CreateWebView. So, we wait until this 1362 // point to dispatch the ShowWidget message. 1363 // 1364 // This method provides us with the information about how to display the newly 1365 // created RenderWidget (i.e., as a blocked popup or as a new tab). 1366 // 1367 void RenderWidget::show(WebNavigationPolicy) { 1368 DCHECK(!did_show_) << "received extraneous Show call"; 1369 DCHECK(routing_id_ != MSG_ROUTING_NONE); 1370 DCHECK(opener_id_ != MSG_ROUTING_NONE); 1371 1372 if (did_show_) 1373 return; 1374 1375 did_show_ = true; 1376 // NOTE: initial_pos_ may still have its default values at this point, but 1377 // that's okay. It'll be ignored if as_popup is false, or the browser 1378 // process will impose a default position otherwise. 1379 Send(new ViewHostMsg_ShowWidget(opener_id_, routing_id_, initial_pos_)); 1380 SetPendingWindowRect(initial_pos_); 1381 } 1382 1383 void RenderWidget::didFocus() { 1384 } 1385 1386 void RenderWidget::didBlur() { 1387 } 1388 1389 void RenderWidget::DoDeferredClose() { 1390 // No more compositing is possible. This prevents shutdown races between 1391 // previously posted CreateOutputSurface tasks and the host being unable to 1392 // create them because the close message was handled. 1393 DestroyLayerTreeView(); 1394 // Also prevent new compositors from being created. 1395 host_closing_ = true; 1396 Send(new ViewHostMsg_Close(routing_id_)); 1397 } 1398 1399 void RenderWidget::closeWidgetSoon() { 1400 if (is_swapped_out_) { 1401 // This widget is currently swapped out, and the active widget is in a 1402 // different process. Have the browser route the close request to the 1403 // active widget instead, so that the correct unload handlers are run. 1404 Send(new ViewHostMsg_RouteCloseEvent(routing_id_)); 1405 return; 1406 } 1407 1408 // If a page calls window.close() twice, we'll end up here twice, but that's 1409 // OK. It is safe to send multiple Close messages. 1410 1411 // Ask the RenderWidgetHost to initiate close. We could be called from deep 1412 // in Javascript. If we ask the RendwerWidgetHost to close now, the window 1413 // could be closed before the JS finishes executing. So instead, post a 1414 // message back to the message loop, which won't run until the JS is 1415 // complete, and then the Close message can be sent. 1416 base::MessageLoop::current()->PostNonNestableTask( 1417 FROM_HERE, base::Bind(&RenderWidget::DoDeferredClose, this)); 1418 } 1419 1420 void RenderWidget::QueueSyntheticGesture( 1421 scoped_ptr<SyntheticGestureParams> gesture_params, 1422 const SyntheticGestureCompletionCallback& callback) { 1423 DCHECK(!callback.is_null()); 1424 1425 pending_synthetic_gesture_callbacks_.push(callback); 1426 1427 SyntheticGesturePacket gesture_packet; 1428 gesture_packet.set_gesture_params(gesture_params.Pass()); 1429 1430 Send(new InputHostMsg_QueueSyntheticGesture(routing_id_, gesture_packet)); 1431 } 1432 1433 void RenderWidget::Close() { 1434 screen_metrics_emulator_.reset(); 1435 DestroyLayerTreeView(); 1436 if (webwidget_) { 1437 webwidget_->close(); 1438 webwidget_ = NULL; 1439 } 1440 } 1441 1442 WebRect RenderWidget::windowRect() { 1443 if (pending_window_rect_count_) 1444 return pending_window_rect_; 1445 1446 return view_screen_rect_; 1447 } 1448 1449 void RenderWidget::setToolTipText(const blink::WebString& text, 1450 WebTextDirection hint) { 1451 Send(new ViewHostMsg_SetTooltipText(routing_id_, text, hint)); 1452 } 1453 1454 void RenderWidget::setWindowRect(const WebRect& rect) { 1455 WebRect pos = rect; 1456 if (popup_origin_scale_for_emulation_) { 1457 float scale = popup_origin_scale_for_emulation_; 1458 pos.x = popup_screen_origin_for_emulation_.x() + 1459 (pos.x - popup_view_origin_for_emulation_.x()) * scale; 1460 pos.y = popup_screen_origin_for_emulation_.y() + 1461 (pos.y - popup_view_origin_for_emulation_.y()) * scale; 1462 } 1463 1464 if (!resizing_mode_selector_->is_synchronous_mode()) { 1465 if (did_show_) { 1466 Send(new ViewHostMsg_RequestMove(routing_id_, pos)); 1467 SetPendingWindowRect(pos); 1468 } else { 1469 initial_pos_ = pos; 1470 } 1471 } else { 1472 ResizeSynchronously(pos); 1473 } 1474 } 1475 1476 void RenderWidget::SetPendingWindowRect(const WebRect& rect) { 1477 pending_window_rect_ = rect; 1478 pending_window_rect_count_++; 1479 } 1480 1481 WebRect RenderWidget::rootWindowRect() { 1482 if (pending_window_rect_count_) { 1483 // NOTE(mbelshe): If there is a pending_window_rect_, then getting 1484 // the RootWindowRect is probably going to return wrong results since the 1485 // browser may not have processed the Move yet. There isn't really anything 1486 // good to do in this case, and it shouldn't happen - since this size is 1487 // only really needed for windowToScreen, which is only used for Popups. 1488 return pending_window_rect_; 1489 } 1490 1491 return window_screen_rect_; 1492 } 1493 1494 WebRect RenderWidget::windowResizerRect() { 1495 return resizer_rect_; 1496 } 1497 1498 void RenderWidget::OnSetInputMethodActive(bool is_active) { 1499 // To prevent this renderer process from sending unnecessary IPC messages to 1500 // a browser process, we permit the renderer process to send IPC messages 1501 // only during the input method attached to the browser process is active. 1502 input_method_is_active_ = is_active; 1503 } 1504 1505 void RenderWidget::OnCandidateWindowShown() { 1506 webwidget_->didShowCandidateWindow(); 1507 } 1508 1509 void RenderWidget::OnCandidateWindowUpdated() { 1510 webwidget_->didUpdateCandidateWindow(); 1511 } 1512 1513 void RenderWidget::OnCandidateWindowHidden() { 1514 webwidget_->didHideCandidateWindow(); 1515 } 1516 1517 void RenderWidget::OnImeSetComposition( 1518 const base::string16& text, 1519 const std::vector<WebCompositionUnderline>& underlines, 1520 int selection_start, int selection_end) { 1521 if (!ShouldHandleImeEvent()) 1522 return; 1523 ImeEventGuard guard(this); 1524 if (!webwidget_->setComposition( 1525 text, WebVector<WebCompositionUnderline>(underlines), 1526 selection_start, selection_end)) { 1527 // If we failed to set the composition text, then we need to let the browser 1528 // process to cancel the input method's ongoing composition session, to make 1529 // sure we are in a consistent state. 1530 Send(new InputHostMsg_ImeCancelComposition(routing_id())); 1531 } 1532 #if defined(OS_MACOSX) || defined(USE_AURA) 1533 UpdateCompositionInfo(true); 1534 #endif 1535 } 1536 1537 void RenderWidget::OnImeConfirmComposition(const base::string16& text, 1538 const gfx::Range& replacement_range, 1539 bool keep_selection) { 1540 if (!ShouldHandleImeEvent()) 1541 return; 1542 ImeEventGuard guard(this); 1543 handling_input_event_ = true; 1544 if (text.length()) 1545 webwidget_->confirmComposition(text); 1546 else if (keep_selection) 1547 webwidget_->confirmComposition(WebWidget::KeepSelection); 1548 else 1549 webwidget_->confirmComposition(WebWidget::DoNotKeepSelection); 1550 handling_input_event_ = false; 1551 #if defined(OS_MACOSX) || defined(USE_AURA) 1552 UpdateCompositionInfo(true); 1553 #endif 1554 } 1555 1556 void RenderWidget::OnRepaint(gfx::Size size_to_paint) { 1557 // During shutdown we can just ignore this message. 1558 if (!webwidget_) 1559 return; 1560 1561 // Even if the browser provides an empty damage rect, it's still expecting to 1562 // receive a repaint ack so just damage the entire widget bounds. 1563 if (size_to_paint.IsEmpty()) { 1564 size_to_paint = size_; 1565 } 1566 1567 set_next_paint_is_repaint_ack(); 1568 if (compositor_) 1569 compositor_->SetNeedsRedrawRect(gfx::Rect(size_to_paint)); 1570 } 1571 1572 void RenderWidget::OnSyntheticGestureCompleted() { 1573 DCHECK(!pending_synthetic_gesture_callbacks_.empty()); 1574 1575 pending_synthetic_gesture_callbacks_.front().Run(); 1576 pending_synthetic_gesture_callbacks_.pop(); 1577 } 1578 1579 void RenderWidget::OnSetTextDirection(WebTextDirection direction) { 1580 if (!webwidget_) 1581 return; 1582 webwidget_->setTextDirection(direction); 1583 } 1584 1585 void RenderWidget::OnUpdateScreenRects(const gfx::Rect& view_screen_rect, 1586 const gfx::Rect& window_screen_rect) { 1587 if (screen_metrics_emulator_) { 1588 screen_metrics_emulator_->OnUpdateScreenRectsMessage( 1589 view_screen_rect, window_screen_rect); 1590 } else { 1591 view_screen_rect_ = view_screen_rect; 1592 window_screen_rect_ = window_screen_rect; 1593 } 1594 Send(new ViewHostMsg_UpdateScreenRects_ACK(routing_id())); 1595 } 1596 1597 void RenderWidget::showImeIfNeeded() { 1598 OnShowImeIfNeeded(); 1599 } 1600 1601 void RenderWidget::OnShowImeIfNeeded() { 1602 #if defined(OS_ANDROID) || defined(USE_AURA) 1603 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME); 1604 #endif 1605 } 1606 1607 #if defined(OS_ANDROID) 1608 void RenderWidget::IncrementOutstandingImeEventAcks() { 1609 ++outstanding_ime_acks_; 1610 } 1611 1612 void RenderWidget::OnImeEventAck() { 1613 --outstanding_ime_acks_; 1614 DCHECK(outstanding_ime_acks_ >= 0); 1615 } 1616 #endif 1617 1618 bool RenderWidget::ShouldHandleImeEvent() { 1619 #if defined(OS_ANDROID) 1620 return !!webwidget_ && outstanding_ime_acks_ == 0; 1621 #else 1622 return !!webwidget_; 1623 #endif 1624 } 1625 1626 bool RenderWidget::SendAckForMouseMoveFromDebugger() { 1627 if (handling_event_type_ == WebInputEvent::MouseMove) { 1628 // If we pause multiple times during a single mouse move event, we should 1629 // only send ACK once. 1630 if (!ignore_ack_for_mouse_move_from_debugger_) { 1631 InputHostMsg_HandleInputEvent_ACK_Params ack; 1632 ack.type = handling_event_type_; 1633 ack.state = INPUT_EVENT_ACK_STATE_CONSUMED; 1634 Send(new InputHostMsg_HandleInputEvent_ACK(routing_id_, ack)); 1635 } 1636 return true; 1637 } 1638 return false; 1639 } 1640 1641 void RenderWidget::IgnoreAckForMouseMoveFromDebugger() { 1642 ignore_ack_for_mouse_move_from_debugger_ = true; 1643 } 1644 1645 void RenderWidget::SetDeviceScaleFactor(float device_scale_factor) { 1646 if (device_scale_factor_ == device_scale_factor) 1647 return; 1648 1649 device_scale_factor_ = device_scale_factor; 1650 scheduleComposite(); 1651 } 1652 1653 bool RenderWidget::SetDeviceColorProfile( 1654 const std::vector<char>& color_profile) { 1655 if (device_color_profile_ == color_profile) 1656 return false; 1657 1658 device_color_profile_ = color_profile; 1659 return true; 1660 } 1661 1662 void RenderWidget::ResetDeviceColorProfileForTesting() { 1663 if (!device_color_profile_.empty()) 1664 device_color_profile_.clear(); 1665 device_color_profile_.push_back('0'); 1666 } 1667 1668 void RenderWidget::OnOrientationChange() { 1669 } 1670 1671 gfx::Vector2d RenderWidget::GetScrollOffset() { 1672 // Bare RenderWidgets don't support scroll offset. 1673 return gfx::Vector2d(); 1674 } 1675 1676 void RenderWidget::SetHidden(bool hidden) { 1677 if (is_hidden_ == hidden) 1678 return; 1679 1680 // The status has changed. Tell the RenderThread about it. 1681 is_hidden_ = hidden; 1682 if (is_hidden_) 1683 RenderThreadImpl::current()->WidgetHidden(); 1684 else 1685 RenderThreadImpl::current()->WidgetRestored(); 1686 } 1687 1688 void RenderWidget::WillToggleFullscreen() { 1689 if (!webwidget_) 1690 return; 1691 1692 if (is_fullscreen_) { 1693 webwidget_->willExitFullScreen(); 1694 } else { 1695 webwidget_->willEnterFullScreen(); 1696 } 1697 } 1698 1699 void RenderWidget::DidToggleFullscreen() { 1700 if (!webwidget_) 1701 return; 1702 1703 if (is_fullscreen_) { 1704 webwidget_->didEnterFullScreen(); 1705 } else { 1706 webwidget_->didExitFullScreen(); 1707 } 1708 } 1709 1710 bool RenderWidget::next_paint_is_resize_ack() const { 1711 return ViewHostMsg_UpdateRect_Flags::is_resize_ack(next_paint_flags_); 1712 } 1713 1714 void RenderWidget::set_next_paint_is_resize_ack() { 1715 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_RESIZE_ACK; 1716 } 1717 1718 void RenderWidget::set_next_paint_is_repaint_ack() { 1719 next_paint_flags_ |= ViewHostMsg_UpdateRect_Flags::IS_REPAINT_ACK; 1720 } 1721 1722 static bool IsDateTimeInput(ui::TextInputType type) { 1723 return type == ui::TEXT_INPUT_TYPE_DATE || 1724 type == ui::TEXT_INPUT_TYPE_DATE_TIME || 1725 type == ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL || 1726 type == ui::TEXT_INPUT_TYPE_MONTH || 1727 type == ui::TEXT_INPUT_TYPE_TIME || 1728 type == ui::TEXT_INPUT_TYPE_WEEK; 1729 } 1730 1731 1732 void RenderWidget::StartHandlingImeEvent() { 1733 DCHECK(!handling_ime_event_); 1734 handling_ime_event_ = true; 1735 } 1736 1737 void RenderWidget::FinishHandlingImeEvent() { 1738 DCHECK(handling_ime_event_); 1739 handling_ime_event_ = false; 1740 // While handling an ime event, text input state and selection bounds updates 1741 // are ignored. These must explicitly be updated once finished handling the 1742 // ime event. 1743 UpdateSelectionBounds(); 1744 #if defined(OS_ANDROID) 1745 UpdateTextInputState(NO_SHOW_IME, FROM_IME); 1746 #endif 1747 } 1748 1749 void RenderWidget::UpdateTextInputType() { 1750 // On Windows, not only an IME but also an on-screen keyboard relies on the 1751 // latest TextInputType to optimize its layout and functionality. Thus 1752 // |input_method_is_active_| is no longer an appropriate condition to suppress 1753 // TextInputTypeChanged IPC on Windows. 1754 // TODO(yukawa, yoichio): Consider to stop checking |input_method_is_active_| 1755 // on other platforms as well as Windows if the overhead is acceptable. 1756 #if !defined(OS_WIN) 1757 if (!input_method_is_active_) 1758 return; 1759 #endif 1760 1761 ui::TextInputType new_type = GetTextInputType(); 1762 if (IsDateTimeInput(new_type)) 1763 return; // Not considered as a text input field in WebKit/Chromium. 1764 1765 bool new_can_compose_inline = CanComposeInline(); 1766 1767 blink::WebTextInputInfo new_info; 1768 if (webwidget_) 1769 new_info = webwidget_->textInputInfo(); 1770 const ui::TextInputMode new_mode = ConvertInputMode(new_info.inputMode); 1771 1772 if (text_input_type_ != new_type 1773 || can_compose_inline_ != new_can_compose_inline 1774 || text_input_mode_ != new_mode) { 1775 Send(new ViewHostMsg_TextInputTypeChanged(routing_id(), 1776 new_type, 1777 new_mode, 1778 new_can_compose_inline)); 1779 text_input_type_ = new_type; 1780 can_compose_inline_ = new_can_compose_inline; 1781 text_input_mode_ = new_mode; 1782 } 1783 } 1784 1785 #if defined(OS_ANDROID) || defined(USE_AURA) 1786 void RenderWidget::UpdateTextInputState(ShowIme show_ime, 1787 ChangeSource change_source) { 1788 if (handling_ime_event_) 1789 return; 1790 if (show_ime == NO_SHOW_IME && !input_method_is_active_) 1791 return; 1792 ui::TextInputType new_type = GetTextInputType(); 1793 if (IsDateTimeInput(new_type)) 1794 return; // Not considered as a text input field in WebKit/Chromium. 1795 1796 blink::WebTextInputInfo new_info; 1797 if (webwidget_) 1798 new_info = webwidget_->textInputInfo(); 1799 1800 bool new_can_compose_inline = CanComposeInline(); 1801 1802 // Only sends text input params if they are changed or if the ime should be 1803 // shown. 1804 if (show_ime == SHOW_IME_IF_NEEDED || 1805 (text_input_type_ != new_type || 1806 text_input_info_ != new_info || 1807 can_compose_inline_ != new_can_compose_inline) 1808 #if defined(OS_ANDROID) 1809 || text_field_is_dirty_ 1810 #endif 1811 ) { 1812 ViewHostMsg_TextInputState_Params p; 1813 p.type = new_type; 1814 p.flags = new_info.flags; 1815 p.value = new_info.value.utf8(); 1816 p.selection_start = new_info.selectionStart; 1817 p.selection_end = new_info.selectionEnd; 1818 p.composition_start = new_info.compositionStart; 1819 p.composition_end = new_info.compositionEnd; 1820 p.can_compose_inline = new_can_compose_inline; 1821 p.show_ime_if_needed = (show_ime == SHOW_IME_IF_NEEDED); 1822 #if defined(USE_AURA) 1823 p.is_non_ime_change = true; 1824 #endif 1825 #if defined(OS_ANDROID) 1826 p.is_non_ime_change = (change_source == FROM_NON_IME) || 1827 text_field_is_dirty_; 1828 if (p.is_non_ime_change) 1829 IncrementOutstandingImeEventAcks(); 1830 text_field_is_dirty_ = false; 1831 #endif 1832 #if defined(USE_AURA) 1833 Send(new ViewHostMsg_TextInputTypeChanged(routing_id(), 1834 new_type, 1835 text_input_mode_, 1836 new_can_compose_inline)); 1837 #endif 1838 Send(new ViewHostMsg_TextInputStateChanged(routing_id(), p)); 1839 1840 text_input_info_ = new_info; 1841 text_input_type_ = new_type; 1842 can_compose_inline_ = new_can_compose_inline; 1843 } 1844 } 1845 #endif 1846 1847 void RenderWidget::GetSelectionBounds(gfx::Rect* focus, gfx::Rect* anchor) { 1848 WebRect focus_webrect; 1849 WebRect anchor_webrect; 1850 webwidget_->selectionBounds(focus_webrect, anchor_webrect); 1851 *focus = focus_webrect; 1852 *anchor = anchor_webrect; 1853 } 1854 1855 void RenderWidget::UpdateSelectionBounds() { 1856 if (!webwidget_) 1857 return; 1858 if (handling_ime_event_) 1859 return; 1860 1861 // With composited selection updates, the selection bounds will be reported 1862 // directly by the compositor, in which case explicit IPC selection 1863 // notifications should be suppressed. 1864 if (!blink::WebRuntimeFeatures::isCompositedSelectionUpdateEnabled()) { 1865 ViewHostMsg_SelectionBounds_Params params; 1866 GetSelectionBounds(¶ms.anchor_rect, ¶ms.focus_rect); 1867 if (selection_anchor_rect_ != params.anchor_rect || 1868 selection_focus_rect_ != params.focus_rect) { 1869 selection_anchor_rect_ = params.anchor_rect; 1870 selection_focus_rect_ = params.focus_rect; 1871 webwidget_->selectionTextDirection(params.focus_dir, params.anchor_dir); 1872 params.is_anchor_first = webwidget_->isSelectionAnchorFirst(); 1873 Send(new ViewHostMsg_SelectionBoundsChanged(routing_id_, params)); 1874 } 1875 } 1876 1877 #if defined(OS_MACOSX) || defined(USE_AURA) 1878 UpdateCompositionInfo(false); 1879 #endif 1880 } 1881 1882 // Check blink::WebTextInputType and ui::TextInputType is kept in sync. 1883 COMPILE_ASSERT(int(blink::WebTextInputTypeNone) == \ 1884 int(ui::TEXT_INPUT_TYPE_NONE), mismatching_enums); 1885 COMPILE_ASSERT(int(blink::WebTextInputTypeText) == \ 1886 int(ui::TEXT_INPUT_TYPE_TEXT), mismatching_enums); 1887 COMPILE_ASSERT(int(blink::WebTextInputTypePassword) == \ 1888 int(ui::TEXT_INPUT_TYPE_PASSWORD), mismatching_enums); 1889 COMPILE_ASSERT(int(blink::WebTextInputTypeSearch) == \ 1890 int(ui::TEXT_INPUT_TYPE_SEARCH), mismatching_enums); 1891 COMPILE_ASSERT(int(blink::WebTextInputTypeEmail) == \ 1892 int(ui::TEXT_INPUT_TYPE_EMAIL), mismatching_enums); 1893 COMPILE_ASSERT(int(blink::WebTextInputTypeNumber) == \ 1894 int(ui::TEXT_INPUT_TYPE_NUMBER), mismatching_enums); 1895 COMPILE_ASSERT(int(blink::WebTextInputTypeTelephone) == \ 1896 int(ui::TEXT_INPUT_TYPE_TELEPHONE), mismatching_enums); 1897 COMPILE_ASSERT(int(blink::WebTextInputTypeURL) == \ 1898 int(ui::TEXT_INPUT_TYPE_URL), mismatching_enums); 1899 COMPILE_ASSERT(int(blink::WebTextInputTypeDate) == \ 1900 int(ui::TEXT_INPUT_TYPE_DATE), mismatching_enum); 1901 COMPILE_ASSERT(int(blink::WebTextInputTypeDateTime) == \ 1902 int(ui::TEXT_INPUT_TYPE_DATE_TIME), mismatching_enum); 1903 COMPILE_ASSERT(int(blink::WebTextInputTypeDateTimeLocal) == \ 1904 int(ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL), mismatching_enum); 1905 COMPILE_ASSERT(int(blink::WebTextInputTypeMonth) == \ 1906 int(ui::TEXT_INPUT_TYPE_MONTH), mismatching_enum); 1907 COMPILE_ASSERT(int(blink::WebTextInputTypeTime) == \ 1908 int(ui::TEXT_INPUT_TYPE_TIME), mismatching_enum); 1909 COMPILE_ASSERT(int(blink::WebTextInputTypeWeek) == \ 1910 int(ui::TEXT_INPUT_TYPE_WEEK), mismatching_enum); 1911 COMPILE_ASSERT(int(blink::WebTextInputTypeTextArea) == \ 1912 int(ui::TEXT_INPUT_TYPE_TEXT_AREA), mismatching_enums); 1913 COMPILE_ASSERT(int(blink::WebTextInputTypeContentEditable) == \ 1914 int(ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE), mismatching_enums); 1915 COMPILE_ASSERT(int(blink::WebTextInputTypeDateTimeField) == \ 1916 int(ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD), mismatching_enums); 1917 1918 ui::TextInputType RenderWidget::WebKitToUiTextInputType( 1919 blink::WebTextInputType type) { 1920 // Check the type is in the range representable by ui::TextInputType. 1921 DCHECK_LE(type, static_cast<int>(ui::TEXT_INPUT_TYPE_MAX)) << 1922 "blink::WebTextInputType and ui::TextInputType not synchronized"; 1923 return static_cast<ui::TextInputType>(type); 1924 } 1925 1926 ui::TextInputType RenderWidget::GetTextInputType() { 1927 if (webwidget_) 1928 return WebKitToUiTextInputType(webwidget_->textInputInfo().type); 1929 return ui::TEXT_INPUT_TYPE_NONE; 1930 } 1931 1932 #if defined(OS_MACOSX) || defined(USE_AURA) 1933 void RenderWidget::UpdateCompositionInfo(bool should_update_range) { 1934 gfx::Range range = gfx::Range(); 1935 if (should_update_range) { 1936 GetCompositionRange(&range); 1937 } else { 1938 range = composition_range_; 1939 } 1940 std::vector<gfx::Rect> character_bounds; 1941 GetCompositionCharacterBounds(&character_bounds); 1942 1943 if (!ShouldUpdateCompositionInfo(range, character_bounds)) 1944 return; 1945 composition_character_bounds_ = character_bounds; 1946 composition_range_ = range; 1947 Send(new InputHostMsg_ImeCompositionRangeChanged( 1948 routing_id(), composition_range_, composition_character_bounds_)); 1949 } 1950 1951 void RenderWidget::GetCompositionCharacterBounds( 1952 std::vector<gfx::Rect>* bounds) { 1953 DCHECK(bounds); 1954 bounds->clear(); 1955 } 1956 1957 void RenderWidget::GetCompositionRange(gfx::Range* range) { 1958 size_t location, length; 1959 if (webwidget_->compositionRange(&location, &length)) { 1960 range->set_start(location); 1961 range->set_end(location + length); 1962 } else if (webwidget_->caretOrSelectionRange(&location, &length)) { 1963 range->set_start(location); 1964 range->set_end(location + length); 1965 } else { 1966 *range = gfx::Range::InvalidRange(); 1967 } 1968 } 1969 1970 bool RenderWidget::ShouldUpdateCompositionInfo( 1971 const gfx::Range& range, 1972 const std::vector<gfx::Rect>& bounds) { 1973 if (composition_range_ != range) 1974 return true; 1975 if (bounds.size() != composition_character_bounds_.size()) 1976 return true; 1977 for (size_t i = 0; i < bounds.size(); ++i) { 1978 if (bounds[i] != composition_character_bounds_[i]) 1979 return true; 1980 } 1981 return false; 1982 } 1983 #endif 1984 1985 #if defined(OS_ANDROID) 1986 void RenderWidget::DidChangeBodyBackgroundColor(SkColor bg_color) { 1987 // If not initialized, default to white. Note that 0 is different from black 1988 // as black still has alpha 0xFF. 1989 if (!bg_color) 1990 bg_color = SK_ColorWHITE; 1991 1992 if (bg_color != body_background_color_) { 1993 body_background_color_ = bg_color; 1994 Send(new ViewHostMsg_DidChangeBodyBackgroundColor(routing_id(), bg_color)); 1995 } 1996 } 1997 #endif 1998 1999 bool RenderWidget::CanComposeInline() { 2000 return true; 2001 } 2002 2003 WebScreenInfo RenderWidget::screenInfo() { 2004 return screen_info_; 2005 } 2006 2007 float RenderWidget::deviceScaleFactor() { 2008 return device_scale_factor_; 2009 } 2010 2011 void RenderWidget::resetInputMethod() { 2012 if (!input_method_is_active_) 2013 return; 2014 2015 ImeEventGuard guard(this); 2016 // If the last text input type is not None, then we should finish any 2017 // ongoing composition regardless of the new text input type. 2018 if (text_input_type_ != ui::TEXT_INPUT_TYPE_NONE) { 2019 // If a composition text exists, then we need to let the browser process 2020 // to cancel the input method's ongoing composition session. 2021 if (webwidget_->confirmComposition()) 2022 Send(new InputHostMsg_ImeCancelComposition(routing_id())); 2023 } 2024 2025 #if defined(OS_MACOSX) || defined(USE_AURA) 2026 UpdateCompositionInfo(true); 2027 #endif 2028 } 2029 2030 void RenderWidget::didHandleGestureEvent( 2031 const WebGestureEvent& event, 2032 bool event_cancelled) { 2033 #if defined(OS_ANDROID) || defined(USE_AURA) 2034 if (event_cancelled) 2035 return; 2036 if (event.type == WebInputEvent::GestureTap) { 2037 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME); 2038 } else if (event.type == WebInputEvent::GestureLongPress) { 2039 DCHECK(webwidget_); 2040 if (webwidget_->textInputInfo().value.isEmpty()) 2041 UpdateTextInputState(NO_SHOW_IME, FROM_NON_IME); 2042 else 2043 UpdateTextInputState(SHOW_IME_IF_NEEDED, FROM_NON_IME); 2044 } 2045 #endif 2046 } 2047 2048 void RenderWidget::StartCompositor() { 2049 // For widgets that are never visible, we don't need the compositor to run 2050 // at all. 2051 if (never_visible_) 2052 return; 2053 compositor_->setSurfaceReady(); 2054 } 2055 2056 void RenderWidget::SchedulePluginMove(const WebPluginGeometry& move) { 2057 size_t i = 0; 2058 for (; i < plugin_window_moves_.size(); ++i) { 2059 if (plugin_window_moves_[i].window == move.window) { 2060 if (move.rects_valid) { 2061 plugin_window_moves_[i] = move; 2062 } else { 2063 plugin_window_moves_[i].visible = move.visible; 2064 } 2065 break; 2066 } 2067 } 2068 2069 if (i == plugin_window_moves_.size()) 2070 plugin_window_moves_.push_back(move); 2071 } 2072 2073 void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) { 2074 for (WebPluginGeometryVector::iterator i = plugin_window_moves_.begin(); 2075 i != plugin_window_moves_.end(); ++i) { 2076 if (i->window == window) { 2077 plugin_window_moves_.erase(i); 2078 break; 2079 } 2080 } 2081 } 2082 2083 2084 RenderWidgetCompositor* RenderWidget::compositor() const { 2085 return compositor_.get(); 2086 } 2087 2088 bool RenderWidget::WillHandleMouseEvent(const blink::WebMouseEvent& event) { 2089 return false; 2090 } 2091 2092 bool RenderWidget::WillHandleGestureEvent( 2093 const blink::WebGestureEvent& event) { 2094 return false; 2095 } 2096 2097 void RenderWidget::hasTouchEventHandlers(bool has_handlers) { 2098 Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers)); 2099 } 2100 2101 void RenderWidget::setTouchAction( 2102 blink::WebTouchAction web_touch_action) { 2103 2104 // Ignore setTouchAction calls that result from synthetic touch events (eg. 2105 // when blink is emulating touch with mouse). 2106 if (handling_event_type_ != WebInputEvent::TouchStart) 2107 return; 2108 2109 // Verify the same values are used by the types so we can cast between them. 2110 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_AUTO) == 2111 blink::WebTouchActionAuto, 2112 enum_values_must_match_for_touch_action); 2113 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_NONE) == 2114 blink::WebTouchActionNone, 2115 enum_values_must_match_for_touch_action); 2116 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_PAN_X) == 2117 blink::WebTouchActionPanX, 2118 enum_values_must_match_for_touch_action); 2119 COMPILE_ASSERT(static_cast<blink::WebTouchAction>(TOUCH_ACTION_PAN_Y) == 2120 blink::WebTouchActionPanY, 2121 enum_values_must_match_for_touch_action); 2122 COMPILE_ASSERT( 2123 static_cast<blink::WebTouchAction>(TOUCH_ACTION_PINCH_ZOOM) == 2124 blink::WebTouchActionPinchZoom, 2125 enum_values_must_match_for_touch_action); 2126 2127 content::TouchAction content_touch_action = 2128 static_cast<content::TouchAction>(web_touch_action); 2129 Send(new InputHostMsg_SetTouchAction(routing_id_, content_touch_action)); 2130 } 2131 2132 void RenderWidget::didUpdateTextOfFocusedElementByNonUserInput() { 2133 #if defined(OS_ANDROID) 2134 text_field_is_dirty_ = true; 2135 #endif 2136 } 2137 2138 bool RenderWidget::HasTouchEventHandlersAt(const gfx::Point& point) const { 2139 return true; 2140 } 2141 2142 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 2143 RenderWidget::CreateGraphicsContext3D() { 2144 if (!webwidget_) 2145 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 2146 if (CommandLine::ForCurrentProcess()->HasSwitch( 2147 switches::kDisableGpuCompositing)) 2148 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 2149 if (!RenderThreadImpl::current()) 2150 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 2151 CauseForGpuLaunch cause = 2152 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE; 2153 scoped_refptr<GpuChannelHost> gpu_channel_host( 2154 RenderThreadImpl::current()->EstablishGpuChannelSync(cause)); 2155 if (!gpu_channel_host.get()) 2156 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 2157 2158 // Explicitly disable antialiasing for the compositor. As of the time of 2159 // this writing, the only platform that supported antialiasing for the 2160 // compositor was Mac OS X, because the on-screen OpenGL context creation 2161 // code paths on Windows and Linux didn't yet have multisampling support. 2162 // Mac OS X essentially always behaves as though it's rendering offscreen. 2163 // Multisampling has a heavy cost especially on devices with relatively low 2164 // fill rate like most notebooks, and the Mac implementation would need to 2165 // be optimized to resolve directly into the IOSurface shared between the 2166 // GPU and browser processes. For these reasons and to avoid platform 2167 // disparities we explicitly disable antialiasing. 2168 blink::WebGraphicsContext3D::Attributes attributes; 2169 attributes.antialias = false; 2170 attributes.shareResources = true; 2171 attributes.noAutomaticFlushes = true; 2172 attributes.depth = false; 2173 attributes.stencil = false; 2174 bool lose_context_when_out_of_memory = true; 2175 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits; 2176 #if defined(OS_ANDROID) 2177 // If we raster too fast we become upload bound, and pending 2178 // uploads consume memory. For maximum upload throughput, we would 2179 // want to allow for upload_throughput * pipeline_time of pending 2180 // uploads, after which we are just wasting memory. Since we don't 2181 // know our upload throughput yet, this just caps our memory usage. 2182 size_t divider = 1; 2183 if (base::SysInfo::IsLowEndDevice()) 2184 divider = 6; 2185 // For reference Nexus10 can upload 1MB in about 2.5ms. 2186 const double max_mb_uploaded_per_ms = 2.0 / (5 * divider); 2187 // Deadline to draw a frame to achieve 60 frames per second. 2188 const size_t kMillisecondsPerFrame = 16; 2189 // Assuming a two frame deep pipeline between the CPU and the GPU. 2190 size_t max_transfer_buffer_usage_mb = 2191 static_cast<size_t>(2 * kMillisecondsPerFrame * max_mb_uploaded_per_ms); 2192 static const size_t kBytesPerMegabyte = 1024 * 1024; 2193 // We keep the MappedMemoryReclaimLimit the same as the upload limit 2194 // to avoid unnecessarily stalling the compositor thread. 2195 limits.mapped_memory_reclaim_limit = 2196 max_transfer_buffer_usage_mb * kBytesPerMegabyte; 2197 #endif 2198 2199 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context( 2200 new WebGraphicsContext3DCommandBufferImpl(surface_id(), 2201 GetURLForGraphicsContext3D(), 2202 gpu_channel_host.get(), 2203 attributes, 2204 lose_context_when_out_of_memory, 2205 limits, 2206 NULL)); 2207 return context.Pass(); 2208 } 2209 2210 void RenderWidget::RegisterRenderFrameProxy(RenderFrameProxy* proxy) { 2211 render_frame_proxies_.AddObserver(proxy); 2212 } 2213 2214 void RenderWidget::UnregisterRenderFrameProxy(RenderFrameProxy* proxy) { 2215 render_frame_proxies_.RemoveObserver(proxy); 2216 } 2217 2218 void RenderWidget::RegisterRenderFrame(RenderFrameImpl* frame) { 2219 render_frames_.AddObserver(frame); 2220 } 2221 2222 void RenderWidget::UnregisterRenderFrame(RenderFrameImpl* frame) { 2223 render_frames_.RemoveObserver(frame); 2224 } 2225 2226 #if defined(VIDEO_HOLE) 2227 void RenderWidget::RegisterVideoHoleFrame(RenderFrameImpl* frame) { 2228 video_hole_frames_.AddObserver(frame); 2229 } 2230 2231 void RenderWidget::UnregisterVideoHoleFrame(RenderFrameImpl* frame) { 2232 video_hole_frames_.RemoveObserver(frame); 2233 } 2234 #endif // defined(VIDEO_HOLE) 2235 2236 } // namespace content 2237