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