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"
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/files/file_path.h"
13 #include "base/strings/string16.h"
14 #include "base/values.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/devtools/devtools_protocol_constants.h"
17 #include "content/browser/devtools/devtools_tracing_handler.h"
18 #include "content/browser/renderer_host/dip_util.h"
19 #include "content/browser/renderer_host/render_view_host_delegate.h"
20 #include "content/browser/renderer_host/render_view_host_impl.h"
21 #include "content/common/view_messages.h"
22 #include "content/port/browser/render_widget_host_view_port.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/devtools_agent_host.h"
25 #include "content/public/browser/javascript_dialog_manager.h"
26 #include "content/public/browser/navigation_controller.h"
27 #include "content/public/browser/navigation_entry.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/render_view_host.h"
30 #include "content/public/browser/render_widget_host_view.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_contents_delegate.h"
33 #include "content/public/common/page_transition_types.h"
34 #include "content/public/common/referrer.h"
35 #include "ipc/ipc_sender.h"
36 #include "third_party/WebKit/public/web/WebInputEvent.h"
37 #include "ui/gfx/codec/jpeg_codec.h"
38 #include "ui/gfx/codec/png_codec.h"
39 #include "ui/gfx/size_conversions.h"
40 #include "ui/snapshot/snapshot.h"
43 using WebKit::WebGestureEvent
;
44 using WebKit::WebInputEvent
;
45 using WebKit::WebMouseEvent
;
51 static const char kPng
[] = "png";
52 static const char kJpeg
[] = "jpeg";
53 static int kDefaultScreenshotQuality
= 80;
54 static int kFrameRateThresholdMs
= 100;
56 void ParseGenericInputParams(base::DictionaryValue
* params
,
57 WebInputEvent
* event
) {
59 if (params
->GetInteger(devtools::Input::kParamModifiers
,
62 event
->modifiers
|= WebInputEvent::AltKey
;
64 event
->modifiers
|= WebInputEvent::ControlKey
;
66 event
->modifiers
|= WebInputEvent::MetaKey
;
68 event
->modifiers
|= WebInputEvent::ShiftKey
;
71 params
->GetDouble(devtools::Input::kParamTimestamp
,
72 &event
->timeStampSeconds
);
77 RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost
* agent
)
80 RegisterCommandHandler(
81 devtools::DOM::setFileInputFiles::kName
,
83 &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles
,
84 base::Unretained(this)));
85 RegisterCommandHandler(
86 devtools::Page::disable::kName
,
88 &RendererOverridesHandler::PageDisable
, base::Unretained(this)));
89 RegisterCommandHandler(
90 devtools::Page::handleJavaScriptDialog::kName
,
92 &RendererOverridesHandler::PageHandleJavaScriptDialog
,
93 base::Unretained(this)));
94 RegisterCommandHandler(
95 devtools::Page::navigate::kName
,
97 &RendererOverridesHandler::PageNavigate
,
98 base::Unretained(this)));
99 RegisterCommandHandler(
100 devtools::Page::reload::kName
,
102 &RendererOverridesHandler::PageReload
,
103 base::Unretained(this)));
104 RegisterCommandHandler(
105 devtools::Page::getNavigationHistory::kName
,
107 &RendererOverridesHandler::PageGetNavigationHistory
,
108 base::Unretained(this)));
109 RegisterCommandHandler(
110 devtools::Page::navigateToHistoryEntry::kName
,
112 &RendererOverridesHandler::PageNavigateToHistoryEntry
,
113 base::Unretained(this)));
114 RegisterCommandHandler(
115 devtools::Page::captureScreenshot::kName
,
117 &RendererOverridesHandler::PageCaptureScreenshot
,
118 base::Unretained(this)));
119 RegisterCommandHandler(
120 devtools::Page::startScreencast::kName
,
122 &RendererOverridesHandler::PageStartScreencast
,
123 base::Unretained(this)));
124 RegisterCommandHandler(
125 devtools::Page::stopScreencast::kName
,
127 &RendererOverridesHandler::PageStopScreencast
,
128 base::Unretained(this)));
129 RegisterCommandHandler(
130 devtools::Input::dispatchMouseEvent::kName
,
132 &RendererOverridesHandler::InputDispatchMouseEvent
,
133 base::Unretained(this)));
134 RegisterCommandHandler(
135 devtools::Input::dispatchGestureEvent::kName
,
137 &RendererOverridesHandler::InputDispatchGestureEvent
,
138 base::Unretained(this)));
141 RendererOverridesHandler::~RendererOverridesHandler() {}
143 void RendererOverridesHandler::OnClientDetached() {
144 screencast_command_
= NULL
;
147 void RendererOverridesHandler::OnSwapCompositorFrame(
148 const IPC::Message
& message
) {
149 ViewHostMsg_SwapCompositorFrame::Param param
;
150 if (!ViewHostMsg_SwapCompositorFrame::Read(&message
, ¶m
))
152 last_compositor_frame_metadata_
= param
.b
.metadata
;
154 if (screencast_command_
)
155 InnerSwapCompositorFrame();
158 void RendererOverridesHandler::OnVisibilityChanged(bool visible
) {
159 if (!screencast_command_
)
161 NotifyScreencastVisibility(visible
);
164 void RendererOverridesHandler::InnerSwapCompositorFrame() {
165 if ((base::TimeTicks::Now() - last_frame_time_
).InMilliseconds() <
166 kFrameRateThresholdMs
) {
170 last_frame_time_
= base::TimeTicks::Now();
172 int quality
= kDefaultScreenshotQuality
;
174 ParseCaptureParameters(screencast_command_
.get(), &format
, &quality
, &scale
);
176 RenderViewHost
* host
= agent_
->GetRenderViewHost();
177 RenderWidgetHostViewPort
* view_port
=
178 RenderWidgetHostViewPort::FromRWHV(host
->GetView());
180 gfx::Rect view_bounds
= host
->GetView()->GetViewBounds();
181 gfx::Size snapshot_size
= gfx::ToFlooredSize(
182 gfx::ScaleSize(view_bounds
.size(), scale
));
184 view_port
->CopyFromCompositingSurface(
185 view_bounds
, snapshot_size
,
186 base::Bind(&RendererOverridesHandler::ScreenshotCaptured
,
187 weak_factory_
.GetWeakPtr(),
188 scoped_refptr
<DevToolsProtocol::Command
>(), format
, quality
,
189 last_compositor_frame_metadata_
));
192 void RendererOverridesHandler::ParseCaptureParameters(
193 DevToolsProtocol::Command
* command
,
197 RenderViewHost
* host
= agent_
->GetRenderViewHost();
198 gfx::Rect view_bounds
= host
->GetView()->GetViewBounds();
200 *quality
= kDefaultScreenshotQuality
;
202 double max_width
= -1;
203 double max_height
= -1;
204 base::DictionaryValue
* params
= command
->params();
206 params
->GetString(devtools::Page::captureScreenshot::kParamFormat
,
208 params
->GetInteger(devtools::Page::captureScreenshot::kParamQuality
,
210 params
->GetDouble(devtools::Page::captureScreenshot::kParamMaxWidth
,
212 params
->GetDouble(devtools::Page::captureScreenshot::kParamMaxHeight
,
216 float device_sf
= last_compositor_frame_metadata_
.device_scale_factor
;
219 *scale
= std::min(*scale
, max_width
/ view_bounds
.width() / device_sf
);
221 *scale
= std::min(*scale
, max_height
/ view_bounds
.height() / device_sf
);
225 if (*quality
< 0 || *quality
> 100)
226 *quality
= kDefaultScreenshotQuality
;
233 // DOM agent handlers --------------------------------------------------------
235 scoped_refptr
<DevToolsProtocol::Response
>
236 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
237 scoped_refptr
<DevToolsProtocol::Command
> command
) {
238 base::DictionaryValue
* params
= command
->params();
239 base::ListValue
* file_list
= NULL
;
241 devtools::DOM::setFileInputFiles::kParamFiles
;
242 if (!params
|| !params
->GetList(param
, &file_list
))
243 return command
->InvalidParamResponse(param
);
244 RenderViewHost
* host
= agent_
->GetRenderViewHost();
248 for (size_t i
= 0; i
< file_list
->GetSize(); ++i
) {
249 base::FilePath::StringType file
;
250 if (!file_list
->GetString(i
, &file
))
251 return command
->InvalidParamResponse(param
);
252 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
253 host
->GetProcess()->GetID(), base::FilePath(file
));
259 // Page agent handlers -------------------------------------------------------
261 scoped_refptr
<DevToolsProtocol::Response
>
262 RendererOverridesHandler::PageDisable(
263 scoped_refptr
<DevToolsProtocol::Command
> command
) {
264 screencast_command_
= NULL
;
268 scoped_refptr
<DevToolsProtocol::Response
>
269 RendererOverridesHandler::PageHandleJavaScriptDialog(
270 scoped_refptr
<DevToolsProtocol::Command
> command
) {
271 base::DictionaryValue
* params
= command
->params();
272 const char* paramAccept
=
273 devtools::Page::handleJavaScriptDialog::kParamAccept
;
275 if (!params
|| !params
->GetBoolean(paramAccept
, &accept
))
276 return command
->InvalidParamResponse(paramAccept
);
277 string16 prompt_override
;
278 string16
* prompt_override_ptr
= &prompt_override
;
279 if (!params
|| !params
->GetString(
280 devtools::Page::handleJavaScriptDialog::kParamPromptText
,
281 prompt_override_ptr
)) {
282 prompt_override_ptr
= NULL
;
285 RenderViewHost
* host
= agent_
->GetRenderViewHost();
287 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
289 JavaScriptDialogManager
* manager
=
290 web_contents
->GetDelegate()->GetJavaScriptDialogManager();
291 if (manager
&& manager
->HandleJavaScriptDialog(
292 web_contents
, accept
, prompt_override_ptr
)) {
297 return command
->InternalErrorResponse("No JavaScript dialog to handle");
300 scoped_refptr
<DevToolsProtocol::Response
>
301 RendererOverridesHandler::PageNavigate(
302 scoped_refptr
<DevToolsProtocol::Command
> command
) {
303 base::DictionaryValue
* params
= command
->params();
305 const char* param
= devtools::Page::navigate::kParamUrl
;
306 if (!params
|| !params
->GetString(param
, &url
))
307 return command
->InvalidParamResponse(param
);
309 if (!gurl
.is_valid()) {
310 return command
->InternalErrorResponse("Cannot navigate to invalid URL");
312 RenderViewHost
* host
= agent_
->GetRenderViewHost();
314 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
316 web_contents
->GetController()
317 .LoadURL(gurl
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
318 return command
->SuccessResponse(new base::DictionaryValue());
321 return command
->InternalErrorResponse("No WebContents to navigate");
324 scoped_refptr
<DevToolsProtocol::Response
>
325 RendererOverridesHandler::PageReload(
326 scoped_refptr
<DevToolsProtocol::Command
> command
) {
327 RenderViewHost
* host
= agent_
->GetRenderViewHost();
329 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
331 // Override only if it is crashed.
332 if (!web_contents
->IsCrashed())
335 web_contents
->GetController().Reload(false);
336 return command
->SuccessResponse(NULL
);
339 return command
->InternalErrorResponse("No WebContents to reload");
342 scoped_refptr
<DevToolsProtocol::Response
>
343 RendererOverridesHandler::PageGetNavigationHistory(
344 scoped_refptr
<DevToolsProtocol::Command
> command
) {
345 RenderViewHost
* host
= agent_
->GetRenderViewHost();
347 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
349 base::DictionaryValue
* result
= new base::DictionaryValue();
350 NavigationController
& controller
= web_contents
->GetController();
352 devtools::Page::getNavigationHistory::kResponseCurrentIndex
,
353 controller
.GetCurrentEntryIndex());
354 ListValue
* entries
= new ListValue();
355 for (int i
= 0; i
!= controller
.GetEntryCount(); ++i
) {
356 const NavigationEntry
* entry
= controller
.GetEntryAtIndex(i
);
357 base::DictionaryValue
* entry_value
= new base::DictionaryValue();
358 entry_value
->SetInteger(
359 devtools::Page::getNavigationHistory::kResponseEntryId
,
360 entry
->GetUniqueID());
361 entry_value
->SetString(
362 devtools::Page::getNavigationHistory::kResponseEntryURL
,
363 entry
->GetURL().spec());
364 entry_value
->SetString(
365 devtools::Page::getNavigationHistory::kResponseEntryTitle
,
367 entries
->Append(entry_value
);
370 devtools::Page::getNavigationHistory::kResponseEntries
,
372 return command
->SuccessResponse(result
);
375 return command
->InternalErrorResponse("No WebContents to navigate");
378 scoped_refptr
<DevToolsProtocol::Response
>
379 RendererOverridesHandler::PageNavigateToHistoryEntry(
380 scoped_refptr
<DevToolsProtocol::Command
> command
) {
383 base::DictionaryValue
* params
= command
->params();
384 const char* param
= devtools::Page::navigateToHistoryEntry::kParamEntryId
;
385 if (!params
|| !params
->GetInteger(param
, &entry_id
)) {
386 return command
->InvalidParamResponse(param
);
389 RenderViewHost
* host
= agent_
->GetRenderViewHost();
391 WebContents
* web_contents
= host
->GetDelegate()->GetAsWebContents();
393 NavigationController
& controller
= web_contents
->GetController();
394 for (int i
= 0; i
!= controller
.GetEntryCount(); ++i
) {
395 if (controller
.GetEntryAtIndex(i
)->GetUniqueID() == entry_id
) {
396 controller
.GoToIndex(i
);
397 return command
->SuccessResponse(new base::DictionaryValue());
400 return command
->InvalidParamResponse(param
);
403 return command
->InternalErrorResponse("No WebContents to navigate");
406 scoped_refptr
<DevToolsProtocol::Response
>
407 RendererOverridesHandler::PageCaptureScreenshot(
408 scoped_refptr
<DevToolsProtocol::Command
> command
) {
410 int quality
= kDefaultScreenshotQuality
;
412 ParseCaptureParameters(command
.get(), &format
, &quality
, &scale
);
414 RenderViewHost
* host
= agent_
->GetRenderViewHost();
415 gfx::Rect view_bounds
= host
->GetView()->GetViewBounds();
417 // Grab screen pixels if available for current platform.
418 // TODO(pfeldman): support format, scale and quality in ui::GrabViewSnapshot.
419 std::vector
<unsigned char> png
;
420 bool is_unscaled_png
= scale
== 1 && format
== kPng
;
421 if (is_unscaled_png
&& ui::GrabViewSnapshot(host
->GetView()->GetNativeView(),
422 &png
, view_bounds
)) {
423 std::string base64_data
;
424 bool success
= base::Base64Encode(
425 base::StringPiece(reinterpret_cast<char*>(&*png
.begin()), png
.size()),
428 base::DictionaryValue
* result
= new base::DictionaryValue();
430 devtools::Page::kData
, base64_data
);
431 return command
->SuccessResponse(result
);
433 return command
->InternalErrorResponse("Unable to base64encode screenshot");
436 // Fallback to copying from compositing surface.
437 RenderWidgetHostViewPort
* view_port
=
438 RenderWidgetHostViewPort::FromRWHV(host
->GetView());
440 gfx::Size snapshot_size
= gfx::ToFlooredSize(
441 gfx::ScaleSize(view_bounds
.size(), scale
));
442 view_port
->CopyFromCompositingSurface(
443 view_bounds
, snapshot_size
,
444 base::Bind(&RendererOverridesHandler::ScreenshotCaptured
,
445 weak_factory_
.GetWeakPtr(), command
, format
, quality
,
446 last_compositor_frame_metadata_
));
447 return command
->AsyncResponsePromise();
450 scoped_refptr
<DevToolsProtocol::Response
>
451 RendererOverridesHandler::PageStartScreencast(
452 scoped_refptr
<DevToolsProtocol::Command
> command
) {
453 screencast_command_
= command
;
454 RenderViewHostImpl
* host
= static_cast<RenderViewHostImpl
*>(
455 agent_
->GetRenderViewHost());
456 bool visible
= !host
->is_hidden();
457 NotifyScreencastVisibility(visible
);
459 InnerSwapCompositorFrame();
460 return command
->SuccessResponse(NULL
);
463 scoped_refptr
<DevToolsProtocol::Response
>
464 RendererOverridesHandler::PageStopScreencast(
465 scoped_refptr
<DevToolsProtocol::Command
> command
) {
466 last_frame_time_
= base::TimeTicks();
467 screencast_command_
= NULL
;
468 return command
->SuccessResponse(NULL
);
471 void RendererOverridesHandler::ScreenshotCaptured(
472 scoped_refptr
<DevToolsProtocol::Command
> command
,
473 const std::string
& format
,
475 const cc::CompositorFrameMetadata
& metadata
,
477 const SkBitmap
& bitmap
) {
481 command
->InternalErrorResponse("Unable to capture screenshot"));
486 std::vector
<unsigned char> data
;
487 SkAutoLockPixels
lock_image(bitmap
);
489 if (format
== kPng
) {
490 encoded
= gfx::PNGCodec::Encode(
491 reinterpret_cast<unsigned char*>(bitmap
.getAddr32(0, 0)),
492 gfx::PNGCodec::FORMAT_SkBitmap
,
493 gfx::Size(bitmap
.width(), bitmap
.height()),
494 bitmap
.width() * bitmap
.bytesPerPixel(),
495 false, std::vector
<gfx::PNGCodec::Comment
>(), &data
);
496 } else if (format
== kJpeg
) {
497 encoded
= gfx::JPEGCodec::Encode(
498 reinterpret_cast<unsigned char*>(bitmap
.getAddr32(0, 0)),
499 gfx::JPEGCodec::FORMAT_SkBitmap
,
502 bitmap
.width() * bitmap
.bytesPerPixel(),
511 command
->InternalErrorResponse("Unable to encode screenshot"));
516 std::string base_64_data
;
517 if (!base::Base64Encode(base::StringPiece(
518 reinterpret_cast<char*>(&data
[0]),
523 command
->InternalErrorResponse("Unable to base64 encode"));
528 base::DictionaryValue
* response
= new base::DictionaryValue();
529 response
->SetString(devtools::Page::kData
, base_64_data
);
531 // Consider metadata empty in case it has no device scale factor.
532 if (metadata
.device_scale_factor
!= 0) {
533 response
->SetDouble(devtools::Page::kParamDeviceScaleFactor
,
534 metadata
.device_scale_factor
);
535 response
->SetDouble(devtools::Page::kParamPageScaleFactor
,
536 metadata
.page_scale_factor
);
537 response
->SetDouble(devtools::Page::kParamPageScaleFactorMin
,
538 metadata
.min_page_scale_factor
);
539 response
->SetDouble(devtools::Page::kParamPageScaleFactorMax
,
540 metadata
.max_page_scale_factor
);
541 response
->SetDouble(devtools::Page::kParamOffsetTop
,
542 metadata
.location_bar_content_translation
.y());
543 response
->SetDouble(devtools::Page::kParamOffsetBottom
,
544 metadata
.overdraw_bottom_height
);
546 base::DictionaryValue
* viewport
= new base::DictionaryValue();
547 viewport
->SetDouble(devtools::kParamX
, metadata
.root_scroll_offset
.x());
548 viewport
->SetDouble(devtools::kParamY
, metadata
.root_scroll_offset
.y());
549 viewport
->SetDouble(devtools::kParamWidth
, metadata
.viewport_size
.width());
550 viewport
->SetDouble(devtools::kParamHeight
,
551 metadata
.viewport_size
.height());
552 response
->Set(devtools::Page::kParamViewport
, viewport
);
556 SendAsyncResponse(command
->SuccessResponse(response
));
558 SendNotification(devtools::Page::screencastFrame::kName
, response
);
562 void RendererOverridesHandler::NotifyScreencastVisibility(bool visible
) {
563 base::DictionaryValue
* params
= new base::DictionaryValue();
565 devtools::Page::screencastVisibilityChanged::kParamVisible
, visible
);
567 devtools::Page::screencastVisibilityChanged::kName
, params
);
570 // Input agent handlers ------------------------------------------------------
572 scoped_refptr
<DevToolsProtocol::Response
>
573 RendererOverridesHandler::InputDispatchMouseEvent(
574 scoped_refptr
<DevToolsProtocol::Command
> command
) {
575 base::DictionaryValue
* params
= command
->params();
579 bool device_space
= false;
580 if (!params
->GetBoolean(devtools::Input::kParamDeviceSpace
,
586 RenderViewHost
* host
= agent_
->GetRenderViewHost();
587 WebKit::WebMouseEvent mouse_event
;
588 ParseGenericInputParams(params
, &mouse_event
);
591 if (params
->GetString(devtools::Input::kParamType
,
593 if (type
== "mousePressed")
594 mouse_event
.type
= WebInputEvent::MouseDown
;
595 else if (type
== "mouseReleased")
596 mouse_event
.type
= WebInputEvent::MouseUp
;
597 else if (type
== "mouseMoved")
598 mouse_event
.type
= WebInputEvent::MouseMove
;
605 if (!params
->GetInteger(devtools::kParamX
, &mouse_event
.x
) ||
606 !params
->GetInteger(devtools::kParamY
, &mouse_event
.y
)) {
610 mouse_event
.windowX
= mouse_event
.x
;
611 mouse_event
.windowY
= mouse_event
.y
;
612 mouse_event
.globalX
= mouse_event
.x
;
613 mouse_event
.globalY
= mouse_event
.y
;
615 params
->GetInteger(devtools::Input::dispatchMouseEvent::kParamClickCount
,
616 &mouse_event
.clickCount
);
619 if (!params
->GetString(devtools::Input::dispatchMouseEvent::kParamButton
,
624 if (button
== "none") {
625 mouse_event
.button
= WebMouseEvent::ButtonNone
;
626 } else if (button
== "left") {
627 mouse_event
.button
= WebMouseEvent::ButtonLeft
;
628 mouse_event
.modifiers
|= WebInputEvent::LeftButtonDown
;
629 } else if (button
== "middle") {
630 mouse_event
.button
= WebMouseEvent::ButtonMiddle
;
631 mouse_event
.modifiers
|= WebInputEvent::MiddleButtonDown
;
632 } else if (button
== "right") {
633 mouse_event
.button
= WebMouseEvent::ButtonRight
;
634 mouse_event
.modifiers
|= WebInputEvent::RightButtonDown
;
639 host
->ForwardMouseEvent(mouse_event
);
640 return command
->SuccessResponse(NULL
);
643 scoped_refptr
<DevToolsProtocol::Response
>
644 RendererOverridesHandler::InputDispatchGestureEvent(
645 scoped_refptr
<DevToolsProtocol::Command
> command
) {
646 base::DictionaryValue
* params
= command
->params();
650 RenderViewHostImpl
* host
= static_cast<RenderViewHostImpl
*>(
651 agent_
->GetRenderViewHost());
652 WebKit::WebGestureEvent event
;
653 ParseGenericInputParams(params
, &event
);
656 if (params
->GetString(devtools::Input::kParamType
,
658 if (type
== "scrollBegin")
659 event
.type
= WebInputEvent::GestureScrollBegin
;
660 else if (type
== "scrollUpdate")
661 event
.type
= WebInputEvent::GestureScrollUpdate
;
662 else if (type
== "scrollEnd")
663 event
.type
= WebInputEvent::GestureScrollEnd
;
664 else if (type
== "tapDown")
665 event
.type
= WebInputEvent::GestureTapDown
;
666 else if (type
== "tap")
667 event
.type
= WebInputEvent::GestureTap
;
668 else if (type
== "pinchBegin")
669 event
.type
= WebInputEvent::GesturePinchBegin
;
670 else if (type
== "pinchUpdate")
671 event
.type
= WebInputEvent::GesturePinchUpdate
;
672 else if (type
== "pinchEnd")
673 event
.type
= WebInputEvent::GesturePinchEnd
;
680 if (!params
->GetInteger(devtools::kParamX
, &event
.x
) ||
681 !params
->GetInteger(devtools::kParamY
, &event
.y
)) {
684 event
.globalX
= event
.x
;
685 event
.globalY
= event
.y
;
687 if (type
== "scrollUpdate") {
690 if (!params
->GetInteger(
691 devtools::Input::dispatchGestureEvent::kParamDeltaX
, &dx
) ||
693 devtools::Input::dispatchGestureEvent::kParamDeltaY
, &dy
)) {
696 event
.data
.scrollUpdate
.deltaX
= dx
;
697 event
.data
.scrollUpdate
.deltaY
= dy
;
700 if (type
== "pinchUpdate") {
702 if (!params
->GetDouble(
703 devtools::Input::dispatchGestureEvent::kParamPinchScale
,
707 event
.data
.pinchUpdate
.scale
= static_cast<float>(scale
);
710 host
->ForwardGestureEvent(event
);
711 return command
->SuccessResponse(NULL
);
714 } // namespace content