blob: a48570d238a2250e1585186c58d76a04cc445676 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/devtools/renderer_overrides_handler.h"
#include <string>
#include "base/barrier_closure.h"
#include "base/base64.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/strings/string16.h"
#include "base/values.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/devtools/devtools_protocol_constants.h"
#include "content/browser/devtools/devtools_tracing_handler.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/common/view_messages.h"
#include "content/port/browser/render_widget_host_view_port.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/page_transition_types.h"
#include "content/public/common/referrer.h"
#include "ipc/ipc_sender.h"
#include "net/base/net_util.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/size_conversions.h"
#include "ui/snapshot/snapshot.h"
#include "url/gurl.h"
#include "webkit/browser/quota/quota_manager.h"
using WebKit::WebGestureEvent;
using WebKit::WebInputEvent;
using WebKit::WebMouseEvent;
namespace content {
namespace {
static const char kPng[] = "png";
static const char kJpeg[] = "jpeg";
static int kDefaultScreenshotQuality = 80;
static int kFrameRateThresholdMs = 100;
static int kCaptureRetryLimit = 2;
void ParseGenericInputParams(base::DictionaryValue* params,
WebInputEvent* event) {
int modifiers = 0;
if (params->GetInteger(devtools::Input::kParamModifiers,
&modifiers)) {
if (modifiers & 1)
event->modifiers |= WebInputEvent::AltKey;
if (modifiers & 2)
event->modifiers |= WebInputEvent::ControlKey;
if (modifiers & 4)
event->modifiers |= WebInputEvent::MetaKey;
if (modifiers & 8)
event->modifiers |= WebInputEvent::ShiftKey;
}
params->GetDouble(devtools::Input::kParamTimestamp,
&event->timeStampSeconds);
}
} // namespace
RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
: agent_(agent),
capture_retry_count_(0),
weak_factory_(this) {
RegisterCommandHandler(
devtools::DOM::setFileInputFiles::kName,
base::Bind(
&RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::disable::kName,
base::Bind(
&RendererOverridesHandler::PageDisable, base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::handleJavaScriptDialog::kName,
base::Bind(
&RendererOverridesHandler::PageHandleJavaScriptDialog,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::navigate::kName,
base::Bind(
&RendererOverridesHandler::PageNavigate,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::reload::kName,
base::Bind(
&RendererOverridesHandler::PageReload,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::getNavigationHistory::kName,
base::Bind(
&RendererOverridesHandler::PageGetNavigationHistory,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::navigateToHistoryEntry::kName,
base::Bind(
&RendererOverridesHandler::PageNavigateToHistoryEntry,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::captureScreenshot::kName,
base::Bind(
&RendererOverridesHandler::PageCaptureScreenshot,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::canScreencast::kName,
base::Bind(
&RendererOverridesHandler::PageCanScreencast,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::startScreencast::kName,
base::Bind(
&RendererOverridesHandler::PageStartScreencast,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::stopScreencast::kName,
base::Bind(
&RendererOverridesHandler::PageStopScreencast,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Page::queryUsageAndQuota::kName,
base::Bind(
&RendererOverridesHandler::PageQueryUsageAndQuota,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Input::dispatchMouseEvent::kName,
base::Bind(
&RendererOverridesHandler::InputDispatchMouseEvent,
base::Unretained(this)));
RegisterCommandHandler(
devtools::Input::dispatchGestureEvent::kName,
base::Bind(
&RendererOverridesHandler::InputDispatchGestureEvent,
base::Unretained(this)));
}
RendererOverridesHandler::~RendererOverridesHandler() {}
void RendererOverridesHandler::OnClientDetached() {
screencast_command_ = NULL;
}
void RendererOverridesHandler::OnSwapCompositorFrame(
const IPC::Message& message) {
ViewHostMsg_SwapCompositorFrame::Param param;
if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
return;
last_compositor_frame_metadata_ = param.b.metadata;
if (screencast_command_)
InnerSwapCompositorFrame();
}
void RendererOverridesHandler::OnVisibilityChanged(bool visible) {
if (!screencast_command_)
return;
NotifyScreencastVisibility(visible);
}
void RendererOverridesHandler::InnerSwapCompositorFrame() {
if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
kFrameRateThresholdMs) {
return;
}
last_frame_time_ = base::TimeTicks::Now();
std::string format;
int quality = kDefaultScreenshotQuality;
double scale = 1;
ParseCaptureParameters(screencast_command_.get(), &format, &quality, &scale);
RenderViewHost* host = agent_->GetRenderViewHost();
RenderWidgetHostViewPort* view_port =
RenderWidgetHostViewPort::FromRWHV(host->GetView());
gfx::Rect view_bounds = host->GetView()->GetViewBounds();
gfx::Size snapshot_size = gfx::ToFlooredSize(
gfx::ScaleSize(view_bounds.size(), scale));
view_port->CopyFromCompositingSurface(
view_bounds, snapshot_size,
base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
weak_factory_.GetWeakPtr(),
scoped_refptr<DevToolsProtocol::Command>(), format, quality,
last_compositor_frame_metadata_));
}
void RendererOverridesHandler::ParseCaptureParameters(
DevToolsProtocol::Command* command,
std::string* format,
int* quality,
double* scale) {
*quality = kDefaultScreenshotQuality;
*scale = 1;
double max_width = -1;
double max_height = -1;
base::DictionaryValue* params = command->params();
if (params) {
params->GetString(devtools::Page::captureScreenshot::kParamFormat,
format);
params->GetInteger(devtools::Page::captureScreenshot::kParamQuality,
quality);
params->GetDouble(devtools::Page::captureScreenshot::kParamMaxWidth,
&max_width);
params->GetDouble(devtools::Page::captureScreenshot::kParamMaxHeight,
&max_height);
}
RenderViewHost* host = agent_->GetRenderViewHost();
if (host->GetView()) {
gfx::Rect view_bounds = host->GetView()->GetViewBounds();
float device_sf = last_compositor_frame_metadata_.device_scale_factor;
if (max_width > 0)
*scale = std::min(*scale, max_width / view_bounds.width() / device_sf);
if (max_height > 0)
*scale = std::min(*scale, max_height / view_bounds.height() / device_sf);
}
if (format->empty())
*format = kPng;
if (*quality < 0 || *quality > 100)
*quality = kDefaultScreenshotQuality;
if (*scale <= 0)
*scale = 0.1;
if (*scale > 5)
*scale = 5;
}
// DOM agent handlers --------------------------------------------------------
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
scoped_refptr<DevToolsProtocol::Command> command) {
base::DictionaryValue* params = command->params();
base::ListValue* file_list = NULL;
const char* param =
devtools::DOM::setFileInputFiles::kParamFiles;
if (!params || !params->GetList(param, &file_list))
return command->InvalidParamResponse(param);
RenderViewHost* host = agent_->GetRenderViewHost();
if (!host)
return NULL;
for (size_t i = 0; i < file_list->GetSize(); ++i) {
base::FilePath::StringType file;
if (!file_list->GetString(i, &file))
return command->InvalidParamResponse(param);
ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
host->GetProcess()->GetID(), base::FilePath(file));
}
return NULL;
}
// Page agent handlers -------------------------------------------------------
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageDisable(
scoped_refptr<DevToolsProtocol::Command> command) {
screencast_command_ = NULL;
return NULL;
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageHandleJavaScriptDialog(
scoped_refptr<DevToolsProtocol::Command> command) {
base::DictionaryValue* params = command->params();
const char* paramAccept =
devtools::Page::handleJavaScriptDialog::kParamAccept;
bool accept;
if (!params || !params->GetBoolean(paramAccept, &accept))
return command->InvalidParamResponse(paramAccept);
string16 prompt_override;
string16* prompt_override_ptr = &prompt_override;
if (!params || !params->GetString(
devtools::Page::handleJavaScriptDialog::kParamPromptText,
prompt_override_ptr)) {
prompt_override_ptr = NULL;
}
RenderViewHost* host = agent_->GetRenderViewHost();
if (host) {
WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
if (web_contents) {
JavaScriptDialogManager* manager =
web_contents->GetDelegate()->GetJavaScriptDialogManager();
if (manager && manager->HandleJavaScriptDialog(
web_contents, accept, prompt_override_ptr)) {
return NULL;
}
}
}
return command->InternalErrorResponse("No JavaScript dialog to handle");
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageNavigate(
scoped_refptr<DevToolsProtocol::Command> command) {
base::DictionaryValue* params = command->params();
std::string url;
const char* param = devtools::Page::navigate::kParamUrl;
if (!params || !params->GetString(param, &url))
return command->InvalidParamResponse(param);
GURL gurl(url);
if (!gurl.is_valid()) {
return command->InternalErrorResponse("Cannot navigate to invalid URL");
}
RenderViewHost* host = agent_->GetRenderViewHost();
if (host) {
WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
if (web_contents) {
web_contents->GetController()
.LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
return command->SuccessResponse(new base::DictionaryValue());
}
}
return command->InternalErrorResponse("No WebContents to navigate");
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageReload(
scoped_refptr<DevToolsProtocol::Command> command) {
RenderViewHost* host = agent_->GetRenderViewHost();
if (host) {
WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
if (web_contents) {
// Override only if it is crashed.
if (!web_contents->IsCrashed())
return NULL;
web_contents->GetController().Reload(false);
return command->SuccessResponse(NULL);
}
}
return command->InternalErrorResponse("No WebContents to reload");
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageGetNavigationHistory(
scoped_refptr<DevToolsProtocol::Command> command) {
RenderViewHost* host = agent_->GetRenderViewHost();
if (host) {
WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
if (web_contents) {
base::DictionaryValue* result = new base::DictionaryValue();
NavigationController& controller = web_contents->GetController();
result->SetInteger(
devtools::Page::getNavigationHistory::kResponseCurrentIndex,
controller.GetCurrentEntryIndex());
ListValue* entries = new ListValue();
for (int i = 0; i != controller.GetEntryCount(); ++i) {
const NavigationEntry* entry = controller.GetEntryAtIndex(i);
base::DictionaryValue* entry_value = new base::DictionaryValue();
entry_value->SetInteger(
devtools::Page::getNavigationHistory::kResponseEntryId,
entry->GetUniqueID());
entry_value->SetString(
devtools::Page::getNavigationHistory::kResponseEntryURL,
entry->GetURL().spec());
entry_value->SetString(
devtools::Page::getNavigationHistory::kResponseEntryTitle,
entry->GetTitle());
entries->Append(entry_value);
}
result->Set(
devtools::Page::getNavigationHistory::kResponseEntries,
entries);
return command->SuccessResponse(result);
}
}
return command->InternalErrorResponse("No WebContents to navigate");
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageNavigateToHistoryEntry(
scoped_refptr<DevToolsProtocol::Command> command) {
int entry_id;
base::DictionaryValue* params = command->params();
const char* param = devtools::Page::navigateToHistoryEntry::kParamEntryId;
if (!params || !params->GetInteger(param, &entry_id)) {
return command->InvalidParamResponse(param);
}
RenderViewHost* host = agent_->GetRenderViewHost();
if (host) {
WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
if (web_contents) {
NavigationController& controller = web_contents->GetController();
for (int i = 0; i != controller.GetEntryCount(); ++i) {
if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
controller.GoToIndex(i);
return command->SuccessResponse(new base::DictionaryValue());
}
}
return command->InvalidParamResponse(param);
}
}
return command->InternalErrorResponse("No WebContents to navigate");
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageCaptureScreenshot(
scoped_refptr<DevToolsProtocol::Command> command) {
std::string format;
int quality = kDefaultScreenshotQuality;
double scale = 1;
ParseCaptureParameters(command.get(), &format, &quality, &scale);
RenderViewHost* host = agent_->GetRenderViewHost();
gfx::Rect view_bounds = host->GetView()->GetViewBounds();
gfx::Size snapshot_size = gfx::ToFlooredSize(
gfx::ScaleSize(view_bounds.size(), scale));
// Grab screen pixels if available for current platform.
// TODO(pfeldman): support format, scale and quality in ui::GrabViewSnapshot.
std::vector<unsigned char> png;
bool is_unscaled_png = scale == 1 && format == kPng;
if (is_unscaled_png && ui::GrabViewSnapshot(host->GetView()->GetNativeView(),
&png,
gfx::Rect(snapshot_size))) {
std::string base64_data;
bool success = base::Base64Encode(
base::StringPiece(reinterpret_cast<char*>(&*png.begin()), png.size()),
&base64_data);
if (success) {
base::DictionaryValue* result = new base::DictionaryValue();
result->SetString(
devtools::Page::kData, base64_data);
return command->SuccessResponse(result);
}
return command->InternalErrorResponse("Unable to base64encode screenshot");
}
// Fallback to copying from compositing surface.
RenderWidgetHostViewPort* view_port =
RenderWidgetHostViewPort::FromRWHV(host->GetView());
view_port->CopyFromCompositingSurface(
view_bounds, snapshot_size,
base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
weak_factory_.GetWeakPtr(), command, format, quality,
last_compositor_frame_metadata_));
return command->AsyncResponsePromise();
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageCanScreencast(
scoped_refptr<DevToolsProtocol::Command> command) {
base::DictionaryValue* result = new base::DictionaryValue();
#if defined(OS_ANDROID)
result->SetBoolean(devtools::kResult, true);
#else
result->SetBoolean(devtools::kResult, false);
#endif // defined(OS_ANDROID)
return command->SuccessResponse(result);
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageStartScreencast(
scoped_refptr<DevToolsProtocol::Command> command) {
screencast_command_ = command;
RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
agent_->GetRenderViewHost());
bool visible = !host->is_hidden();
NotifyScreencastVisibility(visible);
if (visible)
InnerSwapCompositorFrame();
return command->SuccessResponse(NULL);
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageStopScreencast(
scoped_refptr<DevToolsProtocol::Command> command) {
last_frame_time_ = base::TimeTicks();
screencast_command_ = NULL;
return command->SuccessResponse(NULL);
}
void RendererOverridesHandler::ScreenshotCaptured(
scoped_refptr<DevToolsProtocol::Command> command,
const std::string& format,
int quality,
const cc::CompositorFrameMetadata& metadata,
bool success,
const SkBitmap& bitmap) {
if (!success) {
if (command) {
SendAsyncResponse(
command->InternalErrorResponse("Unable to capture screenshot"));
} else if (capture_retry_count_) {
--capture_retry_count_;
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame,
weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
}
return;
}
std::vector<unsigned char> data;
SkAutoLockPixels lock_image(bitmap);
bool encoded;
if (format == kPng) {
encoded = gfx::PNGCodec::Encode(
reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
gfx::PNGCodec::FORMAT_SkBitmap,
gfx::Size(bitmap.width(), bitmap.height()),
bitmap.width() * bitmap.bytesPerPixel(),
false, std::vector<gfx::PNGCodec::Comment>(), &data);
} else if (format == kJpeg) {
encoded = gfx::JPEGCodec::Encode(
reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
gfx::JPEGCodec::FORMAT_SkBitmap,
bitmap.width(),
bitmap.height(),
bitmap.width() * bitmap.bytesPerPixel(),
quality, &data);
} else {
encoded = false;
}
if (!encoded) {
if (command) {
SendAsyncResponse(
command->InternalErrorResponse("Unable to encode screenshot"));
}
return;
}
std::string base_64_data;
if (!base::Base64Encode(base::StringPiece(
reinterpret_cast<char*>(&data[0]),
data.size()),
&base_64_data)) {
if (command) {
SendAsyncResponse(
command->InternalErrorResponse("Unable to base64 encode"));
}
return;
}
base::DictionaryValue* response = new base::DictionaryValue();
response->SetString(devtools::Page::kData, base_64_data);
// Consider metadata empty in case it has no device scale factor.
if (metadata.device_scale_factor != 0) {
response->SetDouble(devtools::Page::kParamDeviceScaleFactor,
metadata.device_scale_factor);
response->SetDouble(devtools::Page::kParamPageScaleFactor,
metadata.page_scale_factor);
response->SetDouble(devtools::Page::kParamPageScaleFactorMin,
metadata.min_page_scale_factor);
response->SetDouble(devtools::Page::kParamPageScaleFactorMax,
metadata.max_page_scale_factor);
response->SetDouble(devtools::Page::kParamOffsetTop,
metadata.location_bar_content_translation.y());
response->SetDouble(devtools::Page::kParamOffsetBottom,
metadata.overdraw_bottom_height);
base::DictionaryValue* viewport = new base::DictionaryValue();
viewport->SetDouble(devtools::kParamX, metadata.root_scroll_offset.x());
viewport->SetDouble(devtools::kParamY, metadata.root_scroll_offset.y());
viewport->SetDouble(devtools::kParamWidth, metadata.viewport_size.width());
viewport->SetDouble(devtools::kParamHeight,
metadata.viewport_size.height());
response->Set(devtools::Page::kParamViewport, viewport);
}
if (command) {
SendAsyncResponse(command->SuccessResponse(response));
} else {
SendNotification(devtools::Page::screencastFrame::kName, response);
}
}
// Quota and Usage ------------------------------------------
namespace {
typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)>
ResponseCallback;
void QueryUsageAndQuotaCompletedOnIOThread(
scoped_ptr<base::DictionaryValue> quota,
scoped_ptr<base::DictionaryValue> usage,
ResponseCallback callback) {
scoped_ptr<base::DictionaryValue> response_data(new base::DictionaryValue);
response_data->Set(devtools::Page::queryUsageAndQuota::kResponseQuota,
quota.release());
response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage,
usage.release());
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(callback, base::Passed(&response_data)));
}
void DidGetHostUsage(
base::ListValue* list,
const std::string& client_id,
const base::Closure& barrier,
int64 value) {
base::DictionaryValue* usage_item = new base::DictionaryValue;
usage_item->SetString(devtools::Page::UsageItem::kItemID, client_id);
usage_item->SetDouble(devtools::Page::UsageItem::kItemValue, value);
list->Append(usage_item);
barrier.Run();
}
void DidGetQuotaValue(
base::DictionaryValue* dictionary,
const std::string& item_name,
const base::Closure& barrier,
quota::QuotaStatusCode status,
int64 value) {
if (status == quota::kQuotaStatusOk)
dictionary->SetDouble(item_name, value);
barrier.Run();
}
void DidGetUsageAndQuotaForWebApps(
base::DictionaryValue* quota,
const std::string& item_name,
const base::Closure& barrier,
quota::QuotaStatusCode status,
int64 used_bytes,
int64 quota_in_bytes) {
if (status == quota::kQuotaStatusOk)
quota->SetDouble(item_name, quota_in_bytes);
barrier.Run();
}
std::string GetStorageTypeName(quota::StorageType type) {
switch (type) {
case quota::kStorageTypeTemporary:
return devtools::Page::Usage::kItemTemporary;
case quota::kStorageTypePersistent:
return devtools::Page::Usage::kItemPersistent;
case quota::kStorageTypeSyncable:
return devtools::Page::Usage::kItemSyncable;
default:
NOTREACHED();
return "";
}
}
std::string GetQuotaClientName(quota::QuotaClient::ID id) {
switch (id) {
case quota::QuotaClient::kFileSystem:
return devtools::Page::UsageItem::ID::kFilesystem;
case quota::QuotaClient::kDatabase:
return devtools::Page::UsageItem::ID::kDatabase;
case quota::QuotaClient::kAppcache:
return devtools::Page::UsageItem::ID::kAppcache;
case quota::QuotaClient::kIndexedDatabase:
return devtools::Page::UsageItem::ID::kIndexedDatabase;
default:
NOTREACHED();
return "";
}
}
void QueryUsageAndQuotaOnIOThread(
scoped_refptr<quota::QuotaManager> quota_manager,
const GURL& security_origin,
const ResponseCallback& callback) {
scoped_ptr<base::DictionaryValue> quota(new base::DictionaryValue);
scoped_ptr<base::DictionaryValue> usage(new base::DictionaryValue);
static quota::QuotaClient::ID kQuotaClients[] = {
quota::QuotaClient::kFileSystem,
quota::QuotaClient::kDatabase,
quota::QuotaClient::kAppcache,
quota::QuotaClient::kIndexedDatabase
};
static const size_t kStorageTypeCount = quota::kStorageTypeUnknown;
base::ListValue* storage_type_lists[kStorageTypeCount];
for (size_t i = 0; i != kStorageTypeCount; i++) {
const quota::StorageType type = static_cast<quota::StorageType>(i);
storage_type_lists[i] = new base::ListValue;
usage->Set(GetStorageTypeName(type), storage_type_lists[i]);
}
COMPILE_ASSERT(kStorageTypeCount == arraysize(storage_type_lists),
inconsistent_storage_type_list);
int kExpectedResults = 2 + arraysize(kQuotaClients) * kStorageTypeCount;
base::DictionaryValue* quota_raw_ptr = quota.get();
// Takes owneship on usage and quota.
base::Closure barrier = BarrierClosure(
kExpectedResults,
base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
base::Passed(&quota),
base::Passed(&usage),
callback));
std::string host = net::GetHostOrSpecFromURL(security_origin);
quota_manager->GetUsageAndQuotaForWebApps(
security_origin,
quota::kStorageTypeTemporary,
base::Bind(&DidGetUsageAndQuotaForWebApps, quota_raw_ptr,
std::string(devtools::Page::Quota::kItemTemporary), barrier));
quota_manager->GetPersistentHostQuota(
host,
base::Bind(&DidGetQuotaValue, quota_raw_ptr,
std::string(devtools::Page::Quota::kItemPersistent),
barrier));
for (size_t i = 0; i != arraysize(kQuotaClients); i++) {
for (size_t j = 0; j != kStorageTypeCount; j++) {
const quota::StorageType type = static_cast<quota::StorageType>(j);
if (!quota_manager->IsTrackingHostUsage(type,
kQuotaClients[i])) {
barrier.Run();
continue;
}
quota_manager->GetHostUsage(host, type,
kQuotaClients[i],
base::Bind(&DidGetHostUsage, storage_type_lists[j],
GetQuotaClientName(kQuotaClients[i]),
barrier));
}
}
}
} // namespace
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::PageQueryUsageAndQuota(
scoped_refptr<DevToolsProtocol::Command> command) {
base::DictionaryValue* params = command->params();
std::string security_origin;
if (!params || !params->GetString(
devtools::Page::queryUsageAndQuota::kParamSecurityOrigin,
&security_origin)) {
return command->InvalidParamResponse(
devtools::Page::queryUsageAndQuota::kParamSecurityOrigin);
}
ResponseCallback callback = base::Bind(
&RendererOverridesHandler::PageQueryUsageAndQuotaCompleted,
weak_factory_.GetWeakPtr(),
command);
scoped_refptr<quota::QuotaManager> quota_manager =
agent_->GetRenderViewHost()->GetProcess()->
GetStoragePartition()->GetQuotaManager();
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(
&QueryUsageAndQuotaOnIOThread,
quota_manager,
GURL(security_origin),
callback));
return command->AsyncResponsePromise();
}
void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted(
scoped_refptr<DevToolsProtocol::Command> command,
scoped_ptr<base::DictionaryValue> response_data) {
SendAsyncResponse(command->SuccessResponse(response_data.release()));
}
void RendererOverridesHandler::NotifyScreencastVisibility(bool visible) {
if (visible)
capture_retry_count_ = kCaptureRetryLimit;
base::DictionaryValue* params = new base::DictionaryValue();
params->SetBoolean(
devtools::Page::screencastVisibilityChanged::kParamVisible, visible);
SendNotification(
devtools::Page::screencastVisibilityChanged::kName, params);
}
// Input agent handlers ------------------------------------------------------
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::InputDispatchMouseEvent(
scoped_refptr<DevToolsProtocol::Command> command) {
base::DictionaryValue* params = command->params();
if (!params)
return NULL;
bool device_space = false;
if (!params->GetBoolean(devtools::Input::kParamDeviceSpace,
&device_space) ||
!device_space) {
return NULL;
}
RenderViewHost* host = agent_->GetRenderViewHost();
WebKit::WebMouseEvent mouse_event;
ParseGenericInputParams(params, &mouse_event);
std::string type;
if (params->GetString(devtools::Input::kParamType,
&type)) {
if (type == "mousePressed")
mouse_event.type = WebInputEvent::MouseDown;
else if (type == "mouseReleased")
mouse_event.type = WebInputEvent::MouseUp;
else if (type == "mouseMoved")
mouse_event.type = WebInputEvent::MouseMove;
else
return NULL;
} else {
return NULL;
}
if (!params->GetInteger(devtools::kParamX, &mouse_event.x) ||
!params->GetInteger(devtools::kParamY, &mouse_event.y)) {
return NULL;
}
mouse_event.windowX = mouse_event.x;
mouse_event.windowY = mouse_event.y;
mouse_event.globalX = mouse_event.x;
mouse_event.globalY = mouse_event.y;
params->GetInteger(devtools::Input::dispatchMouseEvent::kParamClickCount,
&mouse_event.clickCount);
std::string button;
if (!params->GetString(devtools::Input::dispatchMouseEvent::kParamButton,
&button)) {
return NULL;
}
if (button == "none") {
mouse_event.button = WebMouseEvent::ButtonNone;
} else if (button == "left") {
mouse_event.button = WebMouseEvent::ButtonLeft;
mouse_event.modifiers |= WebInputEvent::LeftButtonDown;
} else if (button == "middle") {
mouse_event.button = WebMouseEvent::ButtonMiddle;
mouse_event.modifiers |= WebInputEvent::MiddleButtonDown;
} else if (button == "right") {
mouse_event.button = WebMouseEvent::ButtonRight;
mouse_event.modifiers |= WebInputEvent::RightButtonDown;
} else {
return NULL;
}
host->ForwardMouseEvent(mouse_event);
return command->SuccessResponse(NULL);
}
scoped_refptr<DevToolsProtocol::Response>
RendererOverridesHandler::InputDispatchGestureEvent(
scoped_refptr<DevToolsProtocol::Command> command) {
base::DictionaryValue* params = command->params();
if (!params)
return NULL;
RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
agent_->GetRenderViewHost());
WebKit::WebGestureEvent event;
ParseGenericInputParams(params, &event);
std::string type;
if (params->GetString(devtools::Input::kParamType,
&type)) {
if (type == "scrollBegin")
event.type = WebInputEvent::GestureScrollBegin;
else if (type == "scrollUpdate")
event.type = WebInputEvent::GestureScrollUpdate;
else if (type == "scrollEnd")
event.type = WebInputEvent::GestureScrollEnd;
else if (type == "tapDown")
event.type = WebInputEvent::GestureTapDown;
else if (type == "tap")
event.type = WebInputEvent::GestureTap;
else if (type == "pinchBegin")
event.type = WebInputEvent::GesturePinchBegin;
else if (type == "pinchUpdate")
event.type = WebInputEvent::GesturePinchUpdate;
else if (type == "pinchEnd")
event.type = WebInputEvent::GesturePinchEnd;
else
return NULL;
} else {
return NULL;
}
if (!params->GetInteger(devtools::kParamX, &event.x) ||
!params->GetInteger(devtools::kParamY, &event.y)) {
return NULL;
}
event.globalX = event.x;
event.globalY = event.y;
if (type == "scrollUpdate") {
int dx;
int dy;
if (!params->GetInteger(
devtools::Input::dispatchGestureEvent::kParamDeltaX, &dx) ||
!params->GetInteger(
devtools::Input::dispatchGestureEvent::kParamDeltaY, &dy)) {
return NULL;
}
event.data.scrollUpdate.deltaX = dx;
event.data.scrollUpdate.deltaY = dy;
}
if (type == "pinchUpdate") {
double scale;
if (!params->GetDouble(
devtools::Input::dispatchGestureEvent::kParamPinchScale,
&scale)) {
return NULL;
}
event.data.pinchUpdate.scale = static_cast<float>(scale);
}
host->ForwardGestureEvent(event);
return command->SuccessResponse(NULL);
}
} // namespace content