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.
5 #include "content/browser/devtools/renderer_overrides_handler.h"
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/common/view_messages.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/content_browser_client.h"
28 #include "content/public/browser/devtools_agent_host.h"
29 #include "content/public/browser/javascript_dialog_manager.h"
30 #include "content/public/browser/navigation_controller.h"
31 #include "content/public/browser/navigation_entry.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/browser/render_view_host.h"
34 #include "content/public/browser/render_widget_host_view.h"
35 #include "content/public/browser/storage_partition.h"
36 #include "content/public/browser/web_contents.h"
37 #include "content/public/browser/web_contents_delegate.h"
38 #include "content/public/common/content_client.h"
39 #include "content/public/common/page_transition_types.h"
40 #include "content/public/common/referrer.h"
41 #include "ipc/ipc_sender.h"
42 #include "net/base/net_util.h"
43 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
44 #include "third_party/WebKit/public/web/WebInputEvent.h"
45 #include "ui/gfx/codec/jpeg_codec.h"
46 #include "ui/gfx/codec/png_codec.h"
47 #include "ui/gfx/display.h"
48 #include "ui/gfx/screen.h"
49 #include "ui/gfx/size_conversions.h"
50 #include "ui/snapshot/snapshot.h"
52 #include "webkit/browser/quota/quota_manager.h"
54 using blink::WebGestureEvent;
55 using blink::WebInputEvent;
56 using blink::WebMouseEvent;
62 static const char kPng[] = "png";
63 static const char kJpeg[] = "jpeg";
64 static int kDefaultScreenshotQuality = 80;
65 static int kFrameRateThresholdMs = 100;
66 static int kCaptureRetryLimit = 2;
70 RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
72 has_last_compositor_frame_metadata_(false),
73 capture_retry_count_(0),
75 RegisterCommandHandler(
76 devtools::DOM::setFileInputFiles::kName,
78 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
79 base::Unretained(this)));
80 RegisterCommandHandler(
81 devtools::Network::clearBrowserCache::kName,
83 &RendererOverridesHandler::ClearBrowserCache,
84 base::Unretained(this)));
85 RegisterCommandHandler(
86 devtools::Network::clearBrowserCookies::kName,
88 &RendererOverridesHandler::ClearBrowserCookies,
89 base::Unretained(this)));
90 RegisterCommandHandler(
91 devtools::Page::disable::kName,
93 &RendererOverridesHandler::PageDisable, base::Unretained(this)));
94 RegisterCommandHandler(
95 devtools::Page::handleJavaScriptDialog::kName,
97 &RendererOverridesHandler::PageHandleJavaScriptDialog,
98 base::Unretained(this)));
99 RegisterCommandHandler(
100 devtools::Page::navigate::kName,
102 &RendererOverridesHandler::PageNavigate,
103 base::Unretained(this)));
104 RegisterCommandHandler(
105 devtools::Page::reload::kName,
107 &RendererOverridesHandler::PageReload,
108 base::Unretained(this)));
109 RegisterCommandHandler(
110 devtools::Page::getNavigationHistory::kName,
112 &RendererOverridesHandler::PageGetNavigationHistory,
113 base::Unretained(this)));
114 RegisterCommandHandler(
115 devtools::Page::navigateToHistoryEntry::kName,
117 &RendererOverridesHandler::PageNavigateToHistoryEntry,
118 base::Unretained(this)));
119 RegisterCommandHandler(
120 devtools::Page::captureScreenshot::kName,
122 &RendererOverridesHandler::PageCaptureScreenshot,
123 base::Unretained(this)));
124 RegisterCommandHandler(
125 devtools::Page::canScreencast::kName,
127 &RendererOverridesHandler::PageCanScreencast,
128 base::Unretained(this)));
129 RegisterCommandHandler(
130 devtools::Page::startScreencast::kName,
132 &RendererOverridesHandler::PageStartScreencast,
133 base::Unretained(this)));
134 RegisterCommandHandler(
135 devtools::Page::stopScreencast::kName,
137 &RendererOverridesHandler::PageStopScreencast,
138 base::Unretained(this)));
139 RegisterCommandHandler(
140 devtools::Page::queryUsageAndQuota::kName,
142 &RendererOverridesHandler::PageQueryUsageAndQuota,
143 base::Unretained(this)));
144 RegisterCommandHandler(
145 devtools::Input::emulateTouchFromMouseEvent::kName,
147 &RendererOverridesHandler::InputEmulateTouchFromMouseEvent,
148 base::Unretained(this)));
151 RendererOverridesHandler::~RendererOverridesHandler() {}
153 void RendererOverridesHandler::OnClientDetached() {
154 RenderViewHostImpl* host = GetRenderViewHostImpl();
155 if (screencast_command_ && host)
156 host->SetTouchEventEmulationEnabled(false, false);
157 screencast_command_ = NULL;
160 void RendererOverridesHandler::OnSwapCompositorFrame(
161 const cc::CompositorFrameMetadata& frame_metadata) {
162 last_compositor_frame_metadata_ = frame_metadata;
163 has_last_compositor_frame_metadata_ = true;
165 if (screencast_command_)
166 InnerSwapCompositorFrame();
169 void RendererOverridesHandler::OnVisibilityChanged(bool visible) {
170 if (!screencast_command_)
172 NotifyScreencastVisibility(visible);
175 void RendererOverridesHandler::OnRenderViewHostChanged() {
176 RenderViewHostImpl* host = GetRenderViewHostImpl();
177 if (screencast_command_ && host)
178 host->SetTouchEventEmulationEnabled(true, true);
181 bool RendererOverridesHandler::OnSetTouchEventEmulationEnabled() {
182 return screencast_command_.get() != NULL;
185 void RendererOverridesHandler::InnerSwapCompositorFrame() {
186 if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
187 kFrameRateThresholdMs) {
191 RenderViewHost* host = GetRenderViewHostImpl();
192 if (!host->GetView())
195 last_frame_time_ = base::TimeTicks::Now();
197 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
199 // TODO(vkuzkokov): do not use previous frame metadata.
200 cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_;
202 float page_scale = metadata.page_scale_factor;
203 gfx::SizeF viewport_size_dip = gfx::ScaleSize(
204 metadata.scrollable_viewport_size, page_scale);
206 float total_bar_height_dip = metadata.location_bar_content_translation.y() +
207 metadata.overdraw_bottom_height;
208 gfx::SizeF screen_size_dip(viewport_size_dip.width(),
209 viewport_size_dip.height() + total_bar_height_dip);
212 int quality = kDefaultScreenshotQuality;
214 double max_width = -1;
215 double max_height = -1;
216 base::DictionaryValue* params = screencast_command_->params();
218 params->GetString(devtools::Page::startScreencast::kParamFormat,
220 params->GetInteger(devtools::Page::startScreencast::kParamQuality,
222 params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth,
224 params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight,
228 blink::WebScreenInfo screen_info;
229 view->GetScreenInfo(&screen_info);
230 double device_scale_factor = screen_info.deviceScaleFactor;
233 double max_width_dip = max_width / device_scale_factor;
234 scale = std::min(scale, max_width_dip / screen_size_dip.width());
236 if (max_height > 0) {
237 double max_height_dip = max_height / device_scale_factor;
238 scale = std::min(scale, max_height_dip / screen_size_dip.height());
243 if (quality < 0 || quality > 100)
244 quality = kDefaultScreenshotQuality;
248 gfx::Size snapshot_size_dip(gfx::ToRoundedSize(
249 gfx::ScaleSize(viewport_size_dip, scale)));
251 if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) {
252 gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip));
253 view->CopyFromCompositingSurface(
254 viewport_bounds_dip, snapshot_size_dip,
255 base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured,
256 weak_factory_.GetWeakPtr(),
257 format, quality, last_compositor_frame_metadata_),
262 // DOM agent handlers --------------------------------------------------------
264 scoped_refptr<DevToolsProtocol::Response>
265 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
266 scoped_refptr<DevToolsProtocol::Command> command) {
267 base::DictionaryValue* params = command->params();
268 base::ListValue* file_list = NULL;
270 devtools::DOM::setFileInputFiles::kParamFiles;
271 if (!params || !params->GetList(param, &file_list))
272 return command->InvalidParamResponse(param);
273 RenderViewHost* host = GetRenderViewHostImpl();
277 for (size_t i = 0; i < file_list->GetSize(); ++i) {
278 base::FilePath::StringType file;
279 if (!file_list->GetString(i, &file))
280 return command->InvalidParamResponse(param);
281 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
282 host->GetProcess()->GetID(), base::FilePath(file));
288 // Network agent handlers ----------------------------------------------------
290 scoped_refptr<DevToolsProtocol::Response>
291 RendererOverridesHandler::ClearBrowserCache(
292 scoped_refptr<DevToolsProtocol::Command> command) {
293 GetContentClient()->browser()->ClearCache(GetRenderViewHostImpl());
294 return command->SuccessResponse(NULL);
297 scoped_refptr<DevToolsProtocol::Response>
298 RendererOverridesHandler::ClearBrowserCookies(
299 scoped_refptr<DevToolsProtocol::Command> command) {
300 GetContentClient()->browser()->ClearCookies(GetRenderViewHostImpl());
301 return command->SuccessResponse(NULL);
305 // Page agent handlers -------------------------------------------------------
307 scoped_refptr<DevToolsProtocol::Response>
308 RendererOverridesHandler::PageDisable(
309 scoped_refptr<DevToolsProtocol::Command> command) {
310 RenderViewHostImpl* host = GetRenderViewHostImpl();
311 if (screencast_command_ && host)
312 host->SetTouchEventEmulationEnabled(false, false);
313 screencast_command_ = NULL;
317 scoped_refptr<DevToolsProtocol::Response>
318 RendererOverridesHandler::PageHandleJavaScriptDialog(
319 scoped_refptr<DevToolsProtocol::Command> command) {
320 base::DictionaryValue* params = command->params();
321 const char* paramAccept =
322 devtools::Page::handleJavaScriptDialog::kParamAccept;
324 if (!params || !params->GetBoolean(paramAccept, &accept))
325 return command->InvalidParamResponse(paramAccept);
326 base::string16 prompt_override;
327 base::string16* prompt_override_ptr = &prompt_override;
328 if (!params || !params->GetString(
329 devtools::Page::handleJavaScriptDialog::kParamPromptText,
330 prompt_override_ptr)) {
331 prompt_override_ptr = NULL;
334 WebContents* web_contents = agent_->GetWebContents();
336 JavaScriptDialogManager* manager =
337 web_contents->GetDelegate()->GetJavaScriptDialogManager();
338 if (manager && manager->HandleJavaScriptDialog(
339 web_contents, accept, prompt_override_ptr)) {
340 return command->SuccessResponse(new base::DictionaryValue());
343 return command->InternalErrorResponse("No JavaScript dialog to handle");
346 scoped_refptr<DevToolsProtocol::Response>
347 RendererOverridesHandler::PageNavigate(
348 scoped_refptr<DevToolsProtocol::Command> command) {
349 base::DictionaryValue* params = command->params();
351 const char* param = devtools::Page::navigate::kParamUrl;
352 if (!params || !params->GetString(param, &url))
353 return command->InvalidParamResponse(param);
356 if (!gurl.is_valid())
357 return command->InternalErrorResponse("Cannot navigate to invalid URL");
359 WebContents* web_contents = agent_->GetWebContents();
361 web_contents->GetController()
362 .LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
363 // Fall through into the renderer.
367 return command->InternalErrorResponse("No WebContents to navigate");
370 scoped_refptr<DevToolsProtocol::Response>
371 RendererOverridesHandler::PageReload(
372 scoped_refptr<DevToolsProtocol::Command> command) {
373 WebContents* web_contents = agent_->GetWebContents();
375 // Override only if it is crashed.
376 if (!web_contents->IsCrashed())
379 web_contents->GetController().Reload(false);
380 return command->SuccessResponse(NULL);
382 return command->InternalErrorResponse("No WebContents to reload");
385 scoped_refptr<DevToolsProtocol::Response>
386 RendererOverridesHandler::PageGetNavigationHistory(
387 scoped_refptr<DevToolsProtocol::Command> command) {
388 WebContents* web_contents = agent_->GetWebContents();
390 base::DictionaryValue* result = new base::DictionaryValue();
391 NavigationController& controller = web_contents->GetController();
393 devtools::Page::getNavigationHistory::kResponseCurrentIndex,
394 controller.GetCurrentEntryIndex());
395 base::ListValue* entries = new base::ListValue();
396 for (int i = 0; i != controller.GetEntryCount(); ++i) {
397 const NavigationEntry* entry = controller.GetEntryAtIndex(i);
398 base::DictionaryValue* entry_value = new base::DictionaryValue();
399 entry_value->SetInteger(
400 devtools::Page::NavigationEntry::kParamId,
401 entry->GetUniqueID());
402 entry_value->SetString(
403 devtools::Page::NavigationEntry::kParamUrl,
404 entry->GetURL().spec());
405 entry_value->SetString(
406 devtools::Page::NavigationEntry::kParamTitle,
408 entries->Append(entry_value);
411 devtools::Page::getNavigationHistory::kResponseEntries,
413 return command->SuccessResponse(result);
415 return command->InternalErrorResponse("No WebContents to navigate");
418 scoped_refptr<DevToolsProtocol::Response>
419 RendererOverridesHandler::PageNavigateToHistoryEntry(
420 scoped_refptr<DevToolsProtocol::Command> command) {
421 base::DictionaryValue* params = command->params();
422 const char* param = devtools::Page::navigateToHistoryEntry::kParamEntryId;
424 if (!params || !params->GetInteger(param, &entry_id)) {
425 return command->InvalidParamResponse(param);
428 WebContents* web_contents = agent_->GetWebContents();
430 NavigationController& controller = web_contents->GetController();
431 for (int i = 0; i != controller.GetEntryCount(); ++i) {
432 if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
433 controller.GoToIndex(i);
434 return command->SuccessResponse(new base::DictionaryValue());
437 return command->InvalidParamResponse(param);
439 return command->InternalErrorResponse("No WebContents to navigate");
442 scoped_refptr<DevToolsProtocol::Response>
443 RendererOverridesHandler::PageCaptureScreenshot(
444 scoped_refptr<DevToolsProtocol::Command> command) {
445 RenderViewHostImpl* host = GetRenderViewHostImpl();
446 if (!host->GetView())
447 return command->InternalErrorResponse("Unable to access the view");
449 host->GetSnapshotFromBrowser(
450 base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
451 weak_factory_.GetWeakPtr(), command));
452 return command->AsyncResponsePromise();
455 void RendererOverridesHandler::ScreenshotCaptured(
456 scoped_refptr<DevToolsProtocol::Command> command,
457 const unsigned char* png_data,
459 if (!png_data || !png_size) {
461 command->InternalErrorResponse("Unable to capture screenshot"));
465 std::string base_64_data;
467 base::StringPiece(reinterpret_cast<const char*>(png_data), png_size),
470 base::DictionaryValue* response = new base::DictionaryValue();
471 response->SetString(devtools::Page::screencastFrame::kParamData,
474 SendAsyncResponse(command->SuccessResponse(response));
477 scoped_refptr<DevToolsProtocol::Response>
478 RendererOverridesHandler::PageCanScreencast(
479 scoped_refptr<DevToolsProtocol::Command> command) {
480 base::DictionaryValue* result = new base::DictionaryValue();
481 #if defined(OS_ANDROID)
482 result->SetBoolean(devtools::kResult, true);
484 result->SetBoolean(devtools::kResult, false);
485 #endif // defined(OS_ANDROID)
486 return command->SuccessResponse(result);
489 scoped_refptr<DevToolsProtocol::Response>
490 RendererOverridesHandler::PageStartScreencast(
491 scoped_refptr<DevToolsProtocol::Command> command) {
492 screencast_command_ = command;
493 RenderViewHostImpl* host = GetRenderViewHostImpl();
494 host->SetTouchEventEmulationEnabled(true, true);
495 bool visible = !host->is_hidden();
496 NotifyScreencastVisibility(visible);
498 if (has_last_compositor_frame_metadata_)
499 InnerSwapCompositorFrame();
501 host->Send(new ViewMsg_ForceRedraw(host->GetRoutingID(), 0));
503 return command->SuccessResponse(NULL);
506 scoped_refptr<DevToolsProtocol::Response>
507 RendererOverridesHandler::PageStopScreencast(
508 scoped_refptr<DevToolsProtocol::Command> command) {
509 last_frame_time_ = base::TimeTicks();
510 screencast_command_ = NULL;
511 RenderViewHostImpl* host = GetRenderViewHostImpl();
513 host->SetTouchEventEmulationEnabled(false, false);
514 return command->SuccessResponse(NULL);
517 void RendererOverridesHandler::ScreencastFrameCaptured(
518 const std::string& format,
520 const cc::CompositorFrameMetadata& metadata,
522 const SkBitmap& bitmap) {
524 if (capture_retry_count_) {
525 --capture_retry_count_;
526 base::MessageLoop::current()->PostDelayedTask(
528 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame,
529 weak_factory_.GetWeakPtr()),
530 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
535 std::vector<unsigned char> data;
536 SkAutoLockPixels lock_image(bitmap);
538 if (format == kPng) {
539 encoded = gfx::PNGCodec::Encode(
540 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
541 gfx::PNGCodec::FORMAT_SkBitmap,
542 gfx::Size(bitmap.width(), bitmap.height()),
543 bitmap.width() * bitmap.bytesPerPixel(),
544 false, std::vector<gfx::PNGCodec::Comment>(), &data);
545 } else if (format == kJpeg) {
546 encoded = gfx::JPEGCodec::Encode(
547 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
548 gfx::JPEGCodec::FORMAT_SkBitmap,
551 bitmap.width() * bitmap.bytesPerPixel(),
560 std::string base_64_data;
562 base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
565 base::DictionaryValue* response = new base::DictionaryValue();
566 response->SetString(devtools::Page::screencastFrame::kParamData,
569 // Consider metadata empty in case it has no device scale factor.
570 if (metadata.device_scale_factor != 0) {
571 base::DictionaryValue* response_metadata = new base::DictionaryValue();
573 response_metadata->SetDouble(
574 devtools::Page::ScreencastFrameMetadata::kParamDeviceScaleFactor,
575 metadata.device_scale_factor);
576 response_metadata->SetDouble(
577 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactor,
578 metadata.page_scale_factor);
579 response_metadata->SetDouble(
580 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMin,
581 metadata.min_page_scale_factor);
582 response_metadata->SetDouble(
583 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMax,
584 metadata.max_page_scale_factor);
585 response_metadata->SetDouble(
586 devtools::Page::ScreencastFrameMetadata::kParamOffsetTop,
587 metadata.location_bar_content_translation.y());
588 response_metadata->SetDouble(
589 devtools::Page::ScreencastFrameMetadata::kParamOffsetBottom,
590 metadata.overdraw_bottom_height);
592 base::DictionaryValue* viewport = new base::DictionaryValue();
593 viewport->SetDouble(devtools::DOM::Rect::kParamX,
594 metadata.root_scroll_offset.x());
595 viewport->SetDouble(devtools::DOM::Rect::kParamY,
596 metadata.root_scroll_offset.y());
597 viewport->SetDouble(devtools::DOM::Rect::kParamWidth,
598 metadata.scrollable_viewport_size.width());
599 viewport->SetDouble(devtools::DOM::Rect::kParamHeight,
600 metadata.scrollable_viewport_size.height());
601 response_metadata->Set(
602 devtools::Page::ScreencastFrameMetadata::kParamViewport, viewport);
604 gfx::SizeF viewport_size_dip = gfx::ScaleSize(
605 metadata.scrollable_viewport_size, metadata.page_scale_factor);
606 response_metadata->SetDouble(
607 devtools::Page::ScreencastFrameMetadata::kParamDeviceWidth,
608 viewport_size_dip.width());
609 response_metadata->SetDouble(
610 devtools::Page::ScreencastFrameMetadata::kParamDeviceHeight,
611 viewport_size_dip.height() +
612 metadata.location_bar_content_translation.y() +
613 metadata.overdraw_bottom_height);
614 response_metadata->SetDouble(
615 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetX,
616 metadata.root_scroll_offset.x());
617 response_metadata->SetDouble(
618 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetY,
619 metadata.root_scroll_offset.y());
621 response->Set(devtools::Page::screencastFrame::kParamMetadata,
625 SendNotification(devtools::Page::screencastFrame::kName, response);
628 // Quota and Usage ------------------------------------------
632 typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)>
635 void QueryUsageAndQuotaCompletedOnIOThread(
636 scoped_ptr<base::DictionaryValue> quota,
637 scoped_ptr<base::DictionaryValue> usage,
638 ResponseCallback callback) {
640 scoped_ptr<base::DictionaryValue> response_data(new base::DictionaryValue);
641 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseQuota,
643 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage,
646 BrowserThread::PostTask(
647 BrowserThread::UI, FROM_HERE,
648 base::Bind(callback, base::Passed(&response_data)));
651 void DidGetHostUsage(
652 base::ListValue* list,
653 const std::string& client_id,
654 const base::Closure& barrier,
656 base::DictionaryValue* usage_item = new base::DictionaryValue;
657 usage_item->SetString(devtools::Page::UsageItem::kParamId, client_id);
658 usage_item->SetDouble(devtools::Page::UsageItem::kParamValue, value);
659 list->Append(usage_item);
663 void DidGetQuotaValue(
664 base::DictionaryValue* dictionary,
665 const std::string& item_name,
666 const base::Closure& barrier,
667 quota::QuotaStatusCode status,
669 if (status == quota::kQuotaStatusOk)
670 dictionary->SetDouble(item_name, value);
674 void DidGetUsageAndQuotaForWebApps(
675 base::DictionaryValue* quota,
676 const std::string& item_name,
677 const base::Closure& barrier,
678 quota::QuotaStatusCode status,
680 int64 quota_in_bytes) {
681 if (status == quota::kQuotaStatusOk)
682 quota->SetDouble(item_name, quota_in_bytes);
686 std::string GetStorageTypeName(quota::StorageType type) {
688 case quota::kStorageTypeTemporary:
689 return devtools::Page::Usage::kParamTemporary;
690 case quota::kStorageTypePersistent:
691 return devtools::Page::Usage::kParamPersistent;
692 case quota::kStorageTypeSyncable:
693 return devtools::Page::Usage::kParamSyncable;
694 case quota::kStorageTypeQuotaNotManaged:
695 case quota::kStorageTypeUnknown:
701 std::string GetQuotaClientName(quota::QuotaClient::ID id) {
703 case quota::QuotaClient::kFileSystem:
704 return devtools::Page::UsageItem::Id::kEnumFilesystem;
705 case quota::QuotaClient::kDatabase:
706 return devtools::Page::UsageItem::Id::kEnumDatabase;
707 case quota::QuotaClient::kAppcache:
708 return devtools::Page::UsageItem::Id::kEnumAppcache;
709 case quota::QuotaClient::kIndexedDatabase:
710 return devtools::Page::UsageItem::Id::kEnumIndexeddatabase;
717 void QueryUsageAndQuotaOnIOThread(
718 scoped_refptr<quota::QuotaManager> quota_manager,
719 const GURL& security_origin,
720 const ResponseCallback& callback) {
721 scoped_ptr<base::DictionaryValue> quota(new base::DictionaryValue);
722 scoped_ptr<base::DictionaryValue> usage(new base::DictionaryValue);
724 static quota::QuotaClient::ID kQuotaClients[] = {
725 quota::QuotaClient::kFileSystem,
726 quota::QuotaClient::kDatabase,
727 quota::QuotaClient::kAppcache,
728 quota::QuotaClient::kIndexedDatabase
731 static const size_t kStorageTypeCount = quota::kStorageTypeUnknown;
732 std::map<quota::StorageType, base::ListValue*> storage_type_lists;
734 for (size_t i = 0; i != kStorageTypeCount; i++) {
735 const quota::StorageType type = static_cast<quota::StorageType>(i);
736 if (type == quota::kStorageTypeQuotaNotManaged)
738 storage_type_lists[type] = new base::ListValue;
739 usage->Set(GetStorageTypeName(type), storage_type_lists[type]);
742 const int kExpectedResults =
743 2 + arraysize(kQuotaClients) * storage_type_lists.size();
744 base::DictionaryValue* quota_raw_ptr = quota.get();
746 // Takes ownership on usage and quota.
747 base::Closure barrier = BarrierClosure(
749 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
750 base::Passed("a),
751 base::Passed(&usage),
753 std::string host = net::GetHostOrSpecFromURL(security_origin);
755 quota_manager->GetUsageAndQuotaForWebApps(
757 quota::kStorageTypeTemporary,
758 base::Bind(&DidGetUsageAndQuotaForWebApps, quota_raw_ptr,
759 std::string(devtools::Page::Quota::kParamTemporary), barrier));
761 quota_manager->GetPersistentHostQuota(
763 base::Bind(&DidGetQuotaValue, quota_raw_ptr,
764 std::string(devtools::Page::Quota::kParamPersistent),
767 for (size_t i = 0; i != arraysize(kQuotaClients); i++) {
768 std::map<quota::StorageType, base::ListValue*>::const_iterator iter;
769 for (iter = storage_type_lists.begin();
770 iter != storage_type_lists.end(); ++iter) {
771 const quota::StorageType type = (*iter).first;
772 if (!quota_manager->IsTrackingHostUsage(type, kQuotaClients[i])) {
776 quota_manager->GetHostUsage(
777 host, type, kQuotaClients[i],
778 base::Bind(&DidGetHostUsage, (*iter).second,
779 GetQuotaClientName(kQuotaClients[i]),
787 scoped_refptr<DevToolsProtocol::Response>
788 RendererOverridesHandler::PageQueryUsageAndQuota(
789 scoped_refptr<DevToolsProtocol::Command> command) {
790 base::DictionaryValue* params = command->params();
791 std::string security_origin;
792 if (!params || !params->GetString(
793 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin,
795 return command->InvalidParamResponse(
796 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin);
799 ResponseCallback callback = base::Bind(
800 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted,
801 weak_factory_.GetWeakPtr(),
804 scoped_refptr<quota::QuotaManager> quota_manager = GetRenderViewHostImpl()
806 ->GetStoragePartition()
809 BrowserThread::PostTask(
810 BrowserThread::IO, FROM_HERE,
812 &QueryUsageAndQuotaOnIOThread,
814 GURL(security_origin),
817 return command->AsyncResponsePromise();
820 void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted(
821 scoped_refptr<DevToolsProtocol::Command> command,
822 scoped_ptr<base::DictionaryValue> response_data) {
823 SendAsyncResponse(command->SuccessResponse(response_data.release()));
826 void RendererOverridesHandler::NotifyScreencastVisibility(bool visible) {
828 capture_retry_count_ = kCaptureRetryLimit;
829 base::DictionaryValue* params = new base::DictionaryValue();
831 devtools::Page::screencastVisibilityChanged::kParamVisible, visible);
833 devtools::Page::screencastVisibilityChanged::kName, params);
836 // Input agent handlers ------------------------------------------------------
838 scoped_refptr<DevToolsProtocol::Response>
839 RendererOverridesHandler::InputEmulateTouchFromMouseEvent(
840 scoped_refptr<DevToolsProtocol::Command> command) {
841 if (!screencast_command_)
842 return command->InternalErrorResponse("Screencast should be turned on");
844 base::DictionaryValue* params = command->params();
846 return command->NoSuchMethodErrorResponse();
849 if (!params->GetString(
850 devtools::Input::emulateTouchFromMouseEvent::kParamType,
852 return command->InvalidParamResponse(
853 devtools::Input::emulateTouchFromMouseEvent::kParamType);
856 blink::WebMouseWheelEvent wheel_event;
857 blink::WebMouseEvent mouse_event;
858 blink::WebMouseEvent* event = &mouse_event;
861 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMousePressed) {
862 event->type = WebInputEvent::MouseDown;
864 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseReleased) {
865 event->type = WebInputEvent::MouseUp;
867 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseMoved) {
868 event->type = WebInputEvent::MouseMove;
870 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseWheel) {
873 if (!params->GetDouble(
874 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX,
876 return command->InvalidParamResponse(
877 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX);
879 if (!params->GetDouble(
880 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY,
882 return command->InvalidParamResponse(
883 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY);
885 wheel_event.deltaX = static_cast<float>(deltaX);
886 wheel_event.deltaY = static_cast<float>(deltaY);
887 event = &wheel_event;
888 event->type = WebInputEvent::MouseWheel;
890 return command->InvalidParamResponse(
891 devtools::Input::emulateTouchFromMouseEvent::kParamType);
895 if (params->GetInteger(
896 devtools::Input::emulateTouchFromMouseEvent::kParamModifiers,
899 event->modifiers |= WebInputEvent::AltKey;
901 event->modifiers |= WebInputEvent::ControlKey;
903 event->modifiers |= WebInputEvent::MetaKey;
905 event->modifiers |= WebInputEvent::ShiftKey;
909 devtools::Input::emulateTouchFromMouseEvent::kParamTimestamp,
910 &event->timeStampSeconds);
912 if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamX,
914 return command->InvalidParamResponse(
915 devtools::Input::emulateTouchFromMouseEvent::kParamX);
918 if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamY,
920 return command->InvalidParamResponse(
921 devtools::Input::emulateTouchFromMouseEvent::kParamY);
924 event->windowX = event->x;
925 event->windowY = event->y;
926 event->globalX = event->x;
927 event->globalY = event->y;
930 devtools::Input::emulateTouchFromMouseEvent::kParamClickCount,
934 if (!params->GetString(
935 devtools::Input::emulateTouchFromMouseEvent::kParamButton,
937 return command->InvalidParamResponse(
938 devtools::Input::emulateTouchFromMouseEvent::kParamButton);
941 if (button == "none") {
942 event->button = WebMouseEvent::ButtonNone;
943 } else if (button == "left") {
944 event->button = WebMouseEvent::ButtonLeft;
945 event->modifiers |= WebInputEvent::LeftButtonDown;
946 } else if (button == "middle") {
947 event->button = WebMouseEvent::ButtonMiddle;
948 event->modifiers |= WebInputEvent::MiddleButtonDown;
949 } else if (button == "right") {
950 event->button = WebMouseEvent::ButtonRight;
951 event->modifiers |= WebInputEvent::RightButtonDown;
953 return command->InvalidParamResponse(
954 devtools::Input::emulateTouchFromMouseEvent::kParamButton);
957 RenderViewHost* host = GetRenderViewHostImpl();
958 if (event->type == WebInputEvent::MouseWheel)
959 host->ForwardWheelEvent(wheel_event);
961 host->ForwardMouseEvent(mouse_event);
962 return command->SuccessResponse(NULL);
965 RenderViewHostImpl* RendererOverridesHandler::GetRenderViewHostImpl() {
966 return static_cast<RenderViewHostImpl*>(
967 agent_->GetWebContents()->GetRenderViewHost());
970 } // namespace content