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

Unified Diff: cc/page_scale_animation.cc

Issue 11090062: cc: Rewrite PageScaleAnimation for new coordinate system. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Address gfx::Size::Scale() currently not being mutating Created 8 years, 1 month 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
« cc/layer_tree_host_impl.cc ('K') | « cc/page_scale_animation.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/page_scale_animation.cc
diff --git a/cc/page_scale_animation.cc b/cc/page_scale_animation.cc
index 49948abd333e9ce8aa72f83e6db51e143e58ebe2..877cacb96f501f3996ed4409a08a72c9abc522f1 100644
--- a/cc/page_scale_animation.cc
+++ b/cc/page_scale_animation.cc
@@ -5,29 +5,60 @@
#include "config.h"
#include "cc/page_scale_animation.h"
-
-#include "cc/geometry.h"
+#include "ui/gfx/point_f.h"
#include "ui/gfx/rect_f.h"
-#include "ui/gfx/vector2d_conversions.h"
-#include "ui/gfx/vector2d_f.h"
+#include <algorithm>
#include <math.h>
+namespace {
+
+gfx::PointF toPointF(const gfx::Vector2dF& vector)
+{
+ return gfx::PointF(vector.x(), vector.y());
+}
+
+// This takes a viewport-relative vector and returns a vector whose values are
+// between 0 and 1, representing the percentage position within the viewport.
+gfx::Vector2dF normalizeFromViewport(const gfx::Vector2dF& denormalized, const gfx::SizeF& viewportSize)
+{
+ gfx::Vector2dF normalized(denormalized);
+ normalized.Scale(1 / viewportSize.width(), 1 / viewportSize.height());
+ return normalized;
+}
+
+gfx::Vector2dF denormalizeToViewport(const gfx::Vector2dF& normalized, const gfx::SizeF& viewportSize)
+{
+ gfx::Vector2dF denormalized(normalized);
+ denormalized.Scale(viewportSize.width(), viewportSize.height());
+ return denormalized;
+}
+
+gfx::Vector2dF interpolateBetween(const gfx::Vector2dF& start, const gfx::Vector2dF end, float interp)
+{
+ gfx::Vector2dF result;
+ result.set_x(start.x() + interp * (end.x() - start.x()));
+ result.set_y(start.y() + interp * (end.y() - start.y()));
+ return result;
+}
+
+}
+
namespace cc {
-scoped_ptr<PageScaleAnimation> PageScaleAnimation::create(gfx::Vector2d scrollStart, float pageScaleStart, const gfx::Size& windowSize, const gfx::Size& contentSize, double startTime)
+scoped_ptr<PageScaleAnimation> PageScaleAnimation::create(const gfx::Vector2dF& startScrollOffset, float startPageScaleFactor, const gfx::SizeF& viewportSize, const gfx::SizeF& rootLayerSize, double startTime)
{
- return make_scoped_ptr(new PageScaleAnimation(scrollStart, pageScaleStart, windowSize, contentSize, startTime));
+ return make_scoped_ptr(new PageScaleAnimation(startScrollOffset, startPageScaleFactor, viewportSize, rootLayerSize, startTime));
}
-PageScaleAnimation::PageScaleAnimation(gfx::Vector2d scrollStart, float pageScaleStart, const gfx::Size& windowSize, const gfx::Size& contentSize, double startTime)
- : m_scrollStart(scrollStart)
- , m_pageScaleStart(pageScaleStart)
- , m_windowSize(windowSize)
- , m_contentSize(contentSize)
- , m_anchorMode(false)
- , m_scrollEnd(scrollStart)
- , m_pageScaleEnd(pageScaleStart)
+PageScaleAnimation::PageScaleAnimation(const gfx::Vector2dF& startScrollOffset, float startPageScaleFactor, const gfx::SizeF& viewportSize, const gfx::SizeF& rootLayerSize, double startTime)
+ : m_startPageScaleFactor(startPageScaleFactor)
+ , m_targetPageScaleFactor(0)
+ , m_startScrollOffset(startScrollOffset)
+ , m_startAnchor()
+ , m_targetAnchor()
+ , m_viewportSize(viewportSize)
+ , m_rootLayerSize(rootLayerSize)
, m_startTime(startTime)
, m_duration(0)
{
@@ -37,67 +68,93 @@ PageScaleAnimation::~PageScaleAnimation()
{
}
-void PageScaleAnimation::zoomTo(gfx::Vector2d finalScroll, float finalPageScale, double duration)
-{
- if (m_pageScaleStart != finalPageScale) {
- // For uniform-looking zooming, infer the anchor (point that remains in
- // place throughout the zoom) from the start and end rects.
- gfx::RectF startRect(gfx::PointAtOffsetFromOrigin(m_scrollStart), m_windowSize);
- gfx::RectF endRect(gfx::PointAtOffsetFromOrigin(finalScroll), m_windowSize);
- endRect.Scale(m_pageScaleStart / finalPageScale);
-
- // The anchor is the point which is at the same ratio of the sides of
- // both startRect and endRect. For example, a zoom-in double-tap to a
- // perfectly centered rect will have anchor ratios (0.5, 0.5), while one
- // to a rect touching the bottom-right of the screen will have anchor
- // ratios (1.0, 1.0). In other words, it obeys the equations:
- // anchorX = start_width * ratioX + start_x
- // anchorX = end_width * ratioX + end_x
- // anchorY = start_height * ratioY + start_y
- // anchorY = end_height * ratioY + end_y
- // where both anchor{x,y} and ratio{x,y} begin as unknowns. Solving
- // for the ratios, we get the following formulas:
- float ratioX = (startRect.x() - endRect.x()) / (endRect.width() - startRect.width());
- float ratioY = (startRect.y() - endRect.y()) / (endRect.height() - startRect.height());
-
- gfx::Vector2d anchor(m_windowSize.width() * ratioX, m_windowSize.height() * ratioY);
- zoomWithAnchor(anchor, finalPageScale, duration);
- } else {
- // If this is a pure translation, then there exists no anchor. Linearly
- // interpolate the scroll offset instead.
- m_scrollEnd = finalScroll;
- m_pageScaleEnd = finalPageScale;
- m_duration = duration;
- m_anchorMode = false;
+void PageScaleAnimation::zoomTo(const gfx::Vector2dF& targetScrollOffset, float targetPageScaleFactor, double duration)
+{
+ m_targetPageScaleFactor = targetPageScaleFactor;
+ m_targetScrollOffset = targetScrollOffset;
+ clampTargetScrollOffset();
+ m_duration = duration;
+
+ if (m_startPageScaleFactor == targetPageScaleFactor) {
+ m_startAnchor = m_startScrollOffset;
+ m_targetAnchor = targetScrollOffset;
+ return;
}
+
+ // For uniform-looking zooming, infer an anchor from the start and target
+ // viewport rects.
+ inferTargetAnchorFromScrollOffsets();
+ m_startAnchor = m_targetAnchor;
}
-void PageScaleAnimation::zoomWithAnchor(gfx::Vector2d anchor, float finalPageScale, double duration)
+void PageScaleAnimation::zoomWithAnchor(const gfx::Vector2dF& anchor, float targetPageScaleFactor, double duration)
{
- m_scrollEnd = m_scrollStart + anchor;
- m_scrollEnd = gfx::ToFlooredVector2d(cc::ScaleVector2d(m_scrollEnd, finalPageScale / m_pageScaleStart));
- m_scrollEnd -= anchor;
+ m_startAnchor = anchor;
+ m_targetPageScaleFactor = targetPageScaleFactor;
+ m_duration = duration;
- m_scrollEnd = ClampFromBelow(m_scrollEnd, gfx::Vector2d());
- gfx::SizeF scaledContentSize = m_contentSize.Scale(finalPageScale / m_pageScaleStart);
- gfx::Vector2d maxScrollOffset = gfx::ToRoundedVector2d(BottomRight(gfx::RectF(scaledContentSize)) - BottomRight(gfx::Rect(m_windowSize)));
- m_scrollEnd = m_scrollEnd;
- m_scrollEnd = ClampFromAbove(m_scrollEnd, maxScrollOffset);
+ // We start zooming out from the anchor tapped by the user. But if
+ // the target scale is impossible to attain without hitting the root layer
+ // edges, then infer an anchor that doesn't collide with the edges.
+ // We will interpolate between the two anchors during the animation.
+ inferTargetScrollOffsetFromStartAnchor();
+ clampTargetScrollOffset();
+ inferTargetAnchorFromScrollOffsets();
+}
- m_anchor = anchor;
- m_pageScaleEnd = finalPageScale;
- m_duration = duration;
- m_anchorMode = true;
+gfx::SizeF PageScaleAnimation::viewportSizeAtScale(float pageScaleFactor) const
+{
+ return gfx::SizeF(m_viewportSize.width() / pageScaleFactor, m_viewportSize.height() / pageScaleFactor);
+}
+
+void PageScaleAnimation::inferTargetScrollOffsetFromStartAnchor()
+{
+ gfx::Vector2dF anchorRelativeToStartViewport = m_startAnchor - m_startScrollOffset;
+ gfx::Vector2dF normalized = normalizeFromViewport(anchorRelativeToStartViewport, viewportSizeAtScale(m_startPageScaleFactor));
+ m_targetScrollOffset = m_startAnchor - denormalizeToViewport(normalized, viewportSizeAtScale(m_targetPageScaleFactor));
+}
+
+void PageScaleAnimation::inferTargetAnchorFromScrollOffsets()
+{
+ gfx::RectF startRect(toPointF(m_startScrollOffset), viewportSizeAtScale(m_startPageScaleFactor));
+ gfx::RectF targetRect(toPointF(m_targetScrollOffset), viewportSizeAtScale(m_targetPageScaleFactor));
+
+ // The anchor is the point which is at the same normalized relative position
+ // within both startRect and endRect. For example, a zoom-in double-tap to a
+ // perfectly centered rect will have normalized anchor (0.5, 0.5), while one
+ // to a rect touching the bottom-right of the screen will have normalized
+ // anchor (1.0, 1.0). In other words, it obeys the equations:
+ // anchorX = start_width * normalizedX + start_x
+ // anchorX = target_width * normalizedX + target_x
+ // anchorY = start_height * normalizedY + start_y
+ // anchorY = target_height * normalizedY + target_y
+ // where both anchor{x,y} and normalized{x,y} begin as unknowns. Solving
+ // for the normalized, we get the following formulas:
+ gfx::Vector2dF normalized;
+ normalized.set_x((startRect.x() - targetRect.x()) / (targetRect.width() - startRect.width()));
+ normalized.set_y((startRect.y() - targetRect.y()) / (targetRect.height() - startRect.height()));
+ m_targetAnchor = m_targetScrollOffset + denormalizeToViewport(normalized, viewportSizeAtScale(m_targetPageScaleFactor));
+}
+
+void PageScaleAnimation::clampTargetScrollOffset()
+{
+ gfx::Vector2dF maxScrollPosition;
+ maxScrollPosition.set_x(m_rootLayerSize.width() - viewportSizeAtScale(m_targetPageScaleFactor).width());
+ maxScrollPosition.set_y(m_rootLayerSize.height() - viewportSizeAtScale(m_targetPageScaleFactor).height());
+ m_targetScrollOffset.set_x(std::max<float>(0, m_targetScrollOffset.x()));
+ m_targetScrollOffset.set_y(std::max<float>(0, m_targetScrollOffset.y()));
+ m_targetScrollOffset.set_x(std::min<float>(maxScrollPosition.x(), m_targetScrollOffset.x()));
+ m_targetScrollOffset.set_y(std::min<float>(maxScrollPosition.y(), m_targetScrollOffset.y()));
}
-gfx::Vector2d PageScaleAnimation::scrollOffsetAtTime(double time) const
+gfx::Vector2dF PageScaleAnimation::scrollOffsetAtTime(double time) const
{
- return scrollOffsetAtRatio(progressRatioForTime(time));
+ return scrollOffsetAt(interpAtTime(time));
}
-float PageScaleAnimation::pageScaleAtTime(double time) const
+float PageScaleAnimation::pageScaleFactorAtTime(double time) const
{
- return pageScaleAtRatio(progressRatioForTime(time));
+ return pageScaleFactorAt(interpAtTime(time));
}
bool PageScaleAnimation::isAnimationCompleteAtTime(double time) const
@@ -105,7 +162,7 @@ bool PageScaleAnimation::isAnimationCompleteAtTime(double time) const
return time >= endTime();
}
-float PageScaleAnimation::progressRatioForTime(double time) const
+float PageScaleAnimation::interpAtTime(double time) const
{
if (isAnimationCompleteAtTime(time))
return 1;
@@ -113,52 +170,52 @@ float PageScaleAnimation::progressRatioForTime(double time) const
return (time - m_startTime) / m_duration;
}
-gfx::Vector2d PageScaleAnimation::scrollOffsetAtRatio(float ratio) const
-{
- if (ratio <= 0)
- return m_scrollStart;
- if (ratio >= 1)
- return m_scrollEnd;
-
- float currentPageScale = pageScaleAtRatio(ratio);
- gfx::Vector2d currentScrollOffset;
- if (m_anchorMode) {
- // Keep the anchor stable on the screen at the current scale.
- gfx::Vector2dF documentAnchor = m_scrollStart + m_anchor;
- documentAnchor.Scale(currentPageScale / m_pageScaleStart);
- currentScrollOffset = gfx::ToRoundedVector2d(documentAnchor - m_anchor);
- } else {
- // First move both scroll offsets to the current coordinate space.
- gfx::Vector2dF scaledStartScroll(m_scrollStart);
- scaledStartScroll.Scale(currentPageScale / m_pageScaleStart);
- gfx::Vector2dF scaledEndScroll(m_scrollEnd);
- scaledEndScroll.Scale(currentPageScale / m_pageScaleEnd);
-
- // Linearly interpolate between them.
- gfx::Vector2dF delta = scaledEndScroll - scaledStartScroll;
- delta.Scale(ratio);
- currentScrollOffset = gfx::ToRoundedVector2d(scaledStartScroll + delta);
- }
+gfx::Vector2dF PageScaleAnimation::scrollOffsetAt(float interp) const
+{
+ if (interp <= 0)
+ return m_startScrollOffset;
+ if (interp >= 1)
+ return m_targetScrollOffset;
+
+ return anchorAt(interp) - viewportRelativeAnchorAt(interp);
+}
+
+gfx::Vector2dF PageScaleAnimation::anchorAt(float interp) const
+{
+ // Interpolate from start to target anchor in absolute space.
+ gfx::Vector2dF delta = m_targetAnchor - m_startAnchor;
+ delta.Scale(interp);
+ return m_startAnchor + delta;
+}
+
+gfx::Vector2dF PageScaleAnimation::viewportRelativeAnchorAt(float interp) const
+{
+ // Interpolate from start to target anchor in the space relative to the
+ // viewport at its current scale level.
+ gfx::Vector2dF anchorRelativeToStartViewport = m_startAnchor - m_startScrollOffset;
+ gfx::Vector2dF anchorRelativeToTargetViewport = m_targetAnchor - m_targetScrollOffset;
+
+ gfx::Vector2dF startNormalized = normalizeFromViewport(anchorRelativeToStartViewport, viewportSizeAtScale(m_startPageScaleFactor));
+ gfx::Vector2dF targetNormalized = normalizeFromViewport(anchorRelativeToTargetViewport, viewportSizeAtScale(m_targetPageScaleFactor));
+ gfx::Vector2dF interpNormalized = interpolateBetween(startNormalized, targetNormalized, interp);
- return currentScrollOffset;
+ gfx::SizeF currentViewportSize = viewportSizeAtScale(pageScaleFactorAt(interp));
+ return denormalizeToViewport(interpNormalized, currentViewportSize);
}
-float PageScaleAnimation::pageScaleAtRatio(float ratio) const
+float PageScaleAnimation::pageScaleFactorAt(float interp) const
{
- if (ratio <= 0)
- return m_pageScaleStart;
- if (ratio >= 1)
- return m_pageScaleEnd;
+ if (interp <= 0)
+ return m_startPageScaleFactor;
+ if (interp >= 1)
+ return m_targetPageScaleFactor;
// Linearly interpolate the magnitude in log scale.
- // Log scale is needed to maintain the appearance of uniform zoom. For
- // example, if we zoom from 0.5 to 4.0 in 3 seconds, then we should
- // be zooming by 2x every second.
- float diff = m_pageScaleEnd / m_pageScaleStart;
+ float diff = m_targetPageScaleFactor / m_startPageScaleFactor;
float logDiff = log(diff);
- logDiff *= ratio;
+ logDiff *= interp;
diff = exp(logDiff);
- return m_pageScaleStart * diff;
+ return m_startPageScaleFactor * diff;
}
} // namespace cc
« cc/layer_tree_host_impl.cc ('K') | « cc/page_scale_animation.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698