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

Side by Side 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 unified diff | Download patch
« cc/layer_tree_host_impl.cc ('K') | « cc/page_scale_animation.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "config.h" 5 #include "config.h"
6 6
7 #include "cc/page_scale_animation.h" 7 #include "cc/page_scale_animation.h"
8 #include "ui/gfx/point_f.h"
9 #include "ui/gfx/rect_f.h"
8 10
9 #include "cc/geometry.h" 11 #include <algorithm>
10 #include "ui/gfx/rect_f.h" 12 #include <math.h>
11 #include "ui/gfx/vector2d_conversions.h"
12 #include "ui/gfx/vector2d_f.h"
13 13
14 #include <math.h> 14 namespace {
15
16 gfx::PointF toPointF(const gfx::Vector2dF& vector)
17 {
18 return gfx::PointF(vector.x(), vector.y());
19 }
20
21 // This takes a viewport-relative vector and returns a vector whose values are
22 // between 0 and 1, representing the percentage position within the viewport.
23 gfx::Vector2dF normalizeFromViewport(const gfx::Vector2dF& denormalized, const g fx::SizeF& viewportSize)
24 {
25 gfx::Vector2dF normalized(denormalized);
26 normalized.Scale(1 / viewportSize.width(), 1 / viewportSize.height());
27 return normalized;
28 }
29
30 gfx::Vector2dF denormalizeToViewport(const gfx::Vector2dF& normalized, const gfx ::SizeF& viewportSize)
31 {
32 gfx::Vector2dF denormalized(normalized);
33 denormalized.Scale(viewportSize.width(), viewportSize.height());
34 return denormalized;
35 }
36
37 gfx::Vector2dF interpolateBetween(const gfx::Vector2dF& start, const gfx::Vector 2dF end, float interp)
38 {
39 gfx::Vector2dF result;
40 result.set_x(start.x() + interp * (end.x() - start.x()));
41 result.set_y(start.y() + interp * (end.y() - start.y()));
42 return result;
43 }
44
45 }
15 46
16 namespace cc { 47 namespace cc {
17 48
18 scoped_ptr<PageScaleAnimation> PageScaleAnimation::create(gfx::Vector2d scrollSt art, float pageScaleStart, const gfx::Size& windowSize, const gfx::Size& content Size, double startTime) 49 scoped_ptr<PageScaleAnimation> PageScaleAnimation::create(const gfx::Vector2dF& startScrollOffset, float startPageScaleFactor, const gfx::SizeF& viewportSize, c onst gfx::SizeF& rootLayerSize, double startTime)
19 { 50 {
20 return make_scoped_ptr(new PageScaleAnimation(scrollStart, pageScaleStart, w indowSize, contentSize, startTime)); 51 return make_scoped_ptr(new PageScaleAnimation(startScrollOffset, startPageSc aleFactor, viewportSize, rootLayerSize, startTime));
21 } 52 }
22 53
23 PageScaleAnimation::PageScaleAnimation(gfx::Vector2d scrollStart, float pageScal eStart, const gfx::Size& windowSize, const gfx::Size& contentSize, double startT ime) 54 PageScaleAnimation::PageScaleAnimation(const gfx::Vector2dF& startScrollOffset, float startPageScaleFactor, const gfx::SizeF& viewportSize, const gfx::SizeF& ro otLayerSize, double startTime)
24 : m_scrollStart(scrollStart) 55 : m_startPageScaleFactor(startPageScaleFactor)
25 , m_pageScaleStart(pageScaleStart) 56 , m_targetPageScaleFactor(0)
26 , m_windowSize(windowSize) 57 , m_startScrollOffset(startScrollOffset)
27 , m_contentSize(contentSize) 58 , m_startAnchor()
28 , m_anchorMode(false) 59 , m_targetAnchor()
29 , m_scrollEnd(scrollStart) 60 , m_viewportSize(viewportSize)
30 , m_pageScaleEnd(pageScaleStart) 61 , m_rootLayerSize(rootLayerSize)
31 , m_startTime(startTime) 62 , m_startTime(startTime)
32 , m_duration(0) 63 , m_duration(0)
33 { 64 {
34 } 65 }
35 66
36 PageScaleAnimation::~PageScaleAnimation() 67 PageScaleAnimation::~PageScaleAnimation()
37 { 68 {
38 } 69 }
39 70
40 void PageScaleAnimation::zoomTo(gfx::Vector2d finalScroll, float finalPageScale, double duration) 71 void PageScaleAnimation::zoomTo(const gfx::Vector2dF& targetScrollOffset, float targetPageScaleFactor, double duration)
41 { 72 {
42 if (m_pageScaleStart != finalPageScale) { 73 m_targetPageScaleFactor = targetPageScaleFactor;
43 // For uniform-looking zooming, infer the anchor (point that remains in 74 m_targetScrollOffset = targetScrollOffset;
44 // place throughout the zoom) from the start and end rects. 75 clampTargetScrollOffset();
45 gfx::RectF startRect(gfx::PointAtOffsetFromOrigin(m_scrollStart), m_wind owSize); 76 m_duration = duration;
46 gfx::RectF endRect(gfx::PointAtOffsetFromOrigin(finalScroll), m_windowSi ze);
47 endRect.Scale(m_pageScaleStart / finalPageScale);
48 77
49 // The anchor is the point which is at the same ratio of the sides of 78 if (m_startPageScaleFactor == targetPageScaleFactor) {
50 // both startRect and endRect. For example, a zoom-in double-tap to a 79 m_startAnchor = m_startScrollOffset;
51 // perfectly centered rect will have anchor ratios (0.5, 0.5), while one 80 m_targetAnchor = targetScrollOffset;
52 // to a rect touching the bottom-right of the screen will have anchor 81 return;
53 // ratios (1.0, 1.0). In other words, it obeys the equations: 82 }
54 // anchorX = start_width * ratioX + start_x
55 // anchorX = end_width * ratioX + end_x
56 // anchorY = start_height * ratioY + start_y
57 // anchorY = end_height * ratioY + end_y
58 // where both anchor{x,y} and ratio{x,y} begin as unknowns. Solving
59 // for the ratios, we get the following formulas:
60 float ratioX = (startRect.x() - endRect.x()) / (endRect.width() - startR ect.width());
61 float ratioY = (startRect.y() - endRect.y()) / (endRect.height() - start Rect.height());
62 83
63 gfx::Vector2d anchor(m_windowSize.width() * ratioX, m_windowSize.height( ) * ratioY); 84 // For uniform-looking zooming, infer an anchor from the start and target
64 zoomWithAnchor(anchor, finalPageScale, duration); 85 // viewport rects.
65 } else { 86 inferTargetAnchorFromScrollOffsets();
66 // If this is a pure translation, then there exists no anchor. Linearly 87 m_startAnchor = m_targetAnchor;
67 // interpolate the scroll offset instead.
68 m_scrollEnd = finalScroll;
69 m_pageScaleEnd = finalPageScale;
70 m_duration = duration;
71 m_anchorMode = false;
72 }
73 } 88 }
74 89
75 void PageScaleAnimation::zoomWithAnchor(gfx::Vector2d anchor, float finalPageSca le, double duration) 90 void PageScaleAnimation::zoomWithAnchor(const gfx::Vector2dF& anchor, float targ etPageScaleFactor, double duration)
76 { 91 {
77 m_scrollEnd = m_scrollStart + anchor; 92 m_startAnchor = anchor;
78 m_scrollEnd = gfx::ToFlooredVector2d(cc::ScaleVector2d(m_scrollEnd, finalPag eScale / m_pageScaleStart)); 93 m_targetPageScaleFactor = targetPageScaleFactor;
79 m_scrollEnd -= anchor; 94 m_duration = duration;
80 95
81 m_scrollEnd = ClampFromBelow(m_scrollEnd, gfx::Vector2d()); 96 // We start zooming out from the anchor tapped by the user. But if
82 gfx::SizeF scaledContentSize = m_contentSize.Scale(finalPageScale / m_pageSc aleStart); 97 // the target scale is impossible to attain without hitting the root layer
83 gfx::Vector2d maxScrollOffset = gfx::ToRoundedVector2d(BottomRight(gfx::Rect F(scaledContentSize)) - BottomRight(gfx::Rect(m_windowSize))); 98 // edges, then infer an anchor that doesn't collide with the edges.
84 m_scrollEnd = m_scrollEnd; 99 // We will interpolate between the two anchors during the animation.
85 m_scrollEnd = ClampFromAbove(m_scrollEnd, maxScrollOffset); 100 inferTargetScrollOffsetFromStartAnchor();
86 101 clampTargetScrollOffset();
87 m_anchor = anchor; 102 inferTargetAnchorFromScrollOffsets();
88 m_pageScaleEnd = finalPageScale;
89 m_duration = duration;
90 m_anchorMode = true;
91 } 103 }
92 104
93 gfx::Vector2d PageScaleAnimation::scrollOffsetAtTime(double time) const 105 gfx::SizeF PageScaleAnimation::viewportSizeAtScale(float pageScaleFactor) const
94 { 106 {
95 return scrollOffsetAtRatio(progressRatioForTime(time)); 107 return gfx::SizeF(m_viewportSize.width() / pageScaleFactor, m_viewportSize.h eight() / pageScaleFactor);
96 } 108 }
97 109
98 float PageScaleAnimation::pageScaleAtTime(double time) const 110 void PageScaleAnimation::inferTargetScrollOffsetFromStartAnchor()
99 { 111 {
100 return pageScaleAtRatio(progressRatioForTime(time)); 112 gfx::Vector2dF anchorRelativeToStartViewport = m_startAnchor - m_startScroll Offset;
113 gfx::Vector2dF normalized = normalizeFromViewport(anchorRelativeToStartViewp ort, viewportSizeAtScale(m_startPageScaleFactor));
114 m_targetScrollOffset = m_startAnchor - denormalizeToViewport(normalized, vie wportSizeAtScale(m_targetPageScaleFactor));
115 }
116
117 void PageScaleAnimation::inferTargetAnchorFromScrollOffsets()
118 {
119 gfx::RectF startRect(toPointF(m_startScrollOffset), viewportSizeAtScale(m_st artPageScaleFactor));
120 gfx::RectF targetRect(toPointF(m_targetScrollOffset), viewportSizeAtScale(m_ targetPageScaleFactor));
121
122 // The anchor is the point which is at the same normalized relative position
123 // within both startRect and endRect. For example, a zoom-in double-tap to a
124 // perfectly centered rect will have normalized anchor (0.5, 0.5), while one
125 // to a rect touching the bottom-right of the screen will have normalized
126 // anchor (1.0, 1.0). In other words, it obeys the equations:
127 // anchorX = start_width * normalizedX + start_x
128 // anchorX = target_width * normalizedX + target_x
129 // anchorY = start_height * normalizedY + start_y
130 // anchorY = target_height * normalizedY + target_y
131 // where both anchor{x,y} and normalized{x,y} begin as unknowns. Solving
132 // for the normalized, we get the following formulas:
133 gfx::Vector2dF normalized;
134 normalized.set_x((startRect.x() - targetRect.x()) / (targetRect.width() - st artRect.width()));
135 normalized.set_y((startRect.y() - targetRect.y()) / (targetRect.height() - s tartRect.height()));
136 m_targetAnchor = m_targetScrollOffset + denormalizeToViewport(normalized, vi ewportSizeAtScale(m_targetPageScaleFactor));
137 }
138
139 void PageScaleAnimation::clampTargetScrollOffset()
140 {
141 gfx::Vector2dF maxScrollPosition;
142 maxScrollPosition.set_x(m_rootLayerSize.width() - viewportSizeAtScale(m_targ etPageScaleFactor).width());
143 maxScrollPosition.set_y(m_rootLayerSize.height() - viewportSizeAtScale(m_tar getPageScaleFactor).height());
144 m_targetScrollOffset.set_x(std::max<float>(0, m_targetScrollOffset.x()));
145 m_targetScrollOffset.set_y(std::max<float>(0, m_targetScrollOffset.y()));
146 m_targetScrollOffset.set_x(std::min<float>(maxScrollPosition.x(), m_targetSc rollOffset.x()));
147 m_targetScrollOffset.set_y(std::min<float>(maxScrollPosition.y(), m_targetSc rollOffset.y()));
148 }
149
150 gfx::Vector2dF PageScaleAnimation::scrollOffsetAtTime(double time) const
151 {
152 return scrollOffsetAt(interpAtTime(time));
153 }
154
155 float PageScaleAnimation::pageScaleFactorAtTime(double time) const
156 {
157 return pageScaleFactorAt(interpAtTime(time));
101 } 158 }
102 159
103 bool PageScaleAnimation::isAnimationCompleteAtTime(double time) const 160 bool PageScaleAnimation::isAnimationCompleteAtTime(double time) const
104 { 161 {
105 return time >= endTime(); 162 return time >= endTime();
106 } 163 }
107 164
108 float PageScaleAnimation::progressRatioForTime(double time) const 165 float PageScaleAnimation::interpAtTime(double time) const
109 { 166 {
110 if (isAnimationCompleteAtTime(time)) 167 if (isAnimationCompleteAtTime(time))
111 return 1; 168 return 1;
112 169
113 return (time - m_startTime) / m_duration; 170 return (time - m_startTime) / m_duration;
114 } 171 }
115 172
116 gfx::Vector2d PageScaleAnimation::scrollOffsetAtRatio(float ratio) const 173 gfx::Vector2dF PageScaleAnimation::scrollOffsetAt(float interp) const
117 { 174 {
118 if (ratio <= 0) 175 if (interp <= 0)
119 return m_scrollStart; 176 return m_startScrollOffset;
120 if (ratio >= 1) 177 if (interp >= 1)
121 return m_scrollEnd; 178 return m_targetScrollOffset;
122 179
123 float currentPageScale = pageScaleAtRatio(ratio); 180 return anchorAt(interp) - viewportRelativeAnchorAt(interp);
124 gfx::Vector2d currentScrollOffset;
125 if (m_anchorMode) {
126 // Keep the anchor stable on the screen at the current scale.
127 gfx::Vector2dF documentAnchor = m_scrollStart + m_anchor;
128 documentAnchor.Scale(currentPageScale / m_pageScaleStart);
129 currentScrollOffset = gfx::ToRoundedVector2d(documentAnchor - m_anchor);
130 } else {
131 // First move both scroll offsets to the current coordinate space.
132 gfx::Vector2dF scaledStartScroll(m_scrollStart);
133 scaledStartScroll.Scale(currentPageScale / m_pageScaleStart);
134 gfx::Vector2dF scaledEndScroll(m_scrollEnd);
135 scaledEndScroll.Scale(currentPageScale / m_pageScaleEnd);
136
137 // Linearly interpolate between them.
138 gfx::Vector2dF delta = scaledEndScroll - scaledStartScroll;
139 delta.Scale(ratio);
140 currentScrollOffset = gfx::ToRoundedVector2d(scaledStartScroll + delta);
141 }
142
143 return currentScrollOffset;
144 } 181 }
145 182
146 float PageScaleAnimation::pageScaleAtRatio(float ratio) const 183 gfx::Vector2dF PageScaleAnimation::anchorAt(float interp) const
147 { 184 {
148 if (ratio <= 0) 185 // Interpolate from start to target anchor in absolute space.
149 return m_pageScaleStart; 186 gfx::Vector2dF delta = m_targetAnchor - m_startAnchor;
150 if (ratio >= 1) 187 delta.Scale(interp);
151 return m_pageScaleEnd; 188 return m_startAnchor + delta;
189 }
190
191 gfx::Vector2dF PageScaleAnimation::viewportRelativeAnchorAt(float interp) const
192 {
193 // Interpolate from start to target anchor in the space relative to the
194 // viewport at its current scale level.
195 gfx::Vector2dF anchorRelativeToStartViewport = m_startAnchor - m_startScroll Offset;
196 gfx::Vector2dF anchorRelativeToTargetViewport = m_targetAnchor - m_targetScr ollOffset;
197
198 gfx::Vector2dF startNormalized = normalizeFromViewport(anchorRelativeToStart Viewport, viewportSizeAtScale(m_startPageScaleFactor));
199 gfx::Vector2dF targetNormalized = normalizeFromViewport(anchorRelativeToTarg etViewport, viewportSizeAtScale(m_targetPageScaleFactor));
200 gfx::Vector2dF interpNormalized = interpolateBetween(startNormalized, target Normalized, interp);
201
202 gfx::SizeF currentViewportSize = viewportSizeAtScale(pageScaleFactorAt(inter p));
203 return denormalizeToViewport(interpNormalized, currentViewportSize);
204 }
205
206 float PageScaleAnimation::pageScaleFactorAt(float interp) const
207 {
208 if (interp <= 0)
209 return m_startPageScaleFactor;
210 if (interp >= 1)
211 return m_targetPageScaleFactor;
152 212
153 // Linearly interpolate the magnitude in log scale. 213 // Linearly interpolate the magnitude in log scale.
154 // Log scale is needed to maintain the appearance of uniform zoom. For 214 float diff = m_targetPageScaleFactor / m_startPageScaleFactor;
155 // example, if we zoom from 0.5 to 4.0 in 3 seconds, then we should
156 // be zooming by 2x every second.
157 float diff = m_pageScaleEnd / m_pageScaleStart;
158 float logDiff = log(diff); 215 float logDiff = log(diff);
159 logDiff *= ratio; 216 logDiff *= interp;
160 diff = exp(logDiff); 217 diff = exp(logDiff);
161 return m_pageScaleStart * diff; 218 return m_startPageScaleFactor * diff;
162 } 219 }
163 220
164 } // namespace cc 221 } // namespace cc
OLDNEW
« 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