Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / web / DevToolsEmulator.cpp
blob5d33126a0ef509d549d60df7ea20982eaee39698
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 "config.h"
6 #include "web/DevToolsEmulator.h"
8 #include "core/frame/FrameHost.h"
9 #include "core/frame/FrameView.h"
10 #include "core/frame/Settings.h"
11 #include "core/page/Page.h"
12 #include "platform/RuntimeEnabledFeatures.h"
13 #include "public/platform/WebLayerTreeView.h"
14 #include "public/web/WebDeviceEmulationParams.h"
15 #include "web/InspectorEmulationAgent.h"
16 #include "web/WebInputEventConversion.h"
17 #include "web/WebLocalFrameImpl.h"
18 #include "web/WebSettingsImpl.h"
19 #include "web/WebViewImpl.h"
21 namespace {
23 static float calculateDeviceScaleAdjustment(int width, int height, float deviceScaleFactor)
25 // Chromium on Android uses a device scale adjustment for fonts used in text autosizing for
26 // improved legibility. This function computes this adjusted value for text autosizing.
27 // For a description of the Android device scale adjustment algorithm, see:
28 // chrome/browser/chrome_content_browser_client.cc, GetDeviceScaleAdjustment(...)
29 if (!width || !height || !deviceScaleFactor)
30 return 1;
32 static const float kMinFSM = 1.05f;
33 static const int kWidthForMinFSM = 320;
34 static const float kMaxFSM = 1.3f;
35 static const int kWidthForMaxFSM = 800;
37 float minWidth = std::min(width, height) / deviceScaleFactor;
38 if (minWidth <= kWidthForMinFSM)
39 return kMinFSM;
40 if (minWidth >= kWidthForMaxFSM)
41 return kMaxFSM;
43 // The font scale multiplier varies linearly between kMinFSM and kMaxFSM.
44 float ratio = static_cast<float>(minWidth - kWidthForMinFSM) / (kWidthForMaxFSM - kWidthForMinFSM);
45 return ratio * (kMaxFSM - kMinFSM) + kMinFSM;
48 } // namespace
50 namespace blink {
52 DevToolsEmulator::DevToolsEmulator(WebViewImpl* webViewImpl)
53 : m_webViewImpl(webViewImpl)
54 , m_emulationAgent(nullptr)
55 , m_deviceMetricsEnabled(false)
56 , m_emulateMobileEnabled(false)
57 , m_isOverlayScrollbarsEnabled(false)
58 , m_originalDefaultMinimumPageScaleFactor(0)
59 , m_originalDefaultMaximumPageScaleFactor(0)
60 , m_embedderTextAutosizingEnabled(webViewImpl->page()->settings().textAutosizingEnabled())
61 , m_embedderDeviceScaleAdjustment(webViewImpl->page()->settings().deviceScaleAdjustment())
62 , m_embedderPreferCompositingToLCDTextEnabled(webViewImpl->page()->settings().preferCompositingToLCDTextEnabled())
63 , m_embedderUseMobileViewport(webViewImpl->page()->settings().useMobileViewportStyle())
64 , m_embedderPluginsEnabled(webViewImpl->page()->settings().pluginsEnabled())
65 , m_embedderAvailablePointerTypes(webViewImpl->page()->settings().availablePointerTypes())
66 , m_embedderPrimaryPointerType(webViewImpl->page()->settings().primaryPointerType())
67 , m_embedderAvailableHoverTypes(webViewImpl->page()->settings().availableHoverTypes())
68 , m_embedderPrimaryHoverType(webViewImpl->page()->settings().primaryHoverType())
69 , m_touchEventEmulationEnabled(false)
70 , m_doubleTapToZoomEnabled(false)
71 , m_originalTouchEnabled(false)
72 , m_originalDeviceSupportsMouse(false)
73 , m_originalDeviceSupportsTouch(false)
74 , m_originalMaxTouchPoints(0)
75 , m_embedderScriptEnabled(webViewImpl->page()->settings().scriptEnabled())
76 , m_scriptExecutionDisabled(false)
77 , m_hidePinchScrollbarsNearMinScale(false)
81 DevToolsEmulator::~DevToolsEmulator()
85 PassOwnPtrWillBeRawPtr<DevToolsEmulator> DevToolsEmulator::create(WebViewImpl* webViewImpl)
87 return adoptPtrWillBeNoop(new DevToolsEmulator(webViewImpl));
90 DEFINE_TRACE(DevToolsEmulator)
92 visitor->trace(m_emulationAgent);
95 void DevToolsEmulator::setEmulationAgent(InspectorEmulationAgent* agent)
97 m_emulationAgent = agent;
100 void DevToolsEmulator::viewportChanged()
102 if (m_emulationAgent)
103 m_emulationAgent->viewportChanged();
106 void DevToolsEmulator::setTextAutosizingEnabled(bool enabled)
108 m_embedderTextAutosizingEnabled = enabled;
109 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
110 if (!emulateMobileEnabled)
111 m_webViewImpl->page()->settings().setTextAutosizingEnabled(enabled);
114 void DevToolsEmulator::setDeviceScaleAdjustment(float deviceScaleAdjustment)
116 m_embedderDeviceScaleAdjustment = deviceScaleAdjustment;
117 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
118 if (!emulateMobileEnabled)
119 m_webViewImpl->page()->settings().setDeviceScaleAdjustment(deviceScaleAdjustment);
122 void DevToolsEmulator::setPreferCompositingToLCDTextEnabled(bool enabled)
124 m_embedderPreferCompositingToLCDTextEnabled = enabled;
125 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
126 if (!emulateMobileEnabled)
127 m_webViewImpl->page()->settings().setPreferCompositingToLCDTextEnabled(enabled);
130 void DevToolsEmulator::setUseMobileViewportStyle(bool enabled)
132 m_embedderUseMobileViewport = enabled;
133 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
134 if (!emulateMobileEnabled)
135 m_webViewImpl->page()->settings().setUseMobileViewportStyle(enabled);
138 void DevToolsEmulator::setPluginsEnabled(bool enabled)
140 m_embedderPluginsEnabled = enabled;
141 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
142 if (!emulateMobileEnabled)
143 m_webViewImpl->page()->settings().setPluginsEnabled(enabled);
146 void DevToolsEmulator::setScriptEnabled(bool enabled)
148 m_embedderScriptEnabled = enabled;
149 if (!m_scriptExecutionDisabled)
150 m_webViewImpl->page()->settings().setScriptEnabled(enabled);
153 void DevToolsEmulator::setDoubleTapToZoomEnabled(bool enabled)
155 m_doubleTapToZoomEnabled = enabled;
158 bool DevToolsEmulator::doubleTapToZoomEnabled() const
160 return m_touchEventEmulationEnabled ? true : m_doubleTapToZoomEnabled;
163 void DevToolsEmulator::setHidePinchScrollbarsNearMinScale(bool enabled)
165 m_hidePinchScrollbarsNearMinScale = enabled;
166 if (m_webViewImpl->layerTreeView())
167 m_webViewImpl->layerTreeView()->setHidePinchScrollbarsNearMinScale(enabled);
170 void DevToolsEmulator::setAvailablePointerTypes(int types)
172 m_embedderAvailablePointerTypes = types;
173 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
174 if (!emulateMobileEnabled)
175 m_webViewImpl->page()->settings().setAvailablePointerTypes(types);
178 void DevToolsEmulator::setPrimaryPointerType(PointerType pointerType)
180 m_embedderPrimaryPointerType = pointerType;
181 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
182 if (!emulateMobileEnabled)
183 m_webViewImpl->page()->settings().setPrimaryPointerType(pointerType);
186 void DevToolsEmulator::setAvailableHoverTypes(int types)
188 m_embedderAvailableHoverTypes = types;
189 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
190 if (!emulateMobileEnabled)
191 m_webViewImpl->page()->settings().setAvailableHoverTypes(types);
194 void DevToolsEmulator::setPrimaryHoverType(HoverType hoverType)
196 m_embedderPrimaryHoverType = hoverType;
197 bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled;
198 if (!emulateMobileEnabled)
199 m_webViewImpl->page()->settings().setPrimaryHoverType(hoverType);
202 void DevToolsEmulator::enableDeviceEmulation(const WebDeviceEmulationParams& params)
204 if (!m_deviceMetricsEnabled) {
205 m_deviceMetricsEnabled = true;
206 if (params.viewSize.width || params.viewSize.height)
207 m_webViewImpl->setBackgroundColorOverride(Color::darkGray);
208 m_webViewImpl->updateShowFPSCounter();
211 m_webViewImpl->page()->settings().setDeviceScaleAdjustment(calculateDeviceScaleAdjustment(params.viewSize.width, params.viewSize.height, params.deviceScaleFactor));
213 if (params.screenPosition == WebDeviceEmulationParams::Mobile)
214 enableMobileEmulation();
215 else
216 disableMobileEmulation();
218 m_webViewImpl->setCompositorDeviceScaleFactorOverride(params.deviceScaleFactor);
219 m_webViewImpl->setRootLayerTransform(WebSize(params.offset.x, params.offset.y), params.scale);
220 if (Document* document = m_webViewImpl->mainFrameImpl()->frame()->document())
221 document->mediaQueryAffectingValueChanged();
224 void DevToolsEmulator::disableDeviceEmulation()
226 if (!m_deviceMetricsEnabled)
227 return;
229 m_deviceMetricsEnabled = false;
230 m_webViewImpl->setBackgroundColorOverride(Color::transparent);
231 m_webViewImpl->updateShowFPSCounter();
232 m_webViewImpl->page()->settings().setDeviceScaleAdjustment(m_embedderDeviceScaleAdjustment);
233 disableMobileEmulation();
234 m_webViewImpl->setCompositorDeviceScaleFactorOverride(0.f);
235 m_webViewImpl->setRootLayerTransform(WebSize(0.f, 0.f), 1.f);
236 m_webViewImpl->setPageScaleFactor(1.f);
237 if (Document* document = m_webViewImpl->mainFrameImpl()->frame()->document())
238 document->mediaQueryAffectingValueChanged();
241 void DevToolsEmulator::enableMobileEmulation()
243 if (m_emulateMobileEnabled)
244 return;
245 m_emulateMobileEnabled = true;
246 m_isOverlayScrollbarsEnabled = RuntimeEnabledFeatures::overlayScrollbarsEnabled();
247 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(true);
248 m_webViewImpl->enableViewport();
249 m_webViewImpl->settings()->setViewportMetaEnabled(true);
250 m_webViewImpl->page()->frameHost().visualViewport().initializeScrollbars();
251 m_webViewImpl->settings()->setShrinksViewportContentToFit(true);
252 m_webViewImpl->page()->settings().setTextAutosizingEnabled(true);
253 m_webViewImpl->page()->settings().setPreferCompositingToLCDTextEnabled(true);
254 m_webViewImpl->page()->settings().setUseMobileViewportStyle(true);
255 m_webViewImpl->page()->settings().setPluginsEnabled(false);
256 m_webViewImpl->page()->settings().setAvailablePointerTypes(PointerTypeCoarse);
257 m_webViewImpl->page()->settings().setPrimaryPointerType(PointerTypeCoarse);
258 m_webViewImpl->page()->settings().setAvailableHoverTypes(HoverTypeOnDemand);
259 m_webViewImpl->page()->settings().setPrimaryHoverType(HoverTypeOnDemand);
260 m_webViewImpl->setZoomFactorOverride(1);
262 m_originalDefaultMinimumPageScaleFactor = m_webViewImpl->defaultMinimumPageScaleFactor();
263 m_originalDefaultMaximumPageScaleFactor = m_webViewImpl->defaultMaximumPageScaleFactor();
264 m_webViewImpl->setDefaultPageScaleLimits(0.25f, 5);
267 void DevToolsEmulator::disableMobileEmulation()
269 if (!m_emulateMobileEnabled)
270 return;
271 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(m_isOverlayScrollbarsEnabled);
272 m_webViewImpl->disableViewport();
273 m_webViewImpl->settings()->setViewportMetaEnabled(false);
274 m_webViewImpl->page()->frameHost().visualViewport().initializeScrollbars();
275 m_webViewImpl->settings()->setShrinksViewportContentToFit(false);
276 m_webViewImpl->page()->settings().setTextAutosizingEnabled(m_embedderTextAutosizingEnabled);
277 m_webViewImpl->page()->settings().setPreferCompositingToLCDTextEnabled(m_embedderPreferCompositingToLCDTextEnabled);
278 m_webViewImpl->page()->settings().setUseMobileViewportStyle(m_embedderUseMobileViewport);
279 m_webViewImpl->page()->settings().setPluginsEnabled(m_embedderPluginsEnabled);
280 m_webViewImpl->page()->settings().setAvailablePointerTypes(m_embedderAvailablePointerTypes);
281 m_webViewImpl->page()->settings().setPrimaryPointerType(m_embedderPrimaryPointerType);
282 m_webViewImpl->page()->settings().setAvailableHoverTypes(m_embedderAvailableHoverTypes);
283 m_webViewImpl->page()->settings().setPrimaryHoverType(m_embedderPrimaryHoverType);
284 m_webViewImpl->setZoomFactorOverride(0);
285 m_emulateMobileEnabled = false;
286 m_webViewImpl->setDefaultPageScaleLimits(
287 m_originalDefaultMinimumPageScaleFactor,
288 m_originalDefaultMaximumPageScaleFactor);
291 void DevToolsEmulator::setTouchEventEmulationEnabled(bool enabled)
293 if (m_touchEventEmulationEnabled == enabled)
294 return;
295 if (!m_touchEventEmulationEnabled) {
296 m_originalTouchEnabled = RuntimeEnabledFeatures::touchEnabled();
297 m_originalDeviceSupportsMouse = m_webViewImpl->page()->settings().deviceSupportsMouse();
298 m_originalDeviceSupportsTouch = m_webViewImpl->page()->settings().deviceSupportsTouch();
299 m_originalMaxTouchPoints = m_webViewImpl->page()->settings().maxTouchPoints();
301 RuntimeEnabledFeatures::setTouchEnabled(enabled ? true : m_originalTouchEnabled);
302 if (!m_originalDeviceSupportsTouch) {
303 m_webViewImpl->page()->settings().setDeviceSupportsMouse(enabled ? false : m_originalDeviceSupportsMouse);
304 m_webViewImpl->page()->settings().setDeviceSupportsTouch(enabled ? true : m_originalDeviceSupportsTouch);
305 // Currently emulation does not provide multiple touch points.
306 m_webViewImpl->page()->settings().setMaxTouchPoints(enabled ? 1 : m_originalMaxTouchPoints);
308 m_touchEventEmulationEnabled = enabled;
309 m_webViewImpl->mainFrameImpl()->frameView()->layout();
312 void DevToolsEmulator::setScriptExecutionDisabled(bool scriptExecutionDisabled)
314 m_scriptExecutionDisabled = scriptExecutionDisabled;
315 m_webViewImpl->page()->settings().setScriptEnabled(m_scriptExecutionDisabled ? false : m_embedderScriptEnabled);
318 bool DevToolsEmulator::handleInputEvent(const WebInputEvent& inputEvent)
320 Page* page = m_webViewImpl->page();
321 if (!page)
322 return false;
324 // FIXME: This workaround is required for touch emulation on Mac, where
325 // compositor-side pinch handling is not enabled. See http://crbug.com/138003.
326 bool isPinch = inputEvent.type == WebInputEvent::GesturePinchBegin || inputEvent.type == WebInputEvent::GesturePinchUpdate || inputEvent.type == WebInputEvent::GesturePinchEnd;
327 if (isPinch && m_touchEventEmulationEnabled) {
328 FrameView* frameView = page->deprecatedLocalMainFrame()->view();
329 PlatformGestureEventBuilder gestureEvent(frameView, static_cast<const WebGestureEvent&>(inputEvent));
330 float pageScaleFactor = page->pageScaleFactor();
331 if (gestureEvent.type() == PlatformEvent::GesturePinchBegin) {
332 m_lastPinchAnchorCss = adoptPtr(new IntPoint(frameView->scrollPosition() + gestureEvent.position()));
333 m_lastPinchAnchorDip = adoptPtr(new IntPoint(gestureEvent.position()));
334 m_lastPinchAnchorDip->scale(pageScaleFactor, pageScaleFactor);
336 if (gestureEvent.type() == PlatformEvent::GesturePinchUpdate && m_lastPinchAnchorCss) {
337 float newPageScaleFactor = pageScaleFactor * gestureEvent.scale();
338 IntPoint anchorCss(*m_lastPinchAnchorDip.get());
339 anchorCss.scale(1.f / newPageScaleFactor, 1.f / newPageScaleFactor);
340 m_webViewImpl->setPageScaleFactor(newPageScaleFactor);
341 m_webViewImpl->mainFrame()->setScrollOffset(toIntSize(*m_lastPinchAnchorCss.get() - toIntSize(anchorCss)));
343 if (gestureEvent.type() == PlatformEvent::GesturePinchEnd) {
344 m_lastPinchAnchorCss.clear();
345 m_lastPinchAnchorDip.clear();
347 return true;
350 return false;
353 } // namespace blink