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

Side by Side Diff: chrome/browser/ui/touch/animation/screen_rotation.cc

Issue 7273073: Animated Rotation (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Moved screen rotation code under touch; use lock object to disable painting Created 9 years, 4 months 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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.
4
5 #include "chrome/browser/ui/touch/animation/screen_rotation.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/message_loop.h"
9 #include "base/task.h"
10 #include "ui/base/animation/slide_animation.h"
11 #include "ui/gfx/compositor/layer.h"
12 #include "ui/gfx/interpolated_transform.h"
13 #include "ui/gfx/rect.h"
14 #include "ui/gfx/transform.h"
15 #include "views/animation/paint_lock.h"
16 #include "views/view.h"
17
18 namespace {
19 const int kDefaultTransitionDurationMs = 350;
20
21 } // namespace
22
23 ////////////////////////////////////////////////////////////////////////////////
24 // ScreenRotationListenerInterface public:
25 //
26
27 ScreenRotationListenerInterface::~ScreenRotationListenerInterface() {
28 }
29
30 ////////////////////////////////////////////////////////////////////////////////
31 // ScreenRotation public:
32 //
33
34 ScreenRotation::ScreenRotation(views::View* view,
35 ScreenRotationListenerInterface* listener,
36 float old_degrees,
37 float new_degrees)
38 : view_(view),
39 listener_(listener),
40 old_degrees_(old_degrees),
41 new_degrees_(new_degrees),
42 last_t_(0.0),
43 duration_(kDefaultTransitionDurationMs),
44 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
45 DCHECK(view);
46 DCHECK(listener);
47
48 // A screen rotation is initiated via a call to set transform, which
49 // initiates a paint. This paint is scheduled, but has not been processed.
50 // If we post a delayed task, it will be in the queue after the paint, and
sky 2011/08/25 21:10:12 This is going to be so racy because the paint come
51 // we'll be guaranteed to start animating after the paint is finished.
52 //
53 // TODO(vollick) Find a cleaner way of posting work to be done after painting
54 // completes.
55 MessageLoop::current()->PostDelayedTask(
56 FROM_HERE,
57 method_factory_.NewRunnableMethod(&ScreenRotation::Start),
58 1);
59 }
60
61 ScreenRotation::~ScreenRotation() {
62 }
63
64 void ScreenRotation::Finalize() {
65 ui::Transform final_transform = view_->GetTransform();
66 gfx::Rect final_bounds(0, 0, new_size_.width(), new_size_.height());
67 listener_->OnScreenRotationCompleted(final_transform, final_bounds);
68 }
69
70 void ScreenRotation::SetTarget(float degrees) {
71 if (new_degrees_ == degrees)
72 return;
73
74 new_degrees_ = degrees;
75 Init();
76 }
77
78 ////////////////////////////////////////////////////////////////////////////////
79 // ScreenRotation private:
80 //
81
82 void ScreenRotation::AnimationProgressed(const ui::Animation* anim) {
83 TRACE_EVENT0("ScreenRotation", "step");
84 if (!interpolated_transform_.get() || !view_->layer())
85 return;
86
87 last_t_ = static_cast<float>(anim->GetCurrentValue());
88 view_->layer()->SetTransform(interpolated_transform_->Interpolate(last_t_));
89 view_->layer()->compositor()->SchedulePaint();
90 }
91
92 void ScreenRotation::AnimationEnded(const ui::Animation* anim) {
93 TRACE_EVENT_END0("ScreenRotation", "ScreenRotation");
94 // TODO(vollick) massage matrix so that entries sufficiently close
95 // to 0, 1, or -1 are clamped to these values. The idea is to fight
96 // accumulated numeric error due to successive rotations.
97 if (view_->layer()) {
98 ui::Transform xform = view_->layer()->transform();
99 gfx::Point origin;
100 xform.TransformPoint(origin);
101 ui::Transform translation;
102 translation.SetTranslate(new_origin_.x() - origin.x(),
103 new_origin_.y() - origin.y());
104 xform.ConcatTransform(translation);
105 view_->layer()->SetTransform(xform);
106 view_->layer()->compositor()->SchedulePaint();
107 }
108
109 // the last call to SchedulePaint may not have been processed yet, so if we
110 // set the bounds here, we may hang the ui in an 'almost-rotated' state for
111 // a moment while we layout. If we post a task to execute immediately, it
112 // will get processed after SchedulePaint, and we should be safe.
113 //
114 // TODO(vollick) Find a cleaner way of posting work to be done after painting
115 // completes.
116 MessageLoop::current()->PostDelayedTask(
117 FROM_HERE,
118 method_factory_.NewRunnableMethod(&ScreenRotation::Finalize),
119 1);
120 }
121
122 void ScreenRotation::Init() {
123 TRACE_EVENT0("ScreenRotation", "init");
124 if (!view_->layer()) {
125 view_->SetPaintToLayer(true);
126 }
127
128 // can't proceed without a layer.
129 if (!view_->layer())
130 return;
131
132 ui::Transform current_transform = view_->layer()->transform();
133 int degrees = new_degrees_ - old_degrees_;
134 degrees = NormalizeAngle(degrees);
135
136 // No rotation required.
137 if (degrees == 0)
138 return;
139
140 gfx::Point old_pivot;
141 gfx::Point new_pivot;
142 int width = view_->layer()->bounds().width();
143 int height = view_->layer()->bounds().height();
144
145 switch (degrees) {
146 case 90:
147 new_origin_ = new_pivot = gfx::Point(width, 0);
148 new_size_.SetSize(height, width);
149 break;
150 case -90:
151 new_origin_ = new_pivot = gfx::Point(0, height);
152 new_size_.SetSize(height, width);
153 break;
154 case 180:
155 duration_ = 550;
156 new_pivot = old_pivot = gfx::Point(width / 2, height / 2);
157 new_origin_.SetPoint(width, height);
158 new_size_.SetSize(width, height);
159 break;
160 }
161
162 // Convert points to world space.
163 current_transform.TransformPoint(old_pivot);
164 current_transform.TransformPoint(new_pivot);
165 current_transform.TransformPoint(new_origin_);
166
167 scoped_ptr<ui::InterpolatedTransform> rotation(
168 new ui::InterpolatedTransformAboutPivot(
169 old_pivot,
170 new ui::InterpolatedRotation(0, degrees)));
171
172 scoped_ptr<ui::InterpolatedTransform> translation(
173 new ui::InterpolatedTranslation(
174 gfx::Point(0, 0),
175 gfx::Point(new_pivot.x() - old_pivot.x(),
176 new_pivot.y() - old_pivot.y())));
177
178 float scale_factor = 0.9f;
179 scoped_ptr<ui::InterpolatedTransform> scale_down(
180 new ui::InterpolatedScale(1.0f, scale_factor, 0.0f, 0.5f));
181
182 scoped_ptr<ui::InterpolatedTransform> scale_up(
183 new ui::InterpolatedScale(1.0f, 1.0f / scale_factor, 0.5f, 1.0f));
184
185 scoped_ptr<ui::InterpolatedTransform> transition(
186 new ui::InterpolatedConstantTransform(current_transform));
187
188 scale_up->SetChild(scale_down.release());
189 translation->SetChild(scale_up.release());
190 rotation->SetChild(translation.release());
191 transition->SetChild(rotation.release());
192
193 if (interpolated_transform_.get()) {
194 // We are in the middle of a transition. In this case, we need to create
195 // an interpolated transform that gets us from where we are to the target
196 // transform.
197 ui::Transform target = transition->Interpolate(1.0);
198 interpolated_transform_.reset(
199 new ui::InterpolatedTRSTransform(
200 current_transform, target, last_t_, 1.0));
201 } else {
202 interpolated_transform_.reset(transition.release());
203 }
204 }
205
206 void ScreenRotation::Start() {
207 TRACE_EVENT_BEGIN0("ScreenRotation", "ScreenRotation");
208 Init();
209 if (interpolated_transform_.get()) {
210 paint_lock_.reset(new views::PaintLock(view_));
211 animation_.reset(new ui::SlideAnimation(this));
212 animation_->SetTweenType(ui::Tween::LINEAR);
213 animation_->SetSlideDuration(duration_);
214 animation_->Show();
215 } else {
216 Finalize();
217 }
218 }
219
220 int ScreenRotation::NormalizeAngle(int degrees) {
221 while (degrees <= -180) degrees += 360;
222 while (degrees > 180) degrees -= 360;
223 return degrees;
224 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698