1 // Copyright 2015 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/protocol/emulation_handler.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "content/browser/frame_host/render_frame_host_impl.h"
9 #include "content/browser/geolocation/geolocation_service_context.h"
10 #include "content/browser/renderer_host/render_widget_host_impl.h"
11 #include "content/browser/web_contents/web_contents_impl.h"
12 #include "content/common/view_messages.h"
13 #include "content/public/common/url_constants.h"
19 using Response
= DevToolsProtocolClient::Response
;
23 ui::GestureProviderConfigType
TouchEmulationConfigurationToType(
24 const std::string
& protocol_value
) {
25 ui::GestureProviderConfigType result
=
26 ui::GestureProviderConfigType::CURRENT_PLATFORM
;
28 set_touch_emulation_enabled::kConfigurationMobile
) {
29 result
= ui::GestureProviderConfigType::GENERIC_MOBILE
;
32 set_touch_emulation_enabled::kConfigurationDesktop
) {
33 result
= ui::GestureProviderConfigType::GENERIC_DESKTOP
;
40 EmulationHandler::EmulationHandler(page::PageHandler
* page_handler
)
41 : touch_emulation_enabled_(false),
42 device_emulation_enabled_(false),
43 page_handler_(page_handler
),
46 page_handler
->SetScreencastListener(this);
49 EmulationHandler::~EmulationHandler() {
52 void EmulationHandler::ScreencastEnabledChanged() {
53 UpdateTouchEventEmulationState();
56 void EmulationHandler::SetRenderFrameHost(RenderFrameHostImpl
* host
) {
61 UpdateTouchEventEmulationState();
62 UpdateDeviceEmulationState();
65 void EmulationHandler::Detached() {
66 touch_emulation_enabled_
= false;
67 device_emulation_enabled_
= false;
68 UpdateTouchEventEmulationState();
69 UpdateDeviceEmulationState();
72 Response
EmulationHandler::SetGeolocationOverride(
73 double* latitude
, double* longitude
, double* accuracy
) {
74 if (!GetWebContents())
75 return Response::InternalError("Could not connect to view");
77 GeolocationServiceContext
* geolocation_context
=
78 GetWebContents()->GetGeolocationServiceContext();
79 scoped_ptr
<Geoposition
> geoposition(new Geoposition());
80 if (latitude
&& longitude
&& accuracy
) {
81 geoposition
->latitude
= *latitude
;
82 geoposition
->longitude
= *longitude
;
83 geoposition
->accuracy
= *accuracy
;
84 geoposition
->timestamp
= base::Time::Now();
85 if (!geoposition
->Validate()) {
86 return Response::InternalError("Invalid geolocation");
89 geoposition
->error_code
= Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
;
91 geolocation_context
->SetOverride(geoposition
.Pass());
92 return Response::OK();
95 Response
EmulationHandler::ClearGeolocationOverride() {
96 if (!GetWebContents())
97 return Response::InternalError("Could not connect to view");
99 GeolocationServiceContext
* geolocation_context
=
100 GetWebContents()->GetGeolocationServiceContext();
101 geolocation_context
->ClearOverride();
102 return Response::OK();
105 Response
EmulationHandler::SetTouchEmulationEnabled(
106 bool enabled
, const std::string
* configuration
) {
107 touch_emulation_enabled_
= enabled
;
108 touch_emulation_configuration_
=
109 configuration
? *configuration
: std::string();
110 UpdateTouchEventEmulationState();
111 return Response::FallThrough();
114 Response
EmulationHandler::CanEmulate(bool* result
) {
115 #if defined(OS_ANDROID)
119 if (WebContentsImpl
* web_contents
= GetWebContents())
120 *result
&= !web_contents
->GetVisibleURL().SchemeIs(kChromeDevToolsScheme
);
121 if (host_
&& host_
->GetRenderWidgetHost())
122 *result
&= !host_
->GetRenderWidgetHost()->auto_resize_enabled();
123 #endif // defined(OS_ANDROID)
124 return Response::OK();
127 Response
EmulationHandler::SetDeviceMetricsOverride(
130 double device_scale_factor
,
133 const double* optional_scale
,
134 const double* optional_offset_x
,
135 const double* optional_offset_y
,
136 const int* screen_width
,
137 const int* screen_height
,
138 const int* position_x
,
139 const int* position_y
) {
140 const static int max_size
= 10000000;
141 const static double max_scale
= 10;
144 return Response::InternalError("Could not connect to view");
146 if (screen_width
&& screen_height
&&
147 (*screen_width
< 0 || *screen_height
< 0 ||
148 *screen_width
> max_size
|| *screen_height
> max_size
)) {
149 return Response::InvalidParams(
150 "Screen width and height values must be positive, not greater than " +
151 base::IntToString(max_size
));
154 if (screen_width
&& screen_height
&& position_x
&& position_y
&&
155 (*position_x
< 0 || *position_y
< 0 ||
156 *position_x
> *screen_width
|| *position_y
> *screen_height
)) {
157 return Response::InvalidParams("View position should be on the screen");
160 if (width
< 0 || height
< 0 || width
> max_size
|| height
> max_size
) {
161 return Response::InvalidParams(
162 "Width and height values must be positive, not greater than " +
163 base::IntToString(max_size
));
166 if (device_scale_factor
< 0)
167 return Response::InvalidParams("deviceScaleFactor must be non-negative");
169 if (optional_scale
&& (*optional_scale
<= 0 || *optional_scale
> max_scale
)) {
170 return Response::InvalidParams(
171 "scale must be positive, not greater than " +
172 base::IntToString(max_scale
));
175 blink::WebDeviceEmulationParams params
;
176 params
.screenPosition
= mobile
? blink::WebDeviceEmulationParams::Mobile
:
177 blink::WebDeviceEmulationParams::Desktop
;
178 if (screen_width
&& screen_height
)
179 params
.screenSize
= blink::WebSize(*screen_width
, *screen_height
);
180 if (position_x
&& position_y
)
181 params
.viewPosition
= blink::WebPoint(*position_x
, *position_y
);
182 params
.deviceScaleFactor
= device_scale_factor
;
183 params
.viewSize
= blink::WebSize(width
, height
);
184 params
.fitToView
= fit_window
;
185 params
.scale
= optional_scale
? *optional_scale
: 1;
186 params
.offset
= blink::WebFloatPoint(
187 optional_offset_x
? *optional_offset_x
: 0.f
,
188 optional_offset_y
? *optional_offset_y
: 0.f
);
190 if (device_emulation_enabled_
&& params
== device_emulation_params_
)
191 return Response::OK();
193 device_emulation_enabled_
= true;
194 device_emulation_params_
= params
;
195 UpdateDeviceEmulationState();
196 return Response::OK();
199 Response
EmulationHandler::ClearDeviceMetricsOverride() {
200 if (!device_emulation_enabled_
)
201 return Response::OK();
203 device_emulation_enabled_
= false;
204 UpdateDeviceEmulationState();
205 return Response::OK();
208 WebContentsImpl
* EmulationHandler::GetWebContents() {
210 static_cast<WebContentsImpl
*>(WebContents::FromRenderFrameHost(host_
)) :
214 void EmulationHandler::UpdateTouchEventEmulationState() {
215 RenderWidgetHostImpl
* widget_host
=
216 host_
? host_
->GetRenderWidgetHost() : nullptr;
219 bool enabled
= touch_emulation_enabled_
||
220 page_handler_
->screencast_enabled();
221 ui::GestureProviderConfigType config_type
=
222 TouchEmulationConfigurationToType(touch_emulation_configuration_
);
223 widget_host
->SetTouchEventEmulationEnabled(enabled
, config_type
);
224 if (GetWebContents())
225 GetWebContents()->SetForceDisableOverscrollContent(enabled
);
228 void EmulationHandler::UpdateDeviceEmulationState() {
229 RenderWidgetHostImpl
* widget_host
=
230 host_
? host_
->GetRenderWidgetHost() : nullptr;
233 if (device_emulation_enabled_
) {
234 widget_host
->Send(new ViewMsg_EnableDeviceEmulation(
235 widget_host
->GetRoutingID(), device_emulation_params_
));
237 widget_host
->Send(new ViewMsg_DisableDeviceEmulation(
238 widget_host
->GetRoutingID()));
242 } // namespace emulation
243 } // namespace devtools
244 } // namespace content