Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / devtools / renderer_overrides_handler.cc
blob1fd66da0607687ec7f5db3d6b05cb8ec8ac6daa1
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"
7 #include <map>
8 #include <string>
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/web/WebInputEvent.h"
44 #include "ui/gfx/codec/jpeg_codec.h"
45 #include "ui/gfx/codec/png_codec.h"
46 #include "ui/gfx/size_conversions.h"
47 #include "ui/snapshot/snapshot.h"
48 #include "url/gurl.h"
49 #include "webkit/browser/quota/quota_manager.h"
51 using blink::WebGestureEvent;
52 using blink::WebInputEvent;
53 using blink::WebMouseEvent;
55 namespace content {
57 namespace {
59 static const char kPng[] = "png";
60 static const char kJpeg[] = "jpeg";
61 static int kDefaultScreenshotQuality = 80;
62 static int kFrameRateThresholdMs = 100;
63 static int kCaptureRetryLimit = 2;
65 void ParseGenericInputParams(base::DictionaryValue* params,
66 WebInputEvent* event) {
67 int modifiers = 0;
68 if (params->GetInteger(devtools::Input::dispatchMouseEvent::kParamModifiers,
69 &modifiers)) {
70 if (modifiers & 1)
71 event->modifiers |= WebInputEvent::AltKey;
72 if (modifiers & 2)
73 event->modifiers |= WebInputEvent::ControlKey;
74 if (modifiers & 4)
75 event->modifiers |= WebInputEvent::MetaKey;
76 if (modifiers & 8)
77 event->modifiers |= WebInputEvent::ShiftKey;
80 params->GetDouble(devtools::Input::dispatchMouseEvent::kParamTimestamp,
81 &event->timeStampSeconds);
84 } // namespace
86 RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
87 : agent_(agent),
88 capture_retry_count_(0),
89 weak_factory_(this) {
90 RegisterCommandHandler(
91 devtools::DOM::setFileInputFiles::kName,
92 base::Bind(
93 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
94 base::Unretained(this)));
95 RegisterCommandHandler(
96 devtools::Network::clearBrowserCache::kName,
97 base::Bind(
98 &RendererOverridesHandler::ClearBrowserCache,
99 base::Unretained(this)));
100 RegisterCommandHandler(
101 devtools::Network::clearBrowserCookies::kName,
102 base::Bind(
103 &RendererOverridesHandler::ClearBrowserCookies,
104 base::Unretained(this)));
105 RegisterCommandHandler(
106 devtools::Page::disable::kName,
107 base::Bind(
108 &RendererOverridesHandler::PageDisable, base::Unretained(this)));
109 RegisterCommandHandler(
110 devtools::Page::handleJavaScriptDialog::kName,
111 base::Bind(
112 &RendererOverridesHandler::PageHandleJavaScriptDialog,
113 base::Unretained(this)));
114 RegisterCommandHandler(
115 devtools::Page::navigate::kName,
116 base::Bind(
117 &RendererOverridesHandler::PageNavigate,
118 base::Unretained(this)));
119 RegisterCommandHandler(
120 devtools::Page::reload::kName,
121 base::Bind(
122 &RendererOverridesHandler::PageReload,
123 base::Unretained(this)));
124 RegisterCommandHandler(
125 devtools::Page::getNavigationHistory::kName,
126 base::Bind(
127 &RendererOverridesHandler::PageGetNavigationHistory,
128 base::Unretained(this)));
129 RegisterCommandHandler(
130 devtools::Page::navigateToHistoryEntry::kName,
131 base::Bind(
132 &RendererOverridesHandler::PageNavigateToHistoryEntry,
133 base::Unretained(this)));
134 RegisterCommandHandler(
135 devtools::Page::captureScreenshot::kName,
136 base::Bind(
137 &RendererOverridesHandler::PageCaptureScreenshot,
138 base::Unretained(this)));
139 RegisterCommandHandler(
140 devtools::Page::canScreencast::kName,
141 base::Bind(
142 &RendererOverridesHandler::PageCanScreencast,
143 base::Unretained(this)));
144 RegisterCommandHandler(
145 devtools::Page::startScreencast::kName,
146 base::Bind(
147 &RendererOverridesHandler::PageStartScreencast,
148 base::Unretained(this)));
149 RegisterCommandHandler(
150 devtools::Page::stopScreencast::kName,
151 base::Bind(
152 &RendererOverridesHandler::PageStopScreencast,
153 base::Unretained(this)));
154 RegisterCommandHandler(
155 devtools::Page::queryUsageAndQuota::kName,
156 base::Bind(
157 &RendererOverridesHandler::PageQueryUsageAndQuota,
158 base::Unretained(this)));
159 RegisterCommandHandler(
160 devtools::Input::dispatchMouseEvent::kName,
161 base::Bind(
162 &RendererOverridesHandler::InputDispatchMouseEvent,
163 base::Unretained(this)));
164 RegisterCommandHandler(
165 devtools::Input::dispatchGestureEvent::kName,
166 base::Bind(
167 &RendererOverridesHandler::InputDispatchGestureEvent,
168 base::Unretained(this)));
171 RendererOverridesHandler::~RendererOverridesHandler() {}
173 void RendererOverridesHandler::OnClientDetached() {
174 screencast_command_ = NULL;
177 void RendererOverridesHandler::OnSwapCompositorFrame(
178 const cc::CompositorFrameMetadata& frame_metadata) {
179 last_compositor_frame_metadata_ = frame_metadata;
181 if (screencast_command_)
182 InnerSwapCompositorFrame();
185 void RendererOverridesHandler::OnVisibilityChanged(bool visible) {
186 if (!screencast_command_)
187 return;
188 NotifyScreencastVisibility(visible);
191 void RendererOverridesHandler::InnerSwapCompositorFrame() {
192 if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
193 kFrameRateThresholdMs) {
194 return;
197 RenderViewHost* host = agent_->GetRenderViewHost();
198 if (!host->GetView())
199 return;
201 last_frame_time_ = base::TimeTicks::Now();
202 std::string format;
203 int quality = kDefaultScreenshotQuality;
204 double scale = 1;
205 ParseCaptureParameters(screencast_command_.get(), &format, &quality, &scale);
207 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
208 host->GetView());
210 gfx::Rect view_bounds = host->GetView()->GetViewBounds();
211 gfx::Size snapshot_size = gfx::ToFlooredSize(
212 gfx::ScaleSize(view_bounds.size(), scale));
214 view->CopyFromCompositingSurface(
215 view_bounds, snapshot_size,
216 base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured,
217 weak_factory_.GetWeakPtr(),
218 format, quality, last_compositor_frame_metadata_),
219 SkBitmap::kARGB_8888_Config);
222 void RendererOverridesHandler::ParseCaptureParameters(
223 DevToolsProtocol::Command* command,
224 std::string* format,
225 int* quality,
226 double* scale) {
227 *quality = kDefaultScreenshotQuality;
228 *scale = 1;
229 double max_width = -1;
230 double max_height = -1;
231 base::DictionaryValue* params = command->params();
232 if (params) {
233 params->GetString(devtools::Page::startScreencast::kParamFormat,
234 format);
235 params->GetInteger(devtools::Page::startScreencast::kParamQuality,
236 quality);
237 params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth,
238 &max_width);
239 params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight,
240 &max_height);
243 RenderViewHost* host = agent_->GetRenderViewHost();
244 CHECK(host->GetView());
245 gfx::Rect view_bounds = host->GetView()->GetViewBounds();
246 if (max_width > 0)
247 *scale = std::min(*scale, max_width / view_bounds.width());
248 if (max_height > 0)
249 *scale = std::min(*scale, max_height / view_bounds.height());
251 if (format->empty())
252 *format = kPng;
253 if (*quality < 0 || *quality > 100)
254 *quality = kDefaultScreenshotQuality;
255 if (*scale <= 0)
256 *scale = 0.1;
257 if (*scale > 5)
258 *scale = 5;
261 base::DictionaryValue* RendererOverridesHandler::CreateScreenshotResponse(
262 const std::vector<unsigned char>& png_data) {
263 std::string base_64_data;
264 base::Base64Encode(
265 base::StringPiece(reinterpret_cast<const char*>(&png_data[0]),
266 png_data.size()),
267 &base_64_data);
269 base::DictionaryValue* response = new base::DictionaryValue();
270 response->SetString(
271 devtools::Page::captureScreenshot::kResponseData, base_64_data);
272 return response;
275 // DOM agent handlers --------------------------------------------------------
277 scoped_refptr<DevToolsProtocol::Response>
278 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
279 scoped_refptr<DevToolsProtocol::Command> command) {
280 base::DictionaryValue* params = command->params();
281 base::ListValue* file_list = NULL;
282 const char* param =
283 devtools::DOM::setFileInputFiles::kParamFiles;
284 if (!params || !params->GetList(param, &file_list))
285 return command->InvalidParamResponse(param);
286 RenderViewHost* host = agent_->GetRenderViewHost();
287 if (!host)
288 return NULL;
290 for (size_t i = 0; i < file_list->GetSize(); ++i) {
291 base::FilePath::StringType file;
292 if (!file_list->GetString(i, &file))
293 return command->InvalidParamResponse(param);
294 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
295 host->GetProcess()->GetID(), base::FilePath(file));
297 return NULL;
301 // Network agent handlers ----------------------------------------------------
303 scoped_refptr<DevToolsProtocol::Response>
304 RendererOverridesHandler::ClearBrowserCache(
305 scoped_refptr<DevToolsProtocol::Command> command) {
306 GetContentClient()->browser()->ClearCache(agent_->GetRenderViewHost());
307 return command->SuccessResponse(NULL);
310 scoped_refptr<DevToolsProtocol::Response>
311 RendererOverridesHandler::ClearBrowserCookies(
312 scoped_refptr<DevToolsProtocol::Command> command) {
313 GetContentClient()->browser()->ClearCookies(agent_->GetRenderViewHost());
314 return command->SuccessResponse(NULL);
318 // Page agent handlers -------------------------------------------------------
320 scoped_refptr<DevToolsProtocol::Response>
321 RendererOverridesHandler::PageDisable(
322 scoped_refptr<DevToolsProtocol::Command> command) {
323 screencast_command_ = NULL;
324 return NULL;
327 scoped_refptr<DevToolsProtocol::Response>
328 RendererOverridesHandler::PageHandleJavaScriptDialog(
329 scoped_refptr<DevToolsProtocol::Command> command) {
330 base::DictionaryValue* params = command->params();
331 const char* paramAccept =
332 devtools::Page::handleJavaScriptDialog::kParamAccept;
333 bool accept;
334 if (!params || !params->GetBoolean(paramAccept, &accept))
335 return command->InvalidParamResponse(paramAccept);
336 base::string16 prompt_override;
337 base::string16* prompt_override_ptr = &prompt_override;
338 if (!params || !params->GetString(
339 devtools::Page::handleJavaScriptDialog::kParamPromptText,
340 prompt_override_ptr)) {
341 prompt_override_ptr = NULL;
344 RenderViewHost* host = agent_->GetRenderViewHost();
345 if (host) {
346 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
347 if (web_contents) {
348 JavaScriptDialogManager* manager =
349 web_contents->GetDelegate()->GetJavaScriptDialogManager();
350 if (manager && manager->HandleJavaScriptDialog(
351 web_contents, accept, prompt_override_ptr)) {
352 return command->SuccessResponse(new base::DictionaryValue());
356 return command->InternalErrorResponse("No JavaScript dialog to handle");
359 scoped_refptr<DevToolsProtocol::Response>
360 RendererOverridesHandler::PageNavigate(
361 scoped_refptr<DevToolsProtocol::Command> command) {
362 base::DictionaryValue* params = command->params();
363 std::string url;
364 const char* param = devtools::Page::navigate::kParamUrl;
365 if (!params || !params->GetString(param, &url))
366 return command->InvalidParamResponse(param);
367 GURL gurl(url);
368 if (!gurl.is_valid()) {
369 return command->InternalErrorResponse("Cannot navigate to invalid URL");
371 RenderViewHost* host = agent_->GetRenderViewHost();
372 if (host) {
373 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
374 if (web_contents) {
375 web_contents->GetController()
376 .LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
377 return command->SuccessResponse(new base::DictionaryValue());
380 return command->InternalErrorResponse("No WebContents to navigate");
383 scoped_refptr<DevToolsProtocol::Response>
384 RendererOverridesHandler::PageReload(
385 scoped_refptr<DevToolsProtocol::Command> command) {
386 RenderViewHost* host = agent_->GetRenderViewHost();
387 if (host) {
388 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
389 if (web_contents) {
390 // Override only if it is crashed.
391 if (!web_contents->IsCrashed())
392 return NULL;
394 web_contents->GetController().Reload(false);
395 return command->SuccessResponse(NULL);
398 return command->InternalErrorResponse("No WebContents to reload");
401 scoped_refptr<DevToolsProtocol::Response>
402 RendererOverridesHandler::PageGetNavigationHistory(
403 scoped_refptr<DevToolsProtocol::Command> command) {
404 RenderViewHost* host = agent_->GetRenderViewHost();
405 if (host) {
406 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
407 if (web_contents) {
408 base::DictionaryValue* result = new base::DictionaryValue();
409 NavigationController& controller = web_contents->GetController();
410 result->SetInteger(
411 devtools::Page::getNavigationHistory::kResponseCurrentIndex,
412 controller.GetCurrentEntryIndex());
413 base::ListValue* entries = new base::ListValue();
414 for (int i = 0; i != controller.GetEntryCount(); ++i) {
415 const NavigationEntry* entry = controller.GetEntryAtIndex(i);
416 base::DictionaryValue* entry_value = new base::DictionaryValue();
417 entry_value->SetInteger(
418 devtools::Page::NavigationEntry::kParamId,
419 entry->GetUniqueID());
420 entry_value->SetString(
421 devtools::Page::NavigationEntry::kParamUrl,
422 entry->GetURL().spec());
423 entry_value->SetString(
424 devtools::Page::NavigationEntry::kParamTitle,
425 entry->GetTitle());
426 entries->Append(entry_value);
428 result->Set(
429 devtools::Page::getNavigationHistory::kResponseEntries,
430 entries);
431 return command->SuccessResponse(result);
434 return command->InternalErrorResponse("No WebContents to navigate");
437 scoped_refptr<DevToolsProtocol::Response>
438 RendererOverridesHandler::PageNavigateToHistoryEntry(
439 scoped_refptr<DevToolsProtocol::Command> command) {
440 int entry_id;
442 base::DictionaryValue* params = command->params();
443 const char* param = devtools::Page::navigateToHistoryEntry::kParamEntryId;
444 if (!params || !params->GetInteger(param, &entry_id)) {
445 return command->InvalidParamResponse(param);
448 RenderViewHost* host = agent_->GetRenderViewHost();
449 if (host) {
450 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
451 if (web_contents) {
452 NavigationController& controller = web_contents->GetController();
453 for (int i = 0; i != controller.GetEntryCount(); ++i) {
454 if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
455 controller.GoToIndex(i);
456 return command->SuccessResponse(new base::DictionaryValue());
459 return command->InvalidParamResponse(param);
462 return command->InternalErrorResponse("No WebContents to navigate");
465 scoped_refptr<DevToolsProtocol::Response>
466 RendererOverridesHandler::PageCaptureScreenshot(
467 scoped_refptr<DevToolsProtocol::Command> command) {
468 RenderViewHost* host = agent_->GetRenderViewHost();
469 if (!host->GetView())
470 return command->InternalErrorResponse("Unable to access the view");
472 gfx::Rect view_bounds = host->GetView()->GetViewBounds();
473 gfx::Rect snapshot_bounds(view_bounds.size());
474 gfx::Size snapshot_size = snapshot_bounds.size();
476 std::vector<unsigned char> png_data;
477 if (ui::GrabViewSnapshot(host->GetView()->GetNativeView(),
478 &png_data,
479 snapshot_bounds)) {
480 if (png_data.size())
481 return command->SuccessResponse(CreateScreenshotResponse(png_data));
482 else
483 return command->InternalErrorResponse("Unable to capture screenshot");
486 ui::GrabViewSnapshotAsync(
487 host->GetView()->GetNativeView(),
488 snapshot_bounds,
489 base::ThreadTaskRunnerHandle::Get(),
490 base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
491 weak_factory_.GetWeakPtr(), command));
492 return command->AsyncResponsePromise();
495 void RendererOverridesHandler::ScreenshotCaptured(
496 scoped_refptr<DevToolsProtocol::Command> command,
497 scoped_refptr<base::RefCountedBytes> png_data) {
498 if (png_data) {
499 SendAsyncResponse(
500 command->SuccessResponse(CreateScreenshotResponse(png_data->data())));
501 } else {
502 SendAsyncResponse(
503 command->InternalErrorResponse("Unable to capture screenshot"));
507 scoped_refptr<DevToolsProtocol::Response>
508 RendererOverridesHandler::PageCanScreencast(
509 scoped_refptr<DevToolsProtocol::Command> command) {
510 base::DictionaryValue* result = new base::DictionaryValue();
511 #if defined(OS_ANDROID)
512 result->SetBoolean(devtools::kResult, true);
513 #else
514 result->SetBoolean(devtools::kResult, false);
515 #endif // defined(OS_ANDROID)
516 return command->SuccessResponse(result);
519 scoped_refptr<DevToolsProtocol::Response>
520 RendererOverridesHandler::PageStartScreencast(
521 scoped_refptr<DevToolsProtocol::Command> command) {
522 screencast_command_ = command;
523 RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
524 agent_->GetRenderViewHost());
525 bool visible = !host->is_hidden();
526 NotifyScreencastVisibility(visible);
527 if (visible)
528 InnerSwapCompositorFrame();
529 return command->SuccessResponse(NULL);
532 scoped_refptr<DevToolsProtocol::Response>
533 RendererOverridesHandler::PageStopScreencast(
534 scoped_refptr<DevToolsProtocol::Command> command) {
535 last_frame_time_ = base::TimeTicks();
536 screencast_command_ = NULL;
537 return command->SuccessResponse(NULL);
540 void RendererOverridesHandler::ScreencastFrameCaptured(
541 const std::string& format,
542 int quality,
543 const cc::CompositorFrameMetadata& metadata,
544 bool success,
545 const SkBitmap& bitmap) {
546 if (!success) {
547 if (capture_retry_count_) {
548 --capture_retry_count_;
549 base::MessageLoop::current()->PostDelayedTask(
550 FROM_HERE,
551 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame,
552 weak_factory_.GetWeakPtr()),
553 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
555 return;
558 std::vector<unsigned char> data;
559 SkAutoLockPixels lock_image(bitmap);
560 bool encoded;
561 if (format == kPng) {
562 encoded = gfx::PNGCodec::Encode(
563 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
564 gfx::PNGCodec::FORMAT_SkBitmap,
565 gfx::Size(bitmap.width(), bitmap.height()),
566 bitmap.width() * bitmap.bytesPerPixel(),
567 false, std::vector<gfx::PNGCodec::Comment>(), &data);
568 } else if (format == kJpeg) {
569 encoded = gfx::JPEGCodec::Encode(
570 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
571 gfx::JPEGCodec::FORMAT_SkBitmap,
572 bitmap.width(),
573 bitmap.height(),
574 bitmap.width() * bitmap.bytesPerPixel(),
575 quality, &data);
576 } else {
577 encoded = false;
580 if (!encoded)
581 return;
583 std::string base_64_data;
584 base::Base64Encode(
585 base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
586 &base_64_data);
588 base::DictionaryValue* response = new base::DictionaryValue();
589 response->SetString(devtools::Page::screencastFrame::kParamData,
590 base_64_data);
592 // Consider metadata empty in case it has no device scale factor.
593 if (metadata.device_scale_factor != 0) {
594 base::DictionaryValue* response_metadata = new base::DictionaryValue();
596 response_metadata->SetDouble(
597 devtools::Page::ScreencastFrameMetadata::kParamDeviceScaleFactor,
598 metadata.device_scale_factor);
599 response_metadata->SetDouble(
600 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactor,
601 metadata.page_scale_factor);
602 response_metadata->SetDouble(
603 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMin,
604 metadata.min_page_scale_factor);
605 response_metadata->SetDouble(
606 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMax,
607 metadata.max_page_scale_factor);
608 response_metadata->SetDouble(
609 devtools::Page::ScreencastFrameMetadata::kParamOffsetTop,
610 metadata.location_bar_content_translation.y());
611 response_metadata->SetDouble(
612 devtools::Page::ScreencastFrameMetadata::kParamOffsetBottom,
613 metadata.overdraw_bottom_height);
615 base::DictionaryValue* viewport = new base::DictionaryValue();
616 viewport->SetDouble(devtools::DOM::Rect::kParamX,
617 metadata.root_scroll_offset.x());
618 viewport->SetDouble(devtools::DOM::Rect::kParamY,
619 metadata.root_scroll_offset.y());
620 viewport->SetDouble(devtools::DOM::Rect::kParamWidth,
621 metadata.viewport_size.width());
622 viewport->SetDouble(devtools::DOM::Rect::kParamHeight,
623 metadata.viewport_size.height());
624 response_metadata->Set(
625 devtools::Page::ScreencastFrameMetadata::kParamViewport, viewport);
627 response->Set(devtools::Page::screencastFrame::kParamMetadata,
628 response_metadata);
631 SendNotification(devtools::Page::screencastFrame::kName, response);
634 // Quota and Usage ------------------------------------------
636 namespace {
638 typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)>
639 ResponseCallback;
641 void QueryUsageAndQuotaCompletedOnIOThread(
642 scoped_ptr<base::DictionaryValue> quota,
643 scoped_ptr<base::DictionaryValue> usage,
644 ResponseCallback callback) {
646 scoped_ptr<base::DictionaryValue> response_data(new base::DictionaryValue);
647 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseQuota,
648 quota.release());
649 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage,
650 usage.release());
652 BrowserThread::PostTask(
653 BrowserThread::UI, FROM_HERE,
654 base::Bind(callback, base::Passed(&response_data)));
657 void DidGetHostUsage(
658 base::ListValue* list,
659 const std::string& client_id,
660 const base::Closure& barrier,
661 int64 value) {
662 base::DictionaryValue* usage_item = new base::DictionaryValue;
663 usage_item->SetString(devtools::Page::UsageItem::kParamId, client_id);
664 usage_item->SetDouble(devtools::Page::UsageItem::kParamValue, value);
665 list->Append(usage_item);
666 barrier.Run();
669 void DidGetQuotaValue(
670 base::DictionaryValue* dictionary,
671 const std::string& item_name,
672 const base::Closure& barrier,
673 quota::QuotaStatusCode status,
674 int64 value) {
675 if (status == quota::kQuotaStatusOk)
676 dictionary->SetDouble(item_name, value);
677 barrier.Run();
680 void DidGetUsageAndQuotaForWebApps(
681 base::DictionaryValue* quota,
682 const std::string& item_name,
683 const base::Closure& barrier,
684 quota::QuotaStatusCode status,
685 int64 used_bytes,
686 int64 quota_in_bytes) {
687 if (status == quota::kQuotaStatusOk)
688 quota->SetDouble(item_name, quota_in_bytes);
689 barrier.Run();
692 std::string GetStorageTypeName(quota::StorageType type) {
693 switch (type) {
694 case quota::kStorageTypeTemporary:
695 return devtools::Page::Usage::kParamTemporary;
696 case quota::kStorageTypePersistent:
697 return devtools::Page::Usage::kParamPersistent;
698 case quota::kStorageTypeSyncable:
699 return devtools::Page::Usage::kParamSyncable;
700 case quota::kStorageTypeQuotaNotManaged:
701 case quota::kStorageTypeUnknown:
702 NOTREACHED();
704 return "";
707 std::string GetQuotaClientName(quota::QuotaClient::ID id) {
708 switch (id) {
709 case quota::QuotaClient::kFileSystem:
710 return devtools::Page::UsageItem::Id::kEnumFilesystem;
711 case quota::QuotaClient::kDatabase:
712 return devtools::Page::UsageItem::Id::kEnumDatabase;
713 case quota::QuotaClient::kAppcache:
714 return devtools::Page::UsageItem::Id::kEnumAppcache;
715 case quota::QuotaClient::kIndexedDatabase:
716 return devtools::Page::UsageItem::Id::kEnumIndexeddatabase;
717 default:
718 NOTREACHED();
719 return "";
723 void QueryUsageAndQuotaOnIOThread(
724 scoped_refptr<quota::QuotaManager> quota_manager,
725 const GURL& security_origin,
726 const ResponseCallback& callback) {
727 scoped_ptr<base::DictionaryValue> quota(new base::DictionaryValue);
728 scoped_ptr<base::DictionaryValue> usage(new base::DictionaryValue);
730 static quota::QuotaClient::ID kQuotaClients[] = {
731 quota::QuotaClient::kFileSystem,
732 quota::QuotaClient::kDatabase,
733 quota::QuotaClient::kAppcache,
734 quota::QuotaClient::kIndexedDatabase
737 static const size_t kStorageTypeCount = quota::kStorageTypeUnknown;
738 std::map<quota::StorageType, base::ListValue*> storage_type_lists;
740 for (size_t i = 0; i != kStorageTypeCount; i++) {
741 const quota::StorageType type = static_cast<quota::StorageType>(i);
742 if (type == quota::kStorageTypeQuotaNotManaged)
743 continue;
744 storage_type_lists[type] = new base::ListValue;
745 usage->Set(GetStorageTypeName(type), storage_type_lists[type]);
748 const int kExpectedResults =
749 2 + arraysize(kQuotaClients) * storage_type_lists.size();
750 base::DictionaryValue* quota_raw_ptr = quota.get();
752 // Takes ownership on usage and quota.
753 base::Closure barrier = BarrierClosure(
754 kExpectedResults,
755 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
756 base::Passed(&quota),
757 base::Passed(&usage),
758 callback));
759 std::string host = net::GetHostOrSpecFromURL(security_origin);
761 quota_manager->GetUsageAndQuotaForWebApps(
762 security_origin,
763 quota::kStorageTypeTemporary,
764 base::Bind(&DidGetUsageAndQuotaForWebApps, quota_raw_ptr,
765 std::string(devtools::Page::Quota::kParamTemporary), barrier));
767 quota_manager->GetPersistentHostQuota(
768 host,
769 base::Bind(&DidGetQuotaValue, quota_raw_ptr,
770 std::string(devtools::Page::Quota::kParamPersistent),
771 barrier));
773 for (size_t i = 0; i != arraysize(kQuotaClients); i++) {
774 std::map<quota::StorageType, base::ListValue*>::const_iterator iter;
775 for (iter = storage_type_lists.begin();
776 iter != storage_type_lists.end(); ++iter) {
777 const quota::StorageType type = (*iter).first;
778 if (!quota_manager->IsTrackingHostUsage(type, kQuotaClients[i])) {
779 barrier.Run();
780 continue;
782 quota_manager->GetHostUsage(
783 host, type, kQuotaClients[i],
784 base::Bind(&DidGetHostUsage, (*iter).second,
785 GetQuotaClientName(kQuotaClients[i]),
786 barrier));
791 } // namespace
793 scoped_refptr<DevToolsProtocol::Response>
794 RendererOverridesHandler::PageQueryUsageAndQuota(
795 scoped_refptr<DevToolsProtocol::Command> command) {
796 base::DictionaryValue* params = command->params();
797 std::string security_origin;
798 if (!params || !params->GetString(
799 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin,
800 &security_origin)) {
801 return command->InvalidParamResponse(
802 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin);
805 ResponseCallback callback = base::Bind(
806 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted,
807 weak_factory_.GetWeakPtr(),
808 command);
810 scoped_refptr<quota::QuotaManager> quota_manager =
811 agent_->GetRenderViewHost()->GetProcess()->
812 GetStoragePartition()->GetQuotaManager();
814 BrowserThread::PostTask(
815 BrowserThread::IO, FROM_HERE,
816 base::Bind(
817 &QueryUsageAndQuotaOnIOThread,
818 quota_manager,
819 GURL(security_origin),
820 callback));
822 return command->AsyncResponsePromise();
825 void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted(
826 scoped_refptr<DevToolsProtocol::Command> command,
827 scoped_ptr<base::DictionaryValue> response_data) {
828 SendAsyncResponse(command->SuccessResponse(response_data.release()));
831 void RendererOverridesHandler::NotifyScreencastVisibility(bool visible) {
832 if (visible)
833 capture_retry_count_ = kCaptureRetryLimit;
834 base::DictionaryValue* params = new base::DictionaryValue();
835 params->SetBoolean(
836 devtools::Page::screencastVisibilityChanged::kParamVisible, visible);
837 SendNotification(
838 devtools::Page::screencastVisibilityChanged::kName, params);
841 // Input agent handlers ------------------------------------------------------
843 scoped_refptr<DevToolsProtocol::Response>
844 RendererOverridesHandler::InputDispatchMouseEvent(
845 scoped_refptr<DevToolsProtocol::Command> command) {
846 base::DictionaryValue* params = command->params();
847 if (!params)
848 return NULL;
850 bool device_space = false;
851 if (!params->GetBoolean(
852 devtools::Input::dispatchMouseEvent::kParamDeviceSpace,
853 &device_space) ||
854 !device_space) {
855 return NULL;
858 RenderViewHost* host = agent_->GetRenderViewHost();
859 blink::WebMouseEvent mouse_event;
860 ParseGenericInputParams(params, &mouse_event);
862 std::string type;
863 if (params->GetString(devtools::Input::dispatchMouseEvent::kParamType,
864 &type)) {
865 if (type ==
866 devtools::Input::dispatchMouseEvent::Type::kEnumMousePressed)
867 mouse_event.type = WebInputEvent::MouseDown;
868 else if (type ==
869 devtools::Input::dispatchMouseEvent::Type::kEnumMouseReleased)
870 mouse_event.type = WebInputEvent::MouseUp;
871 else if (type ==
872 devtools::Input::dispatchMouseEvent::Type::kEnumMouseMoved)
873 mouse_event.type = WebInputEvent::MouseMove;
874 else
875 return NULL;
876 } else {
877 return NULL;
880 if (!params->GetInteger(devtools::Input::dispatchMouseEvent::kParamX,
881 &mouse_event.x) ||
882 !params->GetInteger(devtools::Input::dispatchMouseEvent::kParamY,
883 &mouse_event.y)) {
884 return NULL;
887 mouse_event.windowX = mouse_event.x;
888 mouse_event.windowY = mouse_event.y;
889 mouse_event.globalX = mouse_event.x;
890 mouse_event.globalY = mouse_event.y;
892 params->GetInteger(devtools::Input::dispatchMouseEvent::kParamClickCount,
893 &mouse_event.clickCount);
895 std::string button;
896 if (!params->GetString(devtools::Input::dispatchMouseEvent::kParamButton,
897 &button)) {
898 return NULL;
901 if (button == "none") {
902 mouse_event.button = WebMouseEvent::ButtonNone;
903 } else if (button == "left") {
904 mouse_event.button = WebMouseEvent::ButtonLeft;
905 mouse_event.modifiers |= WebInputEvent::LeftButtonDown;
906 } else if (button == "middle") {
907 mouse_event.button = WebMouseEvent::ButtonMiddle;
908 mouse_event.modifiers |= WebInputEvent::MiddleButtonDown;
909 } else if (button == "right") {
910 mouse_event.button = WebMouseEvent::ButtonRight;
911 mouse_event.modifiers |= WebInputEvent::RightButtonDown;
912 } else {
913 return NULL;
916 host->ForwardMouseEvent(mouse_event);
917 return command->SuccessResponse(NULL);
920 scoped_refptr<DevToolsProtocol::Response>
921 RendererOverridesHandler::InputDispatchGestureEvent(
922 scoped_refptr<DevToolsProtocol::Command> command) {
923 base::DictionaryValue* params = command->params();
924 if (!params)
925 return NULL;
927 RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
928 agent_->GetRenderViewHost());
929 blink::WebGestureEvent event;
930 ParseGenericInputParams(params, &event);
931 event.sourceDevice = WebGestureEvent::Touchscreen;
933 std::string type;
934 if (params->GetString(devtools::Input::dispatchGestureEvent::kParamType,
935 &type)) {
936 if (type ==
937 devtools::Input::dispatchGestureEvent::Type::kEnumScrollBegin)
938 event.type = WebInputEvent::GestureScrollBegin;
939 else if (type ==
940 devtools::Input::dispatchGestureEvent::Type::kEnumScrollUpdate)
941 event.type = WebInputEvent::GestureScrollUpdate;
942 else if (type ==
943 devtools::Input::dispatchGestureEvent::Type::kEnumScrollEnd)
944 event.type = WebInputEvent::GestureScrollEnd;
945 else if (type ==
946 devtools::Input::dispatchGestureEvent::Type::kEnumTapDown)
947 event.type = WebInputEvent::GestureTapDown;
948 else if (type ==
949 devtools::Input::dispatchGestureEvent::Type::kEnumTap)
950 event.type = WebInputEvent::GestureTap;
951 else if (type ==
952 devtools::Input::dispatchGestureEvent::Type::kEnumPinchBegin)
953 event.type = WebInputEvent::GesturePinchBegin;
954 else if (type ==
955 devtools::Input::dispatchGestureEvent::Type::kEnumPinchUpdate)
956 event.type = WebInputEvent::GesturePinchUpdate;
957 else if (type ==
958 devtools::Input::dispatchGestureEvent::Type::kEnumPinchEnd)
959 event.type = WebInputEvent::GesturePinchEnd;
960 else
961 return NULL;
962 } else {
963 return NULL;
966 if (!params->GetInteger(devtools::Input::dispatchGestureEvent::kParamX,
967 &event.x) ||
968 !params->GetInteger(devtools::Input::dispatchGestureEvent::kParamY,
969 &event.y)) {
970 return NULL;
972 event.globalX = event.x;
973 event.globalY = event.y;
975 if (type == "scrollUpdate") {
976 int dx;
977 int dy;
978 if (!params->GetInteger(
979 devtools::Input::dispatchGestureEvent::kParamDeltaX, &dx) ||
980 !params->GetInteger(
981 devtools::Input::dispatchGestureEvent::kParamDeltaY, &dy)) {
982 return NULL;
984 event.data.scrollUpdate.deltaX = dx;
985 event.data.scrollUpdate.deltaY = dy;
988 if (type == "pinchUpdate") {
989 double scale;
990 if (!params->GetDouble(
991 devtools::Input::dispatchGestureEvent::kParamPinchScale,
992 &scale)) {
993 return NULL;
995 event.data.pinchUpdate.scale = static_cast<float>(scale);
998 host->ForwardGestureEvent(event);
999 return command->SuccessResponse(NULL);
1002 } // namespace content