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