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"
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
);
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
)
48 , m_viewportSize(viewportSize
)
49 , m_rootLayerSize(rootLayerSize
)
50 , m_startTime(startTime
)
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
;
72 // For uniform-looking zooming, infer an anchor from the start and target
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
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
))
160 return (time
- m_startTime
) / m_duration
;
163 gfx::Vector2dF
PageScaleAnimation::scrollOffsetAt(float interp
) const
166 return m_startScrollOffset
;
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
192 return m_startPageScaleFactor
;
194 return m_targetPageScaleFactor
;
196 // Linearly interpolate the magnitude in log scale.
197 float diff
= m_targetPageScaleFactor
/ m_startPageScaleFactor
;
198 float logDiff
= log(diff
);
201 return m_startPageScaleFactor
* diff
;