1 // Copyright (c) 2013 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/browser/devtools/renderer_overrides_handler.h" 6 7 #include <map> 8 #include <string> 9 10 #include "base/barrier_closure.h" 11 #include "base/base64.h" 12 #include "base/bind.h" 13 #include "base/bind_helpers.h" 14 #include "base/files/file_path.h" 15 #include "base/strings/string16.h" 16 #include "base/thread_task_runner_handle.h" 17 #include "base/values.h" 18 #include "content/browser/child_process_security_policy_impl.h" 19 #include "content/browser/devtools/devtools_protocol_constants.h" 20 #include "content/browser/devtools/devtools_tracing_handler.h" 21 #include "content/browser/renderer_host/dip_util.h" 22 #include "content/browser/renderer_host/render_view_host_delegate.h" 23 #include "content/browser/renderer_host/render_view_host_impl.h" 24 #include "content/browser/renderer_host/render_widget_host_view_base.h" 25 #include "content/browser/web_contents/web_contents_impl.h" 26 #include "content/common/cursors/webcursor.h" 27 #include "content/common/view_messages.h" 28 #include "content/public/browser/browser_thread.h" 29 #include "content/public/browser/content_browser_client.h" 30 #include "content/public/browser/devtools_agent_host.h" 31 #include "content/public/browser/javascript_dialog_manager.h" 32 #include "content/public/browser/navigation_controller.h" 33 #include "content/public/browser/navigation_entry.h" 34 #include "content/public/browser/render_process_host.h" 35 #include "content/public/browser/render_view_host.h" 36 #include "content/public/browser/render_widget_host_view.h" 37 #include "content/public/browser/storage_partition.h" 38 #include "content/public/browser/web_contents.h" 39 #include "content/public/browser/web_contents_delegate.h" 40 #include "content/public/common/content_client.h" 41 #include "content/public/common/referrer.h" 42 #include "content/public/common/url_constants.h" 43 #include "ipc/ipc_sender.h" 44 #include "net/base/net_util.h" 45 #include "storage/browser/quota/quota_manager.h" 46 #include "third_party/WebKit/public/platform/WebCursorInfo.h" 47 #include "third_party/WebKit/public/platform/WebScreenInfo.h" 48 #include "third_party/WebKit/public/web/WebInputEvent.h" 49 #include "third_party/skia/include/core/SkCanvas.h" 50 #include "ui/base/page_transition_types.h" 51 #include "ui/gfx/codec/jpeg_codec.h" 52 #include "ui/gfx/codec/png_codec.h" 53 #include "ui/gfx/display.h" 54 #include "ui/gfx/screen.h" 55 #include "ui/gfx/size_conversions.h" 56 #include "ui/snapshot/snapshot.h" 57 #include "url/gurl.h" 58 59 using blink::WebGestureEvent; 60 using blink::WebInputEvent; 61 using blink::WebMouseEvent; 62 63 namespace content { 64 65 namespace { 66 67 static const char kPng[] = "png"; 68 static const char kJpeg[] = "jpeg"; 69 static int kDefaultScreenshotQuality = 80; 70 static int kFrameRateThresholdMs = 100; 71 static int kCaptureRetryLimit = 2; 72 73 } // namespace 74 75 RendererOverridesHandler::RendererOverridesHandler() 76 : page_domain_enabled_(false), 77 has_last_compositor_frame_metadata_(false), 78 capture_retry_count_(0), 79 touch_emulation_enabled_(false), 80 color_picker_enabled_(false), 81 last_cursor_x_(-1), 82 last_cursor_y_(-1), 83 weak_factory_(this) { 84 RegisterCommandHandler( 85 devtools::DOM::setFileInputFiles::kName, 86 base::Bind( 87 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles, 88 base::Unretained(this))); 89 RegisterCommandHandler( 90 devtools::Network::canEmulateNetworkConditions::kName, 91 base::Bind( 92 &RendererOverridesHandler::CanEmulateNetworkConditions, 93 base::Unretained(this))); 94 RegisterCommandHandler( 95 devtools::Network::clearBrowserCache::kName, 96 base::Bind( 97 &RendererOverridesHandler::ClearBrowserCache, 98 base::Unretained(this))); 99 RegisterCommandHandler( 100 devtools::Network::clearBrowserCookies::kName, 101 base::Bind( 102 &RendererOverridesHandler::ClearBrowserCookies, 103 base::Unretained(this))); 104 RegisterCommandHandler( 105 devtools::Page::enable::kName, 106 base::Bind( 107 &RendererOverridesHandler::PageEnable, base::Unretained(this))); 108 RegisterCommandHandler( 109 devtools::Page::disable::kName, 110 base::Bind( 111 &RendererOverridesHandler::PageDisable, base::Unretained(this))); 112 RegisterCommandHandler( 113 devtools::Page::handleJavaScriptDialog::kName, 114 base::Bind( 115 &RendererOverridesHandler::PageHandleJavaScriptDialog, 116 base::Unretained(this))); 117 RegisterCommandHandler( 118 devtools::Page::navigate::kName, 119 base::Bind( 120 &RendererOverridesHandler::PageNavigate, 121 base::Unretained(this))); 122 RegisterCommandHandler( 123 devtools::Page::reload::kName, 124 base::Bind( 125 &RendererOverridesHandler::PageReload, 126 base::Unretained(this))); 127 RegisterCommandHandler( 128 devtools::Page::getNavigationHistory::kName, 129 base::Bind( 130 &RendererOverridesHandler::PageGetNavigationHistory, 131 base::Unretained(this))); 132 RegisterCommandHandler( 133 devtools::Page::navigateToHistoryEntry::kName, 134 base::Bind( 135 &RendererOverridesHandler::PageNavigateToHistoryEntry, 136 base::Unretained(this))); 137 RegisterCommandHandler( 138 devtools::Page::captureScreenshot::kName, 139 base::Bind( 140 &RendererOverridesHandler::PageCaptureScreenshot, 141 base::Unretained(this))); 142 RegisterCommandHandler( 143 devtools::Page::setTouchEmulationEnabled::kName, 144 base::Bind( 145 &RendererOverridesHandler::PageSetTouchEmulationEnabled, 146 base::Unretained(this))); 147 RegisterCommandHandler( 148 devtools::Page::canEmulate::kName, 149 base::Bind( 150 &RendererOverridesHandler::PageCanEmulate, 151 base::Unretained(this))); 152 RegisterCommandHandler( 153 devtools::Page::canScreencast::kName, 154 base::Bind( 155 &RendererOverridesHandler::PageCanScreencast, 156 base::Unretained(this))); 157 RegisterCommandHandler( 158 devtools::Page::startScreencast::kName, 159 base::Bind( 160 &RendererOverridesHandler::PageStartScreencast, 161 base::Unretained(this))); 162 RegisterCommandHandler( 163 devtools::Page::stopScreencast::kName, 164 base::Bind( 165 &RendererOverridesHandler::PageStopScreencast, 166 base::Unretained(this))); 167 RegisterCommandHandler( 168 devtools::Page::queryUsageAndQuota::kName, 169 base::Bind( 170 &RendererOverridesHandler::PageQueryUsageAndQuota, 171 base::Unretained(this))); 172 RegisterCommandHandler( 173 devtools::Page::setColorPickerEnabled::kName, 174 base::Bind( 175 &RendererOverridesHandler::PageSetColorPickerEnabled, 176 base::Unretained(this))); 177 RegisterCommandHandler( 178 devtools::Input::emulateTouchFromMouseEvent::kName, 179 base::Bind( 180 &RendererOverridesHandler::InputEmulateTouchFromMouseEvent, 181 base::Unretained(this))); 182 mouse_event_callback_ = base::Bind( 183 &RendererOverridesHandler::HandleMouseEvent, 184 base::Unretained(this)); 185 } 186 187 RendererOverridesHandler::~RendererOverridesHandler() {} 188 189 void RendererOverridesHandler::OnClientDetached() { 190 touch_emulation_enabled_ = false; 191 screencast_command_ = NULL; 192 UpdateTouchEventEmulationState(); 193 SetColorPickerEnabled(false); 194 } 195 196 void RendererOverridesHandler::OnSwapCompositorFrame( 197 const cc::CompositorFrameMetadata& frame_metadata) { 198 last_compositor_frame_metadata_ = frame_metadata; 199 has_last_compositor_frame_metadata_ = true; 200 201 if (screencast_command_.get()) 202 InnerSwapCompositorFrame(); 203 if (color_picker_enabled_) 204 UpdateColorPickerFrame(); 205 } 206 207 void RendererOverridesHandler::OnVisibilityChanged(bool visible) { 208 if (!screencast_command_.get()) 209 return; 210 NotifyScreencastVisibility(visible); 211 } 212 213 void RendererOverridesHandler::SetRenderViewHost( 214 RenderViewHostImpl* host) { 215 host_ = host; 216 if (!host) 217 return; 218 UpdateTouchEventEmulationState(); 219 if (color_picker_enabled_) 220 host->AddMouseEventCallback(mouse_event_callback_); 221 } 222 223 void RendererOverridesHandler::ClearRenderViewHost() { 224 if (host_) 225 host_->RemoveMouseEventCallback(mouse_event_callback_); 226 host_ = NULL; 227 ResetColorPickerFrame(); 228 } 229 230 void RendererOverridesHandler::DidAttachInterstitialPage() { 231 if (page_domain_enabled_) 232 SendNotification(devtools::Page::interstitialShown::kName, NULL); 233 } 234 235 void RendererOverridesHandler::DidDetachInterstitialPage() { 236 if (page_domain_enabled_) 237 SendNotification(devtools::Page::interstitialHidden::kName, NULL); 238 } 239 240 void RendererOverridesHandler::InnerSwapCompositorFrame() { 241 if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() < 242 kFrameRateThresholdMs) { 243 return; 244 } 245 246 if (!host_ || !host_->GetView()) 247 return; 248 249 last_frame_time_ = base::TimeTicks::Now(); 250 251 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 252 host_->GetView()); 253 // TODO(vkuzkokov): do not use previous frame metadata. 254 cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_; 255 256 gfx::SizeF viewport_size_dip = gfx::ScaleSize( 257 metadata.scrollable_viewport_size, metadata.page_scale_factor); 258 gfx::SizeF screen_size_dip = gfx::ScaleSize(view->GetPhysicalBackingSize(), 259 1 / metadata.device_scale_factor); 260 261 std::string format; 262 int quality = kDefaultScreenshotQuality; 263 double scale = 1; 264 double max_width = -1; 265 double max_height = -1; 266 base::DictionaryValue* params = screencast_command_->params(); 267 if (params) { 268 params->GetString(devtools::Page::startScreencast::kParamFormat, 269 &format); 270 params->GetInteger(devtools::Page::startScreencast::kParamQuality, 271 &quality); 272 params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth, 273 &max_width); 274 params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight, 275 &max_height); 276 } 277 278 blink::WebScreenInfo screen_info; 279 view->GetScreenInfo(&screen_info); 280 double device_scale_factor = screen_info.deviceScaleFactor; 281 282 if (max_width > 0) { 283 double max_width_dip = max_width / device_scale_factor; 284 scale = std::min(scale, max_width_dip / screen_size_dip.width()); 285 } 286 if (max_height > 0) { 287 double max_height_dip = max_height / device_scale_factor; 288 scale = std::min(scale, max_height_dip / screen_size_dip.height()); 289 } 290 291 if (format.empty()) 292 format = kPng; 293 if (quality < 0 || quality > 100) 294 quality = kDefaultScreenshotQuality; 295 if (scale <= 0) 296 scale = 0.1; 297 298 gfx::Size snapshot_size_dip(gfx::ToRoundedSize( 299 gfx::ScaleSize(viewport_size_dip, scale))); 300 301 if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) { 302 gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip)); 303 view->CopyFromCompositingSurface( 304 viewport_bounds_dip, snapshot_size_dip, 305 base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured, 306 weak_factory_.GetWeakPtr(), 307 format, quality, last_compositor_frame_metadata_), 308 kN32_SkColorType); 309 } 310 } 311 312 // DOM agent handlers -------------------------------------------------------- 313 314 scoped_refptr<DevToolsProtocol::Response> 315 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles( 316 scoped_refptr<DevToolsProtocol::Command> command) { 317 base::DictionaryValue* params = command->params(); 318 base::ListValue* file_list = NULL; 319 const char* param = 320 devtools::DOM::setFileInputFiles::kParamFiles; 321 if (!params || !params->GetList(param, &file_list)) 322 return command->InvalidParamResponse(param); 323 if (!host_) 324 return NULL; 325 326 for (size_t i = 0; i < file_list->GetSize(); ++i) { 327 base::FilePath::StringType file; 328 if (!file_list->GetString(i, &file)) 329 return command->InvalidParamResponse(param); 330 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile( 331 host_->GetProcess()->GetID(), base::FilePath(file)); 332 } 333 return NULL; 334 } 335 336 337 // Network agent handlers ---------------------------------------------------- 338 339 scoped_refptr<DevToolsProtocol::Response> 340 RendererOverridesHandler::CanEmulateNetworkConditions( 341 scoped_refptr<DevToolsProtocol::Command> command) { 342 base::DictionaryValue* result = new base::DictionaryValue(); 343 result->SetBoolean(devtools::kResult, false); 344 return command->SuccessResponse(result); 345 } 346 347 scoped_refptr<DevToolsProtocol::Response> 348 RendererOverridesHandler::ClearBrowserCache( 349 scoped_refptr<DevToolsProtocol::Command> command) { 350 GetContentClient()->browser()->ClearCache(host_); 351 return command->SuccessResponse(NULL); 352 } 353 354 scoped_refptr<DevToolsProtocol::Response> 355 RendererOverridesHandler::ClearBrowserCookies( 356 scoped_refptr<DevToolsProtocol::Command> command) { 357 GetContentClient()->browser()->ClearCookies(host_); 358 return command->SuccessResponse(NULL); 359 } 360 361 362 // Page agent handlers ------------------------------------------------------- 363 364 scoped_refptr<DevToolsProtocol::Response> 365 RendererOverridesHandler::PageEnable( 366 scoped_refptr<DevToolsProtocol::Command> command) { 367 page_domain_enabled_ = true; 368 // Fall through to the renderer. 369 return NULL; 370 } 371 372 scoped_refptr<DevToolsProtocol::Response> 373 RendererOverridesHandler::PageDisable( 374 scoped_refptr<DevToolsProtocol::Command> command) { 375 page_domain_enabled_ = false; 376 OnClientDetached(); 377 // Fall through to the renderer. 378 return NULL; 379 } 380 381 scoped_refptr<DevToolsProtocol::Response> 382 RendererOverridesHandler::PageHandleJavaScriptDialog( 383 scoped_refptr<DevToolsProtocol::Command> command) { 384 base::DictionaryValue* params = command->params(); 385 const char* paramAccept = 386 devtools::Page::handleJavaScriptDialog::kParamAccept; 387 bool accept = false; 388 if (!params || !params->GetBoolean(paramAccept, &accept)) 389 return command->InvalidParamResponse(paramAccept); 390 base::string16 prompt_override; 391 base::string16* prompt_override_ptr = &prompt_override; 392 if (!params || !params->GetString( 393 devtools::Page::handleJavaScriptDialog::kParamPromptText, 394 prompt_override_ptr)) { 395 prompt_override_ptr = NULL; 396 } 397 398 if (!host_) 399 return command->InternalErrorResponse("Could not connect to view"); 400 401 WebContents* web_contents = WebContents::FromRenderViewHost(host_); 402 if (web_contents) { 403 JavaScriptDialogManager* manager = 404 web_contents->GetDelegate()->GetJavaScriptDialogManager(); 405 if (manager && manager->HandleJavaScriptDialog( 406 web_contents, accept, prompt_override_ptr)) { 407 return command->SuccessResponse(new base::DictionaryValue()); 408 } 409 } 410 return command->InternalErrorResponse("No JavaScript dialog to handle"); 411 } 412 413 scoped_refptr<DevToolsProtocol::Response> 414 RendererOverridesHandler::PageNavigate( 415 scoped_refptr<DevToolsProtocol::Command> command) { 416 base::DictionaryValue* params = command->params(); 417 std::string url; 418 const char* param = devtools::Page::navigate::kParamUrl; 419 if (!params || !params->GetString(param, &url)) 420 return command->InvalidParamResponse(param); 421 422 GURL gurl(url); 423 if (!gurl.is_valid()) 424 return command->InternalErrorResponse("Cannot navigate to invalid URL"); 425 426 if (!host_) 427 return command->InternalErrorResponse("Could not connect to view"); 428 429 WebContents* web_contents = WebContents::FromRenderViewHost(host_); 430 if (web_contents) { 431 web_contents->GetController() 432 .LoadURL(gurl, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); 433 // Fall through into the renderer. 434 return NULL; 435 } 436 437 return command->InternalErrorResponse("No WebContents to navigate"); 438 } 439 440 scoped_refptr<DevToolsProtocol::Response> 441 RendererOverridesHandler::PageReload( 442 scoped_refptr<DevToolsProtocol::Command> command) { 443 if (!host_) 444 return command->InternalErrorResponse("Could not connect to view"); 445 446 WebContents* web_contents = WebContents::FromRenderViewHost(host_); 447 if (web_contents) { 448 // Override only if it is crashed. 449 if (!web_contents->IsCrashed()) 450 return NULL; 451 452 web_contents->GetController().Reload(false); 453 return command->SuccessResponse(NULL); 454 } 455 return command->InternalErrorResponse("No WebContents to reload"); 456 } 457 458 scoped_refptr<DevToolsProtocol::Response> 459 RendererOverridesHandler::PageGetNavigationHistory( 460 scoped_refptr<DevToolsProtocol::Command> command) { 461 if (!host_) 462 return command->InternalErrorResponse("Could not connect to view"); 463 WebContents* web_contents = WebContents::FromRenderViewHost(host_); 464 if (web_contents) { 465 base::DictionaryValue* result = new base::DictionaryValue(); 466 NavigationController& controller = web_contents->GetController(); 467 result->SetInteger( 468 devtools::Page::getNavigationHistory::kResponseCurrentIndex, 469 controller.GetCurrentEntryIndex()); 470 base::ListValue* entries = new base::ListValue(); 471 for (int i = 0; i != controller.GetEntryCount(); ++i) { 472 const NavigationEntry* entry = controller.GetEntryAtIndex(i); 473 base::DictionaryValue* entry_value = new base::DictionaryValue(); 474 entry_value->SetInteger( 475 devtools::Page::NavigationEntry::kParamId, 476 entry->GetUniqueID()); 477 entry_value->SetString( 478 devtools::Page::NavigationEntry::kParamUrl, 479 entry->GetURL().spec()); 480 entry_value->SetString( 481 devtools::Page::NavigationEntry::kParamTitle, 482 entry->GetTitle()); 483 entries->Append(entry_value); 484 } 485 result->Set( 486 devtools::Page::getNavigationHistory::kResponseEntries, 487 entries); 488 return command->SuccessResponse(result); 489 } 490 return command->InternalErrorResponse("No WebContents to navigate"); 491 } 492 493 scoped_refptr<DevToolsProtocol::Response> 494 RendererOverridesHandler::PageNavigateToHistoryEntry( 495 scoped_refptr<DevToolsProtocol::Command> command) { 496 base::DictionaryValue* params = command->params(); 497 const char* param = devtools::Page::navigateToHistoryEntry::kParamEntryId; 498 int entry_id = 0; 499 if (!params || !params->GetInteger(param, &entry_id)) { 500 return command->InvalidParamResponse(param); 501 } 502 503 if (!host_) 504 return command->InternalErrorResponse("Could not connect to view"); 505 506 WebContents* web_contents = WebContents::FromRenderViewHost(host_); 507 if (web_contents) { 508 NavigationController& controller = web_contents->GetController(); 509 for (int i = 0; i != controller.GetEntryCount(); ++i) { 510 if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) { 511 controller.GoToIndex(i); 512 return command->SuccessResponse(new base::DictionaryValue()); 513 } 514 } 515 return command->InvalidParamResponse(param); 516 } 517 return command->InternalErrorResponse("No WebContents to navigate"); 518 } 519 520 scoped_refptr<DevToolsProtocol::Response> 521 RendererOverridesHandler::PageCaptureScreenshot( 522 scoped_refptr<DevToolsProtocol::Command> command) { 523 if (!host_ || !host_->GetView()) 524 return command->InternalErrorResponse("Could not connect to view"); 525 526 host_->GetSnapshotFromBrowser( 527 base::Bind(&RendererOverridesHandler::ScreenshotCaptured, 528 weak_factory_.GetWeakPtr(), command)); 529 return command->AsyncResponsePromise(); 530 } 531 532 void RendererOverridesHandler::ScreenshotCaptured( 533 scoped_refptr<DevToolsProtocol::Command> command, 534 const unsigned char* png_data, 535 size_t png_size) { 536 if (!png_data || !png_size) { 537 SendAsyncResponse( 538 command->InternalErrorResponse("Unable to capture screenshot")); 539 return; 540 } 541 542 std::string base_64_data; 543 base::Base64Encode( 544 base::StringPiece(reinterpret_cast<const char*>(png_data), png_size), 545 &base_64_data); 546 547 base::DictionaryValue* response = new base::DictionaryValue(); 548 response->SetString(devtools::Page::screencastFrame::kParamData, 549 base_64_data); 550 551 SendAsyncResponse(command->SuccessResponse(response)); 552 } 553 554 scoped_refptr<DevToolsProtocol::Response> 555 RendererOverridesHandler::PageSetTouchEmulationEnabled( 556 scoped_refptr<DevToolsProtocol::Command> command) { 557 base::DictionaryValue* params = command->params(); 558 bool enabled = false; 559 if (!params || !params->GetBoolean( 560 devtools::Page::setTouchEmulationEnabled::kParamEnabled, 561 &enabled)) { 562 // Pass to renderer. 563 return NULL; 564 } 565 566 touch_emulation_enabled_ = enabled; 567 UpdateTouchEventEmulationState(); 568 569 // Pass to renderer. 570 return NULL; 571 } 572 573 scoped_refptr<DevToolsProtocol::Response> 574 RendererOverridesHandler::PageCanEmulate( 575 scoped_refptr<DevToolsProtocol::Command> command) { 576 base::DictionaryValue* result = new base::DictionaryValue(); 577 #if defined(OS_ANDROID) 578 result->SetBoolean(devtools::kResult, false); 579 #else 580 if (WebContents* web_contents = WebContents::FromRenderViewHost(host_)) { 581 result->SetBoolean( 582 devtools::kResult, 583 !web_contents->GetVisibleURL().SchemeIs(kChromeDevToolsScheme)); 584 } else { 585 result->SetBoolean(devtools::kResult, true); 586 } 587 #endif // defined(OS_ANDROID) 588 return command->SuccessResponse(result); 589 } 590 591 scoped_refptr<DevToolsProtocol::Response> 592 RendererOverridesHandler::PageCanScreencast( 593 scoped_refptr<DevToolsProtocol::Command> command) { 594 base::DictionaryValue* result = new base::DictionaryValue(); 595 #if defined(OS_ANDROID) 596 result->SetBoolean(devtools::kResult, true); 597 #else 598 result->SetBoolean(devtools::kResult, false); 599 #endif // defined(OS_ANDROID) 600 return command->SuccessResponse(result); 601 } 602 603 scoped_refptr<DevToolsProtocol::Response> 604 RendererOverridesHandler::PageStartScreencast( 605 scoped_refptr<DevToolsProtocol::Command> command) { 606 screencast_command_ = command; 607 UpdateTouchEventEmulationState(); 608 if (!host_) 609 return command->InternalErrorResponse("Could not connect to view"); 610 bool visible = !host_->is_hidden(); 611 NotifyScreencastVisibility(visible); 612 if (visible) { 613 if (has_last_compositor_frame_metadata_) 614 InnerSwapCompositorFrame(); 615 else 616 host_->Send(new ViewMsg_ForceRedraw(host_->GetRoutingID(), 0)); 617 } 618 // Pass through to the renderer. 619 return NULL; 620 } 621 622 scoped_refptr<DevToolsProtocol::Response> 623 RendererOverridesHandler::PageStopScreencast( 624 scoped_refptr<DevToolsProtocol::Command> command) { 625 last_frame_time_ = base::TimeTicks(); 626 screencast_command_ = NULL; 627 UpdateTouchEventEmulationState(); 628 // Pass through to the renderer. 629 return NULL; 630 } 631 632 void RendererOverridesHandler::ScreencastFrameCaptured( 633 const std::string& format, 634 int quality, 635 const cc::CompositorFrameMetadata& metadata, 636 bool success, 637 const SkBitmap& bitmap) { 638 if (!success) { 639 if (capture_retry_count_) { 640 --capture_retry_count_; 641 base::MessageLoop::current()->PostDelayedTask( 642 FROM_HERE, 643 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame, 644 weak_factory_.GetWeakPtr()), 645 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs)); 646 } 647 return; 648 } 649 650 std::vector<unsigned char> data; 651 SkAutoLockPixels lock_image(bitmap); 652 bool encoded; 653 if (format == kPng) { 654 encoded = gfx::PNGCodec::Encode( 655 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), 656 gfx::PNGCodec::FORMAT_SkBitmap, 657 gfx::Size(bitmap.width(), bitmap.height()), 658 bitmap.width() * bitmap.bytesPerPixel(), 659 false, std::vector<gfx::PNGCodec::Comment>(), &data); 660 } else if (format == kJpeg) { 661 encoded = gfx::JPEGCodec::Encode( 662 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), 663 gfx::JPEGCodec::FORMAT_SkBitmap, 664 bitmap.width(), 665 bitmap.height(), 666 bitmap.width() * bitmap.bytesPerPixel(), 667 quality, &data); 668 } else { 669 encoded = false; 670 } 671 672 if (!encoded) 673 return; 674 675 std::string base_64_data; 676 base::Base64Encode( 677 base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()), 678 &base_64_data); 679 680 base::DictionaryValue* response = new base::DictionaryValue(); 681 response->SetString(devtools::Page::screencastFrame::kParamData, 682 base_64_data); 683 684 // Consider metadata empty in case it has no device scale factor. 685 if (metadata.device_scale_factor != 0) { 686 base::DictionaryValue* response_metadata = new base::DictionaryValue(); 687 688 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 689 host_->GetView()); 690 if (!view) 691 return; 692 693 gfx::SizeF viewport_size_dip = gfx::ScaleSize( 694 metadata.scrollable_viewport_size, metadata.page_scale_factor); 695 gfx::SizeF screen_size_dip = gfx::ScaleSize( 696 view->GetPhysicalBackingSize(), 1 / metadata.device_scale_factor); 697 698 response_metadata->SetDouble( 699 devtools::Page::ScreencastFrameMetadata::kParamDeviceScaleFactor, 700 metadata.device_scale_factor); 701 response_metadata->SetDouble( 702 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactor, 703 metadata.page_scale_factor); 704 response_metadata->SetDouble( 705 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMin, 706 metadata.min_page_scale_factor); 707 response_metadata->SetDouble( 708 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMax, 709 metadata.max_page_scale_factor); 710 response_metadata->SetDouble( 711 devtools::Page::ScreencastFrameMetadata::kParamOffsetTop, 712 metadata.location_bar_content_translation.y()); 713 response_metadata->SetDouble( 714 devtools::Page::ScreencastFrameMetadata::kParamOffsetBottom, 715 screen_size_dip.height() - 716 metadata.location_bar_content_translation.y() - 717 viewport_size_dip.height()); 718 719 base::DictionaryValue* viewport = new base::DictionaryValue(); 720 viewport->SetDouble(devtools::DOM::Rect::kParamX, 721 metadata.root_scroll_offset.x()); 722 viewport->SetDouble(devtools::DOM::Rect::kParamY, 723 metadata.root_scroll_offset.y()); 724 viewport->SetDouble(devtools::DOM::Rect::kParamWidth, 725 metadata.scrollable_viewport_size.width()); 726 viewport->SetDouble(devtools::DOM::Rect::kParamHeight, 727 metadata.scrollable_viewport_size.height()); 728 response_metadata->Set( 729 devtools::Page::ScreencastFrameMetadata::kParamViewport, viewport); 730 731 response_metadata->SetDouble( 732 devtools::Page::ScreencastFrameMetadata::kParamDeviceWidth, 733 screen_size_dip.width()); 734 response_metadata->SetDouble( 735 devtools::Page::ScreencastFrameMetadata::kParamDeviceHeight, 736 screen_size_dip.height()); 737 response_metadata->SetDouble( 738 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetX, 739 metadata.root_scroll_offset.x()); 740 response_metadata->SetDouble( 741 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetY, 742 metadata.root_scroll_offset.y()); 743 744 response->Set(devtools::Page::screencastFrame::kParamMetadata, 745 response_metadata); 746 } 747 748 SendNotification(devtools::Page::screencastFrame::kName, response); 749 } 750 751 // Quota and Usage ------------------------------------------ 752 753 namespace { 754 755 typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)> 756 ResponseCallback; 757 758 void QueryUsageAndQuotaCompletedOnIOThread( 759 scoped_ptr<base::DictionaryValue> quota, 760 scoped_ptr<base::DictionaryValue> usage, 761 ResponseCallback callback) { 762 763 scoped_ptr<base::DictionaryValue> response_data(new base::DictionaryValue); 764 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseQuota, 765 quota.release()); 766 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage, 767 usage.release()); 768 769 BrowserThread::PostTask( 770 BrowserThread::UI, FROM_HERE, 771 base::Bind(callback, base::Passed(&response_data))); 772 } 773 774 void DidGetHostUsage( 775 base::ListValue* list, 776 const std::string& client_id, 777 const base::Closure& barrier, 778 int64 value) { 779 base::DictionaryValue* usage_item = new base::DictionaryValue; 780 usage_item->SetString(devtools::Page::UsageItem::kParamId, client_id); 781 usage_item->SetDouble(devtools::Page::UsageItem::kParamValue, value); 782 list->Append(usage_item); 783 barrier.Run(); 784 } 785 786 void DidGetQuotaValue(base::DictionaryValue* dictionary, 787 const std::string& item_name, 788 const base::Closure& barrier, 789 storage::QuotaStatusCode status, 790 int64 value) { 791 if (status == storage::kQuotaStatusOk) 792 dictionary->SetDouble(item_name, value); 793 barrier.Run(); 794 } 795 796 void DidGetUsageAndQuotaForWebApps(base::DictionaryValue* quota, 797 const std::string& item_name, 798 const base::Closure& barrier, 799 storage::QuotaStatusCode status, 800 int64 used_bytes, 801 int64 quota_in_bytes) { 802 if (status == storage::kQuotaStatusOk) 803 quota->SetDouble(item_name, quota_in_bytes); 804 barrier.Run(); 805 } 806 807 std::string GetStorageTypeName(storage::StorageType type) { 808 switch (type) { 809 case storage::kStorageTypeTemporary: 810 return devtools::Page::Usage::kParamTemporary; 811 case storage::kStorageTypePersistent: 812 return devtools::Page::Usage::kParamPersistent; 813 case storage::kStorageTypeSyncable: 814 return devtools::Page::Usage::kParamSyncable; 815 case storage::kStorageTypeQuotaNotManaged: 816 case storage::kStorageTypeUnknown: 817 NOTREACHED(); 818 } 819 return ""; 820 } 821 822 std::string GetQuotaClientName(storage::QuotaClient::ID id) { 823 switch (id) { 824 case storage::QuotaClient::kFileSystem: 825 return devtools::Page::UsageItem::Id::kEnumFilesystem; 826 case storage::QuotaClient::kDatabase: 827 return devtools::Page::UsageItem::Id::kEnumDatabase; 828 case storage::QuotaClient::kAppcache: 829 return devtools::Page::UsageItem::Id::kEnumAppcache; 830 case storage::QuotaClient::kIndexedDatabase: 831 return devtools::Page::UsageItem::Id::kEnumIndexeddatabase; 832 default: 833 NOTREACHED(); 834 } 835 return ""; 836 } 837 838 void QueryUsageAndQuotaOnIOThread( 839 scoped_refptr<storage::QuotaManager> quota_manager, 840 const GURL& security_origin, 841 const ResponseCallback& callback) { 842 scoped_ptr<base::DictionaryValue> quota(new base::DictionaryValue); 843 scoped_ptr<base::DictionaryValue> usage(new base::DictionaryValue); 844 845 static storage::QuotaClient::ID kQuotaClients[] = { 846 storage::QuotaClient::kFileSystem, storage::QuotaClient::kDatabase, 847 storage::QuotaClient::kAppcache, storage::QuotaClient::kIndexedDatabase}; 848 849 static const size_t kStorageTypeCount = storage::kStorageTypeUnknown; 850 std::map<storage::StorageType, base::ListValue*> storage_type_lists; 851 852 for (size_t i = 0; i != kStorageTypeCount; i++) { 853 const storage::StorageType type = static_cast<storage::StorageType>(i); 854 if (type == storage::kStorageTypeQuotaNotManaged) 855 continue; 856 storage_type_lists[type] = new base::ListValue; 857 usage->Set(GetStorageTypeName(type), storage_type_lists[type]); 858 } 859 860 const int kExpectedResults = 861 2 + arraysize(kQuotaClients) * storage_type_lists.size(); 862 base::DictionaryValue* quota_raw_ptr = quota.get(); 863 864 // Takes ownership on usage and quota. 865 base::Closure barrier = BarrierClosure( 866 kExpectedResults, 867 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread, 868 base::Passed("a), 869 base::Passed(&usage), 870 callback)); 871 std::string host = net::GetHostOrSpecFromURL(security_origin); 872 873 quota_manager->GetUsageAndQuotaForWebApps( 874 security_origin, 875 storage::kStorageTypeTemporary, 876 base::Bind(&DidGetUsageAndQuotaForWebApps, 877 quota_raw_ptr, 878 std::string(devtools::Page::Quota::kParamTemporary), 879 barrier)); 880 881 quota_manager->GetPersistentHostQuota( 882 host, 883 base::Bind(&DidGetQuotaValue, quota_raw_ptr, 884 std::string(devtools::Page::Quota::kParamPersistent), 885 barrier)); 886 887 for (size_t i = 0; i != arraysize(kQuotaClients); i++) { 888 std::map<storage::StorageType, base::ListValue*>::const_iterator iter; 889 for (iter = storage_type_lists.begin(); 890 iter != storage_type_lists.end(); ++iter) { 891 const storage::StorageType type = (*iter).first; 892 if (!quota_manager->IsTrackingHostUsage(type, kQuotaClients[i])) { 893 barrier.Run(); 894 continue; 895 } 896 quota_manager->GetHostUsage( 897 host, type, kQuotaClients[i], 898 base::Bind(&DidGetHostUsage, (*iter).second, 899 GetQuotaClientName(kQuotaClients[i]), 900 barrier)); 901 } 902 } 903 } 904 905 } // namespace 906 907 scoped_refptr<DevToolsProtocol::Response> 908 RendererOverridesHandler::PageQueryUsageAndQuota( 909 scoped_refptr<DevToolsProtocol::Command> command) { 910 base::DictionaryValue* params = command->params(); 911 std::string security_origin; 912 if (!params || !params->GetString( 913 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin, 914 &security_origin)) { 915 return command->InvalidParamResponse( 916 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin); 917 } 918 919 ResponseCallback callback = base::Bind( 920 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted, 921 weak_factory_.GetWeakPtr(), 922 command); 923 924 if (!host_) 925 return command->InternalErrorResponse("Could not connect to view"); 926 927 scoped_refptr<storage::QuotaManager> quota_manager = 928 host_->GetProcess()->GetStoragePartition()->GetQuotaManager(); 929 930 BrowserThread::PostTask( 931 BrowserThread::IO, FROM_HERE, 932 base::Bind( 933 &QueryUsageAndQuotaOnIOThread, 934 quota_manager, 935 GURL(security_origin), 936 callback)); 937 938 return command->AsyncResponsePromise(); 939 } 940 941 void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted( 942 scoped_refptr<DevToolsProtocol::Command> command, 943 scoped_ptr<base::DictionaryValue> response_data) { 944 SendAsyncResponse(command->SuccessResponse(response_data.release())); 945 } 946 947 void RendererOverridesHandler::NotifyScreencastVisibility(bool visible) { 948 if (visible) 949 capture_retry_count_ = kCaptureRetryLimit; 950 base::DictionaryValue* params = new base::DictionaryValue(); 951 params->SetBoolean( 952 devtools::Page::screencastVisibilityChanged::kParamVisible, visible); 953 SendNotification( 954 devtools::Page::screencastVisibilityChanged::kName, params); 955 } 956 957 scoped_refptr<DevToolsProtocol::Response> 958 RendererOverridesHandler::PageSetColorPickerEnabled( 959 scoped_refptr<DevToolsProtocol::Command> command) { 960 base::DictionaryValue* params = command->params(); 961 bool color_picker_enabled = false; 962 if (!params || !params->GetBoolean( 963 devtools::Page::setColorPickerEnabled::kParamEnabled, 964 &color_picker_enabled)) { 965 return command->InvalidParamResponse( 966 devtools::Page::setColorPickerEnabled::kParamEnabled); 967 } 968 969 SetColorPickerEnabled(color_picker_enabled); 970 return command->SuccessResponse(NULL); 971 } 972 973 void RendererOverridesHandler::SetColorPickerEnabled(bool enabled) { 974 if (color_picker_enabled_ == enabled) 975 return; 976 977 color_picker_enabled_ = enabled; 978 979 if (!host_) 980 return; 981 982 if (enabled) { 983 host_->AddMouseEventCallback(mouse_event_callback_); 984 UpdateColorPickerFrame(); 985 } else { 986 host_->RemoveMouseEventCallback(mouse_event_callback_); 987 ResetColorPickerFrame(); 988 989 WebCursor pointer_cursor; 990 WebCursor::CursorInfo cursor_info; 991 cursor_info.type = blink::WebCursorInfo::TypePointer; 992 pointer_cursor.InitFromCursorInfo(cursor_info); 993 host_->SetCursor(pointer_cursor); 994 } 995 } 996 997 void RendererOverridesHandler::UpdateColorPickerFrame() { 998 if (!host_) 999 return; 1000 RenderWidgetHostViewBase* view = 1001 static_cast<RenderWidgetHostViewBase*>(host_->GetView()); 1002 if (!view) 1003 return; 1004 1005 gfx::Size size = view->GetViewBounds().size(); 1006 view->CopyFromCompositingSurface( 1007 gfx::Rect(size), size, 1008 base::Bind(&RendererOverridesHandler::ColorPickerFrameUpdated, 1009 weak_factory_.GetWeakPtr()), 1010 kN32_SkColorType); 1011 } 1012 1013 void RendererOverridesHandler::ResetColorPickerFrame() { 1014 color_picker_frame_.reset(); 1015 last_cursor_x_ = -1; 1016 last_cursor_y_ = -1; 1017 } 1018 1019 void RendererOverridesHandler::ColorPickerFrameUpdated( 1020 bool succeeded, 1021 const SkBitmap& bitmap) { 1022 if (!color_picker_enabled_) 1023 return; 1024 1025 if (succeeded) { 1026 color_picker_frame_ = bitmap; 1027 UpdateColorPickerCursor(); 1028 } 1029 } 1030 1031 bool RendererOverridesHandler::HandleMouseEvent( 1032 const blink::WebMouseEvent& event) { 1033 last_cursor_x_ = event.x; 1034 last_cursor_y_ = event.y; 1035 if (color_picker_frame_.drawsNothing()) 1036 return true; 1037 1038 if (event.button == blink::WebMouseEvent::ButtonLeft && 1039 event.type == blink::WebInputEvent::MouseDown) { 1040 if (last_cursor_x_ < 0 || last_cursor_x_ >= color_picker_frame_.width() || 1041 last_cursor_y_ < 0 || last_cursor_y_ >= color_picker_frame_.height()) { 1042 return true; 1043 } 1044 1045 SkAutoLockPixels lock_image(color_picker_frame_); 1046 SkColor color = color_picker_frame_.getColor(last_cursor_x_, 1047 last_cursor_y_); 1048 base::DictionaryValue* color_dict = new base::DictionaryValue(); 1049 color_dict->SetInteger("r", SkColorGetR(color)); 1050 color_dict->SetInteger("g", SkColorGetG(color)); 1051 color_dict->SetInteger("b", SkColorGetB(color)); 1052 color_dict->SetInteger("a", SkColorGetA(color)); 1053 base::DictionaryValue* response = new base::DictionaryValue(); 1054 response->Set(devtools::Page::colorPicked::kParamColor, color_dict); 1055 SendNotification(devtools::Page::colorPicked::kName, response); 1056 } 1057 UpdateColorPickerCursor(); 1058 return true; 1059 } 1060 1061 void RendererOverridesHandler::UpdateColorPickerCursor() { 1062 if (!host_ || color_picker_frame_.drawsNothing()) 1063 return; 1064 1065 if (last_cursor_x_ < 0 || last_cursor_x_ >= color_picker_frame_.width() || 1066 last_cursor_y_ < 0 || last_cursor_y_ >= color_picker_frame_.height()) { 1067 return; 1068 } 1069 1070 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 1071 host_->GetView()); 1072 if (!view) 1073 return; 1074 1075 // Due to platform limitations, we are using two different cursors 1076 // depending on the platform. Mac and Win have large cursors with two circles 1077 // for original spot and its magnified projection; Linux gets smaller (64 px) 1078 // magnified projection only with centered hotspot. 1079 // Mac Retina requires cursor to be > 120px in order to render smoothly. 1080 1081 #if defined(OS_LINUX) 1082 const float kCursorSize = 63; 1083 const float kDiameter = 63; 1084 const float kHotspotOffset = 32; 1085 const float kHotspotRadius = 0; 1086 const float kPixelSize = 9; 1087 #else 1088 const float kCursorSize = 150; 1089 const float kDiameter = 110; 1090 const float kHotspotOffset = 25; 1091 const float kHotspotRadius = 5; 1092 const float kPixelSize = 10; 1093 #endif 1094 1095 blink::WebScreenInfo screen_info; 1096 view->GetScreenInfo(&screen_info); 1097 double device_scale_factor = screen_info.deviceScaleFactor; 1098 1099 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(SkCanvas::NewRasterN32( 1100 kCursorSize * device_scale_factor, 1101 kCursorSize * device_scale_factor)); 1102 canvas->scale(device_scale_factor, device_scale_factor); 1103 canvas->translate(0.5f, 0.5f); 1104 1105 SkPaint paint; 1106 1107 // Paint original spot with cross. 1108 if (kHotspotRadius) { 1109 paint.setStrokeWidth(1); 1110 paint.setAntiAlias(false); 1111 paint.setColor(SK_ColorDKGRAY); 1112 paint.setStyle(SkPaint::kStroke_Style); 1113 1114 canvas->drawLine(kHotspotOffset, kHotspotOffset - 2 * kHotspotRadius, 1115 kHotspotOffset, kHotspotOffset - kHotspotRadius, 1116 paint); 1117 canvas->drawLine(kHotspotOffset, kHotspotOffset + kHotspotRadius, 1118 kHotspotOffset, kHotspotOffset + 2 * kHotspotRadius, 1119 paint); 1120 canvas->drawLine(kHotspotOffset - 2 * kHotspotRadius, kHotspotOffset, 1121 kHotspotOffset - kHotspotRadius, kHotspotOffset, 1122 paint); 1123 canvas->drawLine(kHotspotOffset + kHotspotRadius, kHotspotOffset, 1124 kHotspotOffset + 2 * kHotspotRadius, kHotspotOffset, 1125 paint); 1126 1127 paint.setStrokeWidth(2); 1128 paint.setAntiAlias(true); 1129 canvas->drawCircle(kHotspotOffset, kHotspotOffset, kHotspotRadius, paint); 1130 } 1131 1132 // Clip circle for magnified projection. 1133 float padding = (kCursorSize - kDiameter) / 2; 1134 SkPath clip_path; 1135 clip_path.addOval(SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter)); 1136 clip_path.close(); 1137 canvas->clipPath(clip_path, SkRegion::kIntersect_Op, true); 1138 1139 // Project pixels. 1140 int pixel_count = kDiameter / kPixelSize; 1141 SkRect src_rect = SkRect::MakeXYWH(last_cursor_x_ - pixel_count / 2, 1142 last_cursor_y_ - pixel_count / 2, 1143 pixel_count, pixel_count); 1144 SkRect dst_rect = SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter); 1145 canvas->drawBitmapRectToRect(color_picker_frame_, &src_rect, dst_rect); 1146 1147 // Paint grid. 1148 paint.setStrokeWidth(1); 1149 paint.setAntiAlias(false); 1150 paint.setColor(SK_ColorGRAY); 1151 for (int i = 0; i < pixel_count; ++i) { 1152 canvas->drawLine(padding + i * kPixelSize, padding, 1153 padding + i * kPixelSize, kCursorSize - padding, paint); 1154 canvas->drawLine(padding, padding + i * kPixelSize, 1155 kCursorSize - padding, padding + i * kPixelSize, paint); 1156 } 1157 1158 // Paint central pixel in red. 1159 SkRect pixel = SkRect::MakeXYWH((kCursorSize - kPixelSize) / 2, 1160 (kCursorSize - kPixelSize) / 2, 1161 kPixelSize, kPixelSize); 1162 paint.setColor(SK_ColorRED); 1163 paint.setStyle(SkPaint::kStroke_Style); 1164 canvas->drawRect(pixel, paint); 1165 1166 // Paint outline. 1167 paint.setStrokeWidth(2); 1168 paint.setColor(SK_ColorDKGRAY); 1169 paint.setAntiAlias(true); 1170 canvas->drawCircle(kCursorSize / 2, kCursorSize / 2, kDiameter / 2, paint); 1171 1172 SkBitmap result; 1173 result.allocN32Pixels(kCursorSize * device_scale_factor, 1174 kCursorSize * device_scale_factor); 1175 canvas->readPixels(&result, 0, 0); 1176 1177 WebCursor cursor; 1178 WebCursor::CursorInfo cursor_info; 1179 cursor_info.type = blink::WebCursorInfo::TypeCustom; 1180 cursor_info.image_scale_factor = device_scale_factor; 1181 cursor_info.custom_image = result; 1182 cursor_info.hotspot = 1183 gfx::Point(kHotspotOffset * device_scale_factor, 1184 kHotspotOffset * device_scale_factor); 1185 #if defined(OS_WIN) 1186 cursor_info.external_handle = 0; 1187 #endif 1188 1189 cursor.InitFromCursorInfo(cursor_info); 1190 DCHECK(host_); 1191 host_->SetCursor(cursor); 1192 } 1193 1194 // Input agent handlers ------------------------------------------------------ 1195 1196 scoped_refptr<DevToolsProtocol::Response> 1197 RendererOverridesHandler::InputEmulateTouchFromMouseEvent( 1198 scoped_refptr<DevToolsProtocol::Command> command) { 1199 if (!screencast_command_.get()) 1200 return command->InternalErrorResponse("Screencast should be turned on"); 1201 1202 base::DictionaryValue* params = command->params(); 1203 if (!params) 1204 return command->NoSuchMethodErrorResponse(); 1205 1206 std::string type; 1207 if (!params->GetString( 1208 devtools::Input::emulateTouchFromMouseEvent::kParamType, 1209 &type)) { 1210 return command->InvalidParamResponse( 1211 devtools::Input::emulateTouchFromMouseEvent::kParamType); 1212 } 1213 1214 blink::WebMouseWheelEvent wheel_event; 1215 blink::WebMouseEvent mouse_event; 1216 blink::WebMouseEvent* event = &mouse_event; 1217 1218 if (type == 1219 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMousePressed) { 1220 event->type = WebInputEvent::MouseDown; 1221 } else if (type == 1222 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseReleased) { 1223 event->type = WebInputEvent::MouseUp; 1224 } else if (type == 1225 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseMoved) { 1226 event->type = WebInputEvent::MouseMove; 1227 } else if (type == 1228 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseWheel) { 1229 double deltaX = 0; 1230 double deltaY = 0; 1231 if (!params->GetDouble( 1232 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX, 1233 &deltaX)) { 1234 return command->InvalidParamResponse( 1235 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX); 1236 } 1237 if (!params->GetDouble( 1238 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY, 1239 &deltaY)) { 1240 return command->InvalidParamResponse( 1241 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY); 1242 } 1243 wheel_event.deltaX = static_cast<float>(deltaX); 1244 wheel_event.deltaY = static_cast<float>(deltaY); 1245 event = &wheel_event; 1246 event->type = WebInputEvent::MouseWheel; 1247 } else { 1248 return command->InvalidParamResponse( 1249 devtools::Input::emulateTouchFromMouseEvent::kParamType); 1250 } 1251 1252 int modifiers = 0; 1253 if (params->GetInteger( 1254 devtools::Input::emulateTouchFromMouseEvent::kParamModifiers, 1255 &modifiers)) { 1256 if (modifiers & 1) 1257 event->modifiers |= WebInputEvent::AltKey; 1258 if (modifiers & 2) 1259 event->modifiers |= WebInputEvent::ControlKey; 1260 if (modifiers & 4) 1261 event->modifiers |= WebInputEvent::MetaKey; 1262 if (modifiers & 8) 1263 event->modifiers |= WebInputEvent::ShiftKey; 1264 } 1265 1266 params->GetDouble( 1267 devtools::Input::emulateTouchFromMouseEvent::kParamTimestamp, 1268 &event->timeStampSeconds); 1269 1270 if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamX, 1271 &event->x)) { 1272 return command->InvalidParamResponse( 1273 devtools::Input::emulateTouchFromMouseEvent::kParamX); 1274 } 1275 1276 if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamY, 1277 &event->y)) { 1278 return command->InvalidParamResponse( 1279 devtools::Input::emulateTouchFromMouseEvent::kParamY); 1280 } 1281 1282 event->windowX = event->x; 1283 event->windowY = event->y; 1284 event->globalX = event->x; 1285 event->globalY = event->y; 1286 1287 params->GetInteger( 1288 devtools::Input::emulateTouchFromMouseEvent::kParamClickCount, 1289 &event->clickCount); 1290 1291 std::string button; 1292 if (!params->GetString( 1293 devtools::Input::emulateTouchFromMouseEvent::kParamButton, 1294 &button)) { 1295 return command->InvalidParamResponse( 1296 devtools::Input::emulateTouchFromMouseEvent::kParamButton); 1297 } 1298 1299 if (button == "none") { 1300 event->button = WebMouseEvent::ButtonNone; 1301 } else if (button == "left") { 1302 event->button = WebMouseEvent::ButtonLeft; 1303 event->modifiers |= WebInputEvent::LeftButtonDown; 1304 } else if (button == "middle") { 1305 event->button = WebMouseEvent::ButtonMiddle; 1306 event->modifiers |= WebInputEvent::MiddleButtonDown; 1307 } else if (button == "right") { 1308 event->button = WebMouseEvent::ButtonRight; 1309 event->modifiers |= WebInputEvent::RightButtonDown; 1310 } else { 1311 return command->InvalidParamResponse( 1312 devtools::Input::emulateTouchFromMouseEvent::kParamButton); 1313 } 1314 1315 if (!host_) 1316 return command->InternalErrorResponse("Could not connect to view"); 1317 1318 if (event->type == WebInputEvent::MouseWheel) 1319 host_->ForwardWheelEvent(wheel_event); 1320 else 1321 host_->ForwardMouseEvent(mouse_event); 1322 return command->SuccessResponse(NULL); 1323 } 1324 1325 void RendererOverridesHandler::UpdateTouchEventEmulationState() { 1326 if (!host_) 1327 return; 1328 bool enabled = touch_emulation_enabled_ || screencast_command_.get(); 1329 host_->SetTouchEventEmulationEnabled(enabled); 1330 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 1331 WebContents::FromRenderViewHost(host_)); 1332 if (web_contents) 1333 web_contents->SetForceDisableOverscrollContent(enabled); 1334 } 1335 1336 } // namespace content 1337