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"
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"
56 #include "webkit/browser/quota/quota_manager.h"
58 using blink::WebGestureEvent
;
59 using blink::WebInputEvent
;
60 using blink::WebMouseEvent
;
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;
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),
83 RegisterCommandHandler(
84 devtools::DOM::setFileInputFiles::kName
,
86 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles
,
87 base::Unretained(this)));
88 RegisterCommandHandler(
89 devtools::Network::canEmulateNetworkConditions::kName
,
91 &RendererOverridesHandler::CanEmulateNetworkConditions
,
92 base::Unretained(this)));
93 RegisterCommandHandler(
94 devtools::Network::clearBrowserCache::kName
,
96 &RendererOverridesHandler::ClearBrowserCache
,
97 base::Unretained(this)));
98 RegisterCommandHandler(
99 devtools::Network::clearBrowserCookies::kName
,
101 &RendererOverridesHandler::ClearBrowserCookies
,
102 base::Unretained(this)));
103 RegisterCommandHandler(
104 devtools::Page::enable::kName
,
106 &RendererOverridesHandler::PageEnable
, base::Unretained(this)));
107 RegisterCommandHandler(
108 devtools::Page::disable::kName
,
110 &RendererOverridesHandler::PageDisable
, base::Unretained(this)));
111 RegisterCommandHandler(
112 devtools::Page::handleJavaScriptDialog::kName
,
114 &RendererOverridesHandler::PageHandleJavaScriptDialog
,
115 base::Unretained(this)));
116 RegisterCommandHandler(
117 devtools::Page::navigate::kName
,
119 &RendererOverridesHandler::PageNavigate
,
120 base::Unretained(this)));
121 RegisterCommandHandler(
122 devtools::Page::reload::kName
,
124 &RendererOverridesHandler::PageReload
,
125 base::Unretained(this)));
126 RegisterCommandHandler(
127 devtools::Page::getNavigationHistory::kName
,
129 &RendererOverridesHandler::PageGetNavigationHistory
,
130 base::Unretained(this)));
131 RegisterCommandHandler(
132 devtools::Page::navigateToHistoryEntry::kName
,
134 &RendererOverridesHandler::PageNavigateToHistoryEntry
,
135 base::Unretained(this)));
136 RegisterCommandHandler(
137 devtools::Page::captureScreenshot::kName
,
139 &RendererOverridesHandler::PageCaptureScreenshot
,
140 base::Unretained(this)));
141 RegisterCommandHandler(
142 devtools::Page::setTouchEmulationEnabled::kName
,
144 &RendererOverridesHandler::PageSetTouchEmulationEnabled
,
145 base::Unretained(this)));
146 RegisterCommandHandler(
147 devtools::Page::canScreencast::kName
,
149 &RendererOverridesHandler::PageCanScreencast
,
150 base::Unretained(this)));
151 RegisterCommandHandler(
152 devtools::Page::startScreencast::kName
,
154 &RendererOverridesHandler::PageStartScreencast
,
155 base::Unretained(this)));
156 RegisterCommandHandler(
157 devtools::Page::stopScreencast::kName
,
159 &RendererOverridesHandler::PageStopScreencast
,
160 base::Unretained(this)));
161 RegisterCommandHandler(
162 devtools::Page::queryUsageAndQuota::kName
,
164 &RendererOverridesHandler::PageQueryUsageAndQuota
,
165 base::Unretained(this)));
166 RegisterCommandHandler(
167 devtools::Page::setColorPickerEnabled::kName
,
169 &RendererOverridesHandler::PageSetColorPickerEnabled
,
170 base::Unretained(this)));
171 RegisterCommandHandler(
172 devtools::Input::emulateTouchFromMouseEvent::kName
,
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_
)
204 NotifyScreencastVisibility(visible
);
207 void RendererOverridesHandler::SetRenderViewHost(
208 RenderViewHostImpl
* host
) {
212 UpdateTouchEventEmulationState();
213 if (color_picker_enabled_
)
214 host
->AddMouseEventCallback(mouse_event_callback_
);
217 void RendererOverridesHandler::ClearRenderViewHost() {
219 host_
->RemoveMouseEventCallback(mouse_event_callback_
);
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
) {
240 if (!host_
|| !host_
->GetView())
243 last_frame_time_
= base::TimeTicks::Now();
245 RenderWidgetHostViewBase
* view
= static_cast<RenderWidgetHostViewBase
*>(
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
);
256 int quality
= kDefaultScreenshotQuality
;
258 double max_width
= -1;
259 double max_height
= -1;
260 base::DictionaryValue
* params
= screencast_command_
->params();
262 params
->GetString(devtools::Page::startScreencast::kParamFormat
,
264 params
->GetInteger(devtools::Page::startScreencast::kParamQuality
,
266 params
->GetDouble(devtools::Page::startScreencast::kParamMaxWidth
,
268 params
->GetDouble(devtools::Page::startScreencast::kParamMaxHeight
,
272 blink::WebScreenInfo screen_info
;
273 view
->GetScreenInfo(&screen_info
);
274 double device_scale_factor
= screen_info
.deviceScaleFactor
;
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());
287 if (quality
< 0 || quality
> 100)
288 quality
= kDefaultScreenshotQuality
;
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_
),
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
;
314 devtools::DOM::setFileInputFiles::kParamFiles
;
315 if (!params
|| !params
->GetList(param
, &file_list
))
316 return command
->InvalidParamResponse(param
);
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
));
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.
366 scoped_refptr
<DevToolsProtocol::Response
>
367 RendererOverridesHandler::PageDisable(
368 scoped_refptr
<DevToolsProtocol::Command
> command
) {
369 page_domain_enabled_
= false;
371 // Fall through to the renderer.
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
;
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
;
393 return command
->InternalErrorResponse("Could not connect to view");
395 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
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();
412 const char* param
= devtools::Page::navigate::kParamUrl
;
413 if (!params
|| !params
->GetString(param
, &url
))
414 return command
->InvalidParamResponse(param
);
417 if (!gurl
.is_valid())
418 return command
->InternalErrorResponse("Cannot navigate to invalid URL");
421 return command
->InternalErrorResponse("Could not connect to view");
423 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
425 web_contents
->GetController()
426 .LoadURL(gurl
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
427 // Fall through into the renderer.
431 return command
->InternalErrorResponse("No WebContents to navigate");
434 scoped_refptr
<DevToolsProtocol::Response
>
435 RendererOverridesHandler::PageReload(
436 scoped_refptr
<DevToolsProtocol::Command
> command
) {
438 return command
->InternalErrorResponse("Could not connect to view");
440 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
442 // Override only if it is crashed.
443 if (!web_contents
->IsCrashed())
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
) {
456 return command
->InternalErrorResponse("Could not connect to view");
457 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
459 base::DictionaryValue
* result
= new base::DictionaryValue();
460 NavigationController
& controller
= web_contents
->GetController();
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
,
477 entries
->Append(entry_value
);
480 devtools::Page::getNavigationHistory::kResponseEntries
,
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
;
493 if (!params
|| !params
->GetInteger(param
, &entry_id
)) {
494 return command
->InvalidParamResponse(param
);
498 return command
->InternalErrorResponse("Could not connect to view");
500 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
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
,
530 if (!png_data
|| !png_size
) {
532 command
->InternalErrorResponse("Unable to capture screenshot"));
536 std::string base_64_data
;
538 base::StringPiece(reinterpret_cast<const char*>(png_data
), png_size
),
541 base::DictionaryValue
* response
= new base::DictionaryValue();
542 response
->SetString(devtools::Page::screencastFrame::kParamData
,
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
,
560 touch_emulation_enabled_
= enabled
;
561 UpdateTouchEventEmulationState();
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);
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();
585 return command
->InternalErrorResponse("Could not connect to view");
586 bool visible
= !host_
->is_hidden();
587 NotifyScreencastVisibility(visible
);
589 if (has_last_compositor_frame_metadata_
)
590 InnerSwapCompositorFrame();
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
,
609 const cc::CompositorFrameMetadata
& metadata
,
611 const SkBitmap
& bitmap
) {
613 if (capture_retry_count_
) {
614 --capture_retry_count_
;
615 base::MessageLoop::current()->PostDelayedTask(
617 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame
,
618 weak_factory_
.GetWeakPtr()),
619 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs
));
624 std::vector
<unsigned char> data
;
625 SkAutoLockPixels
lock_image(bitmap
);
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
,
640 bitmap
.width() * bitmap
.bytesPerPixel(),
649 std::string base_64_data
;
651 base::StringPiece(reinterpret_cast<char*>(&data
[0]), data
.size()),
654 base::DictionaryValue
* response
= new base::DictionaryValue();
655 response
->SetString(devtools::Page::screencastFrame::kParamData
,
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
*>(
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
,
722 SendNotification(devtools::Page::screencastFrame::kName
, response
);
725 // Quota and Usage ------------------------------------------
729 typedef base::Callback
<void(scoped_ptr
<base::DictionaryValue
>)>
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
,
740 response_data
->Set(devtools::Page::queryUsageAndQuota::kResponseUsage
,
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
,
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
);
760 void DidGetQuotaValue(base::DictionaryValue
* dictionary
,
761 const std::string
& item_name
,
762 const base::Closure
& barrier
,
763 storage::QuotaStatusCode status
,
765 if (status
== storage::kQuotaStatusOk
)
766 dictionary
->SetDouble(item_name
, value
);
770 void DidGetUsageAndQuotaForWebApps(base::DictionaryValue
* quota
,
771 const std::string
& item_name
,
772 const base::Closure
& barrier
,
773 storage::QuotaStatusCode status
,
775 int64 quota_in_bytes
) {
776 if (status
== storage::kQuotaStatusOk
)
777 quota
->SetDouble(item_name
, quota_in_bytes
);
781 std::string
GetStorageTypeName(storage::StorageType 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
:
796 std::string
GetQuotaClientName(storage::QuotaClient::ID 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
;
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
)
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(
841 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread
,
842 base::Passed("a
),
843 base::Passed(&usage
),
845 std::string host
= net::GetHostOrSpecFromURL(security_origin
);
847 quota_manager
->GetUsageAndQuotaForWebApps(
849 storage::kStorageTypeTemporary
,
850 base::Bind(&DidGetUsageAndQuotaForWebApps
,
852 std::string(devtools::Page::Quota::kParamTemporary
),
855 quota_manager
->GetPersistentHostQuota(
857 base::Bind(&DidGetQuotaValue
, quota_raw_ptr
,
858 std::string(devtools::Page::Quota::kParamPersistent
),
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
])) {
870 quota_manager
->GetHostUsage(
871 host
, type
, kQuotaClients
[i
],
872 base::Bind(&DidGetHostUsage
, (*iter
).second
,
873 GetQuotaClientName(kQuotaClients
[i
]),
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
,
889 return command
->InvalidParamResponse(
890 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin
);
893 ResponseCallback callback
= base::Bind(
894 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted
,
895 weak_factory_
.GetWeakPtr(),
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
,
907 &QueryUsageAndQuotaOnIOThread
,
909 GURL(security_origin
),
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
) {
923 capture_retry_count_
= kCaptureRetryLimit
;
924 base::DictionaryValue
* params
= new base::DictionaryValue();
926 devtools::Page::screencastVisibilityChanged::kParamVisible
, visible
);
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
)
951 color_picker_enabled_
= enabled
;
957 host_
->AddMouseEventCallback(mouse_event_callback_
);
958 UpdateColorPickerFrame();
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() {
974 RenderWidgetHostViewBase
* view
=
975 static_cast<RenderWidgetHostViewBase
*>(host_
->GetView());
979 gfx::Size size
= view
->GetViewBounds().size();
980 view
->CopyFromCompositingSurface(
981 gfx::Rect(size
), size
,
982 base::Bind(&RendererOverridesHandler::ColorPickerFrameUpdated
,
983 weak_factory_
.GetWeakPtr()),
987 void RendererOverridesHandler::ResetColorPickerFrame() {
988 color_picker_frame_
.reset();
993 void RendererOverridesHandler::ColorPickerFrameUpdated(
995 const SkBitmap
& bitmap
) {
996 if (!color_picker_enabled_
)
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())
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()) {
1019 SkAutoLockPixels
lock_image(color_picker_frame_
);
1020 SkColor color
= color_picker_frame_
.getColor(last_cursor_x_
,
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();
1035 void RendererOverridesHandler::UpdateColorPickerCursor() {
1036 if (!host_
|| color_picker_frame_
.drawsNothing())
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()) {
1044 RenderWidgetHostViewBase
* view
= static_cast<RenderWidgetHostViewBase
*>(
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;
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;
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
);
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
,
1091 canvas
->drawLine(kHotspotOffset
, kHotspotOffset
+ kHotspotRadius
,
1092 kHotspotOffset
, kHotspotOffset
+ 2 * kHotspotRadius
,
1094 canvas
->drawLine(kHotspotOffset
- 2 * kHotspotRadius
, kHotspotOffset
,
1095 kHotspotOffset
- kHotspotRadius
, kHotspotOffset
,
1097 canvas
->drawLine(kHotspotOffset
+ kHotspotRadius
, kHotspotOffset
,
1098 kHotspotOffset
+ 2 * kHotspotRadius
, kHotspotOffset
,
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;
1109 clip_path
.addOval(SkRect::MakeXYWH(padding
, padding
, kDiameter
, kDiameter
));
1111 canvas
->clipPath(clip_path
, SkRegion::kIntersect_Op
, true);
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
);
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
);
1141 paint
.setStrokeWidth(2);
1142 paint
.setColor(SK_ColorDKGRAY
);
1143 paint
.setAntiAlias(true);
1144 canvas
->drawCircle(kCursorSize
/ 2, kCursorSize
/ 2, kDiameter
/ 2, paint
);
1147 result
.allocN32Pixels(kCursorSize
* device_scale_factor
,
1148 kCursorSize
* device_scale_factor
);
1149 canvas
->readPixels(&result
, 0, 0);
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
);
1160 cursor_info
.external_handle
= 0;
1163 cursor
.InitFromCursorInfo(cursor_info
);
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();
1178 return command
->NoSuchMethodErrorResponse();
1181 if (!params
->GetString(
1182 devtools::Input::emulateTouchFromMouseEvent::kParamType
,
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
;
1193 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMousePressed
) {
1194 event
->type
= WebInputEvent::MouseDown
;
1196 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseReleased
) {
1197 event
->type
= WebInputEvent::MouseUp
;
1199 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseMoved
) {
1200 event
->type
= WebInputEvent::MouseMove
;
1202 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseWheel
) {
1205 if (!params
->GetDouble(
1206 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX
,
1208 return command
->InvalidParamResponse(
1209 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX
);
1211 if (!params
->GetDouble(
1212 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY
,
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
;
1222 return command
->InvalidParamResponse(
1223 devtools::Input::emulateTouchFromMouseEvent::kParamType
);
1227 if (params
->GetInteger(
1228 devtools::Input::emulateTouchFromMouseEvent::kParamModifiers
,
1231 event
->modifiers
|= WebInputEvent::AltKey
;
1233 event
->modifiers
|= WebInputEvent::ControlKey
;
1235 event
->modifiers
|= WebInputEvent::MetaKey
;
1237 event
->modifiers
|= WebInputEvent::ShiftKey
;
1241 devtools::Input::emulateTouchFromMouseEvent::kParamTimestamp
,
1242 &event
->timeStampSeconds
);
1244 if (!params
->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamX
,
1246 return command
->InvalidParamResponse(
1247 devtools::Input::emulateTouchFromMouseEvent::kParamX
);
1250 if (!params
->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamY
,
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
;
1262 devtools::Input::emulateTouchFromMouseEvent::kParamClickCount
,
1263 &event
->clickCount
);
1266 if (!params
->GetString(
1267 devtools::Input::emulateTouchFromMouseEvent::kParamButton
,
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
;
1285 return command
->InvalidParamResponse(
1286 devtools::Input::emulateTouchFromMouseEvent::kParamButton
);
1290 return command
->InternalErrorResponse("Could not connect to view");
1292 if (event
->type
== WebInputEvent::MouseWheel
)
1293 host_
->ForwardWheelEvent(wheel_event
);
1295 host_
->ForwardMouseEvent(mouse_event
);
1296 return command
->SuccessResponse(NULL
);
1299 void RendererOverridesHandler::UpdateTouchEventEmulationState() {
1302 bool enabled
= touch_emulation_enabled_
|| screencast_command_
;
1303 host_
->SetTouchEventEmulationEnabled(enabled
);
1304 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
1305 WebContents::FromRenderViewHost(host_
));
1307 web_contents
->SetForceDisableOverscrollContent(enabled
);
1310 } // namespace content