d700dee9459362adad5459477dd16d4503bf795a
[platform/framework/web/crosswalk.git] / src / content / browser / devtools / renderer_overrides_handler.cc
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.
4
5 #include "content/browser/devtools/renderer_overrides_handler.h"
6
7 #include <map>
8 #include <string>
9
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"
53
54 using blink::WebGestureEvent;
55 using blink::WebInputEvent;
56 using blink::WebMouseEvent;
57
58 namespace content {
59
60 namespace {
61
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;
67
68 }  // namespace
69
70 RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
71     : agent_(agent),
72       has_last_compositor_frame_metadata_(false),
73       capture_retry_count_(0),
74       weak_factory_(this) {
75   RegisterCommandHandler(
76       devtools::DOM::setFileInputFiles::kName,
77       base::Bind(
78           &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
79           base::Unretained(this)));
80   RegisterCommandHandler(
81       devtools::Network::clearBrowserCache::kName,
82       base::Bind(
83           &RendererOverridesHandler::ClearBrowserCache,
84           base::Unretained(this)));
85   RegisterCommandHandler(
86       devtools::Network::clearBrowserCookies::kName,
87       base::Bind(
88           &RendererOverridesHandler::ClearBrowserCookies,
89           base::Unretained(this)));
90   RegisterCommandHandler(
91       devtools::Page::disable::kName,
92       base::Bind(
93           &RendererOverridesHandler::PageDisable, base::Unretained(this)));
94   RegisterCommandHandler(
95       devtools::Page::handleJavaScriptDialog::kName,
96       base::Bind(
97           &RendererOverridesHandler::PageHandleJavaScriptDialog,
98           base::Unretained(this)));
99   RegisterCommandHandler(
100       devtools::Page::navigate::kName,
101       base::Bind(
102           &RendererOverridesHandler::PageNavigate,
103           base::Unretained(this)));
104   RegisterCommandHandler(
105       devtools::Page::reload::kName,
106       base::Bind(
107           &RendererOverridesHandler::PageReload,
108           base::Unretained(this)));
109   RegisterCommandHandler(
110       devtools::Page::getNavigationHistory::kName,
111       base::Bind(
112           &RendererOverridesHandler::PageGetNavigationHistory,
113           base::Unretained(this)));
114   RegisterCommandHandler(
115       devtools::Page::navigateToHistoryEntry::kName,
116       base::Bind(
117           &RendererOverridesHandler::PageNavigateToHistoryEntry,
118           base::Unretained(this)));
119   RegisterCommandHandler(
120       devtools::Page::captureScreenshot::kName,
121       base::Bind(
122           &RendererOverridesHandler::PageCaptureScreenshot,
123           base::Unretained(this)));
124   RegisterCommandHandler(
125       devtools::Page::canScreencast::kName,
126       base::Bind(
127           &RendererOverridesHandler::PageCanScreencast,
128           base::Unretained(this)));
129   RegisterCommandHandler(
130       devtools::Page::startScreencast::kName,
131       base::Bind(
132           &RendererOverridesHandler::PageStartScreencast,
133           base::Unretained(this)));
134   RegisterCommandHandler(
135       devtools::Page::stopScreencast::kName,
136       base::Bind(
137           &RendererOverridesHandler::PageStopScreencast,
138           base::Unretained(this)));
139   RegisterCommandHandler(
140       devtools::Page::queryUsageAndQuota::kName,
141       base::Bind(
142           &RendererOverridesHandler::PageQueryUsageAndQuota,
143           base::Unretained(this)));
144   RegisterCommandHandler(
145       devtools::Input::emulateTouchFromMouseEvent::kName,
146       base::Bind(
147           &RendererOverridesHandler::InputEmulateTouchFromMouseEvent,
148           base::Unretained(this)));
149 }
150
151 RendererOverridesHandler::~RendererOverridesHandler() {}
152
153 void RendererOverridesHandler::OnClientDetached() {
154   RenderViewHostImpl* host = GetRenderViewHostImpl();
155   if (screencast_command_ && host)
156     host->SetTouchEventEmulationEnabled(false, false);
157   screencast_command_ = NULL;
158 }
159
160 void RendererOverridesHandler::OnSwapCompositorFrame(
161     const cc::CompositorFrameMetadata& frame_metadata) {
162   last_compositor_frame_metadata_ = frame_metadata;
163   has_last_compositor_frame_metadata_ = true;
164
165   if (screencast_command_)
166     InnerSwapCompositorFrame();
167 }
168
169 void RendererOverridesHandler::OnVisibilityChanged(bool visible) {
170   if (!screencast_command_)
171     return;
172   NotifyScreencastVisibility(visible);
173 }
174
175 void RendererOverridesHandler::OnRenderViewHostChanged() {
176   RenderViewHostImpl* host = GetRenderViewHostImpl();
177   if (screencast_command_ && host)
178     host->SetTouchEventEmulationEnabled(true, true);
179 }
180
181 bool RendererOverridesHandler::OnSetTouchEventEmulationEnabled() {
182   return screencast_command_.get() != NULL;
183 }
184
185 void RendererOverridesHandler::InnerSwapCompositorFrame() {
186   if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
187           kFrameRateThresholdMs) {
188     return;
189   }
190
191   RenderViewHost* host = GetRenderViewHostImpl();
192   if (!host->GetView())
193     return;
194
195   last_frame_time_ = base::TimeTicks::Now();
196
197   RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
198       host->GetView());
199   // TODO(vkuzkokov): do not use previous frame metadata.
200   cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_;
201
202   float page_scale = metadata.page_scale_factor;
203   gfx::SizeF viewport_size_dip = gfx::ScaleSize(
204       metadata.scrollable_viewport_size, page_scale);
205
206   float total_bar_height_dip = metadata.location_bar_content_translation.y() +
207                                    metadata.overdraw_bottom_height;
208   gfx::SizeF screen_size_dip(viewport_size_dip.width(),
209                              viewport_size_dip.height() + total_bar_height_dip);
210
211   std::string format;
212   int quality = kDefaultScreenshotQuality;
213   double scale = 1;
214   double max_width = -1;
215   double max_height = -1;
216   base::DictionaryValue* params = screencast_command_->params();
217   if (params) {
218     params->GetString(devtools::Page::startScreencast::kParamFormat,
219                       &format);
220     params->GetInteger(devtools::Page::startScreencast::kParamQuality,
221                        &quality);
222     params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth,
223                       &max_width);
224     params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight,
225                       &max_height);
226   }
227
228   blink::WebScreenInfo screen_info;
229   view->GetScreenInfo(&screen_info);
230   double device_scale_factor = screen_info.deviceScaleFactor;
231
232   if (max_width > 0) {
233     double max_width_dip = max_width / device_scale_factor;
234     scale = std::min(scale, max_width_dip / screen_size_dip.width());
235   }
236   if (max_height > 0) {
237     double max_height_dip = max_height / device_scale_factor;
238     scale = std::min(scale, max_height_dip / screen_size_dip.height());
239   }
240
241   if (format.empty())
242     format = kPng;
243   if (quality < 0 || quality > 100)
244     quality = kDefaultScreenshotQuality;
245   if (scale <= 0)
246     scale = 0.1;
247
248   gfx::Size snapshot_size_dip(gfx::ToRoundedSize(
249       gfx::ScaleSize(viewport_size_dip, scale)));
250
251   if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) {
252     gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip));
253     view->CopyFromCompositingSurface(
254         viewport_bounds_dip, snapshot_size_dip,
255         base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured,
256                    weak_factory_.GetWeakPtr(),
257                    format, quality, last_compositor_frame_metadata_),
258         kN32_SkColorType);
259   }
260 }
261
262 // DOM agent handlers  --------------------------------------------------------
263
264 scoped_refptr<DevToolsProtocol::Response>
265 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
266     scoped_refptr<DevToolsProtocol::Command> command) {
267   base::DictionaryValue* params = command->params();
268   base::ListValue* file_list = NULL;
269   const char* param =
270       devtools::DOM::setFileInputFiles::kParamFiles;
271   if (!params || !params->GetList(param, &file_list))
272     return command->InvalidParamResponse(param);
273   RenderViewHost* host = GetRenderViewHostImpl();
274   if (!host)
275     return NULL;
276
277   for (size_t i = 0; i < file_list->GetSize(); ++i) {
278     base::FilePath::StringType file;
279     if (!file_list->GetString(i, &file))
280       return command->InvalidParamResponse(param);
281     ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
282         host->GetProcess()->GetID(), base::FilePath(file));
283   }
284   return NULL;
285 }
286
287
288 // Network agent handlers  ----------------------------------------------------
289
290 scoped_refptr<DevToolsProtocol::Response>
291 RendererOverridesHandler::ClearBrowserCache(
292     scoped_refptr<DevToolsProtocol::Command> command) {
293   GetContentClient()->browser()->ClearCache(GetRenderViewHostImpl());
294   return command->SuccessResponse(NULL);
295 }
296
297 scoped_refptr<DevToolsProtocol::Response>
298 RendererOverridesHandler::ClearBrowserCookies(
299     scoped_refptr<DevToolsProtocol::Command> command) {
300   GetContentClient()->browser()->ClearCookies(GetRenderViewHostImpl());
301   return command->SuccessResponse(NULL);
302 }
303
304
305 // Page agent handlers  -------------------------------------------------------
306
307 scoped_refptr<DevToolsProtocol::Response>
308 RendererOverridesHandler::PageDisable(
309     scoped_refptr<DevToolsProtocol::Command> command) {
310   RenderViewHostImpl* host = GetRenderViewHostImpl();
311   if (screencast_command_ && host)
312     host->SetTouchEventEmulationEnabled(false, false);
313   screencast_command_ = NULL;
314   return NULL;
315 }
316
317 scoped_refptr<DevToolsProtocol::Response>
318 RendererOverridesHandler::PageHandleJavaScriptDialog(
319     scoped_refptr<DevToolsProtocol::Command> command) {
320   base::DictionaryValue* params = command->params();
321   const char* paramAccept =
322       devtools::Page::handleJavaScriptDialog::kParamAccept;
323   bool accept = false;
324   if (!params || !params->GetBoolean(paramAccept, &accept))
325     return command->InvalidParamResponse(paramAccept);
326   base::string16 prompt_override;
327   base::string16* prompt_override_ptr = &prompt_override;
328   if (!params || !params->GetString(
329       devtools::Page::handleJavaScriptDialog::kParamPromptText,
330       prompt_override_ptr)) {
331     prompt_override_ptr = NULL;
332   }
333
334   WebContents* web_contents = agent_->GetWebContents();
335   if (web_contents) {
336     JavaScriptDialogManager* manager =
337         web_contents->GetDelegate()->GetJavaScriptDialogManager();
338     if (manager && manager->HandleJavaScriptDialog(
339             web_contents, accept, prompt_override_ptr)) {
340       return command->SuccessResponse(new base::DictionaryValue());
341     }
342   }
343   return command->InternalErrorResponse("No JavaScript dialog to handle");
344 }
345
346 scoped_refptr<DevToolsProtocol::Response>
347 RendererOverridesHandler::PageNavigate(
348     scoped_refptr<DevToolsProtocol::Command> command) {
349   base::DictionaryValue* params = command->params();
350   std::string url;
351   const char* param = devtools::Page::navigate::kParamUrl;
352   if (!params || !params->GetString(param, &url))
353     return command->InvalidParamResponse(param);
354
355   GURL gurl(url);
356   if (!gurl.is_valid())
357     return command->InternalErrorResponse("Cannot navigate to invalid URL");
358
359   WebContents* web_contents = agent_->GetWebContents();
360   if (web_contents) {
361     web_contents->GetController()
362         .LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
363     // Fall through into the renderer.
364     return NULL;
365   }
366
367   return command->InternalErrorResponse("No WebContents to navigate");
368 }
369
370 scoped_refptr<DevToolsProtocol::Response>
371 RendererOverridesHandler::PageReload(
372     scoped_refptr<DevToolsProtocol::Command> command) {
373   WebContents* web_contents = agent_->GetWebContents();
374   if (web_contents) {
375     // Override only if it is crashed.
376     if (!web_contents->IsCrashed())
377       return NULL;
378
379     web_contents->GetController().Reload(false);
380     return command->SuccessResponse(NULL);
381   }
382   return command->InternalErrorResponse("No WebContents to reload");
383 }
384
385 scoped_refptr<DevToolsProtocol::Response>
386 RendererOverridesHandler::PageGetNavigationHistory(
387     scoped_refptr<DevToolsProtocol::Command> command) {
388   WebContents* web_contents = agent_->GetWebContents();
389   if (web_contents) {
390     base::DictionaryValue* result = new base::DictionaryValue();
391     NavigationController& controller = web_contents->GetController();
392     result->SetInteger(
393         devtools::Page::getNavigationHistory::kResponseCurrentIndex,
394         controller.GetCurrentEntryIndex());
395     base::ListValue* entries = new base::ListValue();
396     for (int i = 0; i != controller.GetEntryCount(); ++i) {
397       const NavigationEntry* entry = controller.GetEntryAtIndex(i);
398       base::DictionaryValue* entry_value = new base::DictionaryValue();
399       entry_value->SetInteger(
400           devtools::Page::NavigationEntry::kParamId,
401           entry->GetUniqueID());
402       entry_value->SetString(
403           devtools::Page::NavigationEntry::kParamUrl,
404           entry->GetURL().spec());
405       entry_value->SetString(
406           devtools::Page::NavigationEntry::kParamTitle,
407           entry->GetTitle());
408       entries->Append(entry_value);
409     }
410     result->Set(
411         devtools::Page::getNavigationHistory::kResponseEntries,
412         entries);
413     return command->SuccessResponse(result);
414   }
415   return command->InternalErrorResponse("No WebContents to navigate");
416 }
417
418 scoped_refptr<DevToolsProtocol::Response>
419 RendererOverridesHandler::PageNavigateToHistoryEntry(
420     scoped_refptr<DevToolsProtocol::Command> command) {
421   base::DictionaryValue* params = command->params();
422   const char* param = devtools::Page::navigateToHistoryEntry::kParamEntryId;
423   int entry_id = 0;
424   if (!params || !params->GetInteger(param, &entry_id)) {
425     return command->InvalidParamResponse(param);
426   }
427
428   WebContents* web_contents = agent_->GetWebContents();
429   if (web_contents) {
430     NavigationController& controller = web_contents->GetController();
431     for (int i = 0; i != controller.GetEntryCount(); ++i) {
432       if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
433         controller.GoToIndex(i);
434         return command->SuccessResponse(new base::DictionaryValue());
435       }
436     }
437     return command->InvalidParamResponse(param);
438   }
439   return command->InternalErrorResponse("No WebContents to navigate");
440 }
441
442 scoped_refptr<DevToolsProtocol::Response>
443 RendererOverridesHandler::PageCaptureScreenshot(
444     scoped_refptr<DevToolsProtocol::Command> command) {
445   RenderViewHostImpl* host = GetRenderViewHostImpl();
446   if (!host->GetView())
447     return command->InternalErrorResponse("Unable to access the view");
448
449   host->GetSnapshotFromBrowser(
450       base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
451           weak_factory_.GetWeakPtr(), command));
452   return command->AsyncResponsePromise();
453 }
454
455 void RendererOverridesHandler::ScreenshotCaptured(
456     scoped_refptr<DevToolsProtocol::Command> command,
457     const unsigned char* png_data,
458     size_t png_size) {
459   if (!png_data || !png_size) {
460     SendAsyncResponse(
461         command->InternalErrorResponse("Unable to capture screenshot"));
462     return;
463   }
464
465   std::string base_64_data;
466   base::Base64Encode(
467       base::StringPiece(reinterpret_cast<const char*>(png_data), png_size),
468       &base_64_data);
469
470   base::DictionaryValue* response = new base::DictionaryValue();
471   response->SetString(devtools::Page::screencastFrame::kParamData,
472                       base_64_data);
473
474   SendAsyncResponse(command->SuccessResponse(response));
475 }
476
477 scoped_refptr<DevToolsProtocol::Response>
478 RendererOverridesHandler::PageCanScreencast(
479     scoped_refptr<DevToolsProtocol::Command> command) {
480   base::DictionaryValue* result = new base::DictionaryValue();
481 #if defined(OS_ANDROID)
482   result->SetBoolean(devtools::kResult, true);
483 #else
484   result->SetBoolean(devtools::kResult, false);
485 #endif  // defined(OS_ANDROID)
486   return command->SuccessResponse(result);
487 }
488
489 scoped_refptr<DevToolsProtocol::Response>
490 RendererOverridesHandler::PageStartScreencast(
491     scoped_refptr<DevToolsProtocol::Command> command) {
492   screencast_command_ = command;
493   RenderViewHostImpl* host = GetRenderViewHostImpl();
494   host->SetTouchEventEmulationEnabled(true, true);
495   bool visible = !host->is_hidden();
496   NotifyScreencastVisibility(visible);
497   if (visible) {
498     if (has_last_compositor_frame_metadata_)
499       InnerSwapCompositorFrame();
500     else
501       host->Send(new ViewMsg_ForceRedraw(host->GetRoutingID(), 0));
502   }
503   return command->SuccessResponse(NULL);
504 }
505
506 scoped_refptr<DevToolsProtocol::Response>
507 RendererOverridesHandler::PageStopScreencast(
508     scoped_refptr<DevToolsProtocol::Command> command) {
509   last_frame_time_ = base::TimeTicks();
510   screencast_command_ = NULL;
511   RenderViewHostImpl* host = GetRenderViewHostImpl();
512   if (host)
513     host->SetTouchEventEmulationEnabled(false, false);
514   return command->SuccessResponse(NULL);
515 }
516
517 void RendererOverridesHandler::ScreencastFrameCaptured(
518     const std::string& format,
519     int quality,
520     const cc::CompositorFrameMetadata& metadata,
521     bool success,
522     const SkBitmap& bitmap) {
523   if (!success) {
524     if (capture_retry_count_) {
525       --capture_retry_count_;
526       base::MessageLoop::current()->PostDelayedTask(
527           FROM_HERE,
528           base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame,
529                      weak_factory_.GetWeakPtr()),
530           base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
531     }
532     return;
533   }
534
535   std::vector<unsigned char> data;
536   SkAutoLockPixels lock_image(bitmap);
537   bool encoded;
538   if (format == kPng) {
539     encoded = gfx::PNGCodec::Encode(
540         reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
541         gfx::PNGCodec::FORMAT_SkBitmap,
542         gfx::Size(bitmap.width(), bitmap.height()),
543         bitmap.width() * bitmap.bytesPerPixel(),
544         false, std::vector<gfx::PNGCodec::Comment>(), &data);
545   } else if (format == kJpeg) {
546     encoded = gfx::JPEGCodec::Encode(
547         reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
548         gfx::JPEGCodec::FORMAT_SkBitmap,
549         bitmap.width(),
550         bitmap.height(),
551         bitmap.width() * bitmap.bytesPerPixel(),
552         quality, &data);
553   } else {
554     encoded = false;
555   }
556
557   if (!encoded)
558     return;
559
560   std::string base_64_data;
561   base::Base64Encode(
562       base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
563       &base_64_data);
564
565   base::DictionaryValue* response = new base::DictionaryValue();
566   response->SetString(devtools::Page::screencastFrame::kParamData,
567                       base_64_data);
568
569   // Consider metadata empty in case it has no device scale factor.
570   if (metadata.device_scale_factor != 0) {
571     base::DictionaryValue* response_metadata = new base::DictionaryValue();
572
573     response_metadata->SetDouble(
574         devtools::Page::ScreencastFrameMetadata::kParamDeviceScaleFactor,
575         metadata.device_scale_factor);
576     response_metadata->SetDouble(
577         devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactor,
578         metadata.page_scale_factor);
579     response_metadata->SetDouble(
580         devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMin,
581         metadata.min_page_scale_factor);
582     response_metadata->SetDouble(
583         devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMax,
584         metadata.max_page_scale_factor);
585     response_metadata->SetDouble(
586         devtools::Page::ScreencastFrameMetadata::kParamOffsetTop,
587         metadata.location_bar_content_translation.y());
588     response_metadata->SetDouble(
589         devtools::Page::ScreencastFrameMetadata::kParamOffsetBottom,
590         metadata.overdraw_bottom_height);
591
592     base::DictionaryValue* viewport = new base::DictionaryValue();
593     viewport->SetDouble(devtools::DOM::Rect::kParamX,
594                         metadata.root_scroll_offset.x());
595     viewport->SetDouble(devtools::DOM::Rect::kParamY,
596                         metadata.root_scroll_offset.y());
597     viewport->SetDouble(devtools::DOM::Rect::kParamWidth,
598                         metadata.scrollable_viewport_size.width());
599     viewport->SetDouble(devtools::DOM::Rect::kParamHeight,
600                         metadata.scrollable_viewport_size.height());
601     response_metadata->Set(
602         devtools::Page::ScreencastFrameMetadata::kParamViewport, viewport);
603
604     gfx::SizeF viewport_size_dip = gfx::ScaleSize(
605         metadata.scrollable_viewport_size, metadata.page_scale_factor);
606     response_metadata->SetDouble(
607         devtools::Page::ScreencastFrameMetadata::kParamDeviceWidth,
608         viewport_size_dip.width());
609     response_metadata->SetDouble(
610         devtools::Page::ScreencastFrameMetadata::kParamDeviceHeight,
611         viewport_size_dip.height() +
612             metadata.location_bar_content_translation.y() +
613             metadata.overdraw_bottom_height);
614     response_metadata->SetDouble(
615         devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetX,
616         metadata.root_scroll_offset.x());
617     response_metadata->SetDouble(
618         devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetY,
619         metadata.root_scroll_offset.y());
620
621     response->Set(devtools::Page::screencastFrame::kParamMetadata,
622                   response_metadata);
623   }
624
625   SendNotification(devtools::Page::screencastFrame::kName, response);
626 }
627
628 // Quota and Usage ------------------------------------------
629
630 namespace {
631
632 typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)>
633     ResponseCallback;
634
635 void QueryUsageAndQuotaCompletedOnIOThread(
636     scoped_ptr<base::DictionaryValue> quota,
637     scoped_ptr<base::DictionaryValue> usage,
638     ResponseCallback callback) {
639
640   scoped_ptr<base::DictionaryValue> response_data(new base::DictionaryValue);
641   response_data->Set(devtools::Page::queryUsageAndQuota::kResponseQuota,
642                      quota.release());
643   response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage,
644                      usage.release());
645
646   BrowserThread::PostTask(
647       BrowserThread::UI, FROM_HERE,
648       base::Bind(callback, base::Passed(&response_data)));
649 }
650
651 void DidGetHostUsage(
652     base::ListValue* list,
653     const std::string& client_id,
654     const base::Closure& barrier,
655     int64 value) {
656   base::DictionaryValue* usage_item = new base::DictionaryValue;
657   usage_item->SetString(devtools::Page::UsageItem::kParamId, client_id);
658   usage_item->SetDouble(devtools::Page::UsageItem::kParamValue, value);
659   list->Append(usage_item);
660   barrier.Run();
661 }
662
663 void DidGetQuotaValue(
664     base::DictionaryValue* dictionary,
665     const std::string& item_name,
666     const base::Closure& barrier,
667     quota::QuotaStatusCode status,
668     int64 value) {
669   if (status == quota::kQuotaStatusOk)
670     dictionary->SetDouble(item_name, value);
671   barrier.Run();
672 }
673
674 void DidGetUsageAndQuotaForWebApps(
675     base::DictionaryValue* quota,
676     const std::string& item_name,
677     const base::Closure& barrier,
678     quota::QuotaStatusCode status,
679     int64 used_bytes,
680     int64 quota_in_bytes) {
681   if (status == quota::kQuotaStatusOk)
682     quota->SetDouble(item_name, quota_in_bytes);
683   barrier.Run();
684 }
685
686 std::string GetStorageTypeName(quota::StorageType type) {
687   switch (type) {
688     case quota::kStorageTypeTemporary:
689       return devtools::Page::Usage::kParamTemporary;
690     case quota::kStorageTypePersistent:
691       return devtools::Page::Usage::kParamPersistent;
692     case quota::kStorageTypeSyncable:
693       return devtools::Page::Usage::kParamSyncable;
694     case quota::kStorageTypeQuotaNotManaged:
695     case quota::kStorageTypeUnknown:
696       NOTREACHED();
697   }
698   return "";
699 }
700
701 std::string GetQuotaClientName(quota::QuotaClient::ID id) {
702   switch (id) {
703     case quota::QuotaClient::kFileSystem:
704       return devtools::Page::UsageItem::Id::kEnumFilesystem;
705     case quota::QuotaClient::kDatabase:
706       return devtools::Page::UsageItem::Id::kEnumDatabase;
707     case quota::QuotaClient::kAppcache:
708       return devtools::Page::UsageItem::Id::kEnumAppcache;
709     case quota::QuotaClient::kIndexedDatabase:
710       return devtools::Page::UsageItem::Id::kEnumIndexeddatabase;
711     default:
712       NOTREACHED();
713   }
714   return "";
715 }
716
717 void QueryUsageAndQuotaOnIOThread(
718     scoped_refptr<quota::QuotaManager> quota_manager,
719     const GURL& security_origin,
720     const ResponseCallback& callback) {
721   scoped_ptr<base::DictionaryValue> quota(new base::DictionaryValue);
722   scoped_ptr<base::DictionaryValue> usage(new base::DictionaryValue);
723
724   static quota::QuotaClient::ID kQuotaClients[] = {
725       quota::QuotaClient::kFileSystem,
726       quota::QuotaClient::kDatabase,
727       quota::QuotaClient::kAppcache,
728       quota::QuotaClient::kIndexedDatabase
729   };
730
731   static const size_t kStorageTypeCount = quota::kStorageTypeUnknown;
732   std::map<quota::StorageType, base::ListValue*> storage_type_lists;
733
734   for (size_t i = 0; i != kStorageTypeCount; i++) {
735     const quota::StorageType type = static_cast<quota::StorageType>(i);
736     if (type == quota::kStorageTypeQuotaNotManaged)
737       continue;
738     storage_type_lists[type] = new base::ListValue;
739     usage->Set(GetStorageTypeName(type), storage_type_lists[type]);
740   }
741
742   const int kExpectedResults =
743       2 + arraysize(kQuotaClients) * storage_type_lists.size();
744   base::DictionaryValue* quota_raw_ptr = quota.get();
745
746   // Takes ownership on usage and quota.
747   base::Closure barrier = BarrierClosure(
748       kExpectedResults,
749       base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
750                  base::Passed(&quota),
751                  base::Passed(&usage),
752                  callback));
753   std::string host = net::GetHostOrSpecFromURL(security_origin);
754
755   quota_manager->GetUsageAndQuotaForWebApps(
756       security_origin,
757       quota::kStorageTypeTemporary,
758       base::Bind(&DidGetUsageAndQuotaForWebApps, quota_raw_ptr,
759                  std::string(devtools::Page::Quota::kParamTemporary), barrier));
760
761   quota_manager->GetPersistentHostQuota(
762       host,
763       base::Bind(&DidGetQuotaValue, quota_raw_ptr,
764                  std::string(devtools::Page::Quota::kParamPersistent),
765                  barrier));
766
767   for (size_t i = 0; i != arraysize(kQuotaClients); i++) {
768     std::map<quota::StorageType, base::ListValue*>::const_iterator iter;
769     for (iter = storage_type_lists.begin();
770          iter != storage_type_lists.end(); ++iter) {
771       const quota::StorageType type = (*iter).first;
772       if (!quota_manager->IsTrackingHostUsage(type, kQuotaClients[i])) {
773         barrier.Run();
774         continue;
775       }
776       quota_manager->GetHostUsage(
777           host, type, kQuotaClients[i],
778           base::Bind(&DidGetHostUsage, (*iter).second,
779                      GetQuotaClientName(kQuotaClients[i]),
780                      barrier));
781     }
782   }
783 }
784
785 } // namespace
786
787 scoped_refptr<DevToolsProtocol::Response>
788 RendererOverridesHandler::PageQueryUsageAndQuota(
789     scoped_refptr<DevToolsProtocol::Command> command) {
790   base::DictionaryValue* params = command->params();
791   std::string security_origin;
792   if (!params || !params->GetString(
793       devtools::Page::queryUsageAndQuota::kParamSecurityOrigin,
794       &security_origin)) {
795     return command->InvalidParamResponse(
796         devtools::Page::queryUsageAndQuota::kParamSecurityOrigin);
797   }
798
799   ResponseCallback callback = base::Bind(
800       &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted,
801       weak_factory_.GetWeakPtr(),
802       command);
803
804   scoped_refptr<quota::QuotaManager> quota_manager = GetRenderViewHostImpl()
805                                                          ->GetProcess()
806                                                          ->GetStoragePartition()
807                                                          ->GetQuotaManager();
808
809   BrowserThread::PostTask(
810       BrowserThread::IO, FROM_HERE,
811       base::Bind(
812           &QueryUsageAndQuotaOnIOThread,
813           quota_manager,
814           GURL(security_origin),
815           callback));
816
817   return command->AsyncResponsePromise();
818 }
819
820 void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted(
821     scoped_refptr<DevToolsProtocol::Command> command,
822     scoped_ptr<base::DictionaryValue> response_data) {
823   SendAsyncResponse(command->SuccessResponse(response_data.release()));
824 }
825
826 void RendererOverridesHandler::NotifyScreencastVisibility(bool visible) {
827   if (visible)
828     capture_retry_count_ = kCaptureRetryLimit;
829   base::DictionaryValue* params = new base::DictionaryValue();
830   params->SetBoolean(
831       devtools::Page::screencastVisibilityChanged::kParamVisible, visible);
832   SendNotification(
833       devtools::Page::screencastVisibilityChanged::kName, params);
834 }
835
836 // Input agent handlers  ------------------------------------------------------
837
838 scoped_refptr<DevToolsProtocol::Response>
839 RendererOverridesHandler::InputEmulateTouchFromMouseEvent(
840     scoped_refptr<DevToolsProtocol::Command> command) {
841   if (!screencast_command_)
842     return command->InternalErrorResponse("Screencast should be turned on");
843
844   base::DictionaryValue* params = command->params();
845   if (!params)
846     return command->NoSuchMethodErrorResponse();
847
848   std::string type;
849   if (!params->GetString(
850           devtools::Input::emulateTouchFromMouseEvent::kParamType,
851           &type)) {
852     return command->InvalidParamResponse(
853         devtools::Input::emulateTouchFromMouseEvent::kParamType);
854   }
855
856   blink::WebMouseWheelEvent wheel_event;
857   blink::WebMouseEvent mouse_event;
858   blink::WebMouseEvent* event = &mouse_event;
859
860   if (type ==
861       devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMousePressed) {
862     event->type = WebInputEvent::MouseDown;
863   } else if (type ==
864       devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseReleased) {
865     event->type = WebInputEvent::MouseUp;
866   } else if (type ==
867       devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseMoved) {
868     event->type = WebInputEvent::MouseMove;
869   } else if (type ==
870       devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseWheel) {
871     double deltaX = 0;
872     double deltaY = 0;
873     if (!params->GetDouble(
874             devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX,
875             &deltaX)) {
876       return command->InvalidParamResponse(
877           devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX);
878     }
879     if (!params->GetDouble(
880             devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY,
881             &deltaY)) {
882       return command->InvalidParamResponse(
883           devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY);
884     }
885     wheel_event.deltaX = static_cast<float>(deltaX);
886     wheel_event.deltaY = static_cast<float>(deltaY);
887     event = &wheel_event;
888     event->type = WebInputEvent::MouseWheel;
889   } else {
890     return command->InvalidParamResponse(
891         devtools::Input::emulateTouchFromMouseEvent::kParamType);
892   }
893
894   int modifiers = 0;
895   if (params->GetInteger(
896           devtools::Input::emulateTouchFromMouseEvent::kParamModifiers,
897           &modifiers)) {
898     if (modifiers & 1)
899       event->modifiers |= WebInputEvent::AltKey;
900     if (modifiers & 2)
901       event->modifiers |= WebInputEvent::ControlKey;
902     if (modifiers & 4)
903       event->modifiers |= WebInputEvent::MetaKey;
904     if (modifiers & 8)
905       event->modifiers |= WebInputEvent::ShiftKey;
906   }
907
908   params->GetDouble(
909       devtools::Input::emulateTouchFromMouseEvent::kParamTimestamp,
910       &event->timeStampSeconds);
911
912   if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamX,
913                           &event->x)) {
914     return command->InvalidParamResponse(
915         devtools::Input::emulateTouchFromMouseEvent::kParamX);
916   }
917
918   if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamY,
919                           &event->y)) {
920     return command->InvalidParamResponse(
921         devtools::Input::emulateTouchFromMouseEvent::kParamY);
922   }
923
924   event->windowX = event->x;
925   event->windowY = event->y;
926   event->globalX = event->x;
927   event->globalY = event->y;
928
929   params->GetInteger(
930       devtools::Input::emulateTouchFromMouseEvent::kParamClickCount,
931       &event->clickCount);
932
933   std::string button;
934   if (!params->GetString(
935           devtools::Input::emulateTouchFromMouseEvent::kParamButton,
936           &button)) {
937     return command->InvalidParamResponse(
938         devtools::Input::emulateTouchFromMouseEvent::kParamButton);
939   }
940
941   if (button == "none") {
942     event->button = WebMouseEvent::ButtonNone;
943   } else if (button == "left") {
944     event->button = WebMouseEvent::ButtonLeft;
945     event->modifiers |= WebInputEvent::LeftButtonDown;
946   } else if (button == "middle") {
947     event->button = WebMouseEvent::ButtonMiddle;
948     event->modifiers |= WebInputEvent::MiddleButtonDown;
949   } else if (button == "right") {
950     event->button = WebMouseEvent::ButtonRight;
951     event->modifiers |= WebInputEvent::RightButtonDown;
952   } else {
953     return command->InvalidParamResponse(
954         devtools::Input::emulateTouchFromMouseEvent::kParamButton);
955   }
956
957   RenderViewHost* host = GetRenderViewHostImpl();
958   if (event->type == WebInputEvent::MouseWheel)
959     host->ForwardWheelEvent(wheel_event);
960   else
961     host->ForwardMouseEvent(mouse_event);
962   return command->SuccessResponse(NULL);
963 }
964
965 RenderViewHostImpl* RendererOverridesHandler::GetRenderViewHostImpl() {
966   return static_cast<RenderViewHostImpl*>(
967       agent_->GetWebContents()->GetRenderViewHost());
968 }
969
970 }  // namespace content