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 "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"
57 #include "webkit/browser/quota/quota_manager.h"
59 using blink::WebGestureEvent
;
60 using blink::WebInputEvent
;
61 using blink::WebMouseEvent
;
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;
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),
84 RegisterCommandHandler(
85 devtools::DOM::setFileInputFiles::kName
,
87 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles
,
88 base::Unretained(this)));
89 RegisterCommandHandler(
90 devtools::Network::canEmulateNetworkConditions::kName
,
92 &RendererOverridesHandler::CanEmulateNetworkConditions
,
93 base::Unretained(this)));
94 RegisterCommandHandler(
95 devtools::Network::clearBrowserCache::kName
,
97 &RendererOverridesHandler::ClearBrowserCache
,
98 base::Unretained(this)));
99 RegisterCommandHandler(
100 devtools::Network::clearBrowserCookies::kName
,
102 &RendererOverridesHandler::ClearBrowserCookies
,
103 base::Unretained(this)));
104 RegisterCommandHandler(
105 devtools::Page::enable::kName
,
107 &RendererOverridesHandler::PageEnable
, base::Unretained(this)));
108 RegisterCommandHandler(
109 devtools::Page::disable::kName
,
111 &RendererOverridesHandler::PageDisable
, base::Unretained(this)));
112 RegisterCommandHandler(
113 devtools::Page::handleJavaScriptDialog::kName
,
115 &RendererOverridesHandler::PageHandleJavaScriptDialog
,
116 base::Unretained(this)));
117 RegisterCommandHandler(
118 devtools::Page::navigate::kName
,
120 &RendererOverridesHandler::PageNavigate
,
121 base::Unretained(this)));
122 RegisterCommandHandler(
123 devtools::Page::reload::kName
,
125 &RendererOverridesHandler::PageReload
,
126 base::Unretained(this)));
127 RegisterCommandHandler(
128 devtools::Page::getNavigationHistory::kName
,
130 &RendererOverridesHandler::PageGetNavigationHistory
,
131 base::Unretained(this)));
132 RegisterCommandHandler(
133 devtools::Page::navigateToHistoryEntry::kName
,
135 &RendererOverridesHandler::PageNavigateToHistoryEntry
,
136 base::Unretained(this)));
137 RegisterCommandHandler(
138 devtools::Page::captureScreenshot::kName
,
140 &RendererOverridesHandler::PageCaptureScreenshot
,
141 base::Unretained(this)));
142 RegisterCommandHandler(
143 devtools::Page::setTouchEmulationEnabled::kName
,
145 &RendererOverridesHandler::PageSetTouchEmulationEnabled
,
146 base::Unretained(this)));
147 RegisterCommandHandler(
148 devtools::Page::canEmulate::kName
,
150 &RendererOverridesHandler::PageCanEmulate
,
151 base::Unretained(this)));
152 RegisterCommandHandler(
153 devtools::Page::canScreencast::kName
,
155 &RendererOverridesHandler::PageCanScreencast
,
156 base::Unretained(this)));
157 RegisterCommandHandler(
158 devtools::Page::startScreencast::kName
,
160 &RendererOverridesHandler::PageStartScreencast
,
161 base::Unretained(this)));
162 RegisterCommandHandler(
163 devtools::Page::stopScreencast::kName
,
165 &RendererOverridesHandler::PageStopScreencast
,
166 base::Unretained(this)));
167 RegisterCommandHandler(
168 devtools::Page::queryUsageAndQuota::kName
,
170 &RendererOverridesHandler::PageQueryUsageAndQuota
,
171 base::Unretained(this)));
172 RegisterCommandHandler(
173 devtools::Page::setColorPickerEnabled::kName
,
175 &RendererOverridesHandler::PageSetColorPickerEnabled
,
176 base::Unretained(this)));
177 RegisterCommandHandler(
178 devtools::Input::emulateTouchFromMouseEvent::kName
,
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())
210 NotifyScreencastVisibility(visible
);
213 void RendererOverridesHandler::SetRenderViewHost(
214 RenderViewHostImpl
* host
) {
218 UpdateTouchEventEmulationState();
219 if (color_picker_enabled_
)
220 host
->AddMouseEventCallback(mouse_event_callback_
);
223 void RendererOverridesHandler::ClearRenderViewHost() {
225 host_
->RemoveMouseEventCallback(mouse_event_callback_
);
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
) {
246 if (!host_
|| !host_
->GetView())
249 last_frame_time_
= base::TimeTicks::Now();
251 RenderWidgetHostViewBase
* view
= static_cast<RenderWidgetHostViewBase
*>(
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
);
262 int quality
= kDefaultScreenshotQuality
;
264 double max_width
= -1;
265 double max_height
= -1;
266 base::DictionaryValue
* params
= screencast_command_
->params();
268 params
->GetString(devtools::Page::startScreencast::kParamFormat
,
270 params
->GetInteger(devtools::Page::startScreencast::kParamQuality
,
272 params
->GetDouble(devtools::Page::startScreencast::kParamMaxWidth
,
274 params
->GetDouble(devtools::Page::startScreencast::kParamMaxHeight
,
278 blink::WebScreenInfo screen_info
;
279 view
->GetScreenInfo(&screen_info
);
280 double device_scale_factor
= screen_info
.deviceScaleFactor
;
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());
293 if (quality
< 0 || quality
> 100)
294 quality
= kDefaultScreenshotQuality
;
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_
),
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
;
320 devtools::DOM::setFileInputFiles::kParamFiles
;
321 if (!params
|| !params
->GetList(param
, &file_list
))
322 return command
->InvalidParamResponse(param
);
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
));
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.
372 scoped_refptr
<DevToolsProtocol::Response
>
373 RendererOverridesHandler::PageDisable(
374 scoped_refptr
<DevToolsProtocol::Command
> command
) {
375 page_domain_enabled_
= false;
377 // Fall through to the renderer.
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
;
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
;
399 return command
->InternalErrorResponse("Could not connect to view");
401 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
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();
418 const char* param
= devtools::Page::navigate::kParamUrl
;
419 if (!params
|| !params
->GetString(param
, &url
))
420 return command
->InvalidParamResponse(param
);
423 if (!gurl
.is_valid())
424 return command
->InternalErrorResponse("Cannot navigate to invalid URL");
427 return command
->InternalErrorResponse("Could not connect to view");
429 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
431 web_contents
->GetController()
432 .LoadURL(gurl
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
433 // Fall through into the renderer.
437 return command
->InternalErrorResponse("No WebContents to navigate");
440 scoped_refptr
<DevToolsProtocol::Response
>
441 RendererOverridesHandler::PageReload(
442 scoped_refptr
<DevToolsProtocol::Command
> command
) {
444 return command
->InternalErrorResponse("Could not connect to view");
446 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
448 // Override only if it is crashed.
449 if (!web_contents
->IsCrashed())
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
) {
462 return command
->InternalErrorResponse("Could not connect to view");
463 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
465 base::DictionaryValue
* result
= new base::DictionaryValue();
466 NavigationController
& controller
= web_contents
->GetController();
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
,
483 entries
->Append(entry_value
);
486 devtools::Page::getNavigationHistory::kResponseEntries
,
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
;
499 if (!params
|| !params
->GetInteger(param
, &entry_id
)) {
500 return command
->InvalidParamResponse(param
);
504 return command
->InternalErrorResponse("Could not connect to view");
506 WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
);
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
,
536 if (!png_data
|| !png_size
) {
538 command
->InternalErrorResponse("Unable to capture screenshot"));
542 std::string base_64_data
;
544 base::StringPiece(reinterpret_cast<const char*>(png_data
), png_size
),
547 base::DictionaryValue
* response
= new base::DictionaryValue();
548 response
->SetString(devtools::Page::screencastFrame::kParamData
,
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
,
566 touch_emulation_enabled_
= enabled
;
567 UpdateTouchEventEmulationState();
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);
580 if (WebContents
* web_contents
= WebContents::FromRenderViewHost(host_
)) {
583 !web_contents
->GetVisibleURL().SchemeIs(kChromeDevToolsScheme
));
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);
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();
609 return command
->InternalErrorResponse("Could not connect to view");
610 bool visible
= !host_
->is_hidden();
611 NotifyScreencastVisibility(visible
);
613 if (has_last_compositor_frame_metadata_
)
614 InnerSwapCompositorFrame();
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
,
633 const cc::CompositorFrameMetadata
& metadata
,
635 const SkBitmap
& bitmap
) {
637 if (capture_retry_count_
) {
638 --capture_retry_count_
;
639 base::MessageLoop::current()->PostDelayedTask(
641 base::Bind(&RendererOverridesHandler::InnerSwapCompositorFrame
,
642 weak_factory_
.GetWeakPtr()),
643 base::TimeDelta::FromMilliseconds(kFrameRateThresholdMs
));
648 std::vector
<unsigned char> data
;
649 SkAutoLockPixels
lock_image(bitmap
);
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
,
664 bitmap
.width() * bitmap
.bytesPerPixel(),
673 std::string base_64_data
;
675 base::StringPiece(reinterpret_cast<char*>(&data
[0]), data
.size()),
678 base::DictionaryValue
* response
= new base::DictionaryValue();
679 response
->SetString(devtools::Page::screencastFrame::kParamData
,
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
*>(
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
,
746 SendNotification(devtools::Page::screencastFrame::kName
, response
);
749 // Quota and Usage ------------------------------------------
753 typedef base::Callback
<void(scoped_ptr
<base::DictionaryValue
>)>
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
,
764 response_data
->Set(devtools::Page::queryUsageAndQuota::kResponseUsage
,
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
,
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
);
784 void DidGetQuotaValue(base::DictionaryValue
* dictionary
,
785 const std::string
& item_name
,
786 const base::Closure
& barrier
,
787 storage::QuotaStatusCode status
,
789 if (status
== storage::kQuotaStatusOk
)
790 dictionary
->SetDouble(item_name
, value
);
794 void DidGetUsageAndQuotaForWebApps(base::DictionaryValue
* quota
,
795 const std::string
& item_name
,
796 const base::Closure
& barrier
,
797 storage::QuotaStatusCode status
,
799 int64 quota_in_bytes
) {
800 if (status
== storage::kQuotaStatusOk
)
801 quota
->SetDouble(item_name
, quota_in_bytes
);
805 std::string
GetStorageTypeName(storage::StorageType 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
:
820 std::string
GetQuotaClientName(storage::QuotaClient::ID 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
;
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
)
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(
865 base::Bind(&QueryUsageAndQuotaCompletedOnIOThread
,
866 base::Passed("a
),
867 base::Passed(&usage
),
869 std::string host
= net::GetHostOrSpecFromURL(security_origin
);
871 quota_manager
->GetUsageAndQuotaForWebApps(
873 storage::kStorageTypeTemporary
,
874 base::Bind(&DidGetUsageAndQuotaForWebApps
,
876 std::string(devtools::Page::Quota::kParamTemporary
),
879 quota_manager
->GetPersistentHostQuota(
881 base::Bind(&DidGetQuotaValue
, quota_raw_ptr
,
882 std::string(devtools::Page::Quota::kParamPersistent
),
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
])) {
894 quota_manager
->GetHostUsage(
895 host
, type
, kQuotaClients
[i
],
896 base::Bind(&DidGetHostUsage
, (*iter
).second
,
897 GetQuotaClientName(kQuotaClients
[i
]),
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
,
913 return command
->InvalidParamResponse(
914 devtools::Page::queryUsageAndQuota::kParamSecurityOrigin
);
917 ResponseCallback callback
= base::Bind(
918 &RendererOverridesHandler::PageQueryUsageAndQuotaCompleted
,
919 weak_factory_
.GetWeakPtr(),
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
,
931 &QueryUsageAndQuotaOnIOThread
,
933 GURL(security_origin
),
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
) {
947 capture_retry_count_
= kCaptureRetryLimit
;
948 base::DictionaryValue
* params
= new base::DictionaryValue();
950 devtools::Page::screencastVisibilityChanged::kParamVisible
, visible
);
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
)
975 color_picker_enabled_
= enabled
;
981 host_
->AddMouseEventCallback(mouse_event_callback_
);
982 UpdateColorPickerFrame();
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() {
998 RenderWidgetHostViewBase
* view
=
999 static_cast<RenderWidgetHostViewBase
*>(host_
->GetView());
1003 gfx::Size size
= view
->GetViewBounds().size();
1004 view
->CopyFromCompositingSurface(
1005 gfx::Rect(size
), size
,
1006 base::Bind(&RendererOverridesHandler::ColorPickerFrameUpdated
,
1007 weak_factory_
.GetWeakPtr()),
1011 void RendererOverridesHandler::ResetColorPickerFrame() {
1012 color_picker_frame_
.reset();
1013 last_cursor_x_
= -1;
1014 last_cursor_y_
= -1;
1017 void RendererOverridesHandler::ColorPickerFrameUpdated(
1019 const SkBitmap
& bitmap
) {
1020 if (!color_picker_enabled_
)
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())
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()) {
1043 SkAutoLockPixels
lock_image(color_picker_frame_
);
1044 SkColor color
= color_picker_frame_
.getColor(last_cursor_x_
,
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();
1059 void RendererOverridesHandler::UpdateColorPickerCursor() {
1060 if (!host_
|| color_picker_frame_
.drawsNothing())
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()) {
1068 RenderWidgetHostViewBase
* view
= static_cast<RenderWidgetHostViewBase
*>(
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;
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;
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
);
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
,
1115 canvas
->drawLine(kHotspotOffset
, kHotspotOffset
+ kHotspotRadius
,
1116 kHotspotOffset
, kHotspotOffset
+ 2 * kHotspotRadius
,
1118 canvas
->drawLine(kHotspotOffset
- 2 * kHotspotRadius
, kHotspotOffset
,
1119 kHotspotOffset
- kHotspotRadius
, kHotspotOffset
,
1121 canvas
->drawLine(kHotspotOffset
+ kHotspotRadius
, kHotspotOffset
,
1122 kHotspotOffset
+ 2 * kHotspotRadius
, kHotspotOffset
,
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;
1133 clip_path
.addOval(SkRect::MakeXYWH(padding
, padding
, kDiameter
, kDiameter
));
1135 canvas
->clipPath(clip_path
, SkRegion::kIntersect_Op
, true);
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
);
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
);
1165 paint
.setStrokeWidth(2);
1166 paint
.setColor(SK_ColorDKGRAY
);
1167 paint
.setAntiAlias(true);
1168 canvas
->drawCircle(kCursorSize
/ 2, kCursorSize
/ 2, kDiameter
/ 2, paint
);
1171 result
.allocN32Pixels(kCursorSize
* device_scale_factor
,
1172 kCursorSize
* device_scale_factor
);
1173 canvas
->readPixels(&result
, 0, 0);
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
);
1184 cursor_info
.external_handle
= 0;
1187 cursor
.InitFromCursorInfo(cursor_info
);
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();
1202 return command
->NoSuchMethodErrorResponse();
1205 if (!params
->GetString(
1206 devtools::Input::emulateTouchFromMouseEvent::kParamType
,
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
;
1217 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMousePressed
) {
1218 event
->type
= WebInputEvent::MouseDown
;
1220 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseReleased
) {
1221 event
->type
= WebInputEvent::MouseUp
;
1223 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseMoved
) {
1224 event
->type
= WebInputEvent::MouseMove
;
1226 devtools::Input::emulateTouchFromMouseEvent::Type::kEnumMouseWheel
) {
1229 if (!params
->GetDouble(
1230 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX
,
1232 return command
->InvalidParamResponse(
1233 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaX
);
1235 if (!params
->GetDouble(
1236 devtools::Input::emulateTouchFromMouseEvent::kParamDeltaY
,
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
;
1246 return command
->InvalidParamResponse(
1247 devtools::Input::emulateTouchFromMouseEvent::kParamType
);
1251 if (params
->GetInteger(
1252 devtools::Input::emulateTouchFromMouseEvent::kParamModifiers
,
1255 event
->modifiers
|= WebInputEvent::AltKey
;
1257 event
->modifiers
|= WebInputEvent::ControlKey
;
1259 event
->modifiers
|= WebInputEvent::MetaKey
;
1261 event
->modifiers
|= WebInputEvent::ShiftKey
;
1265 devtools::Input::emulateTouchFromMouseEvent::kParamTimestamp
,
1266 &event
->timeStampSeconds
);
1268 if (!params
->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamX
,
1270 return command
->InvalidParamResponse(
1271 devtools::Input::emulateTouchFromMouseEvent::kParamX
);
1274 if (!params
->GetInteger(devtools::Input::emulateTouchFromMouseEvent::kParamY
,
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
;
1286 devtools::Input::emulateTouchFromMouseEvent::kParamClickCount
,
1287 &event
->clickCount
);
1290 if (!params
->GetString(
1291 devtools::Input::emulateTouchFromMouseEvent::kParamButton
,
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
;
1309 return command
->InvalidParamResponse(
1310 devtools::Input::emulateTouchFromMouseEvent::kParamButton
);
1314 return command
->InternalErrorResponse("Could not connect to view");
1316 if (event
->type
== WebInputEvent::MouseWheel
)
1317 host_
->ForwardWheelEvent(wheel_event
);
1319 host_
->ForwardMouseEvent(mouse_event
);
1320 return command
->SuccessResponse(NULL
);
1323 void RendererOverridesHandler::UpdateTouchEventEmulationState() {
1326 bool enabled
= touch_emulation_enabled_
|| screencast_command_
.get();
1327 host_
->SetTouchEventEmulationEnabled(enabled
);
1328 WebContentsImpl
* web_contents
= static_cast<WebContentsImpl
*>(
1329 WebContents::FromRenderViewHost(host_
));
1331 web_contents
->SetForceDisableOverscrollContent(enabled
);
1334 } // namespace content