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;
68 void ParseGenericInputParams(base::DictionaryValue
* params
,
69 WebInputEvent
* event
) {
71 if (params
->GetInteger(devtools::Input::dispatchMouseEvent::kParamModifiers
,
74 event
->modifiers
|= WebInputEvent::AltKey
;
76 event
->modifiers
|= WebInputEvent::ControlKey
;
78 event
->modifiers
|= WebInputEvent::MetaKey
;
80 event
->modifiers
|= WebInputEvent::ShiftKey
;
83 params
->GetDouble(devtools::Input::dispatchMouseEvent::kParamTimestamp
,
84 &event
->timeStampSeconds
);
89 RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost
* agent
)
91 capture_retry_count_(0),
93 RegisterCommandHandler(
94 devtools::DOM::setFileInputFiles::kName
,
96 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles
,
97 base::Unretained(this)));
98 RegisterCommandHandler(
99 devtools::Network::clearBrowserCache::kName
,
101 &RendererOverridesHandler::ClearBrowserCache
,
102 base::Unretained(this)));
103 RegisterCommandHandler(
104 devtools::Network::clearBrowserCookies::kName
,
106 &RendererOverridesHandler::ClearBrowserCookies
,
107 base::Unretained(this)));
108 RegisterCommandHandler(
109 devtools::Page::disable::kName
,
111 &RendererOverridesHandler::PageDisable
, base::Unretained(this)));
112 RegisterCommandHandler(
113 devtools::Page::handleJavaScriptDialog::kName
,
115 &RendererOverridesHandler::PageHandleJavaScriptDialog
,
116 base::Unretained(this)));
117 RegisterCommandHandler(
118 devtools::Page::navigate::kName
,
120 &RendererOverridesHandler::PageNavigate
,
121 base::Unretained(this)));
122 RegisterCommandHandler(
123 devtools::Page::reload::kName
,
125 &RendererOverridesHandler::PageReload
,
126 base::Unretained(this)));
127 RegisterCommandHandler(
128 devtools::Page::getNavigationHistory::kName
,
130 &RendererOverridesHandler::PageGetNavigationHistory
,
131 base::Unretained(this)));
132 RegisterCommandHandler(
133 devtools::Page::navigateToHistoryEntry::kName
,
135 &RendererOverridesHandler::PageNavigateToHistoryEntry
,
136 base::Unretained(this)));
137 RegisterCommandHandler(
138 devtools::Page::captureScreenshot::kName
,
140 &RendererOverridesHandler::PageCaptureScreenshot
,
141 base::Unretained(this)));
142 RegisterCommandHandler(
143 devtools::Page::canScreencast::kName
,
145 &RendererOverridesHandler::PageCanScreencast
,
146 base::Unretained(this)));
147 RegisterCommandHandler(
148 devtools::Page::startScreencast::kName
,
150 &RendererOverridesHandler::PageStartScreencast
,
151 base::Unretained(this)));
152 RegisterCommandHandler(
153 devtools::Page::stopScreencast::kName
,
155 &RendererOverridesHandler::PageStopScreencast
,
156 base::Unretained(this)));
157 RegisterCommandHandler(
158 devtools::Page::queryUsageAndQuota::kName
,
160 &RendererOverridesHandler::PageQueryUsageAndQuota
,
161 base::Unretained(this)));
162 RegisterCommandHandler(
163 devtools::Input::dispatchMouseEvent::kName
,
165 &RendererOverridesHandler::InputDispatchMouseEvent
,
166 base::Unretained(this)));
167 RegisterCommandHandler(
168 devtools::Input::dispatchGestureEvent::kName
,
170 &RendererOverridesHandler::InputDispatchGestureEvent
,
171 base::Unretained(this)));
174 RendererOverridesHandler::~RendererOverridesHandler() {}
176 void RendererOverridesHandler::OnClientDetached() {
177 screencast_command_
= NULL
;
180 void RendererOverridesHandler::OnSwapCompositorFrame(
181 const cc::CompositorFrameMetadata
& frame_metadata
) {
182 last_compositor_frame_metadata_
= frame_metadata
;
184 if (screencast_command_
)
185 InnerSwapCompositorFrame();
188 void RendererOverridesHandler::OnVisibilityChanged(bool visible
) {
189 if (!screencast_command_
)
191 NotifyScreencastVisibility(visible
);
194 void RendererOverridesHandler::InnerSwapCompositorFrame() {
195 if ((base::TimeTicks::Now() - last_frame_time_
).InMilliseconds() <
196 kFrameRateThresholdMs
) {
200 RenderViewHost
* host
= agent_
->GetRenderViewHost();
201 if (!host
->GetView())
204 last_frame_time_
= base::TimeTicks::Now();
206 RenderWidgetHostViewBase
* view
= static_cast<RenderWidgetHostViewBase
*>(
208 // TODO(vkuzkokov): do not use previous frame metadata.
209 cc::CompositorFrameMetadata
& metadata
= last_compositor_frame_metadata_
;
211 float page_scale
= metadata
.page_scale_factor
;
212 gfx::SizeF viewport_size_dip
= gfx::ScaleSize(
213 metadata
.scrollable_viewport_size
, page_scale
);
215 float total_bar_height_dip
= metadata
.location_bar_content_translation
.y() +
216 metadata
.overdraw_bottom_height
;
217 gfx::SizeF
screen_size_dip(viewport_size_dip
.width(),
218 viewport_size_dip
.height() + total_bar_height_dip
);
221 int quality
= kDefaultScreenshotQuality
;
223 double max_width
= -1;
224 double max_height
= -1;
225 base::DictionaryValue
* params
= screencast_command_
->params();
227 params
->GetString(devtools::Page::startScreencast::kParamFormat
,
229 params
->GetInteger(devtools::Page::startScreencast::kParamQuality
,
231 params
->GetDouble(devtools::Page::startScreencast::kParamMaxWidth
,
233 params
->GetDouble(devtools::Page::startScreencast::kParamMaxHeight
,
237 blink::WebScreenInfo screen_info
;
238 view
->GetScreenInfo(&screen_info
);
239 double device_scale_factor
= screen_info
.deviceScaleFactor
;
242 double max_width_dip
= max_width
/ device_scale_factor
;
243 scale
= std::min(scale
, max_width_dip
/ screen_size_dip
.width());
245 if (max_height
> 0) {
246 double max_height_dip
= max_height
/ device_scale_factor
;
247 scale
= std::min(scale
, max_height_dip
/ screen_size_dip
.height());
252 if (quality
< 0 || quality
> 100)
253 quality
= kDefaultScreenshotQuality
;
257 gfx::Size
snapshot_size_dip(gfx::ToRoundedSize(
258 gfx::ScaleSize(viewport_size_dip
, scale
)));
260 if (snapshot_size_dip
.width() > 0 && snapshot_size_dip
.height() > 0) {
261 gfx::Rect
viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip
));
262 view
->CopyFromCompositingSurface(
263 viewport_bounds_dip
, snapshot_size_dip
,
264 base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured
,
265 weak_factory_
.GetWeakPtr(),
266 format
, quality
, last_compositor_frame_metadata_
),
271 // DOM agent handlers --------------------------------------------------------
273 scoped_refptr
<DevToolsProtocol::Response
>
274 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
275 scoped_refptr
<DevToolsProtocol::Command
> command
) {
276 base::DictionaryValue
* params
= command
->params();
277 base::ListValue
* file_list
= NULL
;
279 devtools::DOM::setFileInputFiles::kParamFiles
;
280 if (!params
|| !params
->GetList(param
, &file_list
))
281 return command
->InvalidParamResponse(param
);
282 RenderViewHost
* host
= agent_
->GetRenderViewHost();
286 for (size_t i
= 0; i
< file_list
->GetSize(); ++i
) {
287 base::FilePath::StringType file
;
288 if (!file_list
->GetString(i
, &file
))
289 return command
->InvalidParamResponse(param
);
290 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
291 host
->GetProcess()->GetID(), base::FilePath(file
));
297 // Network agent handlers ----------------------------------------------------
299 scoped_refptr
<DevToolsProtocol::Response
>
300 RendererOverridesHandler::ClearBrowserCache(
301 scoped_refptr
<DevToolsProtocol::Command
> command
) {
302 GetContentClient()->browser()->ClearCache(agent_
->GetRenderViewHost());
303 return command
->SuccessResponse(NULL
);
306 scoped_refptr
<DevToolsProtocol::Response
>
307 RendererOverridesHandler::ClearBrowserCookies(
308 scoped_refptr
<DevToolsProtocol::Command
> command
) {
309 GetContentClient()->browser()->ClearCookies(agent_
->GetRenderViewHost());
310 return command
->SuccessResponse(NULL
);
314 // Page agent handlers -------------------------------------------------------
316 scoped_refptr
<DevToolsProtocol::Response
>
317 RendererOverridesHandler::PageDisable(
318 scoped_refptr
<DevToolsProtocol::Command
> command
) {
319 screencast_command_
= NULL
;
323 scoped_refptr
<DevToolsProtocol::Response
>
324 RendererOverridesHandler::PageHandleJavaScriptDialog(
325 scoped_refptr
<DevToolsProtocol::Command
> command
) {
326 base::DictionaryValue
* params
= command
->params();
327 const char* paramAccept
=
328 devtools::Page::handleJavaScriptDialog::kParamAccept
;
330 if (!params
|| !params
->GetBoolean(paramAccept
, &accept
))
331 return command
->InvalidParamResponse(paramAccept
);
332 base::string16 prompt_override
;
333 base::string16
* prompt_override_ptr
= &prompt_override
;
334 if (!params
|| !params
->GetString(
335 devtools::Page::handleJavaScriptDialog::kParamPromptText
,
336 prompt_override_ptr
)) {
337 prompt_override_ptr
= NULL
;
340 RenderViewHost
* host
= agent_
->GetRenderViewHost();
342 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
344 JavaScriptDialogManager
* manager
=
345 web_contents
->GetDelegate()->GetJavaScriptDialogManager();
346 if (manager
&& manager
->HandleJavaScriptDialog(
347 web_contents
, accept
, prompt_override_ptr
)) {
348 return command
->SuccessResponse(new base::DictionaryValue());
352 return command
->InternalErrorResponse("No JavaScript dialog to handle");
355 scoped_refptr
<DevToolsProtocol::Response
>
356 RendererOverridesHandler::PageNavigate(
357 scoped_refptr
<DevToolsProtocol::Command
> command
) {
358 base::DictionaryValue
* params
= command
->params();
360 const char* param
= devtools::Page::navigate::kParamUrl
;
361 if (!params
|| !params
->GetString(param
, &url
))
362 return command
->InvalidParamResponse(param
);
364 if (!gurl
.is_valid()) {
365 return command
->InternalErrorResponse("Cannot navigate to invalid URL");
367 RenderViewHost
* host
= agent_
->GetRenderViewHost();
369 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
371 web_contents
->GetController()
372 .LoadURL(gurl
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
373 // Fall through into the renderer.
377 return command
->InternalErrorResponse("No WebContents to navigate");
380 scoped_refptr
<DevToolsProtocol::Response
>
381 RendererOverridesHandler::PageReload(
382 scoped_refptr
<DevToolsProtocol::Command
> command
) {
383 RenderViewHost
* host
= agent_
->GetRenderViewHost();
385 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
387 // Override only if it is crashed.
388 if (!web_contents
->IsCrashed())
391 web_contents
->GetController().Reload(false);
392 return command
->SuccessResponse(NULL
);
395 return command
->InternalErrorResponse("No WebContents to reload");
398 scoped_refptr
<DevToolsProtocol::Response
>
399 RendererOverridesHandler::PageGetNavigationHistory(
400 scoped_refptr
<DevToolsProtocol::Command
> command
) {
401 RenderViewHost
* host
= agent_
->GetRenderViewHost();
403 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
405 base::DictionaryValue
* result
= new base::DictionaryValue();
406 NavigationController
& controller
= web_contents
->GetController();
408 devtools::Page::getNavigationHistory::kResponseCurrentIndex
,
409 controller
.GetCurrentEntryIndex());
410 base::ListValue
* entries
= new base::ListValue();
411 for (int i
= 0; i
!= controller
.GetEntryCount(); ++i
) {
412 const NavigationEntry
* entry
= controller
.GetEntryAtIndex(i
);
413 base::DictionaryValue
* entry_value
= new base::DictionaryValue();
414 entry_value
->SetInteger(
415 devtools::Page::NavigationEntry::kParamId
,
416 entry
->GetUniqueID());
417 entry_value
->SetString(
418 devtools::Page::NavigationEntry::kParamUrl
,
419 entry
->GetURL().spec());
420 entry_value
->SetString(
421 devtools::Page::NavigationEntry::kParamTitle
,
423 entries
->Append(entry_value
);
426 devtools::Page::getNavigationHistory::kResponseEntries
,
428 return command
->SuccessResponse(result
);
431 return command
->InternalErrorResponse("No WebContents to navigate");
434 scoped_refptr
<DevToolsProtocol::Response
>
435 RendererOverridesHandler::PageNavigateToHistoryEntry(
436 scoped_refptr
<DevToolsProtocol::Command
> command
) {
437 base::DictionaryValue
* params
= command
->params();
438 const char* param
= devtools::Page::navigateToHistoryEntry::kParamEntryId
;
440 if (!params
|| !params
->GetInteger(param
, &entry_id
)) {
441 return command
->InvalidParamResponse(param
);
444 RenderViewHost
* host
= agent_
->GetRenderViewHost();
446 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
448 NavigationController
& controller
= web_contents
->GetController();
449 for (int i
= 0; i
!= controller
.GetEntryCount(); ++i
) {
450 if (controller
.GetEntryAtIndex(i
)->GetUniqueID() == entry_id
) {
451 controller
.GoToIndex(i
);
452 return command
->SuccessResponse(new base::DictionaryValue());
455 return command
->InvalidParamResponse(param
);
458 return command
->InternalErrorResponse("No WebContents to navigate");
461 scoped_refptr
<DevToolsProtocol::Response
>
462 RendererOverridesHandler::PageCaptureScreenshot(
463 scoped_refptr
<DevToolsProtocol::Command
> command
) {
464 RenderViewHostImpl
* host
= static_cast<RenderViewHostImpl
*>(
465 agent_
->GetRenderViewHost());
466 if (!host
->GetView())
467 return command
->InternalErrorResponse("Unable to access the view");
469 host
->GetSnapshotFromBrowser(
470 base::Bind(&RendererOverridesHandler::ScreenshotCaptured
,
471 weak_factory_
.GetWeakPtr(), command
));
472 return command
->AsyncResponsePromise();
475 void RendererOverridesHandler::ScreenshotCaptured(
476 scoped_refptr
<DevToolsProtocol::Command
> command
,
477 const unsigned char* png_data
,
479 if (!png_data
|| !png_size
) {
481 command
->InternalErrorResponse("Unable to capture screenshot"));
485 std::string base_64_data
;
487 base::StringPiece(reinterpret_cast<const char*>(png_data
), png_size
),
490 base::DictionaryValue
* response
= new base::DictionaryValue();
491 response
->SetString(devtools::Page::screencastFrame::kParamData
,
494 SendAsyncResponse(command
->SuccessResponse(response
));
497 scoped_refptr
<DevToolsProtocol::Response
>
498 RendererOverridesHandler::PageCanScreencast(
499 scoped_refptr
<DevToolsProtocol::Command
> command
) {
500 base::DictionaryValue
* result
= new base::DictionaryValue();
501 #if defined(OS_ANDROID)
502 result
->SetBoolean(devtools::kResult
, true);
504 result
->SetBoolean(devtools::kResult
, false);
505 #endif // defined(OS_ANDROID)
506 return command
->SuccessResponse(result
);
509 scoped_refptr
<DevToolsProtocol::Response
>
510 RendererOverridesHandler::PageStartScreencast(
511 scoped_refptr
<DevToolsProtocol::Command
> command
) {
512 screencast_command_
= command
;
513 RenderViewHostImpl
* host
= static_cast<RenderViewHostImpl
*>(
514 agent_
->GetRenderViewHost());
515 bool visible
= !host
->is_hidden();
516 NotifyScreencastVisibility(visible
);
518 InnerSwapCompositorFrame();
519 return command
->SuccessResponse(NULL
);
522 scoped_refptr
<DevToolsProtocol::Response
>
523 RendererOverridesHandler::PageStopScreencast(
524 scoped_refptr
<DevToolsProtocol::Command
> command
) {
525 last_frame_time_
= base::TimeTicks();
526 screencast_command_
= NULL
;
527 return command
->SuccessResponse(NULL
);
530 void RendererOverridesHandler::ScreencastFrameCaptured(
531 const std::string
& format
,
533 const cc::CompositorFrameMetadata
& metadata
,
535 const SkBitmap
& bitmap
) {
537 if (capture_retry_count_
) {
538 --capture_retry_count_
;
539 base::MessageLoop::current()->PostDelayedTask(
541 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame
,
542 weak_factory_
.GetWeakPtr()),
543 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs
));
548 std::vector
<unsigned char> data
;
549 SkAutoLockPixels
lock_image(bitmap
);
551 if (format
== kPng
) {
552 encoded
= gfx::PNGCodec::Encode(
553 reinterpret_cast<unsigned char*>(bitmap
.getAddr32(0, 0)),
554 gfx::PNGCodec::FORMAT_SkBitmap
,
555 gfx::Size(bitmap
.width(), bitmap
.height()),
556 bitmap
.width() * bitmap
.bytesPerPixel(),
557 false, std::vector
<gfx::PNGCodec::Comment
>(), &data
);
558 } else if (format
== kJpeg
) {
559 encoded
= gfx::JPEGCodec::Encode(
560 reinterpret_cast<unsigned char*>(bitmap
.getAddr32(0, 0)),
561 gfx::JPEGCodec::FORMAT_SkBitmap
,
564 bitmap
.width() * bitmap
.bytesPerPixel(),
573 std::string base_64_data
;
575 base::StringPiece(reinterpret_cast<char*>(&data
[0]), data
.size()),
578 base::DictionaryValue
* response
= new base::DictionaryValue();
579 response
->SetString(devtools::Page::screencastFrame::kParamData
,
582 // Consider metadata empty in case it has no device scale factor.
583 if (metadata
.device_scale_factor
!= 0) {
584 base::DictionaryValue
* response_metadata
= new base::DictionaryValue();
586 response_metadata
->SetDouble(
587 devtools::Page::ScreencastFrameMetadata::kParamDeviceScaleFactor
,
588 metadata
.device_scale_factor
);
589 response_metadata
->SetDouble(
590 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactor
,
591 metadata
.page_scale_factor
);
592 response_metadata
->SetDouble(
593 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMin
,
594 metadata
.min_page_scale_factor
);
595 response_metadata
->SetDouble(
596 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMax
,
597 metadata
.max_page_scale_factor
);
598 response_metadata
->SetDouble(
599 devtools::Page::ScreencastFrameMetadata::kParamOffsetTop
,
600 metadata
.location_bar_content_translation
.y());
601 response_metadata
->SetDouble(
602 devtools::Page::ScreencastFrameMetadata::kParamOffsetBottom
,
603 metadata
.overdraw_bottom_height
);
605 base::DictionaryValue
* viewport
= new base::DictionaryValue();
606 viewport
->SetDouble(devtools::DOM::Rect::kParamX
,
607 metadata
.root_scroll_offset
.x());
608 viewport
->SetDouble(devtools::DOM::Rect::kParamY
,
609 metadata
.root_scroll_offset
.y());
610 viewport
->SetDouble(devtools::DOM::Rect::kParamWidth
,
611 metadata
.scrollable_viewport_size
.width());
612 viewport
->SetDouble(devtools::DOM::Rect::kParamHeight
,
613 metadata
.scrollable_viewport_size
.height());
614 response_metadata
->Set(
615 devtools::Page::ScreencastFrameMetadata::kParamViewport
, viewport
);
617 gfx::SizeF viewport_size_dip
= gfx::ScaleSize(
618 metadata
.scrollable_viewport_size
, metadata
.page_scale_factor
);
619 response_metadata
->SetDouble(
620 devtools::Page::ScreencastFrameMetadata::kParamDeviceWidth
,
621 viewport_size_dip
.width());
622 response_metadata
->SetDouble(
623 devtools::Page::ScreencastFrameMetadata::kParamDeviceHeight
,
624 viewport_size_dip
.height() +
625 metadata
.location_bar_content_translation
.y() +
626 metadata
.overdraw_bottom_height
);
627 response_metadata
->SetDouble(
628 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetX
,
629 metadata
.root_scroll_offset
.x());
630 response_metadata
->SetDouble(
631 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetY
,
632 metadata
.root_scroll_offset
.y());
634 response
->Set(devtools::Page::screencastFrame::kParamMetadata
,
638 SendNotification(devtools::Page::screencastFrame::kName
, response
);
641 // Quota and Usage ------------------------------------------
645 typedef base::Callback
<void(scoped_ptr
<base::DictionaryValue
>)>
648 void QueryUsageAndQuotaCompletedOnIOThread(
649 scoped_ptr
<base::DictionaryValue
> quota
,
650 scoped_ptr
<base::DictionaryValue
> usage
,
651 ResponseCallback callback
) {
653 scoped_ptr
<base::DictionaryValue
> response_data(new base::DictionaryValue
);
654 response_data
->Set(devtools::Page::queryUsageAndQuota::kResponseQuota
,
656 response_data
->Set(devtools::Page::queryUsageAndQuota::kResponseUsage
,
659 BrowserThread::PostTask(
660 BrowserThread::UI
, FROM_HERE
,
661 base::Bind(callback
, base::Passed(&response_data
)));
664 void DidGetHostUsage(
665 base::ListValue
* list
,
666 const std::string
& client_id
,
667 const base::Closure
& barrier
,
669 base::DictionaryValue
* usage_item
= new base::DictionaryValue
;
670 usage_item
->SetString(devtools::Page::UsageItem::kParamId
, client_id
);
671 usage_item
->SetDouble(devtools::Page::UsageItem::kParamValue
, value
);
672 list
->Append(usage_item
);
676 void DidGetQuotaValue(
677 base::DictionaryValue
* dictionary
,
678 const std::string
& item_name
,
679 const base::Closure
& barrier
,
680 quota::QuotaStatusCode status
,
682 if (status
== quota::kQuotaStatusOk
)
683 dictionary
->SetDouble(item_name
, value
);
687 void DidGetUsageAndQuotaForWebApps(
688 base::DictionaryValue
* quota
,
689 const std::string
& item_name
,
690 const base::Closure
& barrier
,
691 quota::QuotaStatusCode status
,
693 int64 quota_in_bytes
) {
694 if (status
== quota::kQuotaStatusOk
)
695 quota
->SetDouble(item_name
, quota_in_bytes
);
699 std::string
GetStorageTypeName(quota::StorageType type
) {
701 case quota::kStorageTypeTemporary
:
702 return devtools::Page::Usage::kParamTemporary
;
703 case quota::kStorageTypePersistent
:
704 return devtools::Page::Usage::kParamPersistent
;
705 case quota::kStorageTypeSyncable
:
706 return devtools::Page::Usage::kParamSyncable
;
707 case quota::kStorageTypeQuotaNotManaged
:
708 case quota::kStorageTypeUnknown
:
714 std::string
GetQuotaClientName(quota::QuotaClient::ID id
) {
716 case quota::QuotaClient::kFileSystem
:
717 return devtools::Page::UsageItem::Id::kEnumFilesystem
;
718 case quota::QuotaClient::kDatabase
:
719 return devtools::Page::UsageItem::Id::kEnumDatabase
;
720 case quota::QuotaClient::kAppcache
:
721 return devtools::Page::UsageItem::Id::kEnumAppcache
;
722 case quota::QuotaClient::kIndexedDatabase
:
723 return devtools::Page::UsageItem::Id::kEnumIndexeddatabase
;
730 void QueryUsageAndQuotaOnIOThread(
731 scoped_refptr
<quota::QuotaManager
> quota_manager
,
732 const GURL
& security_origin
,
733 const ResponseCallback
& callback
) {
734 scoped_ptr
<base::DictionaryValue
> quota(new base::DictionaryValue
);
735 scoped_ptr
<base::DictionaryValue
> usage(new base::DictionaryValue
);
737 static quota::QuotaClient::ID kQuotaClients
[] = {
738 quota::QuotaClient::kFileSystem
,
739 quota::QuotaClient::kDatabase
,
740 quota::QuotaClient::kAppcache
,
741 quota::QuotaClient::kIndexedDatabase
744 static const size_t kStorageTypeCount
= quota::kStorageTypeUnknown
;
745 std::map
<quota::StorageType
, base::ListValue
*> storage_type_lists
;
747 for (size_t i
= 0; i
!= kStorageTypeCount
; i
++) {
748 const quota::StorageType type
= static_cast<quota::StorageType
>(i
);
749 if (type
== quota::kStorageTypeQuotaNotManaged
)
751 storage_type_lists
[type
] = new base::ListValue
;
752 usage
->Set(GetStorageTypeName(type
), storage_type_lists
[type
]);
755 const int kExpectedResults
=
756 2 + arraysize(kQuotaClients
) * storage_type_lists
.size();
757 base::DictionaryValue
* quota_raw_ptr
= quota
.get();
759 // Takes ownership on usage and quota.
760 base::Closure barrier
= BarrierClosure(
762 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread
,
763 base::Passed("a
),
764 base::Passed(&usage
),
766 std::string host
= net::GetHostOrSpecFromURL(security_origin
);
768 quota_manager
->GetUsageAndQuotaForWebApps(
770 quota::kStorageTypeTemporary
,
771 base::Bind(&DidGetUsageAndQuotaForWebApps
, quota_raw_ptr
,
772 std::string(devtools::Page::Quota::kParamTemporary
), barrier
));
774 quota_manager
->GetPersistentHostQuota(
776 base::Bind(&DidGetQuotaValue
, quota_raw_ptr
,
777 std::string(devtools::Page::Quota::kParamPersistent
),
780 for (size_t i
= 0; i
!= arraysize(kQuotaClients
); i
++) {
781 std::map
<quota::StorageType
, base::ListValue
*>::const_iterator iter
;
782 for (iter
= storage_type_lists
.begin();
783 iter
!= storage_type_lists
.end(); ++iter
) {
784 const quota::StorageType type
= (*iter
).first
;
785 if (!quota_manager
->IsTrackingHostUsage(type
, kQuotaClients
[i
])) {
789 quota_manager
->GetHostUsage(
790 host
, type
, kQuotaClients
[i
],
791 base::Bind(&DidGetHostUsage
, (*iter
).second
,
792 GetQuotaClientName(kQuotaClients
[i
]),
800 scoped_refptr
<DevToolsProtocol::Response
>
801 RendererOverridesHandler::PageQueryUsageAndQuota(
802 scoped_refptr
<DevToolsProtocol::Command
> command
) {
803 base::DictionaryValue
* params
= command
->params();
804 std::string security_origin
;
805 if (!params
|| !params
->GetString(
806 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin
,
808 return command
->InvalidParamResponse(
809 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin
);
812 ResponseCallback callback
= base::Bind(
813 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted
,
814 weak_factory_
.GetWeakPtr(),
817 scoped_refptr
<quota::QuotaManager
> quota_manager
=
818 agent_
->GetRenderViewHost()->GetProcess()->
819 GetStoragePartition()->GetQuotaManager();
821 BrowserThread::PostTask(
822 BrowserThread::IO
, FROM_HERE
,
824 &QueryUsageAndQuotaOnIOThread
,
826 GURL(security_origin
),
829 return command
->AsyncResponsePromise();
832 void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted(
833 scoped_refptr
<DevToolsProtocol::Command
> command
,
834 scoped_ptr
<base::DictionaryValue
> response_data
) {
835 SendAsyncResponse(command
->SuccessResponse(response_data
.release()));
838 void RendererOverridesHandler::NotifyScreencastVisibility(bool visible
) {
840 capture_retry_count_
= kCaptureRetryLimit
;
841 base::DictionaryValue
* params
= new base::DictionaryValue();
843 devtools::Page::screencastVisibilityChanged::kParamVisible
, visible
);
845 devtools::Page::screencastVisibilityChanged::kName
, params
);
848 // Input agent handlers ------------------------------------------------------
850 scoped_refptr
<DevToolsProtocol::Response
>
851 RendererOverridesHandler::InputDispatchMouseEvent(
852 scoped_refptr
<DevToolsProtocol::Command
> command
) {
853 base::DictionaryValue
* params
= command
->params();
857 bool device_space
= false;
858 if (!params
->GetBoolean(
859 devtools::Input::dispatchMouseEvent::kParamDeviceSpace
,
865 RenderViewHost
* host
= agent_
->GetRenderViewHost();
866 blink::WebMouseEvent mouse_event
;
867 ParseGenericInputParams(params
, &mouse_event
);
870 if (params
->GetString(devtools::Input::dispatchMouseEvent::kParamType
,
873 devtools::Input::dispatchMouseEvent::Type::kEnumMousePressed
)
874 mouse_event
.type
= WebInputEvent::MouseDown
;
876 devtools::Input::dispatchMouseEvent::Type::kEnumMouseReleased
)
877 mouse_event
.type
= WebInputEvent::MouseUp
;
879 devtools::Input::dispatchMouseEvent::Type::kEnumMouseMoved
)
880 mouse_event
.type
= WebInputEvent::MouseMove
;
887 if (!params
->GetInteger(devtools::Input::dispatchMouseEvent::kParamX
,
889 !params
->GetInteger(devtools::Input::dispatchMouseEvent::kParamY
,
894 mouse_event
.windowX
= mouse_event
.x
;
895 mouse_event
.windowY
= mouse_event
.y
;
896 mouse_event
.globalX
= mouse_event
.x
;
897 mouse_event
.globalY
= mouse_event
.y
;
899 params
->GetInteger(devtools::Input::dispatchMouseEvent::kParamClickCount
,
900 &mouse_event
.clickCount
);
903 if (!params
->GetString(devtools::Input::dispatchMouseEvent::kParamButton
,
908 if (button
== "none") {
909 mouse_event
.button
= WebMouseEvent::ButtonNone
;
910 } else if (button
== "left") {
911 mouse_event
.button
= WebMouseEvent::ButtonLeft
;
912 mouse_event
.modifiers
|= WebInputEvent::LeftButtonDown
;
913 } else if (button
== "middle") {
914 mouse_event
.button
= WebMouseEvent::ButtonMiddle
;
915 mouse_event
.modifiers
|= WebInputEvent::MiddleButtonDown
;
916 } else if (button
== "right") {
917 mouse_event
.button
= WebMouseEvent::ButtonRight
;
918 mouse_event
.modifiers
|= WebInputEvent::RightButtonDown
;
923 host
->ForwardMouseEvent(mouse_event
);
924 return command
->SuccessResponse(NULL
);
927 scoped_refptr
<DevToolsProtocol::Response
>
928 RendererOverridesHandler::InputDispatchGestureEvent(
929 scoped_refptr
<DevToolsProtocol::Command
> command
) {
930 base::DictionaryValue
* params
= command
->params();
934 RenderViewHostImpl
* host
= static_cast<RenderViewHostImpl
*>(
935 agent_
->GetRenderViewHost());
936 blink::WebGestureEvent event
;
937 ParseGenericInputParams(params
, &event
);
938 event
.sourceDevice
= blink::WebGestureDeviceTouchscreen
;
941 if (params
->GetString(devtools::Input::dispatchGestureEvent::kParamType
,
944 devtools::Input::dispatchGestureEvent::Type::kEnumScrollBegin
)
945 event
.type
= WebInputEvent::GestureScrollBegin
;
947 devtools::Input::dispatchGestureEvent::Type::kEnumScrollUpdate
)
948 event
.type
= WebInputEvent::GestureScrollUpdate
;
950 devtools::Input::dispatchGestureEvent::Type::kEnumScrollEnd
)
951 event
.type
= WebInputEvent::GestureScrollEnd
;
953 devtools::Input::dispatchGestureEvent::Type::kEnumTapDown
)
954 event
.type
= WebInputEvent::GestureTapDown
;
956 devtools::Input::dispatchGestureEvent::Type::kEnumTap
)
957 event
.type
= WebInputEvent::GestureTap
;
959 devtools::Input::dispatchGestureEvent::Type::kEnumPinchBegin
)
960 event
.type
= WebInputEvent::GesturePinchBegin
;
962 devtools::Input::dispatchGestureEvent::Type::kEnumPinchUpdate
)
963 event
.type
= WebInputEvent::GesturePinchUpdate
;
965 devtools::Input::dispatchGestureEvent::Type::kEnumPinchEnd
)
966 event
.type
= WebInputEvent::GesturePinchEnd
;
973 if (!params
->GetInteger(devtools::Input::dispatchGestureEvent::kParamX
,
975 !params
->GetInteger(devtools::Input::dispatchGestureEvent::kParamY
,
979 event
.globalX
= event
.x
;
980 event
.globalY
= event
.y
;
982 if (type
== "scrollUpdate") {
985 if (!params
->GetInteger(
986 devtools::Input::dispatchGestureEvent::kParamDeltaX
, &dx
) ||
988 devtools::Input::dispatchGestureEvent::kParamDeltaY
, &dy
)) {
991 event
.data
.scrollUpdate
.deltaX
= dx
;
992 event
.data
.scrollUpdate
.deltaY
= dy
;
995 if (type
== "pinchUpdate") {
997 if (!params
->GetDouble(
998 devtools::Input::dispatchGestureEvent::kParamPinchScale
,
1002 event
.data
.pinchUpdate
.scale
= static_cast<float>(scale
);
1005 host
->ForwardGestureEvent(event
);
1006 return command
->SuccessResponse(NULL
);
1009 } // namespace content