| Index: views/animation/screen_rotation.cc
|
| diff --git a/views/animation/screen_rotation.cc b/views/animation/screen_rotation.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..37f8d5f10d29154353d50a605accb3650c9a8710
|
| --- /dev/null
|
| +++ b/views/animation/screen_rotation.cc
|
| @@ -0,0 +1,180 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "views/animation/screen_rotation.h"
|
| +
|
| +#include "base/debug/trace_event.h"
|
| +#include "base/message_loop.h"
|
| +#include "ui/base/animation/slide_animation.h"
|
| +#include "ui/gfx/interpolated_transform.h"
|
| +#include "ui/gfx/rect.h"
|
| +#include "ui/gfx/transform.h"
|
| +#include "views/view.h"
|
| +
|
| +namespace {
|
| +
|
| +class ScreenRotationCompletedTask : public Task {
|
| + public:
|
| + ScreenRotationCompletedTask(views::ScreenRotation* rotation)
|
| + : rotation_(rotation) {
|
| + }
|
| +
|
| + virtual void Run() OVERRIDE {
|
| + rotation_->CleanUp();
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<views::ScreenRotation> rotation_;
|
| +
|
| + // copy and assign are allowed
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +namespace views {
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// ScreenRotation public:
|
| +//
|
| +
|
| +ScreenRotation::ScreenRotation(View* root,
|
| + float old_degrees,
|
| + float new_degrees)
|
| + : root_(root),
|
| + old_degrees_(old_degrees),
|
| + new_degrees_(new_degrees) {
|
| + Init();
|
| +}
|
| +
|
| +void ScreenRotation::CleanUp() {
|
| + // TODO(vollick) massage matrix so that entries sufficiently close
|
| + // to 0, 1, or -1 are clamped to these values. The idea is to fight
|
| + // accumulated numeric error due to successive rotations.
|
| + ui::Transform xform = root_->GetTransform();
|
| + if (root_->layer()) {
|
| + xform = root_->layer()->transform();
|
| + }
|
| + gfx::Point origin;
|
| + xform.TransformPoint(origin);
|
| + ui::Transform translation;
|
| + translation.SetTranslate(new_origin_.x() - origin.x(),
|
| + new_origin_.y() - origin.y());
|
| + xform.ConcatTransform(translation);
|
| + root_->SetTransform(xform);
|
| + root_->SetBounds(0, 0, new_size_.width(), new_size_.height());
|
| + root_->set_painting_enabled(true);
|
| + root_->SchedulePaint();
|
| +}
|
| +
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// ScreenRotation protected:
|
| +//
|
| +
|
| +ScreenRotation::~ScreenRotation() {}
|
| +
|
| +void ScreenRotation::OnAnimationProgressed(double t) OVERRIDE {
|
| + if (!interpolated_transform_.get() || !layer())
|
| + return;
|
| +
|
| + if (root_->painting_enabled())
|
| + root_->set_painting_enabled(false);
|
| +
|
| + layer()->SetTransform(interpolated_transform_->Interpolate(t));
|
| + layer()->compositor()->SchedulePaint();
|
| +}
|
| +
|
| +void ScreenRotation::OnAnimationEnded() OVERRIDE {
|
| + TRACE_EVENT_END0("ScreenRotation", "Start rotating");
|
| + if (interpolated_transform_.get() && layer()) {
|
| + layer()->SetTransform(interpolated_transform_->Interpolate(1.0));
|
| + layer()->compositor()->SchedulePaint();
|
| + }
|
| + MessageLoop::current()->PostDelayedTask(
|
| + FROM_HERE,
|
| + new ScreenRotationCompletedTask(this),
|
| + 100);
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// ScreenRotation private:
|
| +//
|
| +
|
| +int ScreenRotation::NormalizeAngle(int degrees) {
|
| + while (degrees <= -180) degrees += 360;
|
| + while (degrees > 180) degrees -= 360;
|
| + return degrees;
|
| +}
|
| +
|
| +void ScreenRotation::Init() {
|
| + TRACE_EVENT_BEGIN0("ScreenRotation", "Start rotating");
|
| + if (!root_->layer()) {
|
| + root_->SetPaintToLayer(true);
|
| + root_->SchedulePaint();
|
| + }
|
| +
|
| + int degrees = new_degrees_ - old_degrees_;
|
| + degrees = NormalizeAngle(degrees);
|
| +
|
| + // No rotation required.
|
| + if (degrees == 0)
|
| + return;
|
| +
|
| + gfx::Point old_pivot;
|
| + gfx::Point new_pivot;
|
| +
|
| + switch (degrees) {
|
| + case 90:
|
| + set_duration(500);
|
| + new_origin_ = new_pivot = gfx::Point(root_->width(), 0);
|
| + new_size_.SetSize(root_->height(), root_->width());
|
| + break;
|
| + case -90:
|
| + set_duration(500);
|
| + new_origin_ = new_pivot = gfx::Point(0, root_->height());
|
| + new_size_.SetSize(root_->height(), root_->width());
|
| + break;
|
| + case 180:
|
| + set_duration(750);
|
| + new_pivot = old_pivot = gfx::Point(root_->width() / 2,
|
| + root_->height() / 2);
|
| + new_origin_.SetPoint(root_->width(), root_->height());
|
| + new_size_.SetSize(root_->width(), root_->height());
|
| + break;
|
| + }
|
| +
|
| + // Convert points to world space.
|
| + const ui::Transform& xform = root_->GetTransform();
|
| + xform.TransformPoint(old_pivot);
|
| + xform.TransformPoint(new_pivot);
|
| + xform.TransformPoint(new_origin_);
|
| +
|
| + scoped_ptr<ui::InterpolatedTransform> rotation(
|
| + new ui::InterpolatedTransformAboutPivot(
|
| + old_pivot,
|
| + new ui::InterpolatedRotation(0, degrees)));
|
| +
|
| + scoped_ptr<ui::InterpolatedTransform> translation(
|
| + new ui::InterpolatedTranslation(
|
| + gfx::Point(0, 0),
|
| + gfx::Point(new_pivot.x() - old_pivot.x(),
|
| + new_pivot.y() - old_pivot.y())));
|
| +
|
| + float scale_factor = 0.9f;
|
| + scoped_ptr<ui::InterpolatedTransform> scale_down(
|
| + new ui::InterpolatedScale(1.0f, scale_factor, 0.0f, 0.5f));
|
| +
|
| + scoped_ptr<ui::InterpolatedTransform> scale_up(
|
| + new ui::InterpolatedScale(1.0f, 1.0f / scale_factor, 0.5f, 1.0f));
|
| +
|
| + interpolated_transform_.reset(
|
| + new ui::InterpolatedConstantTransform(xform));
|
| +
|
| + scale_up->SetChild(scale_down.release());
|
| + translation->SetChild(scale_up.release());
|
| + rotation->SetChild(translation.release());
|
| + interpolated_transform_->SetChild(rotation.release());
|
| +}
|
| +
|
| +} // namespace views
|
|
|