Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / devtools / renderer_overrides_handler.cc
blob0279f59c7b84f48d42d7459c4f68e09ab9271a05
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/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"
51 #include "url/gurl.h"
52 #include "webkit/browser/quota/quota_manager.h"
54 using blink::WebGestureEvent;
55 using blink::WebInputEvent;
56 using blink::WebMouseEvent;
58 namespace content {
60 namespace {
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) {
70 int modifiers = 0;
71 if (params->GetInteger(devtools::Input::dispatchMouseEvent::kParamModifiers,
72 &modifiers)) {
73 if (modifiers & 1)
74 event->modifiers |= WebInputEvent::AltKey;
75 if (modifiers & 2)
76 event->modifiers |= WebInputEvent::ControlKey;
77 if (modifiers & 4)
78 event->modifiers |= WebInputEvent::MetaKey;
79 if (modifiers & 8)
80 event->modifiers |= WebInputEvent::ShiftKey;
83 params->GetDouble(devtools::Input::dispatchMouseEvent::kParamTimestamp,
84 &event->timeStampSeconds);
87 } // namespace
89 RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
90 : agent_(agent),
91 capture_retry_count_(0),
92 weak_factory_(this) {
93 RegisterCommandHandler(
94 devtools::DOM::setFileInputFiles::kName,
95 base::Bind(
96 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
97 base::Unretained(this)));
98 RegisterCommandHandler(
99 devtools::Network::clearBrowserCache::kName,
100 base::Bind(
101 &RendererOverridesHandler::ClearBrowserCache,
102 base::Unretained(this)));
103 RegisterCommandHandler(
104 devtools::Network::clearBrowserCookies::kName,
105 base::Bind(
106 &RendererOverridesHandler::ClearBrowserCookies,
107 base::Unretained(this)));
108 RegisterCommandHandler(
109 devtools::Page::disable::kName,
110 base::Bind(
111 &RendererOverridesHandler::PageDisable, base::Unretained(this)));
112 RegisterCommandHandler(
113 devtools::Page::handleJavaScriptDialog::kName,
114 base::Bind(
115 &RendererOverridesHandler::PageHandleJavaScriptDialog,
116 base::Unretained(this)));
117 RegisterCommandHandler(
118 devtools::Page::navigate::kName,
119 base::Bind(
120 &RendererOverridesHandler::PageNavigate,
121 base::Unretained(this)));
122 RegisterCommandHandler(
123 devtools::Page::reload::kName,
124 base::Bind(
125 &RendererOverridesHandler::PageReload,
126 base::Unretained(this)));
127 RegisterCommandHandler(
128 devtools::Page::getNavigationHistory::kName,
129 base::Bind(
130 &RendererOverridesHandler::PageGetNavigationHistory,
131 base::Unretained(this)));
132 RegisterCommandHandler(
133 devtools::Page::navigateToHistoryEntry::kName,
134 base::Bind(
135 &RendererOverridesHandler::PageNavigateToHistoryEntry,
136 base::Unretained(this)));
137 RegisterCommandHandler(
138 devtools::Page::captureScreenshot::kName,
139 base::Bind(
140 &RendererOverridesHandler::PageCaptureScreenshot,
141 base::Unretained(this)));
142 RegisterCommandHandler(
143 devtools::Page::canScreencast::kName,
144 base::Bind(
145 &RendererOverridesHandler::PageCanScreencast,
146 base::Unretained(this)));
147 RegisterCommandHandler(
148 devtools::Page::startScreencast::kName,
149 base::Bind(
150 &RendererOverridesHandler::PageStartScreencast,
151 base::Unretained(this)));
152 RegisterCommandHandler(
153 devtools::Page::stopScreencast::kName,
154 base::Bind(
155 &RendererOverridesHandler::PageStopScreencast,
156 base::Unretained(this)));
157 RegisterCommandHandler(
158 devtools::Page::queryUsageAndQuota::kName,
159 base::Bind(
160 &RendererOverridesHandler::PageQueryUsageAndQuota,
161 base::Unretained(this)));
162 RegisterCommandHandler(
163 devtools::Input::dispatchMouseEvent::kName,
164 base::Bind(
165 &RendererOverridesHandler::InputDispatchMouseEvent,
166 base::Unretained(this)));
167 RegisterCommandHandler(
168 devtools::Input::dispatchGestureEvent::kName,
169 base::Bind(
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_)
190 return;
191 NotifyScreencastVisibility(visible);
194 void RendererOverridesHandler::InnerSwapCompositorFrame() {
195 if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
196 kFrameRateThresholdMs) {
197 return;
200 RenderViewHost* host = agent_->GetRenderViewHost();
201 if (!host->GetView())
202 return;
204 last_frame_time_ = base::TimeTicks::Now();
206 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
207 host->GetView());
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);
220 std::string format;
221 int quality = kDefaultScreenshotQuality;
222 double scale = 1;
223 double max_width = -1;
224 double max_height = -1;
225 base::DictionaryValue* params = screencast_command_->params();
226 if (params) {
227 params->GetString(devtools::Page::startScreencast::kParamFormat,
228 &format);
229 params->GetInteger(devtools::Page::startScreencast::kParamQuality,
230 &quality);
231 params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth,
232 &max_width);
233 params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight,
234 &max_height);
237 blink::WebScreenInfo screen_info;
238 view->GetScreenInfo(&screen_info);
239 double device_scale_factor = screen_info.deviceScaleFactor;
241 if (max_width > 0) {
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());
250 if (format.empty())
251 format = kPng;
252 if (quality < 0 || quality > 100)
253 quality = kDefaultScreenshotQuality;
254 if (scale <= 0)
255 scale = 0.1;
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_),
267 kN32_SkColorType);
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;
278 const char* param =
279 devtools::DOM::setFileInputFiles::kParamFiles;
280 if (!params || !params->GetList(param, &file_list))
281 return command->InvalidParamResponse(param);
282 RenderViewHost* host = agent_->GetRenderViewHost();
283 if (!host)
284 return NULL;
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));
293 return NULL;
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;
320 return 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;
329 bool accept = false;
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();
341 if (host) {
342 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
343 if (web_contents) {
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();
359 std::string url;
360 const char* param = devtools::Page::navigate::kParamUrl;
361 if (!params || !params->GetString(param, &url))
362 return command->InvalidParamResponse(param);
363 GURL gurl(url);
364 if (!gurl.is_valid()) {
365 return command->InternalErrorResponse("Cannot navigate to invalid URL");
367 RenderViewHost* host = agent_->GetRenderViewHost();
368 if (host) {
369 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
370 if (web_contents) {
371 web_contents->GetController()
372 .LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
373 // Fall through into the renderer.
374 return NULL;
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();
384 if (host) {
385 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
386 if (web_contents) {
387 // Override only if it is crashed.
388 if (!web_contents->IsCrashed())
389 return NULL;
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();
402 if (host) {
403 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
404 if (web_contents) {
405 base::DictionaryValue* result = new base::DictionaryValue();
406 NavigationController& controller = web_contents->GetController();
407 result->SetInteger(
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,
422 entry->GetTitle());
423 entries->Append(entry_value);
425 result->Set(
426 devtools::Page::getNavigationHistory::kResponseEntries,
427 entries);
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;
439 int entry_id = 0;
440 if (!params || !params->GetInteger(param, &entry_id)) {
441 return command->InvalidParamResponse(param);
444 RenderViewHost* host = agent_->GetRenderViewHost();
445 if (host) {
446 WebContents* web_contents = host->GetDelegate()->GetAsWebContents();
447 if (web_contents) {
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,
478 size_t png_size) {
479 if (!png_data || !png_size) {
480 SendAsyncResponse(
481 command->InternalErrorResponse("Unable to capture screenshot"));
482 return;
485 std::string base_64_data;
486 base::Base64Encode(
487 base::StringPiece(reinterpret_cast<const char*>(png_data), png_size),
488 &base_64_data);
490 base::DictionaryValue* response = new base::DictionaryValue();
491 response->SetString(devtools::Page::screencastFrame::kParamData,
492 base_64_data);
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);
503 #else
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);
517 if (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,
532 int quality,
533 const cc::CompositorFrameMetadata& metadata,
534 bool success,
535 const SkBitmap& bitmap) {
536 if (!success) {
537 if (capture_retry_count_) {
538 --capture_retry_count_;
539 base::MessageLoop::current()->PostDelayedTask(
540 FROM_HERE,
541 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame,
542 weak_factory_.GetWeakPtr()),
543 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
545 return;
548 std::vector<unsigned char> data;
549 SkAutoLockPixels lock_image(bitmap);
550 bool encoded;
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,
562 bitmap.width(),
563 bitmap.height(),
564 bitmap.width() * bitmap.bytesPerPixel(),
565 quality, &data);
566 } else {
567 encoded = false;
570 if (!encoded)
571 return;
573 std::string base_64_data;
574 base::Base64Encode(
575 base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
576 &base_64_data);
578 base::DictionaryValue* response = new base::DictionaryValue();
579 response->SetString(devtools::Page::screencastFrame::kParamData,
580 base_64_data);
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,
635 response_metadata);
638 SendNotification(devtools::Page::screencastFrame::kName, response);
641 // Quota and Usage ------------------------------------------
643 namespace {
645 typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)>
646 ResponseCallback;
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,
655 quota.release());
656 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage,
657 usage.release());
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,
668 int64 value) {
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);
673 barrier.Run();
676 void DidGetQuotaValue(
677 base::DictionaryValue* dictionary,
678 const std::string& item_name,
679 const base::Closure& barrier,
680 quota::QuotaStatusCode status,
681 int64 value) {
682 if (status == quota::kQuotaStatusOk)
683 dictionary->SetDouble(item_name, value);
684 barrier.Run();
687 void DidGetUsageAndQuotaForWebApps(
688 base::DictionaryValue* quota,
689 const std::string& item_name,
690 const base::Closure& barrier,
691 quota::QuotaStatusCode status,
692 int64 used_bytes,
693 int64 quota_in_bytes) {
694 if (status == quota::kQuotaStatusOk)
695 quota->SetDouble(item_name, quota_in_bytes);
696 barrier.Run();
699 std::string GetStorageTypeName(quota::StorageType type) {
700 switch (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:
709 NOTREACHED();
711 return "";
714 std::string GetQuotaClientName(quota::QuotaClient::ID id) {
715 switch (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;
724 default:
725 NOTREACHED();
727 return "";
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)
750 continue;
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(
761 kExpectedResults,
762 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
763 base::Passed(&quota),
764 base::Passed(&usage),
765 callback));
766 std::string host = net::GetHostOrSpecFromURL(security_origin);
768 quota_manager->GetUsageAndQuotaForWebApps(
769 security_origin,
770 quota::kStorageTypeTemporary,
771 base::Bind(&DidGetUsageAndQuotaForWebApps, quota_raw_ptr,
772 std::string(devtools::Page::Quota::kParamTemporary), barrier));
774 quota_manager->GetPersistentHostQuota(
775 host,
776 base::Bind(&DidGetQuotaValue, quota_raw_ptr,
777 std::string(devtools::Page::Quota::kParamPersistent),
778 barrier));
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])) {
786 barrier.Run();
787 continue;
789 quota_manager->GetHostUsage(
790 host, type, kQuotaClients[i],
791 base::Bind(&DidGetHostUsage, (*iter).second,
792 GetQuotaClientName(kQuotaClients[i]),
793 barrier));
798 } // namespace
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,
807 &security_origin)) {
808 return command->InvalidParamResponse(
809 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin);
812 ResponseCallback callback = base::Bind(
813 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted,
814 weak_factory_.GetWeakPtr(),
815 command);
817 scoped_refptr<quota::QuotaManager> quota_manager =
818 agent_->GetRenderViewHost()->GetProcess()->
819 GetStoragePartition()->GetQuotaManager();
821 BrowserThread::PostTask(
822 BrowserThread::IO, FROM_HERE,
823 base::Bind(
824 &QueryUsageAndQuotaOnIOThread,
825 quota_manager,
826 GURL(security_origin),
827 callback));
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) {
839 if (visible)
840 capture_retry_count_ = kCaptureRetryLimit;
841 base::DictionaryValue* params = new base::DictionaryValue();
842 params->SetBoolean(
843 devtools::Page::screencastVisibilityChanged::kParamVisible, visible);
844 SendNotification(
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();
854 if (!params)
855 return NULL;
857 bool device_space = false;
858 if (!params->GetBoolean(
859 devtools::Input::dispatchMouseEvent::kParamDeviceSpace,
860 &device_space) ||
861 !device_space) {
862 return NULL;
865 RenderViewHost* host = agent_->GetRenderViewHost();
866 blink::WebMouseEvent mouse_event;
867 ParseGenericInputParams(params, &mouse_event);
869 std::string type;
870 if (params->GetString(devtools::Input::dispatchMouseEvent::kParamType,
871 &type)) {
872 if (type ==
873 devtools::Input::dispatchMouseEvent::Type::kEnumMousePressed)
874 mouse_event.type = WebInputEvent::MouseDown;
875 else if (type ==
876 devtools::Input::dispatchMouseEvent::Type::kEnumMouseReleased)
877 mouse_event.type = WebInputEvent::MouseUp;
878 else if (type ==
879 devtools::Input::dispatchMouseEvent::Type::kEnumMouseMoved)
880 mouse_event.type = WebInputEvent::MouseMove;
881 else
882 return NULL;
883 } else {
884 return NULL;
887 if (!params->GetInteger(devtools::Input::dispatchMouseEvent::kParamX,
888 &mouse_event.x) ||
889 !params->GetInteger(devtools::Input::dispatchMouseEvent::kParamY,
890 &mouse_event.y)) {
891 return NULL;
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);
902 std::string button;
903 if (!params->GetString(devtools::Input::dispatchMouseEvent::kParamButton,
904 &button)) {
905 return NULL;
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;
919 } else {
920 return NULL;
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();
931 if (!params)
932 return NULL;
934 RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
935 agent_->GetRenderViewHost());
936 blink::WebGestureEvent event;
937 ParseGenericInputParams(params, &event);
938 event.sourceDevice = blink::WebGestureDeviceTouchscreen;
940 std::string type;
941 if (params->GetString(devtools::Input::dispatchGestureEvent::kParamType,
942 &type)) {
943 if (type ==
944 devtools::Input::dispatchGestureEvent::Type::kEnumScrollBegin)
945 event.type = WebInputEvent::GestureScrollBegin;
946 else if (type ==
947 devtools::Input::dispatchGestureEvent::Type::kEnumScrollUpdate)
948 event.type = WebInputEvent::GestureScrollUpdate;
949 else if (type ==
950 devtools::Input::dispatchGestureEvent::Type::kEnumScrollEnd)
951 event.type = WebInputEvent::GestureScrollEnd;
952 else if (type ==
953 devtools::Input::dispatchGestureEvent::Type::kEnumTapDown)
954 event.type = WebInputEvent::GestureTapDown;
955 else if (type ==
956 devtools::Input::dispatchGestureEvent::Type::kEnumTap)
957 event.type = WebInputEvent::GestureTap;
958 else if (type ==
959 devtools::Input::dispatchGestureEvent::Type::kEnumPinchBegin)
960 event.type = WebInputEvent::GesturePinchBegin;
961 else if (type ==
962 devtools::Input::dispatchGestureEvent::Type::kEnumPinchUpdate)
963 event.type = WebInputEvent::GesturePinchUpdate;
964 else if (type ==
965 devtools::Input::dispatchGestureEvent::Type::kEnumPinchEnd)
966 event.type = WebInputEvent::GesturePinchEnd;
967 else
968 return NULL;
969 } else {
970 return NULL;
973 if (!params->GetInteger(devtools::Input::dispatchGestureEvent::kParamX,
974 &event.x) ||
975 !params->GetInteger(devtools::Input::dispatchGestureEvent::kParamY,
976 &event.y)) {
977 return NULL;
979 event.globalX = event.x;
980 event.globalY = event.y;
982 if (type == "scrollUpdate") {
983 int dx = 0;
984 int dy = 0;
985 if (!params->GetInteger(
986 devtools::Input::dispatchGestureEvent::kParamDeltaX, &dx) ||
987 !params->GetInteger(
988 devtools::Input::dispatchGestureEvent::kParamDeltaY, &dy)) {
989 return NULL;
991 event.data.scrollUpdate.deltaX = dx;
992 event.data.scrollUpdate.deltaY = dy;
995 if (type == "pinchUpdate") {
996 double scale;
997 if (!params->GetDouble(
998 devtools::Input::dispatchGestureEvent::kParamPinchScale,
999 &scale)) {
1000 return NULL;
1002 event.data.pinchUpdate.scale = static_cast<float>(scale);
1005 host->ForwardGestureEvent(event);
1006 return command->SuccessResponse(NULL);
1009 } // namespace content