Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / devtools / renderer_overrides_handler.cc
blob7bb629b9aaffacb9fee9a90e0d40460ce892d62d
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 "content/public/common/url_constants.h"
44 #include "ipc/ipc_sender.h"
45 #include "net/base/net_util.h"
46 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
47 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
48 #include "third_party/WebKit/public/web/WebInputEvent.h"
49 #include "third_party/skia/include/core/SkCanvas.h"
50 #include "ui/gfx/codec/jpeg_codec.h"
51 #include "ui/gfx/codec/png_codec.h"
52 #include "ui/gfx/display.h"
53 #include "ui/gfx/screen.h"
54 #include "ui/gfx/size_conversions.h"
55 #include "ui/snapshot/snapshot.h"
56 #include "url/gurl.h"
57 #include "webkit/browser/quota/quota_manager.h"
59 using blink::WebGestureEvent;
60 using blink::WebInputEvent;
61 using blink::WebMouseEvent;
63 namespace content {
65 namespace {
67 static const char kPng[] = "png";
68 static const char kJpeg[] = "jpeg";
69 static int kDefaultScreenshotQuality = 80;
70 static int kFrameRateThresholdMs = 100;
71 static int kCaptureRetryLimit = 2;
73 } // namespace
75 RendererOverridesHandler::RendererOverridesHandler()
76 : page_domain_enabled_(false),
77 has_last_compositor_frame_metadata_(false),
78 capture_retry_count_(0),
79 touch_emulation_enabled_(false),
80 color_picker_enabled_(false),
81 last_cursor_x_(-1),
82 last_cursor_y_(-1),
83 weak_factory_(this) {
84 RegisterCommandHandler(
85 devtools::DOM::setFileInputFiles::kName,
86 base::Bind(
87 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
88 base::Unretained(this)));
89 RegisterCommandHandler(
90 devtools::Network::canEmulateNetworkConditions::kName,
91 base::Bind(
92 &RendererOverridesHandler::CanEmulateNetworkConditions,
93 base::Unretained(this)));
94 RegisterCommandHandler(
95 devtools::Network::clearBrowserCache::kName,
96 base::Bind(
97 &RendererOverridesHandler::ClearBrowserCache,
98 base::Unretained(this)));
99 RegisterCommandHandler(
100 devtools::Network::clearBrowserCookies::kName,
101 base::Bind(
102 &RendererOverridesHandler::ClearBrowserCookies,
103 base::Unretained(this)));
104 RegisterCommandHandler(
105 devtools::Page::enable::kName,
106 base::Bind(
107 &RendererOverridesHandler::PageEnable, base::Unretained(this)));
108 RegisterCommandHandler(
109 devtools::Page::disable::kName,
110 base::Bind(
111 &RendererOverridesHandler::PageDisable, base::Unretained(this)));
112 RegisterCommandHandler(
113 devtools::Page::handleJavaScriptDialog::kName,
114 base::Bind(
115 &RendererOverridesHandler::PageHandleJavaScriptDialog,
116 base::Unretained(this)));
117 RegisterCommandHandler(
118 devtools::Page::navigate::kName,
119 base::Bind(
120 &RendererOverridesHandler::PageNavigate,
121 base::Unretained(this)));
122 RegisterCommandHandler(
123 devtools::Page::reload::kName,
124 base::Bind(
125 &RendererOverridesHandler::PageReload,
126 base::Unretained(this)));
127 RegisterCommandHandler(
128 devtools::Page::getNavigationHistory::kName,
129 base::Bind(
130 &RendererOverridesHandler::PageGetNavigationHistory,
131 base::Unretained(this)));
132 RegisterCommandHandler(
133 devtools::Page::navigateToHistoryEntry::kName,
134 base::Bind(
135 &RendererOverridesHandler::PageNavigateToHistoryEntry,
136 base::Unretained(this)));
137 RegisterCommandHandler(
138 devtools::Page::captureScreenshot::kName,
139 base::Bind(
140 &RendererOverridesHandler::PageCaptureScreenshot,
141 base::Unretained(this)));
142 RegisterCommandHandler(
143 devtools::Page::setTouchEmulationEnabled::kName,
144 base::Bind(
145 &RendererOverridesHandler::PageSetTouchEmulationEnabled,
146 base::Unretained(this)));
147 RegisterCommandHandler(
148 devtools::Page::canEmulate::kName,
149 base::Bind(
150 &RendererOverridesHandler::PageCanEmulate,
151 base::Unretained(this)));
152 RegisterCommandHandler(
153 devtools::Page::canScreencast::kName,
154 base::Bind(
155 &RendererOverridesHandler::PageCanScreencast,
156 base::Unretained(this)));
157 RegisterCommandHandler(
158 devtools::Page::startScreencast::kName,
159 base::Bind(
160 &RendererOverridesHandler::PageStartScreencast,
161 base::Unretained(this)));
162 RegisterCommandHandler(
163 devtools::Page::stopScreencast::kName,
164 base::Bind(
165 &RendererOverridesHandler::PageStopScreencast,
166 base::Unretained(this)));
167 RegisterCommandHandler(
168 devtools::Page::queryUsageAndQuota::kName,
169 base::Bind(
170 &RendererOverridesHandler::PageQueryUsageAndQuota,
171 base::Unretained(this)));
172 RegisterCommandHandler(
173 devtools::Page::setColorPickerEnabled::kName,
174 base::Bind(
175 &RendererOverridesHandler::PageSetColorPickerEnabled,
176 base::Unretained(this)));
177 RegisterCommandHandler(
178 devtools::Input::emulateTouchFromMouseEvent::kName,
179 base::Bind(
180 &RendererOverridesHandler::InputEmulateTouchFromMouseEvent,
181 base::Unretained(this)));
182 mouse_event_callback_ = base::Bind(
183 &RendererOverridesHandler::HandleMouseEvent,
184 base::Unretained(this));
187 RendererOverridesHandler::~RendererOverridesHandler() {}
189 void RendererOverridesHandler::OnClientDetached() {
190 touch_emulation_enabled_ = false;
191 screencast_command_ = NULL;
192 UpdateTouchEventEmulationState();
193 SetColorPickerEnabled(false);
196 void RendererOverridesHandler::OnSwapCompositorFrame(
197 const cc::CompositorFrameMetadata& frame_metadata) {
198 last_compositor_frame_metadata_ = frame_metadata;
199 has_last_compositor_frame_metadata_ = true;
201 if (screencast_command_.get())
202 InnerSwapCompositorFrame();
203 if (color_picker_enabled_)
204 UpdateColorPickerFrame();
207 void RendererOverridesHandler::OnVisibilityChanged(bool visible) {
208 if (!screencast_command_.get())
209 return;
210 NotifyScreencastVisibility(visible);
213 void RendererOverridesHandler::SetRenderViewHost(
214 RenderViewHostImpl* host) {
215 host_ = host;
216 if (!host)
217 return;
218 UpdateTouchEventEmulationState();
219 if (color_picker_enabled_)
220 host->AddMouseEventCallback(mouse_event_callback_);
223 void RendererOverridesHandler::ClearRenderViewHost() {
224 if (host_)
225 host_->RemoveMouseEventCallback(mouse_event_callback_);
226 host_ = NULL;
227 ResetColorPickerFrame();
230 void RendererOverridesHandler::DidAttachInterstitialPage() {
231 if (page_domain_enabled_)
232 SendNotification(devtools::Page::interstitialShown::kName, NULL);
235 void RendererOverridesHandler::DidDetachInterstitialPage() {
236 if (page_domain_enabled_)
237 SendNotification(devtools::Page::interstitialHidden::kName, NULL);
240 void RendererOverridesHandler::InnerSwapCompositorFrame() {
241 if ((base::TimeTicks::Now() - last_frame_time_).InMilliseconds() <
242 kFrameRateThresholdMs) {
243 return;
246 if (!host_ || !host_->GetView())
247 return;
249 last_frame_time_ = base::TimeTicks::Now();
251 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
252 host_->GetView());
253 // TODO(vkuzkokov): do not use previous frame metadata.
254 cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_;
256 gfx::SizeF viewport_size_dip = gfx::ScaleSize(
257 metadata.scrollable_viewport_size, metadata.page_scale_factor);
258 gfx::SizeF screen_size_dip = gfx::ScaleSize(view->GetPhysicalBackingSize(),
259 1 / metadata.device_scale_factor);
261 std::string format;
262 int quality = kDefaultScreenshotQuality;
263 double scale = 1;
264 double max_width = -1;
265 double max_height = -1;
266 base::DictionaryValue* params = screencast_command_->params();
267 if (params) {
268 params->GetString(devtools::Page::startScreencast::kParamFormat,
269 &format);
270 params->GetInteger(devtools::Page::startScreencast::kParamQuality,
271 &quality);
272 params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth,
273 &max_width);
274 params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight,
275 &max_height);
278 blink::WebScreenInfo screen_info;
279 view->GetScreenInfo(&screen_info);
280 double device_scale_factor = screen_info.deviceScaleFactor;
282 if (max_width > 0) {
283 double max_width_dip = max_width / device_scale_factor;
284 scale = std::min(scale, max_width_dip / screen_size_dip.width());
286 if (max_height > 0) {
287 double max_height_dip = max_height / device_scale_factor;
288 scale = std::min(scale, max_height_dip / screen_size_dip.height());
291 if (format.empty())
292 format = kPng;
293 if (quality < 0 || quality > 100)
294 quality = kDefaultScreenshotQuality;
295 if (scale <= 0)
296 scale = 0.1;
298 gfx::Size snapshot_size_dip(gfx::ToRoundedSize(
299 gfx::ScaleSize(viewport_size_dip, scale)));
301 if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) {
302 gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip));
303 view->CopyFromCompositingSurface(
304 viewport_bounds_dip, snapshot_size_dip,
305 base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured,
306 weak_factory_.GetWeakPtr(),
307 format, quality, last_compositor_frame_metadata_),
308 kN32_SkColorType);
312 // DOM agent handlers --------------------------------------------------------
314 scoped_refptr<DevToolsProtocol::Response>
315 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
316 scoped_refptr<DevToolsProtocol::Command> command) {
317 base::DictionaryValue* params = command->params();
318 base::ListValue* file_list = NULL;
319 const char* param =
320 devtools::DOM::setFileInputFiles::kParamFiles;
321 if (!params || !params->GetList(param, &file_list))
322 return command->InvalidParamResponse(param);
323 if (!host_)
324 return NULL;
326 for (size_t i = 0; i < file_list->GetSize(); ++i) {
327 base::FilePath::StringType file;
328 if (!file_list->GetString(i, &file))
329 return command->InvalidParamResponse(param);
330 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
331 host_->GetProcess()->GetID(), base::FilePath(file));
333 return NULL;
337 // Network agent handlers ----------------------------------------------------
339 scoped_refptr<DevToolsProtocol::Response>
340 RendererOverridesHandler::CanEmulateNetworkConditions(
341 scoped_refptr<DevToolsProtocol::Command> command) {
342 base::DictionaryValue* result = new base::DictionaryValue();
343 result->SetBoolean(devtools::kResult, false);
344 return command->SuccessResponse(result);
347 scoped_refptr<DevToolsProtocol::Response>
348 RendererOverridesHandler::ClearBrowserCache(
349 scoped_refptr<DevToolsProtocol::Command> command) {
350 GetContentClient()->browser()->ClearCache(host_);
351 return command->SuccessResponse(NULL);
354 scoped_refptr<DevToolsProtocol::Response>
355 RendererOverridesHandler::ClearBrowserCookies(
356 scoped_refptr<DevToolsProtocol::Command> command) {
357 GetContentClient()->browser()->ClearCookies(host_);
358 return command->SuccessResponse(NULL);
362 // Page agent handlers -------------------------------------------------------
364 scoped_refptr<DevToolsProtocol::Response>
365 RendererOverridesHandler::PageEnable(
366 scoped_refptr<DevToolsProtocol::Command> command) {
367 page_domain_enabled_ = true;
368 // Fall through to the renderer.
369 return NULL;
372 scoped_refptr<DevToolsProtocol::Response>
373 RendererOverridesHandler::PageDisable(
374 scoped_refptr<DevToolsProtocol::Command> command) {
375 page_domain_enabled_ = false;
376 OnClientDetached();
377 // Fall through to the renderer.
378 return NULL;
381 scoped_refptr<DevToolsProtocol::Response>
382 RendererOverridesHandler::PageHandleJavaScriptDialog(
383 scoped_refptr<DevToolsProtocol::Command> command) {
384 base::DictionaryValue* params = command->params();
385 const char* paramAccept =
386 devtools::Page::handleJavaScriptDialog::kParamAccept;
387 bool accept = false;
388 if (!params || !params->GetBoolean(paramAccept, &accept))
389 return command->InvalidParamResponse(paramAccept);
390 base::string16 prompt_override;
391 base::string16* prompt_override_ptr = &prompt_override;
392 if (!params || !params->GetString(
393 devtools::Page::handleJavaScriptDialog::kParamPromptText,
394 prompt_override_ptr)) {
395 prompt_override_ptr = NULL;
398 if (!host_)
399 return command->InternalErrorResponse("Could not connect to view");
401 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
402 if (web_contents) {
403 JavaScriptDialogManager* manager =
404 web_contents->GetDelegate()->GetJavaScriptDialogManager();
405 if (manager && manager->HandleJavaScriptDialog(
406 web_contents, accept, prompt_override_ptr)) {
407 return command->SuccessResponse(new base::DictionaryValue());
410 return command->InternalErrorResponse("No JavaScript dialog to handle");
413 scoped_refptr<DevToolsProtocol::Response>
414 RendererOverridesHandler::PageNavigate(
415 scoped_refptr<DevToolsProtocol::Command> command) {
416 base::DictionaryValue* params = command->params();
417 std::string url;
418 const char* param = devtools::Page::navigate::kParamUrl;
419 if (!params || !params->GetString(param, &url))
420 return command->InvalidParamResponse(param);
422 GURL gurl(url);
423 if (!gurl.is_valid())
424 return command->InternalErrorResponse("Cannot navigate to invalid URL");
426 if (!host_)
427 return command->InternalErrorResponse("Could not connect to view");
429 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
430 if (web_contents) {
431 web_contents->GetController()
432 .LoadURL(gurl, Referrer(), PAGE_TRANSITION_TYPED, std::string());
433 // Fall through into the renderer.
434 return NULL;
437 return command->InternalErrorResponse("No WebContents to navigate");
440 scoped_refptr<DevToolsProtocol::Response>
441 RendererOverridesHandler::PageReload(
442 scoped_refptr<DevToolsProtocol::Command> command) {
443 if (!host_)
444 return command->InternalErrorResponse("Could not connect to view");
446 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
447 if (web_contents) {
448 // Override only if it is crashed.
449 if (!web_contents->IsCrashed())
450 return NULL;
452 web_contents->GetController().Reload(false);
453 return command->SuccessResponse(NULL);
455 return command->InternalErrorResponse("No WebContents to reload");
458 scoped_refptr<DevToolsProtocol::Response>
459 RendererOverridesHandler::PageGetNavigationHistory(
460 scoped_refptr<DevToolsProtocol::Command> command) {
461 if (!host_)
462 return command->InternalErrorResponse("Could not connect to view");
463 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
464 if (web_contents) {
465 base::DictionaryValue* result = new base::DictionaryValue();
466 NavigationController& controller = web_contents->GetController();
467 result->SetInteger(
468 devtools::Page::getNavigationHistory::kResponseCurrentIndex,
469 controller.GetCurrentEntryIndex());
470 base::ListValue* entries = new base::ListValue();
471 for (int i = 0; i != controller.GetEntryCount(); ++i) {
472 const NavigationEntry* entry = controller.GetEntryAtIndex(i);
473 base::DictionaryValue* entry_value = new base::DictionaryValue();
474 entry_value->SetInteger(
475 devtools::Page::NavigationEntry::kParamId,
476 entry->GetUniqueID());
477 entry_value->SetString(
478 devtools::Page::NavigationEntry::kParamUrl,
479 entry->GetURL().spec());
480 entry_value->SetString(
481 devtools::Page::NavigationEntry::kParamTitle,
482 entry->GetTitle());
483 entries->Append(entry_value);
485 result->Set(
486 devtools::Page::getNavigationHistory::kResponseEntries,
487 entries);
488 return command->SuccessResponse(result);
490 return command->InternalErrorResponse("No WebContents to navigate");
493 scoped_refptr<DevToolsProtocol::Response>
494 RendererOverridesHandler::PageNavigateToHistoryEntry(
495 scoped_refptr<DevToolsProtocol::Command> command) {
496 base::DictionaryValue* params = command->params();
497 const char* param = devtools::Page::navigateToHistoryEntry::kParamEntryId;
498 int entry_id = 0;
499 if (!params || !params->GetInteger(param, &entry_id)) {
500 return command->InvalidParamResponse(param);
503 if (!host_)
504 return command->InternalErrorResponse("Could not connect to view");
506 WebContents* web_contents = WebContents::FromRenderViewHost(host_);
507 if (web_contents) {
508 NavigationController& controller = web_contents->GetController();
509 for (int i = 0; i != controller.GetEntryCount(); ++i) {
510 if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) {
511 controller.GoToIndex(i);
512 return command->SuccessResponse(new base::DictionaryValue());
515 return command->InvalidParamResponse(param);
517 return command->InternalErrorResponse("No WebContents to navigate");
520 scoped_refptr<DevToolsProtocol::Response>
521 RendererOverridesHandler::PageCaptureScreenshot(
522 scoped_refptr<DevToolsProtocol::Command> command) {
523 if (!host_ || !host_->GetView())
524 return command->InternalErrorResponse("Could not connect to view");
526 host_->GetSnapshotFromBrowser(
527 base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
528 weak_factory_.GetWeakPtr(), command));
529 return command->AsyncResponsePromise();
532 void RendererOverridesHandler::ScreenshotCaptured(
533 scoped_refptr<DevToolsProtocol::Command> command,
534 const unsigned char* png_data,
535 size_t png_size) {
536 if (!png_data || !png_size) {
537 SendAsyncResponse(
538 command->InternalErrorResponse("Unable to capture screenshot"));
539 return;
542 std::string base_64_data;
543 base::Base64Encode(
544 base::StringPiece(reinterpret_cast<const char*>(png_data), png_size),
545 &base_64_data);
547 base::DictionaryValue* response = new base::DictionaryValue();
548 response->SetString(devtools::Page::screencastFrame::kParamData,
549 base_64_data);
551 SendAsyncResponse(command->SuccessResponse(response));
554 scoped_refptr<DevToolsProtocol::Response>
555 RendererOverridesHandler::PageSetTouchEmulationEnabled(
556 scoped_refptr<DevToolsProtocol::Command> command) {
557 base::DictionaryValue* params = command->params();
558 bool enabled = false;
559 if (!params || !params->GetBoolean(
560 devtools::Page::setTouchEmulationEnabled::kParamEnabled,
561 &enabled)) {
562 // Pass to renderer.
563 return NULL;
566 touch_emulation_enabled_ = enabled;
567 UpdateTouchEventEmulationState();
569 // Pass to renderer.
570 return NULL;
573 scoped_refptr<DevToolsProtocol::Response>
574 RendererOverridesHandler::PageCanEmulate(
575 scoped_refptr<DevToolsProtocol::Command> command) {
576 base::DictionaryValue* result = new base::DictionaryValue();
577 #if defined(OS_ANDROID)
578 result->SetBoolean(devtools::kResult, false);
579 #else
580 if (WebContents* web_contents = WebContents::FromRenderViewHost(host_)) {
581 result->SetBoolean(
582 devtools::kResult,
583 !web_contents->GetVisibleURL().SchemeIs(kChromeDevToolsScheme));
584 } else {
585 result->SetBoolean(devtools::kResult, true);
587 #endif // defined(OS_ANDROID)
588 return command->SuccessResponse(result);
591 scoped_refptr<DevToolsProtocol::Response>
592 RendererOverridesHandler::PageCanScreencast(
593 scoped_refptr<DevToolsProtocol::Command> command) {
594 base::DictionaryValue* result = new base::DictionaryValue();
595 #if defined(OS_ANDROID)
596 result->SetBoolean(devtools::kResult, true);
597 #else
598 result->SetBoolean(devtools::kResult, false);
599 #endif // defined(OS_ANDROID)
600 return command->SuccessResponse(result);
603 scoped_refptr<DevToolsProtocol::Response>
604 RendererOverridesHandler::PageStartScreencast(
605 scoped_refptr<DevToolsProtocol::Command> command) {
606 screencast_command_ = command;
607 UpdateTouchEventEmulationState();
608 if (!host_)
609 return command->InternalErrorResponse("Could not connect to view");
610 bool visible = !host_->is_hidden();
611 NotifyScreencastVisibility(visible);
612 if (visible) {
613 if (has_last_compositor_frame_metadata_)
614 InnerSwapCompositorFrame();
615 else
616 host_->Send(new ViewMsg_ForceRedraw(host_->GetRoutingID(), 0));
618 return command->SuccessResponse(NULL);
621 scoped_refptr<DevToolsProtocol::Response>
622 RendererOverridesHandler::PageStopScreencast(
623 scoped_refptr<DevToolsProtocol::Command> command) {
624 last_frame_time_ = base::TimeTicks();
625 screencast_command_ = NULL;
626 UpdateTouchEventEmulationState();
627 return command->SuccessResponse(NULL);
630 void RendererOverridesHandler::ScreencastFrameCaptured(
631 const std::string& format,
632 int quality,
633 const cc::CompositorFrameMetadata& metadata,
634 bool success,
635 const SkBitmap& bitmap) {
636 if (!success) {
637 if (capture_retry_count_) {
638 --capture_retry_count_;
639 base::MessageLoop::current()->PostDelayedTask(
640 FROM_HERE,
641 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame,
642 weak_factory_.GetWeakPtr()),
643 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs));
645 return;
648 std::vector<unsigned char> data;
649 SkAutoLockPixels lock_image(bitmap);
650 bool encoded;
651 if (format == kPng) {
652 encoded = gfx::PNGCodec::Encode(
653 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
654 gfx::PNGCodec::FORMAT_SkBitmap,
655 gfx::Size(bitmap.width(), bitmap.height()),
656 bitmap.width() * bitmap.bytesPerPixel(),
657 false, std::vector<gfx::PNGCodec::Comment>(), &data);
658 } else if (format == kJpeg) {
659 encoded = gfx::JPEGCodec::Encode(
660 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
661 gfx::JPEGCodec::FORMAT_SkBitmap,
662 bitmap.width(),
663 bitmap.height(),
664 bitmap.width() * bitmap.bytesPerPixel(),
665 quality, &data);
666 } else {
667 encoded = false;
670 if (!encoded)
671 return;
673 std::string base_64_data;
674 base::Base64Encode(
675 base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
676 &base_64_data);
678 base::DictionaryValue* response = new base::DictionaryValue();
679 response->SetString(devtools::Page::screencastFrame::kParamData,
680 base_64_data);
682 // Consider metadata empty in case it has no device scale factor.
683 if (metadata.device_scale_factor != 0) {
684 base::DictionaryValue* response_metadata = new base::DictionaryValue();
686 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
687 host_->GetView());
688 if (!view)
689 return;
691 gfx::SizeF viewport_size_dip = gfx::ScaleSize(
692 metadata.scrollable_viewport_size, metadata.page_scale_factor);
693 gfx::SizeF screen_size_dip = gfx::ScaleSize(
694 view->GetPhysicalBackingSize(), 1 / metadata.device_scale_factor);
696 response_metadata->SetDouble(
697 devtools::Page::ScreencastFrameMetadata::kParamDeviceScaleFactor,
698 metadata.device_scale_factor);
699 response_metadata->SetDouble(
700 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactor,
701 metadata.page_scale_factor);
702 response_metadata->SetDouble(
703 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMin,
704 metadata.min_page_scale_factor);
705 response_metadata->SetDouble(
706 devtools::Page::ScreencastFrameMetadata::kParamPageScaleFactorMax,
707 metadata.max_page_scale_factor);
708 response_metadata->SetDouble(
709 devtools::Page::ScreencastFrameMetadata::kParamOffsetTop,
710 metadata.location_bar_content_translation.y());
711 response_metadata->SetDouble(
712 devtools::Page::ScreencastFrameMetadata::kParamOffsetBottom,
713 screen_size_dip.height() -
714 metadata.location_bar_content_translation.y() -
715 viewport_size_dip.height());
717 base::DictionaryValue* viewport = new base::DictionaryValue();
718 viewport->SetDouble(devtools::DOM::Rect::kParamX,
719 metadata.root_scroll_offset.x());
720 viewport->SetDouble(devtools::DOM::Rect::kParamY,
721 metadata.root_scroll_offset.y());
722 viewport->SetDouble(devtools::DOM::Rect::kParamWidth,
723 metadata.scrollable_viewport_size.width());
724 viewport->SetDouble(devtools::DOM::Rect::kParamHeight,
725 metadata.scrollable_viewport_size.height());
726 response_metadata->Set(
727 devtools::Page::ScreencastFrameMetadata::kParamViewport, viewport);
729 response_metadata->SetDouble(
730 devtools::Page::ScreencastFrameMetadata::kParamDeviceWidth,
731 screen_size_dip.width());
732 response_metadata->SetDouble(
733 devtools::Page::ScreencastFrameMetadata::kParamDeviceHeight,
734 screen_size_dip.height());
735 response_metadata->SetDouble(
736 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetX,
737 metadata.root_scroll_offset.x());
738 response_metadata->SetDouble(
739 devtools::Page::ScreencastFrameMetadata::kParamScrollOffsetY,
740 metadata.root_scroll_offset.y());
742 response->Set(devtools::Page::screencastFrame::kParamMetadata,
743 response_metadata);
746 SendNotification(devtools::Page::screencastFrame::kName, response);
749 // Quota and Usage ------------------------------------------
751 namespace {
753 typedef base::Callback<void(scoped_ptr<base::DictionaryValue>)>
754 ResponseCallback;
756 void QueryUsageAndQuotaCompletedOnIOThread(
757 scoped_ptr<base::DictionaryValue> quota,
758 scoped_ptr<base::DictionaryValue> usage,
759 ResponseCallback callback) {
761 scoped_ptr<base::DictionaryValue> response_data(new base::DictionaryValue);
762 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseQuota,
763 quota.release());
764 response_data->Set(devtools::Page::queryUsageAndQuota::kResponseUsage,
765 usage.release());
767 BrowserThread::PostTask(
768 BrowserThread::UI, FROM_HERE,
769 base::Bind(callback, base::Passed(&response_data)));
772 void DidGetHostUsage(
773 base::ListValue* list,
774 const std::string& client_id,
775 const base::Closure& barrier,
776 int64 value) {
777 base::DictionaryValue* usage_item = new base::DictionaryValue;
778 usage_item->SetString(devtools::Page::UsageItem::kParamId, client_id);
779 usage_item->SetDouble(devtools::Page::UsageItem::kParamValue, value);
780 list->Append(usage_item);
781 barrier.Run();
784 void DidGetQuotaValue(base::DictionaryValue* dictionary,
785 const std::string& item_name,
786 const base::Closure& barrier,
787 storage::QuotaStatusCode status,
788 int64 value) {
789 if (status == storage::kQuotaStatusOk)
790 dictionary->SetDouble(item_name, value);
791 barrier.Run();
794 void DidGetUsageAndQuotaForWebApps(base::DictionaryValue* quota,
795 const std::string& item_name,
796 const base::Closure& barrier,
797 storage::QuotaStatusCode status,
798 int64 used_bytes,
799 int64 quota_in_bytes) {
800 if (status == storage::kQuotaStatusOk)
801 quota->SetDouble(item_name, quota_in_bytes);
802 barrier.Run();
805 std::string GetStorageTypeName(storage::StorageType type) {
806 switch (type) {
807 case storage::kStorageTypeTemporary:
808 return devtools::Page::Usage::kParamTemporary;
809 case storage::kStorageTypePersistent:
810 return devtools::Page::Usage::kParamPersistent;
811 case storage::kStorageTypeSyncable:
812 return devtools::Page::Usage::kParamSyncable;
813 case storage::kStorageTypeQuotaNotManaged:
814 case storage::kStorageTypeUnknown:
815 NOTREACHED();
817 return "";
820 std::string GetQuotaClientName(storage::QuotaClient::ID id) {
821 switch (id) {
822 case storage::QuotaClient::kFileSystem:
823 return devtools::Page::UsageItem::Id::kEnumFilesystem;
824 case storage::QuotaClient::kDatabase:
825 return devtools::Page::UsageItem::Id::kEnumDatabase;
826 case storage::QuotaClient::kAppcache:
827 return devtools::Page::UsageItem::Id::kEnumAppcache;
828 case storage::QuotaClient::kIndexedDatabase:
829 return devtools::Page::UsageItem::Id::kEnumIndexeddatabase;
830 default:
831 NOTREACHED();
833 return "";
836 void QueryUsageAndQuotaOnIOThread(
837 scoped_refptr<storage::QuotaManager> quota_manager,
838 const GURL& security_origin,
839 const ResponseCallback& callback) {
840 scoped_ptr<base::DictionaryValue> quota(new base::DictionaryValue);
841 scoped_ptr<base::DictionaryValue> usage(new base::DictionaryValue);
843 static storage::QuotaClient::ID kQuotaClients[] = {
844 storage::QuotaClient::kFileSystem, storage::QuotaClient::kDatabase,
845 storage::QuotaClient::kAppcache, storage::QuotaClient::kIndexedDatabase};
847 static const size_t kStorageTypeCount = storage::kStorageTypeUnknown;
848 std::map<storage::StorageType, base::ListValue*> storage_type_lists;
850 for (size_t i = 0; i != kStorageTypeCount; i++) {
851 const storage::StorageType type = static_cast<storage::StorageType>(i);
852 if (type == storage::kStorageTypeQuotaNotManaged)
853 continue;
854 storage_type_lists[type] = new base::ListValue;
855 usage->Set(GetStorageTypeName(type), storage_type_lists[type]);
858 const int kExpectedResults =
859 2 + arraysize(kQuotaClients) * storage_type_lists.size();
860 base::DictionaryValue* quota_raw_ptr = quota.get();
862 // Takes ownership on usage and quota.
863 base::Closure barrier = BarrierClosure(
864 kExpectedResults,
865 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread,
866 base::Passed(&quota),
867 base::Passed(&usage),
868 callback));
869 std::string host = net::GetHostOrSpecFromURL(security_origin);
871 quota_manager->GetUsageAndQuotaForWebApps(
872 security_origin,
873 storage::kStorageTypeTemporary,
874 base::Bind(&DidGetUsageAndQuotaForWebApps,
875 quota_raw_ptr,
876 std::string(devtools::Page::Quota::kParamTemporary),
877 barrier));
879 quota_manager->GetPersistentHostQuota(
880 host,
881 base::Bind(&DidGetQuotaValue, quota_raw_ptr,
882 std::string(devtools::Page::Quota::kParamPersistent),
883 barrier));
885 for (size_t i = 0; i != arraysize(kQuotaClients); i++) {
886 std::map<storage::StorageType, base::ListValue*>::const_iterator iter;
887 for (iter = storage_type_lists.begin();
888 iter != storage_type_lists.end(); ++iter) {
889 const storage::StorageType type = (*iter).first;
890 if (!quota_manager->IsTrackingHostUsage(type, kQuotaClients[i])) {
891 barrier.Run();
892 continue;
894 quota_manager->GetHostUsage(
895 host, type, kQuotaClients[i],
896 base::Bind(&DidGetHostUsage, (*iter).second,
897 GetQuotaClientName(kQuotaClients[i]),
898 barrier));
903 } // namespace
905 scoped_refptr<DevToolsProtocol::Response>
906 RendererOverridesHandler::PageQueryUsageAndQuota(
907 scoped_refptr<DevToolsProtocol::Command> command) {
908 base::DictionaryValue* params = command->params();
909 std::string security_origin;
910 if (!params || !params->GetString(
911 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin,
912 &security_origin)) {
913 return command->InvalidParamResponse(
914 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin);
917 ResponseCallback callback = base::Bind(
918 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted,
919 weak_factory_.GetWeakPtr(),
920 command);
922 if (!host_)
923 return command->InternalErrorResponse("Could not connect to view");
925 scoped_refptr<storage::QuotaManager> quota_manager =
926 host_->GetProcess()->GetStoragePartition()->GetQuotaManager();
928 BrowserThread::PostTask(
929 BrowserThread::IO, FROM_HERE,
930 base::Bind(
931 &QueryUsageAndQuotaOnIOThread,
932 quota_manager,
933 GURL(security_origin),
934 callback));
936 return command->AsyncResponsePromise();
939 void RendererOverridesHandler::PageQueryUsageAndQuotaCompleted(
940 scoped_refptr<DevToolsProtocol::Command> command,
941 scoped_ptr<base::DictionaryValue> response_data) {
942 SendAsyncResponse(command->SuccessResponse(response_data.release()));
945 void RendererOverridesHandler::NotifyScreencastVisibility(bool visible) {
946 if (visible)
947 capture_retry_count_ = kCaptureRetryLimit;
948 base::DictionaryValue* params = new base::DictionaryValue();
949 params->SetBoolean(
950 devtools::Page::screencastVisibilityChanged::kParamVisible, visible);
951 SendNotification(
952 devtools::Page::screencastVisibilityChanged::kName, params);
955 scoped_refptr<DevToolsProtocol::Response>
956 RendererOverridesHandler::PageSetColorPickerEnabled(
957 scoped_refptr<DevToolsProtocol::Command> command) {
958 base::DictionaryValue* params = command->params();
959 bool color_picker_enabled = false;
960 if (!params || !params->GetBoolean(
961 devtools::Page::setColorPickerEnabled::kParamEnabled,
962 &color_picker_enabled)) {
963 return command->InvalidParamResponse(
964 devtools::Page::setColorPickerEnabled::kParamEnabled);
967 SetColorPickerEnabled(color_picker_enabled);
968 return command->SuccessResponse(NULL);
971 void RendererOverridesHandler::SetColorPickerEnabled(bool enabled) {
972 if (color_picker_enabled_ == enabled)
973 return;
975 color_picker_enabled_ = enabled;
977 if (!host_)
978 return;
980 if (enabled) {
981 host_->AddMouseEventCallback(mouse_event_callback_);
982 UpdateColorPickerFrame();
983 } else {
984 host_->RemoveMouseEventCallback(mouse_event_callback_);
985 ResetColorPickerFrame();
987 WebCursor pointer_cursor;
988 WebCursor::CursorInfo cursor_info;
989 cursor_info.type = blink::WebCursorInfo::TypePointer;
990 pointer_cursor.InitFromCursorInfo(cursor_info);
991 host_->SetCursor(pointer_cursor);
995 void RendererOverridesHandler::UpdateColorPickerFrame() {
996 if (!host_)
997 return;
998 RenderWidgetHostViewBase* view =
999 static_cast<RenderWidgetHostViewBase*>(host_->GetView());
1000 if (!view)
1001 return;
1003 gfx::Size size = view->GetViewBounds().size();
1004 view->CopyFromCompositingSurface(
1005 gfx::Rect(size), size,
1006 base::Bind(&RendererOverridesHandler::ColorPickerFrameUpdated,
1007 weak_factory_.GetWeakPtr()),
1008 kN32_SkColorType);
1011 void RendererOverridesHandler::ResetColorPickerFrame() {
1012 color_picker_frame_.reset();
1013 last_cursor_x_ = -1;
1014 last_cursor_y_ = -1;
1017 void RendererOverridesHandler::ColorPickerFrameUpdated(
1018 bool succeeded,
1019 const SkBitmap& bitmap) {
1020 if (!color_picker_enabled_)
1021 return;
1023 if (succeeded) {
1024 color_picker_frame_ = bitmap;
1025 UpdateColorPickerCursor();
1029 bool RendererOverridesHandler::HandleMouseEvent(
1030 const blink::WebMouseEvent& event) {
1031 last_cursor_x_ = event.x;
1032 last_cursor_y_ = event.y;
1033 if (color_picker_frame_.drawsNothing())
1034 return true;
1036 if (event.button == blink::WebMouseEvent::ButtonLeft &&
1037 event.type == blink::WebInputEvent::MouseDown) {
1038 if (last_cursor_x_ < 0 || last_cursor_x_ >= color_picker_frame_.width() ||
1039 last_cursor_y_ < 0 || last_cursor_y_ >= color_picker_frame_.height()) {
1040 return true;
1043 SkAutoLockPixels lock_image(color_picker_frame_);
1044 SkColor color = color_picker_frame_.getColor(last_cursor_x_,
1045 last_cursor_y_);
1046 base::DictionaryValue* color_dict = new base::DictionaryValue();
1047 color_dict->SetInteger("r", SkColorGetR(color));
1048 color_dict->SetInteger("g", SkColorGetG(color));
1049 color_dict->SetInteger("b", SkColorGetB(color));
1050 color_dict->SetInteger("a", SkColorGetA(color));
1051 base::DictionaryValue* response = new base::DictionaryValue();
1052 response->Set(devtools::Page::colorPicked::kParamColor, color_dict);
1053 SendNotification(devtools::Page::colorPicked::kName, response);
1055 UpdateColorPickerCursor();
1056 return true;
1059 void RendererOverridesHandler::UpdateColorPickerCursor() {
1060 if (!host_ || color_picker_frame_.drawsNothing())
1061 return;
1063 if (last_cursor_x_ < 0 || last_cursor_x_ >= color_picker_frame_.width() ||
1064 last_cursor_y_ < 0 || last_cursor_y_ >= color_picker_frame_.height()) {
1065 return;
1068 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
1069 host_->GetView());
1070 if (!view)
1071 return;
1073 // Due to platform limitations, we are using two different cursors
1074 // depending on the platform. Mac and Win have large cursors with two circles
1075 // for original spot and its magnified projection; Linux gets smaller (64 px)
1076 // magnified projection only with centered hotspot.
1077 // Mac Retina requires cursor to be > 120px in order to render smoothly.
1079 #if defined(OS_LINUX)
1080 const float kCursorSize = 63;
1081 const float kDiameter = 63;
1082 const float kHotspotOffset = 32;
1083 const float kHotspotRadius = 0;
1084 const float kPixelSize = 9;
1085 #else
1086 const float kCursorSize = 150;
1087 const float kDiameter = 110;
1088 const float kHotspotOffset = 25;
1089 const float kHotspotRadius = 5;
1090 const float kPixelSize = 10;
1091 #endif
1093 blink::WebScreenInfo screen_info;
1094 view->GetScreenInfo(&screen_info);
1095 double device_scale_factor = screen_info.deviceScaleFactor;
1097 skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(SkCanvas::NewRasterN32(
1098 kCursorSize * device_scale_factor,
1099 kCursorSize * device_scale_factor));
1100 canvas->scale(device_scale_factor, device_scale_factor);
1101 canvas->translate(0.5f, 0.5f);
1103 SkPaint paint;
1105 // Paint original spot with cross.
1106 if (kHotspotRadius) {
1107 paint.setStrokeWidth(1);
1108 paint.setAntiAlias(false);
1109 paint.setColor(SK_ColorDKGRAY);
1110 paint.setStyle(SkPaint::kStroke_Style);
1112 canvas->drawLine(kHotspotOffset, kHotspotOffset - 2 * kHotspotRadius,
1113 kHotspotOffset, kHotspotOffset - kHotspotRadius,
1114 paint);
1115 canvas->drawLine(kHotspotOffset, kHotspotOffset + kHotspotRadius,
1116 kHotspotOffset, kHotspotOffset + 2 * kHotspotRadius,
1117 paint);
1118 canvas->drawLine(kHotspotOffset - 2 * kHotspotRadius, kHotspotOffset,
1119 kHotspotOffset - kHotspotRadius, kHotspotOffset,
1120 paint);
1121 canvas->drawLine(kHotspotOffset + kHotspotRadius, kHotspotOffset,
1122 kHotspotOffset + 2 * kHotspotRadius, kHotspotOffset,
1123 paint);
1125 paint.setStrokeWidth(2);
1126 paint.setAntiAlias(true);
1127 canvas->drawCircle(kHotspotOffset, kHotspotOffset, kHotspotRadius, paint);
1130 // Clip circle for magnified projection.
1131 float padding = (kCursorSize - kDiameter) / 2;
1132 SkPath clip_path;
1133 clip_path.addOval(SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter));
1134 clip_path.close();
1135 canvas->clipPath(clip_path, SkRegion::kIntersect_Op, true);
1137 // Project pixels.
1138 int pixel_count = kDiameter / kPixelSize;
1139 SkRect src_rect = SkRect::MakeXYWH(last_cursor_x_ - pixel_count / 2,
1140 last_cursor_y_ - pixel_count / 2,
1141 pixel_count, pixel_count);
1142 SkRect dst_rect = SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter);
1143 canvas->drawBitmapRectToRect(color_picker_frame_, &src_rect, dst_rect);
1145 // Paint grid.
1146 paint.setStrokeWidth(1);
1147 paint.setAntiAlias(false);
1148 paint.setColor(SK_ColorGRAY);
1149 for (int i = 0; i < pixel_count; ++i) {
1150 canvas->drawLine(padding + i * kPixelSize, padding,
1151 padding + i * kPixelSize, kCursorSize - padding, paint);
1152 canvas->drawLine(padding, padding + i * kPixelSize,
1153 kCursorSize - padding, padding + i * kPixelSize, paint);
1156 // Paint central pixel in red.
1157 SkRect pixel = SkRect::MakeXYWH((kCursorSize - kPixelSize) / 2,
1158 (kCursorSize - kPixelSize) / 2,
1159 kPixelSize, kPixelSize);
1160 paint.setColor(SK_ColorRED);
1161 paint.setStyle(SkPaint::kStroke_Style);
1162 canvas->drawRect(pixel, paint);
1164 // Paint outline.
1165 paint.setStrokeWidth(2);
1166 paint.setColor(SK_ColorDKGRAY);
1167 paint.setAntiAlias(true);
1168 canvas->drawCircle(kCursorSize / 2, kCursorSize / 2, kDiameter / 2, paint);
1170 SkBitmap result;
1171 result.allocN32Pixels(kCursorSize * device_scale_factor,
1172 kCursorSize * device_scale_factor);
1173 canvas->readPixels(&result, 0, 0);
1175 WebCursor cursor;
1176 WebCursor::CursorInfo cursor_info;
1177 cursor_info.type = blink::WebCursorInfo::TypeCustom;
1178 cursor_info.image_scale_factor = device_scale_factor;
1179 cursor_info.custom_image = result;
1180 cursor_info.hotspot =
1181 gfx::Point(kHotspotOffset * device_scale_factor,
1182 kHotspotOffset * device_scale_factor);
1183 #if defined(OS_WIN)
1184 cursor_info.external_handle = 0;
1185 #endif
1187 cursor.InitFromCursorInfo(cursor_info);
1188 DCHECK(host_);
1189 host_->SetCursor(cursor);
1192 // Input agent handlers ------------------------------------------------------
1194 scoped_refptr<DevToolsProtocol::Response>
1195 RendererOverridesHandler::InputEmulateTouchFromMouseEvent(
1196 scoped_refptr<DevToolsProtocol::Command> command) {
1197 if (!screencast_command_.get())
1198 return command->InternalErrorResponse("Screencast should be turned on");
1200 base::DictionaryValue* params = command->params();
1201 if (!params)
1202 return command->NoSuchMethodErrorResponse();
1204 std::string type;
1205 if (!params->GetString(
1206 devtools::Input::emulateTouchFromMouseEvent::kParamType,
1207 &type)) {
1208 return command->InvalidParamResponse(
1209 devtools::Input::emulateTouchFromMouseEvent::kParamType);
1212 blink::WebMouseWheelEvent wheel_event;
1213 blink::WebMouseEvent mouse_event;
1214 blink::WebMouseEvent* event = &mouse_event;
1216 if (type ==
1217 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMousePressed) {
1218 event->type = WebInputEvent::MouseDown;
1219 } else if (type ==
1220 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseReleased) {
1221 event->type = WebInputEvent::MouseUp;
1222 } else if (type ==
1223 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseMoved) {
1224 event->type = WebInputEvent::MouseMove;
1225 } else if (type ==
1226 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseWheel) {
1227 double deltaX = 0;
1228 double deltaY = 0;
1229 if (!params->GetDouble(
1230 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX,
1231 &deltaX)) {
1232 return command->InvalidParamResponse(
1233 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX);
1235 if (!params->GetDouble(
1236 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY,
1237 &deltaY)) {
1238 return command->InvalidParamResponse(
1239 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY);
1241 wheel_event.deltaX = static_cast<float>(deltaX);
1242 wheel_event.deltaY = static_cast<float>(deltaY);
1243 event = &wheel_event;
1244 event->type = WebInputEvent::MouseWheel;
1245 } else {
1246 return command->InvalidParamResponse(
1247 devtools::Input::emulateTouchFromMouseEvent::kParamType);
1250 int modifiers = 0;
1251 if (params->GetInteger(
1252 devtools::Input::emulateTouchFromMouseEvent::kParamModifiers,
1253 &modifiers)) {
1254 if (modifiers & 1)
1255 event->modifiers |= WebInputEvent::AltKey;
1256 if (modifiers & 2)
1257 event->modifiers |= WebInputEvent::ControlKey;
1258 if (modifiers & 4)
1259 event->modifiers |= WebInputEvent::MetaKey;
1260 if (modifiers & 8)
1261 event->modifiers |= WebInputEvent::ShiftKey;
1264 params->GetDouble(
1265 devtools::Input::emulateTouchFromMouseEvent::kParamTimestamp,
1266 &event->timeStampSeconds);
1268 if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamX,
1269 &event->x)) {
1270 return command->InvalidParamResponse(
1271 devtools::Input::emulateTouchFromMouseEvent::kParamX);
1274 if (!params->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamY,
1275 &event->y)) {
1276 return command->InvalidParamResponse(
1277 devtools::Input::emulateTouchFromMouseEvent::kParamY);
1280 event->windowX = event->x;
1281 event->windowY = event->y;
1282 event->globalX = event->x;
1283 event->globalY = event->y;
1285 params->GetInteger(
1286 devtools::Input::emulateTouchFromMouseEvent::kParamClickCount,
1287 &event->clickCount);
1289 std::string button;
1290 if (!params->GetString(
1291 devtools::Input::emulateTouchFromMouseEvent::kParamButton,
1292 &button)) {
1293 return command->InvalidParamResponse(
1294 devtools::Input::emulateTouchFromMouseEvent::kParamButton);
1297 if (button == "none") {
1298 event->button = WebMouseEvent::ButtonNone;
1299 } else if (button == "left") {
1300 event->button = WebMouseEvent::ButtonLeft;
1301 event->modifiers |= WebInputEvent::LeftButtonDown;
1302 } else if (button == "middle") {
1303 event->button = WebMouseEvent::ButtonMiddle;
1304 event->modifiers |= WebInputEvent::MiddleButtonDown;
1305 } else if (button == "right") {
1306 event->button = WebMouseEvent::ButtonRight;
1307 event->modifiers |= WebInputEvent::RightButtonDown;
1308 } else {
1309 return command->InvalidParamResponse(
1310 devtools::Input::emulateTouchFromMouseEvent::kParamButton);
1313 if (!host_)
1314 return command->InternalErrorResponse("Could not connect to view");
1316 if (event->type == WebInputEvent::MouseWheel)
1317 host_->ForwardWheelEvent(wheel_event);
1318 else
1319 host_->ForwardMouseEvent(mouse_event);
1320 return command->SuccessResponse(NULL);
1323 void RendererOverridesHandler::UpdateTouchEventEmulationState() {
1324 if (!host_)
1325 return;
1326 bool enabled = touch_emulation_enabled_ || screencast_command_.get();
1327 host_->SetTouchEventEmulationEnabled(enabled);
1328 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
1329 WebContents::FromRenderViewHost(host_));
1330 if (web_contents)
1331 web_contents->SetForceDisableOverscrollContent(enabled);
1334 } // namespace content