Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Unified Diff: Source/WebKit/chromium/src/WebViewImpl.cpp

Issue 13704012: Improve mobile device rotation behavior. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebase Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | Source/WebKit/chromium/tests/WebFrameTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/WebKit/chromium/src/WebViewImpl.cpp
diff --git a/Source/WebKit/chromium/src/WebViewImpl.cpp b/Source/WebKit/chromium/src/WebViewImpl.cpp
index 0a7b1f89494d0fbbcfd72c97ca7d33e6ddc9ec00..369b199873e47b2265ef21c3e99d44236b509e77 100644
--- a/Source/WebKit/chromium/src/WebViewImpl.cpp
+++ b/Source/WebKit/chromium/src/WebViewImpl.cpp
@@ -197,6 +197,10 @@ static const float doubleTapZoomContentMinimumMargin = 2;
static const double doubleTapZoomAnimationDurationInSeconds = 0.25;
static const float doubleTapZoomAlreadyLegibleRatio = 1.2f;
+static const float viewportAnchorRelativeEpsilon = 0.1f;
+static const float viewportAnchorXCoord = 0.5f;
+static const float viewportAnchorYCoord = 0;
+
// Constants for zooming in on a focused text field.
static const double scrollAndScaleAnimationDurationInSeconds = 0.2;
static const int minReadableCaretHeight = 18;
@@ -206,6 +210,105 @@ static const int caretPadding = 10;
namespace WebKit {
+#if ENABLE(VIEWPORT)
+namespace {
+// ViewportAnchor provides a way to anchor a viewport origin to a DOM node.
+// In particular, the user supplies the current viewport (in CSS coordinates)
+// and an anchor point (in view coordinates, e.g., (0, 0) == viewport origin,
+// (0.5, 0) == viewport top center). The anchor point tracks the underlying DOM
+// node; as the node moves or the view is resized, the viewport anchor maintains
+// its orientation relative to the node, and the viewport origin maintains its
+// orientation relative to the anchor.
+class ViewportAnchor {
abarth-chromium 2013/04/12 17:33:30 This class should go in its own file. WebViewImpl
jdduke (slow) 2013/04/12 19:20:16 Done.
+public:
+ ViewportAnchor(EventHandler* eventHandler)
abarth-chromium 2013/04/12 17:33:30 one-argument constructors should be marked explici
jdduke (slow) 2013/04/12 19:20:16 Done.
+ : m_eventHandler(eventHandler) { }
+
+ void setAnchor(const IntRect& viewRect, const FloatSize& anchorInViewCoords)
+ {
+ m_viewRect = viewRect;
+ m_anchorNode.clear();
+ m_anchorNodeBounds = LayoutRect();
+ m_anchorInNodeCoords = FloatSize();
+ m_anchorInViewCoords = anchorInViewCoords;
+
+ if (viewRect.isEmpty())
+ return;
+
+ // Preserve origins at the absolute screen origin
+ if (viewRect.location() == IntPoint::zero())
+ return;
+
+ FloatSize anchorOffset = viewRect.size();
+ anchorOffset.scale(anchorInViewCoords.width(), anchorInViewCoords.height());
+ const FloatPoint anchorPoint = FloatPoint(viewRect.location()) + anchorOffset;
+
+ Node* node = findNonEmptyAnchorNode(flooredIntPoint(anchorPoint), viewRect, m_eventHandler);
+ if (!node)
+ return;
+
+ m_anchorNode = node;
+ m_anchorNodeBounds = node->boundingBox();
+ m_anchorInNodeCoords = anchorPoint - m_anchorNodeBounds.location();
+ m_anchorInNodeCoords.scale(1.f / m_anchorNodeBounds.width(), 1.f / m_anchorNodeBounds.height());
+ }
+
+ // Note: The returned point may not lie within the document bounds.
+ IntPoint computeOrigin(const IntSize& currentViewSize) const
+ {
+ if (!m_anchorNode || !m_anchorNode->inDocument())
+ return m_viewRect.location();
+
+ const LayoutRect currentNodeBounds = m_anchorNode->boundingBox();
+ if (m_anchorNodeBounds == currentNodeBounds)
+ return m_viewRect.location();
+
+ // Compute the new anchor point relative to the node position
+ FloatSize anchorOffsetFromNode = currentNodeBounds.size();
+ anchorOffsetFromNode.scale(m_anchorInNodeCoords.width(), m_anchorInNodeCoords.height());
+ FloatPoint anchorPoint = currentNodeBounds.location() + anchorOffsetFromNode;
+
+ // Compute the new origin point relative to the new anchor point
+ FloatSize anchorOffsetFromOrigin = currentViewSize;
+ anchorOffsetFromOrigin.scale(m_anchorInViewCoords.width(), m_anchorInViewCoords.height());
+ return flooredIntPoint(anchorPoint - anchorOffsetFromOrigin);
+ }
+
+private:
+ ViewportAnchor();
+
+ static Node* findNonEmptyAnchorNode(const IntPoint& point, const IntRect& viewRect, EventHandler* eventHandler)
+ {
+ Node* node = eventHandler->hitTestResultAtPoint(point).innerNode();
+
+ // If the node bounding box contains the view, make a single attempt to
+ // find a smaller node; the larger the node bounds, the greater the
+ // variability under resize.
+ if (node && node->boundingBox().contains(viewRect)) {
+ IntSize pointOffset = viewRect.size();
+ pointOffset.scale(viewportAnchorRelativeEpsilon);
+ node = eventHandler->hitTestResultAtPoint(point + pointOffset).innerNode();
+ }
+
+ while (node && node->boundingBox().isEmpty())
+ node = node->parentNode();
+
+ return node;
+ }
+
+ EventHandler* m_eventHandler;
+
+ IntRect m_viewRect;
+
+ RefPtr<Node> m_anchorNode;
+ LayoutRect m_anchorNodeBounds;
+
+ FloatSize m_anchorInViewCoords;
+ FloatSize m_anchorInNodeCoords;
+};
+}
+#endif // ENABLE(VIEWPORT)
+
// Change the text zoom level by kTextSizeMultiplierRatio each time the user
// zooms text in or out (ie., change by 20%). The min and max values limit
// text zoom to half and 3x the original text size. These three values match
@@ -1654,12 +1757,18 @@ void WebViewImpl::resize(const WebSize& newSize)
WebSize oldSize = m_size;
float oldPageScaleFactor = pageScaleFactor();
- IntSize oldScrollOffset = view->scrollOffset();
+ float oldMinimumPageScaleFactor = m_minimumPageScaleFactor;
int oldFixedLayoutWidth = fixedLayoutSize().width;
+ int oldContentsWidth = contentsSize().width();
m_size = newSize;
#if ENABLE(VIEWPORT)
+ ViewportAnchor viewportAnchor(mainFrameImpl()->frame()->eventHandler());
+ if (settings()->viewportEnabled())
+ viewportAnchor.setAnchor(view->visibleContentRect(),
+ FloatSize(viewportAnchorXCoord, viewportAnchorYCoord));
+
ViewportArguments viewportArguments = mainFrameImpl()->frame()->document()->viewportArguments();
m_page->chrome()->client()->dispatchViewportPropertiesDidChange(viewportArguments);
#endif
@@ -1679,21 +1788,29 @@ void WebViewImpl::resize(const WebSize& newSize)
if (view->needsLayout())
view->layout();
- // When the device rotates:
- // - If the page width is unchanged, then zoom by new width/old width
- // such as to keep the same content horizontally onscreen.
- // - If the page width stretches proportionally to the change in
- // screen width, then don't zoom at all (assuming the content has
- // scaled uniformly, then the same content will be horizontally
- // onscreen).
- // - If the page width partially stretches, then zoom partially to
- // make up the difference.
- // In all cases try to keep the same content at the top of the screen.
+ // The minimum scale limit may change as a result of layout content
+ // changes; in this case, scale relative to the change in content width.
+ // Otherwise scale relative to the change in layout width.
+ // Don't do any scaling if the old width was zero (i.e., first resize).
+ float scalingWidthRatio = 1;
+ if (oldSize.width && oldContentsWidth && m_minimumPageScaleFactor != oldMinimumPageScaleFactor)
+ scalingWidthRatio = contentsSize().width() / (float) oldContentsWidth;
+ else if (oldFixedLayoutWidth)
+ scalingWidthRatio = fixedLayoutSize().width / (float) oldFixedLayoutWidth;
+
float viewportWidthRatio = !oldSize.width ? 1 : newSize.width / (float) oldSize.width;
- float fixedLayoutWidthRatio = !oldFixedLayoutWidth ? 1 : fixedLayoutSize().width / (float) oldFixedLayoutWidth;
- float scaleMultiplier = viewportWidthRatio / fixedLayoutWidthRatio;
- if (scaleMultiplier != 1)
- setPageScaleFactor(oldPageScaleFactor * scaleMultiplier, WebPoint(oldScrollOffset.width(), oldScrollOffset.height()));
+ float scaleMultiplier = viewportWidthRatio / scalingWidthRatio;
+
+ IntSize viewportSize = view->visibleContentRect().size();
+ if (scaleMultiplier != 1) {
+ float newPageScaleFactor = oldPageScaleFactor * scaleMultiplier;
+ viewportSize.scale(pageScaleFactor() / newPageScaleFactor);
+ IntPoint scrollOffsetAtNewScale = viewportAnchor.computeOrigin(viewportSize);
+ setPageScaleFactor(newPageScaleFactor, scrollOffsetAtNewScale);
+ } else {
+ IntPoint scrollOffsetAtNewScale = clampOffsetAtScale(viewportAnchor.computeOrigin(viewportSize), pageScaleFactor());
+ updateMainFrameScrollPosition(scrollOffsetAtNewScale, false);
+ }
}
#endif
« no previous file with comments | « no previous file | Source/WebKit/chromium/tests/WebFrameTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698