Use TargetTransform instead of transform in ConvertPointFor/FromAncestor
[chromium-blink-merge.git] / cc / page_scale_animation.cc
blobb8f1fe6185899e4426bdcdbaf1d406e84684b415
1 // Copyright 2012 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 "cc/page_scale_animation.h"
7 #include "base/logging.h"
8 #include "ui/gfx/point_f.h"
9 #include "ui/gfx/rect_f.h"
10 #include "ui/gfx/vector2d_conversions.h"
12 #include <math.h>
14 namespace {
16 // This takes a viewport-relative vector and returns a vector whose values are
17 // between 0 and 1, representing the percentage position within the viewport.
18 gfx::Vector2dF normalizeFromViewport(const gfx::Vector2dF& denormalized, const gfx::SizeF& viewportSize)
20 return gfx::ScaleVector2d(denormalized, 1 / viewportSize.width(), 1 / viewportSize.height());
23 gfx::Vector2dF denormalizeToViewport(const gfx::Vector2dF& normalized, const gfx::SizeF& viewportSize)
25 return gfx::ScaleVector2d(normalized, viewportSize.width(), viewportSize.height());
28 gfx::Vector2dF interpolateBetween(const gfx::Vector2dF& start, const gfx::Vector2dF end, float interp)
30 return start + gfx::ScaleVector2d(end - start, interp);
35 namespace cc {
37 scoped_ptr<PageScaleAnimation> PageScaleAnimation::create(const gfx::Vector2dF& startScrollOffset, float startPageScaleFactor, const gfx::SizeF& viewportSize, const gfx::SizeF& rootLayerSize, double startTime)
39 return make_scoped_ptr(new PageScaleAnimation(startScrollOffset, startPageScaleFactor, viewportSize, rootLayerSize, startTime));
42 PageScaleAnimation::PageScaleAnimation(const gfx::Vector2dF& startScrollOffset, float startPageScaleFactor, const gfx::SizeF& viewportSize, const gfx::SizeF& rootLayerSize, double startTime)
43 : m_startPageScaleFactor(startPageScaleFactor)
44 , m_targetPageScaleFactor(0)
45 , m_startScrollOffset(startScrollOffset)
46 , m_startAnchor()
47 , m_targetAnchor()
48 , m_viewportSize(viewportSize)
49 , m_rootLayerSize(rootLayerSize)
50 , m_startTime(startTime)
51 , m_duration(0)
55 PageScaleAnimation::~PageScaleAnimation()
59 void PageScaleAnimation::zoomTo(const gfx::Vector2dF& targetScrollOffset, float targetPageScaleFactor, double duration)
61 m_targetPageScaleFactor = targetPageScaleFactor;
62 m_targetScrollOffset = targetScrollOffset;
63 clampTargetScrollOffset();
64 m_duration = duration;
66 if (m_startPageScaleFactor == targetPageScaleFactor) {
67 m_startAnchor = m_startScrollOffset;
68 m_targetAnchor = targetScrollOffset;
69 return;
72 // For uniform-looking zooming, infer an anchor from the start and target
73 // viewport rects.
74 inferTargetAnchorFromScrollOffsets();
75 m_startAnchor = m_targetAnchor;
78 void PageScaleAnimation::zoomWithAnchor(const gfx::Vector2dF& anchor, float targetPageScaleFactor, double duration)
80 m_startAnchor = anchor;
81 m_targetPageScaleFactor = targetPageScaleFactor;
82 m_duration = duration;
84 // We start zooming out from the anchor tapped by the user. But if
85 // the target scale is impossible to attain without hitting the root layer
86 // edges, then infer an anchor that doesn't collide with the edges.
87 // We will interpolate between the two anchors during the animation.
88 inferTargetScrollOffsetFromStartAnchor();
89 clampTargetScrollOffset();
90 inferTargetAnchorFromScrollOffsets();
93 void PageScaleAnimation::inferTargetScrollOffsetFromStartAnchor()
95 gfx::Vector2dF normalized = normalizeFromViewport(m_startAnchor - m_startScrollOffset, startViewportSize());
96 m_targetScrollOffset = m_startAnchor - denormalizeToViewport(normalized, targetViewportSize());
99 void PageScaleAnimation::inferTargetAnchorFromScrollOffsets()
101 // The anchor is the point which is at the same normalized relative position
102 // within both start viewport rect and target viewport rect. For example, a
103 // zoom-in double-tap to a perfectly centered rect will have normalized
104 // anchor (0.5, 0.5), while one to a rect touching the bottom-right of the
105 // screen will have normalized anchor (1.0, 1.0). In other words, it obeys
106 // the equations:
107 // anchor = start_size * normalized + start_offset
108 // anchor = target_size * normalized + target_offset
109 // where both anchor and normalized begin as unknowns. Solving
110 // for the normalized, we get the following:
111 float widthScale = 1 / (targetViewportSize().width() - startViewportSize().width());
112 float heightScale = 1 / (targetViewportSize().height() - startViewportSize().height());
113 gfx::Vector2dF normalized = gfx::ScaleVector2d(m_startScrollOffset - m_targetScrollOffset, widthScale, heightScale);
114 m_targetAnchor = m_targetScrollOffset + denormalizeToViewport(normalized, targetViewportSize());
117 void PageScaleAnimation::clampTargetScrollOffset()
119 gfx::Vector2dF maxScrollOffset = gfx::RectF(m_rootLayerSize).bottom_right() - gfx::RectF(targetViewportSize()).bottom_right();
120 m_targetScrollOffset.ClampToMin(gfx::Vector2dF());
121 m_targetScrollOffset.ClampToMax(maxScrollOffset);
124 gfx::SizeF PageScaleAnimation::startViewportSize() const
126 return gfx::ScaleSize(m_viewportSize, 1 / m_startPageScaleFactor);
129 gfx::SizeF PageScaleAnimation::targetViewportSize() const
131 return gfx::ScaleSize(m_viewportSize, 1 / m_targetPageScaleFactor);
134 gfx::SizeF PageScaleAnimation::viewportSizeAt(float interp) const
136 return gfx::ScaleSize(m_viewportSize, 1 / pageScaleFactorAt(interp));
139 gfx::Vector2dF PageScaleAnimation::scrollOffsetAtTime(double time) const
141 return scrollOffsetAt(interpAtTime(time));
144 float PageScaleAnimation::pageScaleFactorAtTime(double time) const
146 return pageScaleFactorAt(interpAtTime(time));
149 bool PageScaleAnimation::isAnimationCompleteAtTime(double time) const
151 return time >= endTime();
154 float PageScaleAnimation::interpAtTime(double time) const
156 DCHECK_GE(time, m_startTime);
157 if (isAnimationCompleteAtTime(time))
158 return 1;
160 return (time - m_startTime) / m_duration;
163 gfx::Vector2dF PageScaleAnimation::scrollOffsetAt(float interp) const
165 if (interp <= 0)
166 return m_startScrollOffset;
167 if (interp >= 1)
168 return m_targetScrollOffset;
170 return anchorAt(interp) - viewportRelativeAnchorAt(interp);
173 gfx::Vector2dF PageScaleAnimation::anchorAt(float interp) const
175 // Interpolate from start to target anchor in absolute space.
176 return interpolateBetween(m_startAnchor, m_targetAnchor, interp);
179 gfx::Vector2dF PageScaleAnimation::viewportRelativeAnchorAt(float interp) const
181 // Interpolate from start to target anchor in normalized space.
182 gfx::Vector2dF startNormalized = normalizeFromViewport(m_startAnchor - m_startScrollOffset, startViewportSize());
183 gfx::Vector2dF targetNormalized = normalizeFromViewport(m_targetAnchor - m_targetScrollOffset, targetViewportSize());
184 gfx::Vector2dF interpNormalized = interpolateBetween(startNormalized, targetNormalized, interp);
186 return denormalizeToViewport(interpNormalized, viewportSizeAt(interp));
189 float PageScaleAnimation::pageScaleFactorAt(float interp) const
191 if (interp <= 0)
192 return m_startPageScaleFactor;
193 if (interp >= 1)
194 return m_targetPageScaleFactor;
196 // Linearly interpolate the magnitude in log scale.
197 float diff = m_targetPageScaleFactor / m_startPageScaleFactor;
198 float logDiff = log(diff);
199 logDiff *= interp;
200 diff = exp(logDiff);
201 return m_startPageScaleFactor * diff;
204 } // namespace cc