Home | History | Annotate | Download | only in devtools
      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(&quota),
    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