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