OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/page_scale_animation.h" | 5 #include "cc/page_scale_animation.h" |
6 | 6 |
| 7 #include "base/logging.h" |
7 #include "cc/geometry.h" | 8 #include "cc/geometry.h" |
8 #include "ui/gfx/point_f.h" | 9 #include "ui/gfx/point_f.h" |
9 #include "ui/gfx/rect_f.h" | 10 #include "ui/gfx/rect_f.h" |
| 11 #include "ui/gfx/vector2d_conversions.h" |
10 | 12 |
11 #include <math.h> | 13 #include <math.h> |
12 | 14 |
13 namespace { | 15 namespace { |
14 | 16 |
15 gfx::PointF toPointF(const gfx::Vector2dF& vector) | |
16 { | |
17 return gfx::PointF(vector.x(), vector.y()); | |
18 } | |
19 | |
20 // This takes a viewport-relative vector and returns a vector whose values are | 17 // This takes a viewport-relative vector and returns a vector whose values are |
21 // between 0 and 1, representing the percentage position within the viewport. | 18 // between 0 and 1, representing the percentage position within the viewport. |
22 gfx::Vector2dF normalizeFromViewport(const gfx::Vector2dF& denormalized, const g
fx::SizeF& viewportSize) | 19 gfx::Vector2dF normalizeFromViewport(const gfx::Vector2dF& denormalized, const g
fx::SizeF& viewportSize) |
23 { | 20 { |
24 return gfx::ScaleVector2d(denormalized, 1 / viewportSize.width(), 1 / viewpo
rtSize.height()); | 21 return gfx::ScaleVector2d(denormalized, 1 / viewportSize.width(), 1 / viewpo
rtSize.height()); |
25 } | 22 } |
26 | 23 |
27 gfx::Vector2dF denormalizeToViewport(const gfx::Vector2dF& normalized, const gfx
::SizeF& viewportSize) | 24 gfx::Vector2dF denormalizeToViewport(const gfx::Vector2dF& normalized, const gfx
::SizeF& viewportSize) |
28 { | 25 { |
29 return gfx::ScaleVector2d(normalized, viewportSize.width(), viewportSize.hei
ght()); | 26 return gfx::ScaleVector2d(normalized, viewportSize.width(), viewportSize.hei
ght()); |
30 } | 27 } |
31 | 28 |
32 gfx::Vector2dF interpolateBetween(const gfx::Vector2dF& start, const gfx::Vector
2dF end, float interp) | 29 gfx::Vector2dF interpolateBetween(const gfx::Vector2dF& start, const gfx::Vector
2dF end, float interp) |
33 { | 30 { |
34 gfx::Vector2dF result; | 31 return start + gfx::ScaleVector2d(end - start, interp); |
35 result.set_x(start.x() + interp * (end.x() - start.x())); | |
36 result.set_y(start.y() + interp * (end.y() - start.y())); | |
37 return result; | |
38 } | 32 } |
39 | 33 |
40 } | 34 } |
41 | 35 |
42 namespace cc { | 36 namespace cc { |
43 | 37 |
44 scoped_ptr<PageScaleAnimation> PageScaleAnimation::create(const gfx::Vector2dF&
startScrollOffset, float startPageScaleFactor, const gfx::SizeF& viewportSize, c
onst gfx::SizeF& rootLayerSize, double startTime) | 38 scoped_ptr<PageScaleAnimation> PageScaleAnimation::create(const gfx::Vector2dF&
startScrollOffset, float startPageScaleFactor, const gfx::SizeF& viewportSize, c
onst gfx::SizeF& rootLayerSize, double startTime) |
45 { | 39 { |
46 return make_scoped_ptr(new PageScaleAnimation(startScrollOffset, startPageSc
aleFactor, viewportSize, rootLayerSize, startTime)); | 40 return make_scoped_ptr(new PageScaleAnimation(startScrollOffset, startPageSc
aleFactor, viewportSize, rootLayerSize, startTime)); |
47 } | 41 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 | 84 |
91 // We start zooming out from the anchor tapped by the user. But if | 85 // We start zooming out from the anchor tapped by the user. But if |
92 // the target scale is impossible to attain without hitting the root layer | 86 // the target scale is impossible to attain without hitting the root layer |
93 // edges, then infer an anchor that doesn't collide with the edges. | 87 // edges, then infer an anchor that doesn't collide with the edges. |
94 // We will interpolate between the two anchors during the animation. | 88 // We will interpolate between the two anchors during the animation. |
95 inferTargetScrollOffsetFromStartAnchor(); | 89 inferTargetScrollOffsetFromStartAnchor(); |
96 clampTargetScrollOffset(); | 90 clampTargetScrollOffset(); |
97 inferTargetAnchorFromScrollOffsets(); | 91 inferTargetAnchorFromScrollOffsets(); |
98 } | 92 } |
99 | 93 |
100 gfx::SizeF PageScaleAnimation::viewportSizeAtScale(float pageScaleFactor) const | |
101 { | |
102 return gfx::ScaleSize(m_viewportSize, 1 / pageScaleFactor); | |
103 } | |
104 | |
105 void PageScaleAnimation::inferTargetScrollOffsetFromStartAnchor() | 94 void PageScaleAnimation::inferTargetScrollOffsetFromStartAnchor() |
106 { | 95 { |
107 gfx::Vector2dF anchorRelativeToStartViewport = m_startAnchor - m_startScroll
Offset; | 96 gfx::Vector2dF normalized = normalizeFromViewport(m_startAnchor - m_startScr
ollOffset, startViewportSize()); |
108 gfx::Vector2dF normalized = normalizeFromViewport(anchorRelativeToStartViewp
ort, viewportSizeAtScale(m_startPageScaleFactor)); | 97 m_targetScrollOffset = m_startAnchor - denormalizeToViewport(normalized, tar
getViewportSize()); |
109 m_targetScrollOffset = m_startAnchor - denormalizeToViewport(normalized, vie
wportSizeAtScale(m_targetPageScaleFactor)); | |
110 } | 98 } |
111 | 99 |
112 void PageScaleAnimation::inferTargetAnchorFromScrollOffsets() | 100 void PageScaleAnimation::inferTargetAnchorFromScrollOffsets() |
113 { | 101 { |
114 gfx::RectF startRect(toPointF(m_startScrollOffset), viewportSizeAtScale(m_st
artPageScaleFactor)); | |
115 gfx::RectF targetRect(toPointF(m_targetScrollOffset), viewportSizeAtScale(m_
targetPageScaleFactor)); | |
116 | |
117 // The anchor is the point which is at the same normalized relative position | 102 // The anchor is the point which is at the same normalized relative position |
118 // within both startRect and endRect. For example, a zoom-in double-tap to a | 103 // within both start viewport rect and target viewport rect. For example, a |
119 // perfectly centered rect will have normalized anchor (0.5, 0.5), while one | 104 // zoom-in double-tap to a perfectly centered rect will have normalized |
120 // to a rect touching the bottom-right of the screen will have normalized | 105 // anchor (0.5, 0.5), while one to a rect touching the bottom-right of the |
121 // anchor (1.0, 1.0). In other words, it obeys the equations: | 106 // screen will have normalized anchor (1.0, 1.0). In other words, it obeys |
122 // anchorX = start_width * normalizedX + start_x | 107 // the equations: |
123 // anchorX = target_width * normalizedX + target_x | 108 // anchor = start_size * normalized + start_offset |
124 // anchorY = start_height * normalizedY + start_y | 109 // anchor = target_size * normalized + target_offset |
125 // anchorY = target_height * normalizedY + target_y | 110 // where both anchor and normalized begin as unknowns. Solving |
126 // where both anchor{x,y} and normalized{x,y} begin as unknowns. Solving | 111 // for the normalized, we get the following: |
127 // for the normalized, we get the following formulas: | 112 float widthScale = 1 / (targetViewportSize().width() - startViewportSize().w
idth()); |
128 gfx::Vector2dF normalized; | 113 float heightScale = 1 / (targetViewportSize().height() - startViewportSize()
.height()); |
129 normalized.set_x((startRect.x() - targetRect.x()) / (targetRect.width() - st
artRect.width())); | 114 gfx::Vector2dF normalized = gfx::ScaleVector2d(m_startScrollOffset - m_targe
tScrollOffset, widthScale, heightScale); |
130 normalized.set_y((startRect.y() - targetRect.y()) / (targetRect.height() - s
tartRect.height())); | 115 m_targetAnchor = m_targetScrollOffset + denormalizeToViewport(normalized, ta
rgetViewportSize()); |
131 m_targetAnchor = m_targetScrollOffset + denormalizeToViewport(normalized, vi
ewportSizeAtScale(m_targetPageScaleFactor)); | |
132 } | 116 } |
133 | 117 |
134 void PageScaleAnimation::clampTargetScrollOffset() | 118 void PageScaleAnimation::clampTargetScrollOffset() |
135 { | 119 { |
136 gfx::Vector2dF maxScrollOffset = BottomRight(gfx::RectF(m_rootLayerSize)) -
BottomRight(gfx::RectF(viewportSizeAtScale(m_targetPageScaleFactor))); | 120 gfx::Vector2dF maxScrollOffset = BottomRight(gfx::RectF(m_rootLayerSize)) -
BottomRight(gfx::RectF(targetViewportSize())); |
137 m_targetScrollOffset.ClampToMin(gfx::Vector2dF()); | 121 m_targetScrollOffset.ClampToMin(gfx::Vector2dF()); |
138 m_targetScrollOffset.ClampToMax(maxScrollOffset); | 122 m_targetScrollOffset.ClampToMax(maxScrollOffset); |
139 } | 123 } |
140 | 124 |
| 125 gfx::SizeF PageScaleAnimation::startViewportSize() const |
| 126 { |
| 127 return gfx::ScaleSize(m_viewportSize, 1 / m_startPageScaleFactor); |
| 128 } |
| 129 |
| 130 gfx::SizeF PageScaleAnimation::targetViewportSize() const |
| 131 { |
| 132 return gfx::ScaleSize(m_viewportSize, 1 / m_targetPageScaleFactor); |
| 133 } |
| 134 |
| 135 gfx::SizeF PageScaleAnimation::viewportSizeAt(float interp) const |
| 136 { |
| 137 return gfx::ScaleSize(m_viewportSize, 1 / pageScaleFactorAt(interp)); |
| 138 } |
| 139 |
141 gfx::Vector2dF PageScaleAnimation::scrollOffsetAtTime(double time) const | 140 gfx::Vector2dF PageScaleAnimation::scrollOffsetAtTime(double time) const |
142 { | 141 { |
143 return scrollOffsetAt(interpAtTime(time)); | 142 return scrollOffsetAt(interpAtTime(time)); |
144 } | 143 } |
145 | 144 |
146 float PageScaleAnimation::pageScaleFactorAtTime(double time) const | 145 float PageScaleAnimation::pageScaleFactorAtTime(double time) const |
147 { | 146 { |
148 return pageScaleFactorAt(interpAtTime(time)); | 147 return pageScaleFactorAt(interpAtTime(time)); |
149 } | 148 } |
150 | 149 |
151 bool PageScaleAnimation::isAnimationCompleteAtTime(double time) const | 150 bool PageScaleAnimation::isAnimationCompleteAtTime(double time) const |
152 { | 151 { |
153 return time >= endTime(); | 152 return time >= endTime(); |
154 } | 153 } |
155 | 154 |
156 float PageScaleAnimation::interpAtTime(double time) const | 155 float PageScaleAnimation::interpAtTime(double time) const |
157 { | 156 { |
| 157 DCHECK_GE(time, m_startTime); |
158 if (isAnimationCompleteAtTime(time)) | 158 if (isAnimationCompleteAtTime(time)) |
159 return 1; | 159 return 1; |
160 | 160 |
161 return (time - m_startTime) / m_duration; | 161 return (time - m_startTime) / m_duration; |
162 } | 162 } |
163 | 163 |
164 gfx::Vector2dF PageScaleAnimation::scrollOffsetAt(float interp) const | 164 gfx::Vector2dF PageScaleAnimation::scrollOffsetAt(float interp) const |
165 { | 165 { |
166 if (interp <= 0) | 166 if (interp <= 0) |
167 return m_startScrollOffset; | 167 return m_startScrollOffset; |
168 if (interp >= 1) | 168 if (interp >= 1) |
169 return m_targetScrollOffset; | 169 return m_targetScrollOffset; |
170 | 170 |
171 return anchorAt(interp) - viewportRelativeAnchorAt(interp); | 171 return anchorAt(interp) - viewportRelativeAnchorAt(interp); |
172 } | 172 } |
173 | 173 |
174 gfx::Vector2dF PageScaleAnimation::anchorAt(float interp) const | 174 gfx::Vector2dF PageScaleAnimation::anchorAt(float interp) const |
175 { | 175 { |
176 // Interpolate from start to target anchor in absolute space. | 176 // Interpolate from start to target anchor in absolute space. |
177 gfx::Vector2dF delta = gfx::ScaleVector2d(m_targetAnchor - m_startAnchor, in
terp); | 177 return interpolateBetween(m_startAnchor, m_targetAnchor, interp); |
178 return m_startAnchor + delta; | |
179 } | 178 } |
180 | 179 |
181 gfx::Vector2dF PageScaleAnimation::viewportRelativeAnchorAt(float interp) const | 180 gfx::Vector2dF PageScaleAnimation::viewportRelativeAnchorAt(float interp) const |
182 { | 181 { |
183 // Interpolate from start to target anchor in the space relative to the | 182 // Interpolate from start to target anchor in normalized space. |
184 // viewport at its current scale level. | 183 gfx::Vector2dF startNormalized = normalizeFromViewport(m_startAnchor - m_sta
rtScrollOffset, startViewportSize()); |
185 gfx::Vector2dF anchorRelativeToStartViewport = m_startAnchor - m_startScroll
Offset; | 184 gfx::Vector2dF targetNormalized = normalizeFromViewport(m_targetAnchor - m_t
argetScrollOffset, targetViewportSize()); |
186 gfx::Vector2dF anchorRelativeToTargetViewport = m_targetAnchor - m_targetScr
ollOffset; | |
187 | |
188 gfx::Vector2dF startNormalized = normalizeFromViewport(anchorRelativeToStart
Viewport, viewportSizeAtScale(m_startPageScaleFactor)); | |
189 gfx::Vector2dF targetNormalized = normalizeFromViewport(anchorRelativeToTarg
etViewport, viewportSizeAtScale(m_targetPageScaleFactor)); | |
190 gfx::Vector2dF interpNormalized = interpolateBetween(startNormalized, target
Normalized, interp); | 185 gfx::Vector2dF interpNormalized = interpolateBetween(startNormalized, target
Normalized, interp); |
191 | 186 |
192 gfx::SizeF currentViewportSize = viewportSizeAtScale(pageScaleFactorAt(inter
p)); | 187 return denormalizeToViewport(interpNormalized, viewportSizeAt(interp)); |
193 return denormalizeToViewport(interpNormalized, currentViewportSize); | |
194 } | 188 } |
195 | 189 |
196 float PageScaleAnimation::pageScaleFactorAt(float interp) const | 190 float PageScaleAnimation::pageScaleFactorAt(float interp) const |
197 { | 191 { |
198 if (interp <= 0) | 192 if (interp <= 0) |
199 return m_startPageScaleFactor; | 193 return m_startPageScaleFactor; |
200 if (interp >= 1) | 194 if (interp >= 1) |
201 return m_targetPageScaleFactor; | 195 return m_targetPageScaleFactor; |
202 | 196 |
203 // Linearly interpolate the magnitude in log scale. | 197 // Linearly interpolate the magnitude in log scale. |
204 float diff = m_targetPageScaleFactor / m_startPageScaleFactor; | 198 float diff = m_targetPageScaleFactor / m_startPageScaleFactor; |
205 float logDiff = log(diff); | 199 float logDiff = log(diff); |
206 logDiff *= interp; | 200 logDiff *= interp; |
207 diff = exp(logDiff); | 201 diff = exp(logDiff); |
208 return m_startPageScaleFactor * diff; | 202 return m_startPageScaleFactor * diff; |
209 } | 203 } |
210 | 204 |
211 } // namespace cc | 205 } // namespace cc |
OLD | NEW |