[DevTools] Implement Inspector.interstitial events.
[chromium-blink-merge.git] / content / browser / devtools / renderer_overrides_handler.cc
blob1a2fb120656f9d72bd77bddb486067f8306d0bca
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/devtools/renderer_overrides_handler.h"
7 #include <map>
8 #include <string>
10 #include "base/barrier_closure.h"
11 #include "base/base64.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/files/file_path.h"
15 #include "base/strings/string16.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "base/values.h"
18 #include "content/browser/child_process_security_policy_impl.h"
19 #include "content/browser/devtools/devtools_protocol_constants.h"
20 #include "content/browser/devtools/devtools_tracing_handler.h"
21 #include "content/browser/renderer_host/dip_util.h"
22 #include "content/browser/renderer_host/render_view_host_delegate.h"
23 #include "content/browser/renderer_host/render_view_host_impl.h"
24 #include "content/browser/renderer_host/render_widget_host_view_base.h"
25 #include "content/browser/web_contents/web_contents_impl.h"
26 #include "content/common/cursors/webcursor.h"
27 #include "content/common/view_messages.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/content_browser_client.h"
30 #include "content/public/browser/devtools_agent_host.h"
31 #include "content/public/browser/javascript_dialog_manager.h"
32 #include "content/public/browser/navigation_controller.h"
33 #include "content/public/browser/navigation_entry.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/render_view_host.h"
36 #include "content/public/browser/render_widget_host_view.h"
37 #include "content/public/browser/storage_partition.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_contents_delegate.h"
40 #include "content/public/common/content_client.h"
41 #include "content/public/common/page_transition_types.h"
42 #include "content/public/common/referrer.h"
43 #include "ipc/ipc_sender.h"
44 #include "net/base/net_util.h"
45 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
46 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
47 #include "third_party/WebKit/public/web/WebInputEvent.h"
48 #include "third_party/skia/include/core/SkCanvas.h"
49 #include "ui/gfx/codec/jpeg_codec.h"
50 #include "ui/gfx/codec/png_codec.h"
51 #include "ui/gfx/display.h"
52 #include "ui/gfx/screen.h"
53 #include "ui/gfx/size_conversions.h"
54 #include "ui/snapshot/snapshot.h"
55 #include "url/gurl.h"
56 #include "webkit/browser/quota/quota_manager.h"
58 using blink::WebGestureEvent;
59 using blink::WebInputEvent;
60 using blink::WebMouseEvent;
62 namespace content {
64 namespace {
66 static const char kPng[] = "png";
67 static const char kJpeg[] = "jpeg";
68 static int kDefaultScreenshotQuality = 80;
69 static int kFrameRateThresholdMs = 100;
70 static int kCaptureRetryLimit = 2;
72 } // namespace
74 RendererOverridesHandler::RendererOverridesHandler()
75 : page_domain_enabled_(false),
76 has_last_compositor_frame_metadata_(false),
77 capture_retry_count_(0),
78 touch_emulation_enabled_(false),
79 color_picker_enabled_(false),
80 last_cursor_x_(-1),
81 last_cursor_y_(-1),
82 weak_factory_(this) {
83 RegisterCommandHandler(
84 devtools::DOM::setFileInputFiles::kName,
85 base::Bind(
86 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
87 base::Unretained(this)));
88 RegisterCommandHandler(
89 devtools::Network::canEmulateNetworkConditions::kName,
90 base::Bind(
91 &RendererOverridesHandler::CanEmulateNetworkConditions,
92 base::Unretained(this)));
93 RegisterCommandHandler(
94 devtools::Network::clearBrowserCache::kName,
95 base::Bind(
96 &RendererOverridesHandler::ClearBrowserCache,
97 base::Unretained(this)));
98 RegisterCommandHandler(
99 devtools::Network::clearBrowserCookies::kName,
100 base::Bind(
101 &RendererOverridesHandler::ClearBrowserCookies,
102 base::Unretained(this)));
103 RegisterCommandHandler(
104 devtools::Page::enable::kName,
105 base::Bind(
106 &RendererOverridesHandler::PageEnable, base::Unretained(this)));
107 RegisterCommandHandler(
108 devtools::Page::disable::kName,
109 base::Bind(
110 &RendererOverridesHandler::PageDisable, base::Unretained(this)));
111 RegisterCommandHandler(
112 devtools::Page::handleJavaScriptDialog::kName,
113 base::Bind(
114 &RendererOverridesHandler::PageHandleJavaScriptDialog,
115 base::Unretained(this)));
116 RegisterCommandHandler(
117 devtools::Page::navigate::kName,
118 base::Bind(
119 &RendererOverridesHandler::PageNavigate,
120 base::Unretained(this)));
121 RegisterCommandHandler(
122 devtools::Page::reload::kName,
123 base::Bind(
124 &RendererOverridesHandler::PageReload,
125 base::Unretained(this)));
126 RegisterCommandHandler(
127 devtools::Page::getNavigationHistory::kName,
128 base::Bind(
129 &RendererOverridesHandler::PageGetNavigationHistory,
130 base::Unretained(this)));
131 RegisterCommandHandler(
132 devtools::Page::navigateToHistoryEntry::kName,
133 base::Bind(
134 &RendererOverridesHandler::PageNavigateToHistoryEntry,
135 base::Unretained(this)));
136 RegisterCommandHandler(
137 devtools::Page::captureScreenshot::kName,
138 base::Bind(
139 &RendererOverridesHandler::PageCaptureScreenshot,
140 base::Unretained(this)));
141 RegisterCommandHandler(
142 devtools::Page::setTouchEmulationEnabled::kName,
143 base::Bind(
144 &RendererOverridesHandler::PageSetTouchEmulationEnabled,
145 base::Unretained(this)));
146 RegisterCommandHandler(
147 devtools::Page::canScreencast::kName,
148 base::Bind(
149 &RendererOverridesHandler::PageCanScreencast,
150 base::Unretained(this)));
151 RegisterCommandHandler(
152 devtools::Page::startScreencast::kName,
153 base::Bind(
154 &RendererOverridesHandler::PageStartScreencast,
155 base::Unretained(this)));
156 RegisterCommandHandler(
157 devtools::Page::stopScreencast::kName,
158 base::Bind(
159 &RendererOverridesHandler::PageStopScreencast,
160 base::Unretained(this)));
161 RegisterCommandHandler(
162 devtools::Page::queryUsageAndQuota::kName,
163 base::Bind(
164 &RendererOverridesHandler::PageQueryUsageAndQuota,
165 base::Unretained(this)));
166 RegisterCommandHandler(
167 devtools::Page::setColorPickerEnabled::kName,
168 base::Bind(
169 &RendererOverridesHandler::PageSetColorPickerEnabled,
170 base::Unretained(this)));
171 RegisterCommandHandler(
172 devtools::Input::emulateTouchFromMouseEvent::kName,
173 base::Bind(
174 &RendererOverridesHandler::InputEmulateTouchFromMouseEvent,
175 base::Unretained(this)));
176 mouse_event_callback_ = base::Bind(
177 &RendererOverridesHandler::HandleMouseEvent,
178 base::Unretained(this));
181 RendererOverridesHandler::~RendererOverridesHandler() {}
183 void RendererOverridesHandler::OnClientDetached() {
184 touch_emulation_enabled_ = false;
185 screencast_command_ = NULL;
186 UpdateTouchEventEmulationState();
187 SetColorPickerEnabled(false);
190 void RendererOverridesHandler::OnSwapCompositorFrame(
191 const cc::CompositorFrameMetadata& frame_metadata) {
192 last_compositor_frame_metadata_ = frame_metadata;
193 has_last_compositor_frame_metadata_ = true;
195 if (screencast_command_)
196 InnerSwapCompositorFrame();
197 if (color_picker_enabled_)
198 UpdateColorPickerFrame();
201 void RendererOverridesHandler::OnVisibilityChanged(bool visible) {
202 if (!screencast_command_)
203 return;
204 NotifyScreencastVisibility(visible);
207 void RendererOverridesHandler::SetRenderViewHost(
208 RenderViewHostImpl* host) {
209 host_ = host;
210 if (!host)
211 return;
212 UpdateTouchEventEmulationState();
213 if (color_picker_enabled_)
214 host->AddMouseEventCallback(mouse_event_callback_);
217 void RendererOverridesHandler::ClearRenderViewHost() {
218 if (host_)
219 host_->RemoveMouseEventCallback(mouse_event_callback_);
220 host_ = NULL;
221 ResetColorPickerFrame();
224 void RendererOverridesHandler::DidAttachInterstitialPage() {
225 if (page_domain_enabled_)
226 SendNotification(devtools::Page::interstitialShown::kName, NULL);
229 void RendererOverridesHandler::DidDetachInterstitialPage() {
230 if (page_domain_enabled_)
231 SendNotification(devtools::Page::interstitialHidden::kName, NULL);
234 void RendererOverridesHandler::InnerSwapCompositorFrame() {
235 if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
236 kFrameRateThresholdMs) {
237 return;
240 if (!host_ || !host_->GetView())
241 return;
243 last_frame_time_ = base::TimeTicks::Now();
245 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
246 host_->GetView());
247 // TODO(vkuzkokov): do not use previous frame metadata.
248 cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_;
250 gfx::SizeF viewport_size_dip = gfx::ScaleSize(
251 metadata.scrollable_viewport_size, metadata.page_scale_factor);
252 gfx::SizeF screen_size_dip = gfx::ScaleSize(view->GetPhysicalBackingSize(),
253 1 / metadata.device_scale_factor);
255 std::string format;
256 int quality = kDefaultScreenshotQuality;
257 double scale = 1;
258 double max_width = -1;
259 double max_height = -1;
260 base::DictionaryValue* params = screencast_command_->params();
261 if (params) {
262 params->GetString(devtools::Page::startScreencast::kParamFormat,
263 &format);
264 params->GetInteger(devtools::Page::startScreencast::kParamQuality,
265 &quality);
266 params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth,
267 &max_width);
268 params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight,
269 &max_height);
272 blink::WebScreenInfo screen_info;
273 view->GetScreenInfo(&screen_info);
274 double device_scale_factor = screen_info.deviceScaleFactor;
276 if (max_width > 0) {
277 double max_width_dip = max_width / device_scale_factor;
278 scale = std::min(scale, max_width_dip / screen_size_dip.width());
280 if (max_height > 0) {
281 double max_height_dip = max_height / device_scale_factor;
282 scale = std::min(scale, max_height_dip / screen_size_dip.height());
285 if (format.empty())
286 format = kPng;
287 if (quality < 0 || quality > 100)
288 quality = kDefaultScreenshotQuality;
289 if (scale <= 0)
290 scale = 0.1;
292 gfx::Size snapshot_size_dip(gfx::ToRoundedSize(
293 gfx::ScaleSize(viewport_size_dip, scale)));
295 if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) {
296 gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip));
297 view->CopyFromCompositingSurface(
298 viewport_bounds_dip, snapshot_size_dip,
299 base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured,
300 weak_factory_.GetWeakPtr(),
301 format, quality, last_compositor_frame_metadata_),
302 kN32_SkColorType);
306 // DOM agent handlers --------------------------------------------------------
308 scoped_refptr<DevToolsProtocol::Response>
309 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
310 scoped_refptr<DevToolsProtocol::Command> command) {
311 base::DictionaryValue* params = command->params();
312 base::ListValue* file_list = NULL;
313 const char* param =
314 devtools::DOM::setFileInputFiles::kParamFiles;
315 if (!params || !params->GetList(param, &file_list))
316 return command->InvalidParamResponse(param);
317 if (!host_)
318 return NULL;
320 for (size_t i = 0; i < file_list->GetSize(); ++i) {
321 base::FilePath::StringType file;
322 if (!file_list->GetString(i, &file))
323 return command->InvalidParamResponse(param);
324 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
325 host_->GetProcess()->GetID(), base::FilePath(file));
327 return NULL;
331 // Network agent handlers ----------------------------------------------------
333 scoped_refptr<DevToolsProtocol::Response>
334 RendererOverridesHandler::CanEmulateNetworkConditions(
335 scoped_refptr<DevToolsProtocol::Command> command) {
336 base::DictionaryValue* result = new base::DictionaryValue();
337 result->SetBoolean(devtools::kResult, false);
338 return command->SuccessResponse(result);
341 scoped_refptr<DevToolsProtocol::Response>
342 RendererOverridesHandler::ClearBrowserCache(
343 scoped_refptr<DevToolsProtocol::Command> command) {
344 GetContentClient()->browser()->ClearCache(host_);
345 return command->SuccessResponse(NULL);
348 scoped_refptr<DevToolsProtocol::Response>
349 RendererOverridesHandler::ClearBrowserCookies(
350 scoped_refptr<DevToolsProtocol::Command> command) {
351 GetContentClient()->browser()->ClearCookies(host_);
352 return command->SuccessResponse(NULL);
356 // Page agent handlers -------------------------------------------------------
358 scoped_refptr<DevToolsProtocol::Response>
359 RendererOverridesHandler::PageEnable(
360 scoped_refptr<DevToolsProtocol::Command> command) {
361 page_domain_enabled_ = true;
362 // Fall through to the renderer.
363 return NULL;
366 scoped_refptr<DevToolsProtocol::Response>
367 RendererOverridesHandler::PageDisable(
368 scoped_refptr<DevToolsProtocol::Command> command) {
369 page_domain_enabled_ = false;
370 OnClientDetached();
371 // Fall through to the renderer.
372 return NULL;
375 scoped_refptr<DevToolsProtocol::Response>
376 RendererOverridesHandler::PageHandleJavaScriptDialog(
377 scoped_refptr<DevToolsProtocol::Command> command) {
378 base::DictionaryValue* params = command->params();
379 const char* paramAccept =
380 devtools::Page::handleJavaScriptDialog::kParamAccept;
381 bool accept = false;
382 if (!params || !params->GetBoolean(paramAccept, &accept))
383 return command->InvalidParamResponse(paramAccept);
384 base::string16 prompt_override;
385 base::string16* prompt_override_ptr = &prompt_override;
386 if (!params || !params->GetString(
387 devtools::Page::handleJavaScriptDialog::kParamPromptText,
388 prompt_override_ptr)) {
389 prompt_override_ptr = NULL;
392 if (!host_)
393 return command->InternalErrorResponse("Could not connect to view");
395 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
396 if (web_contents) {
397 JavaScriptDialogManager* manager =
398 web_contents->GetDelegate()->GetJavaScriptDialogManager();
399 if (manager && manager->HandleJavaScriptDialog(
400 web_contents, accept, prompt_override_ptr)) {
401 return command->SuccessResponse(new base::DictionaryValue());
404 return command->InternalErrorResponse("No JavaScript dialog to handle");
407 scoped_refptr<DevToolsProtocol::Response>
408 RendererOverridesHandler::PageNavigate(
409 scoped_refptr<DevToolsProtocol::Command> command) {
410 base::DictionaryValue* params = command->params();
411 std::string url;
412 const char* param = devtools::Page::navigate::kParamUrl;
413 if (!params || !params->GetString(param, &url))
414 return command->InvalidParamResponse(param);
416 GURL gurl(url);
417 if (!gurl.is_valid())
418 return command->InternalErrorResponse("Cannot navigate to invalid URL");
420 if (!host_)
421 return command->InternalErrorResponse("Could not connect to view");
423 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
424 if (web_contents) {
425 web_contents->GetController()
426 .LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
427 // Fall through into the renderer.
428 return NULL;
431 return command->InternalErrorResponse("No WebContents to navigate");
434 scoped_refptr<DevToolsProtocol::Response>
435 RendererOverridesHandler::PageReload(
436 scoped_refptr<DevToolsProtocol::Command> command) {
437 if (!host_)
438 return command->InternalErrorResponse("Could not connect to view");
440 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
441 if (web_contents) {
442 // Override only if it is crashed.
443 if (!web_contents->IsCrashed())
444 return NULL;
446 web_contents->GetController().Reload(false);
447 return command->SuccessResponse(NULL);
449 return command->InternalErrorResponse("No WebContents to reload");
452 scoped_refptr<DevToolsProtocol::Response>
453 RendererOverridesHandler::PageGetNavigationHistory(
454 scoped_refptr<DevToolsProtocol::Command> command) {
455 if (!host_)
456 return command->InternalErrorResponse("Could not connect to view");
457 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
458 if (web_contents) {
459 base::DictionaryValue* result = new base::DictionaryValue();
460 NavigationController& controller = web_contents->GetController();
461 result->SetInteger(
462 devtools::Page::getNavigationHistory::kResponseCurrentIndex,
463 controller.GetCurrentEntryIndex());
464 base::ListValue* entries = new base::ListValue();
465 for (int i = 0; i != controller.GetEntryCount(); ++i) {
466 const NavigationEntry* entry = controller.GetEntryAtIndex(i);
467 base::DictionaryValue* entry_value = new base::DictionaryValue();
468 entry_value->SetInteger(
469 devtools::Page::NavigationEntry::kParamId,
470 entry->GetUniqueID());
471 entry_value->SetString(
472 devtools::Page::NavigationEntry::kParamUrl,
473 entry->GetURL().spec());
474 entry_value->SetString(
475 devtools::Page::NavigationEntry::kParamTitle,
476 entry->GetTitle());
477 entries->Append(entry_value);
479 result->Set(
480 devtools::Page::getNavigationHistory::kResponseEntries,
481 entries);
482 return command->SuccessResponse(result);
484 return command->InternalErrorResponse("No WebContents to navigate");
487 scoped_refptr<DevToolsProtocol::Response>
488 RendererOverridesHandler::PageNavigateToHistoryEntry(
489 scoped_refptr<DevToolsProtocol::Command> command) {
490 base::DictionaryValue* params = command->params();
491 const char* param = devtools::Page::navigateToHistoryEntry::kParamEntryId;
492 int entry_id = 0;
493 if (!params || !params->GetInteger(param, &entry_id)) {
494 return command->InvalidParamResponse(param);
497 if (!host_)
498 return command->InternalErrorResponse("Could not connect to view");
500 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
501 if (web_contents) {
502 NavigationController& controller = web_contents->GetController();
503 for (int i = 0; i != controller.GetEntryCount(); ++i) {
504 if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
505 controller.GoToIndex(i);
506 return command->SuccessResponse(new base::DictionaryValue());
509 return command->InvalidParamResponse(param);
511 return command->InternalErrorResponse("No WebContents to navigate");
514 scoped_refptr<DevToolsProtocol::Response>
515 RendererOverridesHandler::PageCaptureScreenshot(
516 scoped_refptr<DevToolsProtocol::Command> command) {
517 if (!host_ || !host_->GetView())
518 return command->InternalErrorResponse("Could not connect to view");
520 host_->GetSnapshotFromBrowser(
521 base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
522 weak_factory_.GetWeakPtr(), command));
523 return command->AsyncResponsePromise();
526 void RendererOverridesHandler::ScreenshotCaptured(
527 scoped_refptr<DevToolsProtocol::Command> command,
528 const unsigned char* png_data,
529 size_t png_size) {
530 if (!png_data || !png_size) {
531 SendAsyncResponse(
532 command->InternalErrorResponse("Unable to capture screenshot"));
533 return;
536 std::string base_64_data;
537 base::Base64Encode(
538 base::StringPiece(reinterpret_cast<const char*>(png_data), png_size),
539 &base_64_data);
541 base::DictionaryValue* response = new base::DictionaryValue();
542 response->SetString(devtools::Page::screencastFrame::kParamData,
543 base_64_data);
545 SendAsyncResponse(command->SuccessResponse(response));
548 scoped_refptr<DevToolsProtocol::Response>
549 RendererOverridesHandler::PageSetTouchEmulationEnabled(
550 scoped_refptr<DevToolsProtocol::Command> command) {
551 base::DictionaryValue* params = command->params();
552 bool enabled = false;
553 if (!params || !params->GetBoolean(
554 devtools::Page::setTouchEmulationEnabled::kParamEnabled,
555 &enabled)) {
556 // Pass to renderer.
557 return NULL;
560 touch_emulation_enabled_ = enabled;
561 UpdateTouchEventEmulationState();
563 // Pass to renderer.
564 return NULL;
567 scoped_refptr<DevToolsProtocol::Response>
568 RendererOverridesHandler::PageCanScreencast(
569 scoped_refptr<DevToolsProtocol::Command> command) {
570 base::DictionaryValue* result = new base::DictionaryValue();
571 #if defined(OS_ANDROID)
572 result->SetBoolean(devtools::kResult, true);
573 #else
574 result->SetBoolean(devtools::kResult, false);
575 #endif // defined(OS_ANDROID)
576 return command->SuccessResponse(result);
579 scoped_refptr<DevToolsProtocol::Response>
580 RendererOverridesHandler::PageStartScreencast(
581 scoped_refptr<DevToolsProtocol::Command> command) {
582 screencast_command_ = command;
583 UpdateTouchEventEmulationState();
584 if (!host_)
585 return command->InternalErrorResponse("Could not connect to view");
586 bool visible = !host_->is_hidden();
587 NotifyScreencastVisibility(visible);
588 if (visible) {
589 if (has_last_compositor_frame_metadata_)
590 InnerSwapCompositorFrame();
591 else
592 host_->Send(new ViewMsg_ForceRedraw(host_->GetRoutingID(), 0));
594 return command->SuccessResponse(NULL);
597 scoped_refptr<DevToolsProtocol::Response>
598 RendererOverridesHandler::PageStopScreencast(
599 scoped_refptr<DevToolsProtocol::Command> command) {
600 last_frame_time_ = base::TimeTicks();
601 screencast_command_ = NULL;
602 UpdateTouchEventEmulationState();
603 return command->SuccessResponse(NULL);
606 void RendererOverridesHandler::ScreencastFrameCaptured(
607 const std::string& format,
608 int quality,
609 const cc::CompositorFrameMetadata& metadata,
610 bool success,
611 const SkBitmap& bitmap) {
612 if (!success) {
613 if (capture_retry_count_) {
614 --capture_retry_count_;
615 base::MessageLoop::current()->PostDelayedTask(
616 FROM_HERE,
617 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame,
618 weak_factory_.GetWeakPtr()),
619 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
621 return;
624 std::vector<unsigned char> data;
625 SkAutoLockPixels lock_image(bitmap);
626 bool encoded;
627 if (format == kPng) {
628 encoded = gfx::PNGCodec::Encode(
629 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
630 gfx::PNGCodec::FORMAT_SkBitmap,
631 gfx::Size(bitmap.width(), bitmap.height()),
632 bitmap.width() * bitmap.bytesPerPixel(),
633 false, std::vector<gfx::PNGCodec::Comment>(), &data);
634 } else if (format == kJpeg) {
635 encoded = gfx::JPEGCodec::Encode(
636 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
637 gfx::JPEGCodec::FORMAT_SkBitmap,
638 bitmap.width(),
639 bitmap.height(),
640 bitmap.width() * bitmap.bytesPerPixel(),
641 quality, &data);
642 } else {
643 encoded = false;
646 if (!encoded)
647 return;
649 std::string base_64_data;
650 base::Base64Encode(
651 base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
652 &base_64_data);
654 base::DictionaryValue* response = new base::DictionaryValue();
655 response->SetString(devtools::Page::screencastFrame::kParamData,
656 base_64_data);
658 // Consider metadata empty in case it has no device scale factor.
659 if (metadata.device_scale_factor != 0) {
660 base::DictionaryValue* response_metadata = new base::DictionaryValue();
662 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
663 host_->GetView());
664 if (!view)
665 return;
667 gfx::SizeF viewport_size_dip = gfx::ScaleSize(
668 metadata.scrollable_viewport_size, metadata.page_scale_factor);
669 gfx::SizeF screen_size_dip = gfx::ScaleSize(
670 view->GetPhysicalBackingSize(), 1 / metadata.device_scale_factor);
672 response_metadata->SetDouble(
673 devtools::Page::ScreencastFrameMetadata::kParamDeviceScaleFactor,
674 metadata.device_scale_factor);
675 response_metadata->SetDouble(
676 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactor,
677 metadata.page_scale_factor);
678 response_metadata->SetDouble(
679 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMin,
680 metadata.min_page_scale_factor);
681 response_metadata->SetDouble(
682 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMax,
683 metadata.max_page_scale_factor);
684 response_metadata->SetDouble(
685 devtools::Page::ScreencastFrameMetadata::kParamOffsetTop,
686 metadata.location_bar_content_translation.y());
687 response_metadata->SetDouble(
688 devtools::Page::ScreencastFrameMetadata::kParamOffsetBottom,
689 screen_size_dip.height() -
690 metadata.location_bar_content_translation.y() -
691 viewport_size_dip.height());
693 base::DictionaryValue* viewport = new base::DictionaryValue();
694 viewport->SetDouble(devtools::DOM::Rect::kParamX,
695 metadata.root_scroll_offset.x());
696 viewport->SetDouble(devtools::DOM::Rect::kParamY,
697 metadata.root_scroll_offset.y());
698 viewport->SetDouble(devtools::DOM::Rect::kParamWidth,
699 metadata.scrollable_viewport_size.width());
700 viewport->SetDouble(devtools::DOM::Rect::kParamHeight,
701 metadata.scrollable_viewport_size.height());
702 response_metadata->Set(
703 devtools::Page::ScreencastFrameMetadata::kParamViewport, viewport);
705 response_metadata->SetDouble(
706 devtools::Page::ScreencastFrameMetadata::kParamDeviceWidth,
707 screen_size_dip.width());
708 response_metadata->SetDouble(
709 devtools::Page::ScreencastFrameMetadata::kParamDeviceHeight,
710 screen_size_dip.height());
711 response_metadata->SetDouble(
712 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetX,
713 metadata.root_scroll_offset.x());
714 response_metadata->SetDouble(
715 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetY,
716 metadata.root_scroll_offset.y());
718 response->Set(devtools::Page::screencastFrame::kParamMetadata,
719 response_metadata);
722 SendNotification(devtools::Page::screencastFrame::kName, response);
725 // Quota and Usage ------------------------------------------
727 namespace {
729 typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)>
730 ResponseCallback;
732 void QueryUsageAndQuotaCompletedOnIOThread(
733 scoped_ptr<base::DictionaryValue> quota,
734 scoped_ptr<base::DictionaryValue> usage,
735 ResponseCallback callback) {
737 scoped_ptr<base::DictionaryValue> response_data(new base::DictionaryValue);
738 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseQuota,
739 quota.release());
740 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage,
741 usage.release());
743 BrowserThread::PostTask(
744 BrowserThread::UI, FROM_HERE,
745 base::Bind(callback, base::Passed(&response_data)));
748 void DidGetHostUsage(
749 base::ListValue* list,
750 const std::string& client_id,
751 const base::Closure& barrier,
752 int64 value) {
753 base::DictionaryValue* usage_item = new base::DictionaryValue;
754 usage_item->SetString(devtools::Page::UsageItem::kParamId, client_id);
755 usage_item->SetDouble(devtools::Page::UsageItem::kParamValue, value);
756 list->Append(usage_item);
757 barrier.Run();
760 void DidGetQuotaValue(base::DictionaryValue* dictionary,
761 const std::string& item_name,
762 const base::Closure& barrier,
763 storage::QuotaStatusCode status,
764 int64 value) {
765 if (status == storage::kQuotaStatusOk)
766 dictionary->SetDouble(item_name, value);
767 barrier.Run();
770 void DidGetUsageAndQuotaForWebApps(base::DictionaryValue* quota,
771 const std::string& item_name,
772 const base::Closure& barrier,
773 storage::QuotaStatusCode status,
774 int64 used_bytes,
775 int64 quota_in_bytes) {
776 if (status == storage::kQuotaStatusOk)
777 quota->SetDouble(item_name, quota_in_bytes);
778 barrier.Run();
781 std::string GetStorageTypeName(storage::StorageType type) {
782 switch (type) {
783 case storage::kStorageTypeTemporary:
784 return devtools::Page::Usage::kParamTemporary;
785 case storage::kStorageTypePersistent:
786 return devtools::Page::Usage::kParamPersistent;
787 case storage::kStorageTypeSyncable:
788 return devtools::Page::Usage::kParamSyncable;
789 case storage::kStorageTypeQuotaNotManaged:
790 case storage::kStorageTypeUnknown:
791 NOTREACHED();
793 return "";
796 std::string GetQuotaClientName(storage::QuotaClient::ID id) {
797 switch (id) {
798 case storage::QuotaClient::kFileSystem:
799 return devtools::Page::UsageItem::Id::kEnumFilesystem;
800 case storage::QuotaClient::kDatabase:
801 return devtools::Page::UsageItem::Id::kEnumDatabase;
802 case storage::QuotaClient::kAppcache:
803 return devtools::Page::UsageItem::Id::kEnumAppcache;
804 case storage::QuotaClient::kIndexedDatabase:
805 return devtools::Page::UsageItem::Id::kEnumIndexeddatabase;
806 default:
807 NOTREACHED();
809 return "";
812 void QueryUsageAndQuotaOnIOThread(
813 scoped_refptr<storage::QuotaManager> quota_manager,
814 const GURL& security_origin,
815 const ResponseCallback& callback) {
816 scoped_ptr<base::DictionaryValue> quota(new base::DictionaryValue);
817 scoped_ptr<base::DictionaryValue> usage(new base::DictionaryValue);
819 static storage::QuotaClient::ID kQuotaClients[] = {
820 storage::QuotaClient::kFileSystem, storage::QuotaClient::kDatabase,
821 storage::QuotaClient::kAppcache, storage::QuotaClient::kIndexedDatabase};
823 static const size_t kStorageTypeCount = storage::kStorageTypeUnknown;
824 std::map<storage::StorageType, base::ListValue*> storage_type_lists;
826 for (size_t i = 0; i != kStorageTypeCount; i++) {
827 const storage::StorageType type = static_cast<storage::StorageType>(i);
828 if (type == storage::kStorageTypeQuotaNotManaged)
829 continue;
830 storage_type_lists[type] = new base::ListValue;
831 usage->Set(GetStorageTypeName(type), storage_type_lists[type]);
834 const int kExpectedResults =
835 2 + arraysize(kQuotaClients) * storage_type_lists.size();
836 base::DictionaryValue* quota_raw_ptr = quota.get();
838 // Takes ownership on usage and quota.
839 base::Closure barrier = BarrierClosure(
840 kExpectedResults,
841 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
842 base::Passed(&quota),
843 base::Passed(&usage),
844 callback));
845 std::string host = net::GetHostOrSpecFromURL(security_origin);
847 quota_manager->GetUsageAndQuotaForWebApps(
848 security_origin,
849 storage::kStorageTypeTemporary,
850 base::Bind(&DidGetUsageAndQuotaForWebApps,
851 quota_raw_ptr,
852 std::string(devtools::Page::Quota::kParamTemporary),
853 barrier));
855 quota_manager->GetPersistentHostQuota(
856 host,
857 base::Bind(&DidGetQuotaValue, quota_raw_ptr,
858 std::string(devtools::Page::Quota::kParamPersistent),
859 barrier));
861 for (size_t i = 0; i != arraysize(kQuotaClients); i++) {
862 std::map<storage::StorageType, base::ListValue*>::const_iterator iter;
863 for (iter = storage_type_lists.begin();
864 iter != storage_type_lists.end(); ++iter) {
865 const storage::StorageType type = (*iter).first;
866 if (!quota_manager->IsTrackingHostUsage(type, kQuotaClients[i])) {
867 barrier.Run();
868 continue;
870 quota_manager->GetHostUsage(
871 host, type, kQuotaClients[i],
872 base::Bind(&DidGetHostUsage, (*iter).second,
873 GetQuotaClientName(kQuotaClients[i]),
874 barrier));
879 } // namespace
881 scoped_refptr<DevToolsProtocol::Response>
882 RendererOverridesHandler::PageQueryUsageAndQuota(
883 scoped_refptr<DevToolsProtocol::Command> command) {
884 base::DictionaryValue* params = command->params();
885 std::string security_origin;
886 if (!params || !params->GetString(
887 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin,
888 &security_origin)) {
889 return command->InvalidParamResponse(
890 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin);
893 ResponseCallback callback = base::Bind(
894 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted,
895 weak_factory_.GetWeakPtr(),
896 command);
898 if (!host_)
899 return command->InternalErrorResponse("Could not connect to view");
901 scoped_refptr<storage::QuotaManager> quota_manager =
902 host_->GetProcess()->GetStoragePartition()->GetQuotaManager();
904 BrowserThread::PostTask(
905 BrowserThread::IO, FROM_HERE,
906 base::Bind(
907 &QueryUsageAndQuotaOnIOThread,
908 quota_manager,
909 GURL(security_origin),
910 callback));
912 return command->AsyncResponsePromise();
915 void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted(
916 scoped_refptr<DevToolsProtocol::Command> command,
917 scoped_ptr<base::DictionaryValue> response_data) {
918 SendAsyncResponse(command->SuccessResponse(response_data.release()));
921 void RendererOverridesHandler::NotifyScreencastVisibility(bool visible) {
922 if (visible)
923 capture_retry_count_ = kCaptureRetryLimit;
924 base::DictionaryValue* params = new base::DictionaryValue();
925 params->SetBoolean(
926 devtools::Page::screencastVisibilityChanged::kParamVisible, visible);
927 SendNotification(
928 devtools::Page::screencastVisibilityChanged::kName, params);
931 scoped_refptr<DevToolsProtocol::Response>
932 RendererOverridesHandler::PageSetColorPickerEnabled(
933 scoped_refptr<DevToolsProtocol::Command> command) {
934 base::DictionaryValue* params = command->params();
935 bool color_picker_enabled = false;
936 if (!params || !params->GetBoolean(
937 devtools::Page::setColorPickerEnabled::kParamEnabled,
938 &color_picker_enabled)) {
939 return command->InvalidParamResponse(
940 devtools::Page::setColorPickerEnabled::kParamEnabled);
943 SetColorPickerEnabled(color_picker_enabled);
944 return command->SuccessResponse(NULL);
947 void RendererOverridesHandler::SetColorPickerEnabled(bool enabled) {
948 if (color_picker_enabled_ == enabled)
949 return;
951 color_picker_enabled_ = enabled;
953 if (!host_)
954 return;
956 if (enabled) {
957 host_->AddMouseEventCallback(mouse_event_callback_);
958 UpdateColorPickerFrame();
959 } else {
960 host_->RemoveMouseEventCallback(mouse_event_callback_);
961 ResetColorPickerFrame();
963 WebCursor pointer_cursor;
964 WebCursor::CursorInfo cursor_info;
965 cursor_info.type = blink::WebCursorInfo::TypePointer;
966 pointer_cursor.InitFromCursorInfo(cursor_info);
967 host_->SetCursor(pointer_cursor);
971 void RendererOverridesHandler::UpdateColorPickerFrame() {
972 if (!host_)
973 return;
974 RenderWidgetHostViewBase* view =
975 static_cast<RenderWidgetHostViewBase*>(host_->GetView());
976 if (!view)
977 return;
979 gfx::Size size = view->GetViewBounds().size();
980 view->CopyFromCompositingSurface(
981 gfx::Rect(size), size,
982 base::Bind(&RendererOverridesHandler::ColorPickerFrameUpdated,
983 weak_factory_.GetWeakPtr()),
984 kN32_SkColorType);
987 void RendererOverridesHandler::ResetColorPickerFrame() {
988 color_picker_frame_.reset();
989 last_cursor_x_ = -1;
990 last_cursor_y_ = -1;
993 void RendererOverridesHandler::ColorPickerFrameUpdated(
994 bool succeeded,
995 const SkBitmap& bitmap) {
996 if (!color_picker_enabled_)
997 return;
999 if (succeeded) {
1000 color_picker_frame_ = bitmap;
1001 UpdateColorPickerCursor();
1005 bool RendererOverridesHandler::HandleMouseEvent(
1006 const blink::WebMouseEvent& event) {
1007 last_cursor_x_ = event.x;
1008 last_cursor_y_ = event.y;
1009 if (color_picker_frame_.drawsNothing())
1010 return true;
1012 if (event.button == blink::WebMouseEvent::ButtonLeft &&
1013 event.type == blink::WebInputEvent::MouseDown) {
1014 if (last_cursor_x_ < 0 || last_cursor_x_ >= color_picker_frame_.width() ||
1015 last_cursor_y_ < 0 || last_cursor_y_ >= color_picker_frame_.height()) {
1016 return true;
1019 SkAutoLockPixels lock_image(color_picker_frame_);
1020 SkColor color = color_picker_frame_.getColor(last_cursor_x_,
1021 last_cursor_y_);
1022 base::DictionaryValue* color_dict = new base::DictionaryValue();
1023 color_dict->SetInteger("r", SkColorGetR(color));
1024 color_dict->SetInteger("g", SkColorGetG(color));
1025 color_dict->SetInteger("b", SkColorGetB(color));
1026 color_dict->SetInteger("a", SkColorGetA(color));
1027 base::DictionaryValue* response = new base::DictionaryValue();
1028 response->Set(devtools::Page::colorPicked::kParamColor, color_dict);
1029 SendNotification(devtools::Page::colorPicked::kName, response);
1031 UpdateColorPickerCursor();
1032 return true;
1035 void RendererOverridesHandler::UpdateColorPickerCursor() {
1036 if (!host_ || color_picker_frame_.drawsNothing())
1037 return;
1039 if (last_cursor_x_ < 0 || last_cursor_x_ >= color_picker_frame_.width() ||
1040 last_cursor_y_ < 0 || last_cursor_y_ >= color_picker_frame_.height()) {
1041 return;
1044 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
1045 host_->GetView());
1046 if (!view)
1047 return;
1049 // Due to platform limitations, we are using two different cursors
1050 // depending on the platform. Mac and Win have large cursors with two circles
1051 // for original spot and its magnified projection; Linux gets smaller (64 px)
1052 // magnified projection only with centered hotspot.
1053 // Mac Retina requires cursor to be > 120px in order to render smoothly.
1055 #if defined(OS_LINUX)
1056 const float kCursorSize = 63;
1057 const float kDiameter = 63;
1058 const float kHotspotOffset = 32;
1059 const float kHotspotRadius = 0;
1060 const float kPixelSize = 9;
1061 #else
1062 const float kCursorSize = 150;
1063 const float kDiameter = 110;
1064 const float kHotspotOffset = 25;
1065 const float kHotspotRadius = 5;
1066 const float kPixelSize = 10;
1067 #endif
1069 blink::WebScreenInfo screen_info;
1070 view->GetScreenInfo(&screen_info);
1071 double device_scale_factor = screen_info.deviceScaleFactor;
1073 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(SkCanvas::NewRasterN32(
1074 kCursorSize * device_scale_factor,
1075 kCursorSize * device_scale_factor));
1076 canvas->scale(device_scale_factor, device_scale_factor);
1077 canvas->translate(0.5f, 0.5f);
1079 SkPaint paint;
1081 // Paint original spot with cross.
1082 if (kHotspotRadius) {
1083 paint.setStrokeWidth(1);
1084 paint.setAntiAlias(false);
1085 paint.setColor(SK_ColorDKGRAY);
1086 paint.setStyle(SkPaint::kStroke_Style);
1088 canvas->drawLine(kHotspotOffset, kHotspotOffset - 2 * kHotspotRadius,
1089 kHotspotOffset, kHotspotOffset - kHotspotRadius,
1090 paint);
1091 canvas->drawLine(kHotspotOffset, kHotspotOffset + kHotspotRadius,
1092 kHotspotOffset, kHotspotOffset + 2 * kHotspotRadius,
1093 paint);
1094 canvas->drawLine(kHotspotOffset - 2 * kHotspotRadius, kHotspotOffset,
1095 kHotspotOffset - kHotspotRadius, kHotspotOffset,
1096 paint);
1097 canvas->drawLine(kHotspotOffset + kHotspotRadius, kHotspotOffset,
1098 kHotspotOffset + 2 * kHotspotRadius, kHotspotOffset,
1099 paint);
1101 paint.setStrokeWidth(2);
1102 paint.setAntiAlias(true);
1103 canvas->drawCircle(kHotspotOffset, kHotspotOffset, kHotspotRadius, paint);
1106 // Clip circle for magnified projection.
1107 float padding = (kCursorSize - kDiameter) / 2;
1108 SkPath clip_path;
1109 clip_path.addOval(SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter));
1110 clip_path.close();
1111 canvas->clipPath(clip_path, SkRegion::kIntersect_Op, true);
1113 // Project pixels.
1114 int pixel_count = kDiameter / kPixelSize;
1115 SkRect src_rect = SkRect::MakeXYWH(last_cursor_x_ - pixel_count / 2,
1116 last_cursor_y_ - pixel_count / 2,
1117 pixel_count, pixel_count);
1118 SkRect dst_rect = SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter);
1119 canvas->drawBitmapRectToRect(color_picker_frame_, &src_rect, dst_rect);
1121 // Paint grid.
1122 paint.setStrokeWidth(1);
1123 paint.setAntiAlias(false);
1124 paint.setColor(SK_ColorGRAY);
1125 for (int i = 0; i < pixel_count; ++i) {
1126 canvas->drawLine(padding + i * kPixelSize, padding,
1127 padding + i * kPixelSize, kCursorSize - padding, paint);
1128 canvas->drawLine(padding, padding + i * kPixelSize,
1129 kCursorSize - padding, padding + i * kPixelSize, paint);
1132 // Paint central pixel in red.
1133 SkRect pixel = SkRect::MakeXYWH((kCursorSize - kPixelSize) / 2,
1134 (kCursorSize - kPixelSize) / 2,
1135 kPixelSize, kPixelSize);
1136 paint.setColor(SK_ColorRED);
1137 paint.setStyle(SkPaint::kStroke_Style);
1138 canvas->drawRect(pixel, paint);
1140 // Paint outline.
1141 paint.setStrokeWidth(2);
1142 paint.setColor(SK_ColorDKGRAY);
1143 paint.setAntiAlias(true);
1144 canvas->drawCircle(kCursorSize / 2, kCursorSize / 2, kDiameter / 2, paint);
1146 SkBitmap result;
1147 result.allocN32Pixels(kCursorSize * device_scale_factor,
1148 kCursorSize * device_scale_factor);
1149 canvas->readPixels(&result, 0, 0);
1151 WebCursor cursor;
1152 WebCursor::CursorInfo cursor_info;
1153 cursor_info.type = blink::WebCursorInfo::TypeCustom;
1154 cursor_info.image_scale_factor = device_scale_factor;
1155 cursor_info.custom_image = result;
1156 cursor_info.hotspot =
1157 gfx::Point(kHotspotOffset * device_scale_factor,
1158 kHotspotOffset * device_scale_factor);
1159 #if defined(OS_WIN)
1160 cursor_info.external_handle = 0;
1161 #endif
1163 cursor.InitFromCursorInfo(cursor_info);
1164 DCHECK(host_);
1165 host_->SetCursor(cursor);
1168 // Input agent handlers ------------------------------------------------------
1170 scoped_refptr<DevToolsProtocol::Response>
1171 RendererOverridesHandler::InputEmulateTouchFromMouseEvent(
1172 scoped_refptr<DevToolsProtocol::Command> command) {
1173 if (!screencast_command_)
1174 return command->InternalErrorResponse("Screencast should be turned on");
1176 base::DictionaryValue* params = command->params();
1177 if (!params)
1178 return command->NoSuchMethodErrorResponse();
1180 std::string type;
1181 if (!params->GetString(
1182 devtools::Input::emulateTouchFromMouseEvent::kParamType,
1183 &type)) {
1184 return command->InvalidParamResponse(
1185 devtools::Input::emulateTouchFromMouseEvent::kParamType);
1188 blink::WebMouseWheelEvent wheel_event;
1189 blink::WebMouseEvent mouse_event;
1190 blink::WebMouseEvent* event = &mouse_event;
1192 if (type ==
1193 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMousePressed) {
1194 event->type = WebInputEvent::MouseDown;
1195 } else if (type ==
1196 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseReleased) {
1197 event->type = WebInputEvent::MouseUp;
1198 } else if (type ==
1199 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseMoved) {
1200 event->type = WebInputEvent::MouseMove;
1201 } else if (type ==
1202 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseWheel) {
1203 double deltaX = 0;
1204 double deltaY = 0;
1205 if (!params->GetDouble(
1206 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX,
1207 &deltaX)) {
1208 return command->InvalidParamResponse(
1209 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX);
1211 if (!params->GetDouble(
1212 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY,
1213 &deltaY)) {
1214 return command->InvalidParamResponse(
1215 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY);
1217 wheel_event.deltaX = static_cast<float>(deltaX);
1218 wheel_event.deltaY = static_cast<float>(deltaY);
1219 event = &wheel_event;
1220 event->type = WebInputEvent::MouseWheel;
1221 } else {
1222 return command->InvalidParamResponse(
1223 devtools::Input::emulateTouchFromMouseEvent::kParamType);
1226 int modifiers = 0;
1227 if (params->GetInteger(
1228 devtools::Input::emulateTouchFromMouseEvent::kParamModifiers,
1229 &modifiers)) {
1230 if (modifiers & 1)
1231 event->modifiers |= WebInputEvent::AltKey;
1232 if (modifiers & 2)
1233 event->modifiers |= WebInputEvent::ControlKey;
1234 if (modifiers & 4)
1235 event->modifiers |= WebInputEvent::MetaKey;
1236 if (modifiers & 8)
1237 event->modifiers |= WebInputEvent::ShiftKey;
1240 params->GetDouble(
1241 devtools::Input::emulateTouchFromMouseEvent::kParamTimestamp,
1242 &event->timeStampSeconds);
1244 if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamX,
1245 &event->x)) {
1246 return command->InvalidParamResponse(
1247 devtools::Input::emulateTouchFromMouseEvent::kParamX);
1250 if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamY,
1251 &event->y)) {
1252 return command->InvalidParamResponse(
1253 devtools::Input::emulateTouchFromMouseEvent::kParamY);
1256 event->windowX = event->x;
1257 event->windowY = event->y;
1258 event->globalX = event->x;
1259 event->globalY = event->y;
1261 params->GetInteger(
1262 devtools::Input::emulateTouchFromMouseEvent::kParamClickCount,
1263 &event->clickCount);
1265 std::string button;
1266 if (!params->GetString(
1267 devtools::Input::emulateTouchFromMouseEvent::kParamButton,
1268 &button)) {
1269 return command->InvalidParamResponse(
1270 devtools::Input::emulateTouchFromMouseEvent::kParamButton);
1273 if (button == "none") {
1274 event->button = WebMouseEvent::ButtonNone;
1275 } else if (button == "left") {
1276 event->button = WebMouseEvent::ButtonLeft;
1277 event->modifiers |= WebInputEvent::LeftButtonDown;
1278 } else if (button == "middle") {
1279 event->button = WebMouseEvent::ButtonMiddle;
1280 event->modifiers |= WebInputEvent::MiddleButtonDown;
1281 } else if (button == "right") {
1282 event->button = WebMouseEvent::ButtonRight;
1283 event->modifiers |= WebInputEvent::RightButtonDown;
1284 } else {
1285 return command->InvalidParamResponse(
1286 devtools::Input::emulateTouchFromMouseEvent::kParamButton);
1289 if (!host_)
1290 return command->InternalErrorResponse("Could not connect to view");
1292 if (event->type == WebInputEvent::MouseWheel)
1293 host_->ForwardWheelEvent(wheel_event);
1294 else
1295 host_->ForwardMouseEvent(mouse_event);
1296 return command->SuccessResponse(NULL);
1299 void RendererOverridesHandler::UpdateTouchEventEmulationState() {
1300 if (!host_)
1301 return;
1302 bool enabled = touch_emulation_enabled_ || screencast_command_;
1303 host_->SetTouchEventEmulationEnabled(enabled);
1304 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1305 WebContents::FromRenderViewHost(host_));
1306 if (web_contents)
1307 web_contents->SetForceDisableOverscrollContent(enabled);
1310 } // namespace content