| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "web/DevToolsEmulator.h" |
| |
| #include "core/frame/FrameHost.h" |
| #include "core/frame/FrameView.h" |
| #include "core/frame/Settings.h" |
| #include "core/frame/VisualViewport.h" |
| #include "core/input/EventHandler.h" |
| #include "core/page/Page.h" |
| #include "core/style/ComputedStyle.h" |
| #include "platform/RuntimeEnabledFeatures.h" |
| #include "platform/geometry/FloatRect.h" |
| #include "platform/geometry/FloatSize.h" |
| #include "platform/geometry/IntRect.h" |
| #include "platform/geometry/IntSize.h" |
| #include "platform/loader/fetch/MemoryCache.h" |
| #include "public/platform/WebLayerTreeView.h" |
| #include "web/WebInputEventConversion.h" |
| #include "web/WebLocalFrameImpl.h" |
| #include "web/WebSettingsImpl.h" |
| #include "web/WebViewImpl.h" |
| #include "wtf/PtrUtil.h" |
| |
| namespace { |
| |
| static float calculateDeviceScaleAdjustment(int width, |
| int height, |
| float deviceScaleFactor) { |
| // Chromium on Android uses a device scale adjustment for fonts used in text |
| // autosizing for improved legibility. This function computes this adjusted |
| // value for text autosizing. |
| // For a description of the Android device scale adjustment algorithm, see: |
| // chrome/browser/chrome_content_browser_client.cc, |
| // GetDeviceScaleAdjustment(...) |
| if (!width || !height || !deviceScaleFactor) |
| return 1; |
| |
| static const float kMinFSM = 1.05f; |
| static const int kWidthForMinFSM = 320; |
| static const float kMaxFSM = 1.3f; |
| static const int kWidthForMaxFSM = 800; |
| |
| float minWidth = std::min(width, height) / deviceScaleFactor; |
| if (minWidth <= kWidthForMinFSM) |
| return kMinFSM; |
| if (minWidth >= kWidthForMaxFSM) |
| return kMaxFSM; |
| |
| // The font scale multiplier varies linearly between kMinFSM and kMaxFSM. |
| float ratio = static_cast<float>(minWidth - kWidthForMinFSM) / |
| (kWidthForMaxFSM - kWidthForMinFSM); |
| return ratio * (kMaxFSM - kMinFSM) + kMinFSM; |
| } |
| |
| } // namespace |
| |
| namespace blink { |
| |
| DevToolsEmulator::DevToolsEmulator(WebViewImpl* webViewImpl) |
| : m_webViewImpl(webViewImpl), |
| m_deviceMetricsEnabled(false), |
| m_emulateMobileEnabled(false), |
| m_isOverlayScrollbarsEnabled(false), |
| m_isOrientationEventEnabled(false), |
| m_isMobileLayoutThemeEnabled(false), |
| m_originalDefaultMinimumPageScaleFactor(0), |
| m_originalDefaultMaximumPageScaleFactor(0), |
| m_embedderTextAutosizingEnabled( |
| webViewImpl->page()->settings().textAutosizingEnabled()), |
| m_embedderDeviceScaleAdjustment( |
| webViewImpl->page()->settings().getDeviceScaleAdjustment()), |
| m_embedderPreferCompositingToLCDTextEnabled( |
| webViewImpl->page() |
| ->settings() |
| .getPreferCompositingToLCDTextEnabled()), |
| m_embedderViewportStyle( |
| webViewImpl->page()->settings().getViewportStyle()), |
| m_embedderPluginsEnabled( |
| webViewImpl->page()->settings().getPluginsEnabled()), |
| m_embedderAvailablePointerTypes( |
| webViewImpl->page()->settings().getAvailablePointerTypes()), |
| m_embedderPrimaryPointerType( |
| webViewImpl->page()->settings().getPrimaryPointerType()), |
| m_embedderAvailableHoverTypes( |
| webViewImpl->page()->settings().getAvailableHoverTypes()), |
| m_embedderPrimaryHoverType( |
| webViewImpl->page()->settings().getPrimaryHoverType()), |
| m_embedderMainFrameResizesAreOrientationChanges( |
| webViewImpl->page() |
| ->settings() |
| .getMainFrameResizesAreOrientationChanges()), |
| m_touchEventEmulationEnabled(false), |
| m_doubleTapToZoomEnabled(false), |
| m_originalTouchEventFeatureDetectionEnabled(false), |
| m_originalDeviceSupportsTouch(false), |
| m_originalMaxTouchPoints(0), |
| m_embedderScriptEnabled( |
| webViewImpl->page()->settings().getScriptEnabled()), |
| m_scriptExecutionDisabled(false) {} |
| |
| DevToolsEmulator::~DevToolsEmulator() {} |
| |
| DevToolsEmulator* DevToolsEmulator::create(WebViewImpl* webViewImpl) { |
| return new DevToolsEmulator(webViewImpl); |
| } |
| |
| DEFINE_TRACE(DevToolsEmulator) {} |
| |
| void DevToolsEmulator::setTextAutosizingEnabled(bool enabled) { |
| m_embedderTextAutosizingEnabled = enabled; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setTextAutosizingEnabled(enabled); |
| } |
| |
| void DevToolsEmulator::setDeviceScaleAdjustment(float deviceScaleAdjustment) { |
| m_embedderDeviceScaleAdjustment = deviceScaleAdjustment; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setDeviceScaleAdjustment( |
| deviceScaleAdjustment); |
| } |
| |
| void DevToolsEmulator::setPreferCompositingToLCDTextEnabled(bool enabled) { |
| m_embedderPreferCompositingToLCDTextEnabled = enabled; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setPreferCompositingToLCDTextEnabled( |
| enabled); |
| } |
| |
| void DevToolsEmulator::setViewportStyle(WebViewportStyle style) { |
| m_embedderViewportStyle = style; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setViewportStyle(style); |
| } |
| |
| void DevToolsEmulator::setPluginsEnabled(bool enabled) { |
| m_embedderPluginsEnabled = enabled; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setPluginsEnabled(enabled); |
| } |
| |
| void DevToolsEmulator::setScriptEnabled(bool enabled) { |
| m_embedderScriptEnabled = enabled; |
| if (!m_scriptExecutionDisabled) |
| m_webViewImpl->page()->settings().setScriptEnabled(enabled); |
| } |
| |
| void DevToolsEmulator::setDoubleTapToZoomEnabled(bool enabled) { |
| m_doubleTapToZoomEnabled = enabled; |
| } |
| |
| bool DevToolsEmulator::doubleTapToZoomEnabled() const { |
| return m_touchEventEmulationEnabled ? true : m_doubleTapToZoomEnabled; |
| } |
| |
| void DevToolsEmulator::setMainFrameResizesAreOrientationChanges(bool value) { |
| m_embedderMainFrameResizesAreOrientationChanges = value; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setMainFrameResizesAreOrientationChanges( |
| value); |
| } |
| |
| void DevToolsEmulator::setAvailablePointerTypes(int types) { |
| m_embedderAvailablePointerTypes = types; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setAvailablePointerTypes(types); |
| } |
| |
| void DevToolsEmulator::setPrimaryPointerType(PointerType pointerType) { |
| m_embedderPrimaryPointerType = pointerType; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setPrimaryPointerType(pointerType); |
| } |
| |
| void DevToolsEmulator::setAvailableHoverTypes(int types) { |
| m_embedderAvailableHoverTypes = types; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setAvailableHoverTypes(types); |
| } |
| |
| void DevToolsEmulator::setPrimaryHoverType(HoverType hoverType) { |
| m_embedderPrimaryHoverType = hoverType; |
| bool emulateMobileEnabled = m_deviceMetricsEnabled && m_emulateMobileEnabled; |
| if (!emulateMobileEnabled) |
| m_webViewImpl->page()->settings().setPrimaryHoverType(hoverType); |
| } |
| |
| void DevToolsEmulator::enableDeviceEmulation( |
| const WebDeviceEmulationParams& params) { |
| if (m_deviceMetricsEnabled && m_emulationParams.viewSize == params.viewSize && |
| m_emulationParams.screenPosition == params.screenPosition && |
| m_emulationParams.deviceScaleFactor == params.deviceScaleFactor && |
| m_emulationParams.offset == params.offset && |
| m_emulationParams.scale == params.scale) { |
| return; |
| } |
| if (m_emulationParams.deviceScaleFactor != params.deviceScaleFactor || |
| !m_deviceMetricsEnabled) |
| memoryCache()->evictResources(); |
| |
| m_emulationParams = params; |
| |
| if (!m_deviceMetricsEnabled) { |
| m_deviceMetricsEnabled = true; |
| if (params.viewSize.width || params.viewSize.height) |
| m_webViewImpl->setBackgroundColorOverride(Color::darkGray); |
| } |
| |
| m_webViewImpl->page()->settings().setDeviceScaleAdjustment( |
| calculateDeviceScaleAdjustment(params.viewSize.width, |
| params.viewSize.height, |
| params.deviceScaleFactor)); |
| |
| if (params.screenPosition == WebDeviceEmulationParams::Mobile) |
| enableMobileEmulation(); |
| else |
| disableMobileEmulation(); |
| |
| m_webViewImpl->setCompositorDeviceScaleFactorOverride( |
| params.deviceScaleFactor); |
| updateRootLayerTransform(); |
| // TODO(dgozman): mainFrameImpl() is null when it's remote. Figure out how |
| // we end up with enabling emulation in this case. |
| if (m_webViewImpl->mainFrameImpl()) { |
| if (Document* document = |
| m_webViewImpl->mainFrameImpl()->frame()->document()) |
| document->mediaQueryAffectingValueChanged(); |
| } |
| } |
| |
| void DevToolsEmulator::disableDeviceEmulation() { |
| if (!m_deviceMetricsEnabled) |
| return; |
| |
| memoryCache()->evictResources(); |
| m_deviceMetricsEnabled = false; |
| m_webViewImpl->setBackgroundColorOverride(Color::transparent); |
| m_webViewImpl->page()->settings().setDeviceScaleAdjustment( |
| m_embedderDeviceScaleAdjustment); |
| disableMobileEmulation(); |
| m_webViewImpl->setCompositorDeviceScaleFactorOverride(0.f); |
| m_webViewImpl->setPageScaleFactor(1.f); |
| updateRootLayerTransform(); |
| // mainFrameImpl() could be null during cleanup or remote <-> local swap. |
| if (m_webViewImpl->mainFrameImpl()) { |
| if (Document* document = |
| m_webViewImpl->mainFrameImpl()->frame()->document()) |
| document->mediaQueryAffectingValueChanged(); |
| } |
| } |
| |
| void DevToolsEmulator::enableMobileEmulation() { |
| if (m_emulateMobileEnabled) |
| return; |
| m_emulateMobileEnabled = true; |
| m_isOverlayScrollbarsEnabled = |
| RuntimeEnabledFeatures::overlayScrollbarsEnabled(); |
| RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(true); |
| m_isOrientationEventEnabled = |
| RuntimeEnabledFeatures::orientationEventEnabled(); |
| RuntimeEnabledFeatures::setOrientationEventEnabled(true); |
| m_isMobileLayoutThemeEnabled = |
| RuntimeEnabledFeatures::mobileLayoutThemeEnabled(); |
| RuntimeEnabledFeatures::setMobileLayoutThemeEnabled(true); |
| ComputedStyle::invalidateInitialStyle(); |
| m_webViewImpl->page()->settings().setViewportStyle(WebViewportStyle::Mobile); |
| m_webViewImpl->page()->settings().setViewportEnabled(true); |
| m_webViewImpl->page()->settings().setViewportMetaEnabled(true); |
| m_webViewImpl->page()->visualViewport().initializeScrollbars(); |
| m_webViewImpl->settings()->setShrinksViewportContentToFit(true); |
| m_webViewImpl->page()->settings().setTextAutosizingEnabled(true); |
| m_webViewImpl->page()->settings().setPreferCompositingToLCDTextEnabled(true); |
| m_webViewImpl->page()->settings().setPluginsEnabled(false); |
| m_webViewImpl->page()->settings().setAvailablePointerTypes(PointerTypeCoarse); |
| m_webViewImpl->page()->settings().setPrimaryPointerType(PointerTypeCoarse); |
| m_webViewImpl->page()->settings().setAvailableHoverTypes(HoverTypeNone); |
| m_webViewImpl->page()->settings().setPrimaryHoverType(HoverTypeNone); |
| m_webViewImpl->page()->settings().setMainFrameResizesAreOrientationChanges( |
| true); |
| m_webViewImpl->setZoomFactorOverride(1); |
| |
| m_originalDefaultMinimumPageScaleFactor = |
| m_webViewImpl->defaultMinimumPageScaleFactor(); |
| m_originalDefaultMaximumPageScaleFactor = |
| m_webViewImpl->defaultMaximumPageScaleFactor(); |
| m_webViewImpl->setDefaultPageScaleLimits(0.25f, 5); |
| // TODO(dgozman): mainFrameImpl() is null when it's remote. Figure out how |
| // we end up with enabling emulation in this case. |
| if (m_webViewImpl->mainFrameImpl()) |
| m_webViewImpl->mainFrameImpl()->frameView()->layout(); |
| } |
| |
| void DevToolsEmulator::disableMobileEmulation() { |
| if (!m_emulateMobileEnabled) |
| return; |
| RuntimeEnabledFeatures::setOverlayScrollbarsEnabled( |
| m_isOverlayScrollbarsEnabled); |
| RuntimeEnabledFeatures::setOrientationEventEnabled( |
| m_isOrientationEventEnabled); |
| RuntimeEnabledFeatures::setMobileLayoutThemeEnabled( |
| m_isMobileLayoutThemeEnabled); |
| ComputedStyle::invalidateInitialStyle(); |
| m_webViewImpl->page()->settings().setViewportEnabled(false); |
| m_webViewImpl->page()->settings().setViewportMetaEnabled(false); |
| m_webViewImpl->page()->visualViewport().initializeScrollbars(); |
| m_webViewImpl->settings()->setShrinksViewportContentToFit(false); |
| m_webViewImpl->page()->settings().setTextAutosizingEnabled( |
| m_embedderTextAutosizingEnabled); |
| m_webViewImpl->page()->settings().setPreferCompositingToLCDTextEnabled( |
| m_embedderPreferCompositingToLCDTextEnabled); |
| m_webViewImpl->page()->settings().setViewportStyle(m_embedderViewportStyle); |
| m_webViewImpl->page()->settings().setPluginsEnabled(m_embedderPluginsEnabled); |
| m_webViewImpl->page()->settings().setAvailablePointerTypes( |
| m_embedderAvailablePointerTypes); |
| m_webViewImpl->page()->settings().setPrimaryPointerType( |
| m_embedderPrimaryPointerType); |
| m_webViewImpl->page()->settings().setAvailableHoverTypes( |
| m_embedderAvailableHoverTypes); |
| m_webViewImpl->page()->settings().setPrimaryHoverType( |
| m_embedderPrimaryHoverType); |
| m_webViewImpl->page()->settings().setMainFrameResizesAreOrientationChanges( |
| m_embedderMainFrameResizesAreOrientationChanges); |
| m_webViewImpl->setZoomFactorOverride(0); |
| m_emulateMobileEnabled = false; |
| m_webViewImpl->setDefaultPageScaleLimits( |
| m_originalDefaultMinimumPageScaleFactor, |
| m_originalDefaultMaximumPageScaleFactor); |
| // mainFrameImpl() could be null during cleanup or remote <-> local swap. |
| if (m_webViewImpl->mainFrameImpl()) |
| m_webViewImpl->mainFrameImpl()->frameView()->layout(); |
| } |
| |
| float DevToolsEmulator::compositorDeviceScaleFactor() const { |
| if (m_deviceMetricsEnabled) |
| return m_emulationParams.deviceScaleFactor; |
| return m_webViewImpl->page()->deviceScaleFactorDeprecated(); |
| } |
| |
| void DevToolsEmulator::forceViewport(const WebFloatPoint& position, |
| float scale) { |
| GraphicsLayer* containerLayer = |
| m_webViewImpl->page()->visualViewport().containerLayer(); |
| if (!m_viewportOverride) { |
| m_viewportOverride = ViewportOverride(); |
| |
| // Disable clipping on the visual viewport layer, to ensure the whole area |
| // is painted. |
| if (containerLayer) { |
| m_viewportOverride->originalVisualViewportMasking = |
| containerLayer->masksToBounds(); |
| containerLayer->setMasksToBounds(false); |
| } |
| } |
| |
| m_viewportOverride->position = position; |
| m_viewportOverride->scale = scale; |
| |
| // Move the correct (scaled) content area to show in the top left of the |
| // CompositorFrame via the root transform. |
| updateRootLayerTransform(); |
| } |
| |
| void DevToolsEmulator::resetViewport() { |
| if (!m_viewportOverride) |
| return; |
| |
| bool originalMasking = m_viewportOverride->originalVisualViewportMasking; |
| m_viewportOverride = WTF::nullopt; |
| |
| GraphicsLayer* containerLayer = |
| m_webViewImpl->page()->visualViewport().containerLayer(); |
| if (containerLayer) |
| containerLayer->setMasksToBounds(originalMasking); |
| updateRootLayerTransform(); |
| } |
| |
| void DevToolsEmulator::mainFrameScrollOrScaleChanged() { |
| // Viewport override has to take current page scale and scroll offset into |
| // account. Update the transform if override is active. |
| if (m_viewportOverride) |
| updateRootLayerTransform(); |
| } |
| |
| void DevToolsEmulator::applyDeviceEmulationTransform( |
| TransformationMatrix* transform) { |
| if (m_deviceMetricsEnabled) { |
| WebSize offset(m_emulationParams.offset.x, m_emulationParams.offset.y); |
| // Scale first, so that translation is unaffected. |
| transform->translate(offset.width, offset.height); |
| transform->scale(m_emulationParams.scale); |
| if (m_webViewImpl->mainFrameImpl()) |
| m_webViewImpl->mainFrameImpl()->setInputEventsTransformForEmulation( |
| offset, m_emulationParams.scale); |
| } else { |
| if (m_webViewImpl->mainFrameImpl()) |
| m_webViewImpl->mainFrameImpl()->setInputEventsTransformForEmulation( |
| WebSize(0, 0), 1.0); |
| } |
| } |
| |
| void DevToolsEmulator::applyViewportOverride(TransformationMatrix* transform) { |
| if (!m_viewportOverride) |
| return; |
| |
| // Transform operations follow in reverse application. |
| // Last, scale positioned area according to override. |
| transform->scale(m_viewportOverride->scale); |
| |
| // Translate while taking into account current scroll offset. |
| WebSize scrollOffset = m_webViewImpl->mainFrame()->getScrollOffset(); |
| WebFloatPoint visualOffset = m_webViewImpl->visualViewportOffset(); |
| float scrollX = scrollOffset.width + visualOffset.x; |
| float scrollY = scrollOffset.height + visualOffset.y; |
| transform->translate(-m_viewportOverride->position.x + scrollX, |
| -m_viewportOverride->position.y + scrollY); |
| |
| // First, reverse page scale, so we don't have to take it into account for |
| // calculation of the translation. |
| transform->scale(1. / m_webViewImpl->pageScaleFactor()); |
| } |
| |
| void DevToolsEmulator::updateRootLayerTransform() { |
| TransformationMatrix transform; |
| |
| // Apply device emulation transform first, so that it is affected by the |
| // viewport override. |
| applyViewportOverride(&transform); |
| applyDeviceEmulationTransform(&transform); |
| m_webViewImpl->setDeviceEmulationTransform(transform); |
| } |
| |
| WTF::Optional<IntRect> DevToolsEmulator::visibleContentRectForPainting() const { |
| if (!m_viewportOverride) |
| return WTF::nullopt; |
| FloatSize viewportSize(m_webViewImpl->layerTreeView()->getViewportSize()); |
| viewportSize.scale(1. / compositorDeviceScaleFactor()); |
| viewportSize.scale(1. / m_viewportOverride->scale); |
| return enclosingIntRect( |
| FloatRect(m_viewportOverride->position.x, m_viewportOverride->position.y, |
| viewportSize.width(), viewportSize.height())); |
| } |
| |
| void DevToolsEmulator::setTouchEventEmulationEnabled(bool enabled) { |
| if (m_touchEventEmulationEnabled == enabled) |
| return; |
| if (!m_touchEventEmulationEnabled) { |
| m_originalTouchEventFeatureDetectionEnabled = |
| RuntimeEnabledFeatures::touchEventFeatureDetectionEnabled(); |
| m_originalDeviceSupportsTouch = |
| m_webViewImpl->page()->settings().getDeviceSupportsTouch(); |
| m_originalMaxTouchPoints = |
| m_webViewImpl->page()->settings().getMaxTouchPoints(); |
| } |
| RuntimeEnabledFeatures::setTouchEventFeatureDetectionEnabled( |
| enabled ? true : m_originalTouchEventFeatureDetectionEnabled); |
| if (!m_originalDeviceSupportsTouch) { |
| if (enabled && m_webViewImpl->mainFrameImpl()) { |
| m_webViewImpl->mainFrameImpl() |
| ->frame() |
| ->eventHandler() |
| .clearMouseEventManager(); |
| } |
| m_webViewImpl->page()->settings().setDeviceSupportsTouch( |
| enabled ? true : m_originalDeviceSupportsTouch); |
| // Currently emulation does not provide multiple touch points. |
| m_webViewImpl->page()->settings().setMaxTouchPoints( |
| enabled ? 1 : m_originalMaxTouchPoints); |
| } |
| m_touchEventEmulationEnabled = enabled; |
| // TODO(dgozman): mainFrameImpl() check in this class should be unnecessary. |
| // It is only needed when we reattach and restore InspectorEmulationAgent, |
| // which happens before everything has been setup correctly, and therefore |
| // fails during remote -> local main frame transition. |
| // We should instead route emulation from browser through the WebViewImpl |
| // to the local main frame, and remove InspectorEmulationAgent entirely. |
| if (m_webViewImpl->mainFrameImpl()) |
| m_webViewImpl->mainFrameImpl()->frameView()->layout(); |
| } |
| |
| void DevToolsEmulator::setScriptExecutionDisabled( |
| bool scriptExecutionDisabled) { |
| m_scriptExecutionDisabled = scriptExecutionDisabled; |
| m_webViewImpl->page()->settings().setScriptEnabled( |
| m_scriptExecutionDisabled ? false : m_embedderScriptEnabled); |
| } |
| |
| bool DevToolsEmulator::handleInputEvent(const WebInputEvent& inputEvent) { |
| Page* page = m_webViewImpl->page(); |
| if (!page) |
| return false; |
| |
| // FIXME: This workaround is required for touch emulation on Mac, where |
| // compositor-side pinch handling is not enabled. See http://crbug.com/138003. |
| bool isPinch = inputEvent.type() == WebInputEvent::GesturePinchBegin || |
| inputEvent.type() == WebInputEvent::GesturePinchUpdate || |
| inputEvent.type() == WebInputEvent::GesturePinchEnd; |
| if (isPinch && m_touchEventEmulationEnabled) { |
| FrameView* frameView = page->deprecatedLocalMainFrame()->view(); |
| WebGestureEvent scaledEvent = TransformWebGestureEvent( |
| frameView, static_cast<const WebGestureEvent&>(inputEvent)); |
| float pageScaleFactor = page->pageScaleFactor(); |
| if (scaledEvent.type() == WebInputEvent::GesturePinchBegin) { |
| WebFloatPoint gesturePosition = scaledEvent.positionInRootFrame(); |
| m_lastPinchAnchorCss = WTF::wrapUnique(new IntPoint( |
| roundedIntPoint(gesturePosition + frameView->getScrollOffset()))); |
| m_lastPinchAnchorDip = |
| WTF::wrapUnique(new IntPoint(flooredIntPoint(gesturePosition))); |
| m_lastPinchAnchorDip->scale(pageScaleFactor, pageScaleFactor); |
| } |
| if (scaledEvent.type() == WebInputEvent::GesturePinchUpdate && |
| m_lastPinchAnchorCss) { |
| float newPageScaleFactor = pageScaleFactor * scaledEvent.pinchScale(); |
| IntPoint anchorCss(*m_lastPinchAnchorDip.get()); |
| anchorCss.scale(1.f / newPageScaleFactor, 1.f / newPageScaleFactor); |
| m_webViewImpl->setPageScaleFactor(newPageScaleFactor); |
| m_webViewImpl->mainFrame()->setScrollOffset( |
| toIntSize(*m_lastPinchAnchorCss.get() - toIntSize(anchorCss))); |
| } |
| if (scaledEvent.type() == WebInputEvent::GesturePinchEnd) { |
| m_lastPinchAnchorCss.reset(); |
| m_lastPinchAnchorDip.reset(); |
| } |
| return true; |
| } |
| |
| return false; |
| } |
| |
| } // namespace blink |