summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-29 15:38:12 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-29 15:38:12 +0000
commit7fca53d420d201e1ec5a637ad236056c61e4e4b1 (patch)
tree8489ef482f21b5a0250582aa2dabff1c4335b270 /ui
parent79a5004a179fc12eb4e7ed6d1d12bd8b454fde6b (diff)
downloadchromium_src-7fca53d420d201e1ec5a637ad236056c61e4e4b1.zip
chromium_src-7fca53d420d201e1ec5a637ad236056c61e4e4b1.tar.gz
chromium_src-7fca53d420d201e1ec5a637ad236056c61e4e4b1.tar.bz2
Adds the ability to set an Animation on Layer so that future changes to the layer result in animating the property. See code in desktop_window_view.cc and window.cc for usage.
BUG=none TEST=none Review URL: http://codereview.chromium.org/7972023 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@103282 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/aura/demo/demo_main.cc6
-rw-r--r--ui/aura/desktop.cc4
-rw-r--r--ui/aura/toplevel_window_event_filter.cc2
-rw-r--r--ui/aura/window.cc29
-rw-r--r--ui/aura/window.h12
-rw-r--r--ui/aura/window_unittest.cc4
-rw-r--r--ui/aura_shell/desktop_layout_manager.cc2
-rw-r--r--ui/aura_shell/examples/window_type_launcher.cc122
-rw-r--r--ui/aura_shell/examples/window_type_launcher.h15
-rw-r--r--ui/gfx/compositor/compositor.gyp1
-rw-r--r--ui/gfx/compositor/layer.cc134
-rw-r--r--ui/gfx/compositor/layer.h44
-rw-r--r--ui/gfx/compositor/layer_animator.cc215
-rw-r--r--ui/gfx/compositor/layer_animator.h87
-rw-r--r--ui/gfx/compositor/layer_animator_delegate.h32
15 files changed, 504 insertions, 205 deletions
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc
index 4230f73..e970f14 100644
--- a/ui/aura/demo/demo_main.cc
+++ b/ui/aura/demo/demo_main.cc
@@ -86,7 +86,7 @@ int main(int argc, char** argv) {
aura::Window window1(&window_delegate1);
window1.set_id(1);
window1.Init();
- window1.SetBounds(gfx::Rect(100, 100, 400, 400), 0);
+ window1.SetBounds(gfx::Rect(100, 100, 400, 400));
window1.SetVisibility(aura::Window::VISIBILITY_SHOWN);
window1.SetParent(NULL);
@@ -94,7 +94,7 @@ int main(int argc, char** argv) {
aura::Window window2(&window_delegate2);
window2.set_id(2);
window2.Init();
- window2.SetBounds(gfx::Rect(200, 200, 350, 350), 0);
+ window2.SetBounds(gfx::Rect(200, 200, 350, 350));
window2.SetVisibility(aura::Window::VISIBILITY_SHOWN);
window2.SetParent(NULL);
@@ -102,7 +102,7 @@ int main(int argc, char** argv) {
aura::Window window3(&window_delegate3);
window3.set_id(3);
window3.Init();
- window3.SetBounds(gfx::Rect(10, 10, 50, 50), 0);
+ window3.SetBounds(gfx::Rect(10, 10, 50, 50));
window3.SetVisibility(aura::Window::VISIBILITY_SHOWN);
window3.SetParent(&window2);
diff --git a/ui/aura/desktop.cc b/ui/aura/desktop.cc
index 94a7034..94399c1 100644
--- a/ui/aura/desktop.cc
+++ b/ui/aura/desktop.cc
@@ -52,7 +52,7 @@ void Desktop::Init() {
window_->Init();
compositor()->SetRootLayer(window_->layer());
toplevel_window_container_->Init();
- toplevel_window_container_->SetBounds(gfx::Rect(0, 0, 1280, 1024), 0);
+ toplevel_window_container_->SetBounds(gfx::Rect(0, 0, 1280, 1024));
toplevel_window_container_->SetVisibility(aura::Window::VISIBILITY_SHOWN);
toplevel_window_container_->SetParent(window_.get());
}
@@ -88,7 +88,7 @@ bool Desktop::OnKeyEvent(const KeyEvent& event) {
void Desktop::OnHostResized(const gfx::Size& size) {
gfx::Rect bounds(window_->bounds().origin(), size);
- window_->SetBounds(bounds, 0);
+ window_->SetBounds(bounds);
compositor_->WidgetSizeChanged(size);
}
diff --git a/ui/aura/toplevel_window_event_filter.cc b/ui/aura/toplevel_window_event_filter.cc
index b578b04..90b61c6 100644
--- a/ui/aura/toplevel_window_event_filter.cc
+++ b/ui/aura/toplevel_window_event_filter.cc
@@ -46,7 +46,7 @@ bool ToplevelWindowEventFilter::OnMouseEvent(Window* target,
gfx::Point new_origin(event->location());
new_origin.Offset(-mouse_down_offset_.x(), -mouse_down_offset_.y());
new_origin.Offset(target->bounds().x(), target->bounds().y());
- target->SetBounds(gfx::Rect(new_origin, target->bounds().size()), 0);
+ target->SetBounds(gfx::Rect(new_origin, target->bounds().size()));
return true;
}
break;
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index 7e8070ee..86e1dda 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -13,6 +13,7 @@
#include "ui/aura/focus_manager.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window_delegate.h"
+#include "ui/base/animation/multi_animation.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/compositor/compositor.h"
#include "ui/gfx/compositor/layer.h"
@@ -84,23 +85,26 @@ void Window::SetLayoutManager(LayoutManager* layout_manager) {
layout_manager_.reset(layout_manager);
}
-void Window::SetBounds(const gfx::Rect& bounds, int anim_ms) {
- // TODO: support anim_ms
+void Window::SetBounds(const gfx::Rect& new_bounds) {
// TODO: funnel this through the Desktop.
- bool was_move = bounds_.size() == bounds.size();
- gfx::Rect old_bounds = bounds_;
- bounds_ = bounds;
- layer_->SetBounds(bounds);
+ gfx::Rect old_bounds = bounds();
+ bool was_move = old_bounds.size() == new_bounds.size();
+ layer_->SetBounds(new_bounds);
+
if (layout_manager_.get())
layout_manager_->OnWindowResized();
if (delegate_)
- delegate_->OnBoundsChanged(old_bounds, bounds_);
+ delegate_->OnBoundsChanged(old_bounds, new_bounds);
if (was_move)
SchedulePaintInRect(gfx::Rect());
else
SchedulePaint();
}
+const gfx::Rect& Window::bounds() const {
+ return layer_->bounds();
+}
+
void Window::SchedulePaintInRect(const gfx::Rect& rect) {
layer_->SchedulePaint(rect);
}
@@ -231,12 +235,21 @@ bool Window::HasCapture() {
return root && root->capture_window() == this;
}
+// static
+ui::Animation* Window::CreateDefaultAnimation() {
+ std::vector<ui::MultiAnimation::Part> parts;
+ parts.push_back(ui::MultiAnimation::Part(200, ui::Tween::LINEAR));
+ ui::MultiAnimation* multi_animation = new ui::MultiAnimation(parts);
+ multi_animation->set_continuous(false);
+ return multi_animation;
+}
+
internal::RootWindow* Window::GetRoot() {
return parent_ ? parent_->GetRoot() : NULL;
}
void Window::SchedulePaint() {
- SchedulePaintInRect(gfx::Rect(0, 0, bounds_.width(), bounds_.height()));
+ SchedulePaintInRect(gfx::Rect(0, 0, bounds().width(), bounds().height()));
}
void Window::OnPaintLayer(gfx::Canvas* canvas) {
diff --git a/ui/aura/window.h b/ui/aura/window.h
index 17971d7..144f290 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -18,6 +18,7 @@
class SkCanvas;
namespace ui {
+class Animation;
class Compositor;
class Layer;
}
@@ -78,8 +79,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate {
void SetLayoutManager(LayoutManager* layout_manager);
// Changes the bounds of the window.
- void SetBounds(const gfx::Rect& bounds, int anim_ms);
- const gfx::Rect& bounds() const { return bounds_; }
+ void SetBounds(const gfx::Rect& new_bounds);
+ const gfx::Rect& bounds() const;
// Marks the a portion of window as needing to be painted.
void SchedulePaintInRect(const gfx::Rect& rect);
@@ -151,6 +152,10 @@ class AURA_EXPORT Window : public ui::LayerDelegate {
// Returns true if this window has a mouse capture.
bool HasCapture();
+ // Returns an animation configured with the default duration. All animations
+ // should use this. Caller owns returned value.
+ static ui::Animation* CreateDefaultAnimation();
+
protected:
// Returns the RootWindow or NULL if we don't yet have a RootWindow.
virtual internal::RootWindow* GetRoot();
@@ -168,9 +173,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate {
scoped_ptr<ui::Layer> layer_;
- // Bounds of the window in the desktop's coordinate system.
- gfx::Rect bounds_;
-
// The Window's parent.
// TODO(beng): Implement NULL-ness for toplevels.
Window* parent_;
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index c1b74644..eed3247 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -199,7 +199,7 @@ class WindowTest : public testing::Test {
Window* window = new Window(delegate);
window->set_id(id);
window->Init();
- window->SetBounds(bounds, 0);
+ window->SetBounds(bounds);
window->SetVisibility(Window::VISIBILITY_SHOWN);
window->SetParent(parent);
return window;
@@ -222,7 +222,7 @@ TEST_F(WindowTest, HitTest) {
Window w1(new TestWindowDelegate(SK_ColorWHITE));
w1.set_id(1);
w1.Init();
- w1.SetBounds(gfx::Rect(10, 10, 50, 50), 0);
+ w1.SetBounds(gfx::Rect(10, 10, 50, 50));
w1.SetVisibility(Window::VISIBILITY_SHOWN);
w1.SetParent(NULL);
diff --git a/ui/aura_shell/desktop_layout_manager.cc b/ui/aura_shell/desktop_layout_manager.cc
index 4585f58..6a8e639 100644
--- a/ui/aura_shell/desktop_layout_manager.cc
+++ b/ui/aura_shell/desktop_layout_manager.cc
@@ -30,7 +30,7 @@ DesktopLayoutManager::~DesktopLayoutManager() {
void DesktopLayoutManager::OnWindowResized() {
gfx::Rect fullscreen_bounds =
gfx::Rect(owner_->bounds().width(), owner_->bounds().height());
- toplevel_window_container_->SetBounds(fullscreen_bounds, 0);
+ toplevel_window_container_->SetBounds(fullscreen_bounds);
background_widget_->SetBounds(fullscreen_bounds);
diff --git a/ui/aura_shell/examples/window_type_launcher.cc b/ui/aura_shell/examples/window_type_launcher.cc
index b4a9681..0865692 100644
--- a/ui/aura_shell/examples/window_type_launcher.cc
+++ b/ui/aura_shell/examples/window_type_launcher.cc
@@ -5,11 +5,13 @@
#include "ui/aura_shell/examples/window_type_launcher.h"
#include "base/utf_string_conversions.h"
+#include "ui/aura/desktop.h"
#include "ui/aura/window.h"
#include "ui/aura_shell/examples/example_factory.h"
#include "ui/aura_shell/examples/toplevel_window.h"
#include "ui/aura_shell/toplevel_frame_view.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/compositor/layer.h"
#include "views/controls/button/text_button.h"
#include "views/controls/menu/menu_item_view.h"
#include "views/controls/menu/menu_runner.h"
@@ -21,6 +23,64 @@ using views::MenuRunner;
namespace aura_shell {
namespace examples {
+namespace {
+
+typedef std::pair<aura::Window*, gfx::Rect> WindowAndBoundsPair;
+
+void CalculateWindowBoundsAndScaleForTiling(
+ const gfx::Size& containing_size,
+ const aura::Window::Windows& windows,
+ float* x_scale,
+ float* y_scale,
+ std::vector<WindowAndBoundsPair>* bounds) {
+ *x_scale = 1.0f;
+ *y_scale = 1.0f;
+ int total_width = 0;
+ int max_height = 0;
+ int shown_window_count = 0;
+ for (aura::Window::Windows::const_iterator i = windows.begin();
+ i != windows.end(); ++i) {
+ if ((*i)->visibility() != aura::Window::VISIBILITY_HIDDEN) {
+ total_width += (*i)->bounds().width();
+ max_height = std::max((*i)->bounds().height(), max_height);
+ shown_window_count++;
+ }
+ }
+
+ if (shown_window_count == 0)
+ return;
+
+ const int kPadding = 10;
+ total_width += (shown_window_count - 1) * kPadding;
+ if (total_width > containing_size.width()) {
+ *x_scale = static_cast<float>(containing_size.width()) /
+ static_cast<float>(total_width);
+ }
+ if (max_height > containing_size.height()) {
+ *y_scale = static_cast<float>(containing_size.height()) /
+ static_cast<float>(max_height);
+ }
+ *x_scale = *y_scale = std::min(*x_scale, *y_scale);
+
+ int x = std::max(0, static_cast<int>(
+ (containing_size.width() * - total_width * *x_scale) / 2));
+ for (aura::Window::Windows::const_iterator i = windows.begin();
+ i != windows.end();
+ ++i) {
+ if ((*i)->visibility() != aura::Window::VISIBILITY_HIDDEN) {
+ const gfx::Rect& current_bounds((*i)->bounds());
+ int y = (containing_size.height() -
+ current_bounds.height() * *y_scale) / 2;
+ bounds->push_back(std::make_pair(*i,
+ gfx::Rect(x, y, current_bounds.width(), current_bounds.height())));
+ x += static_cast<int>(
+ static_cast<float>(current_bounds.width() + kPadding) * *x_scale);
+ }
+ }
+}
+
+} // namespace
+
void InitWindowTypeLauncher() {
views::Widget* widget =
views::Widget::CreateWindowWithBounds(new WindowTypeLauncher,
@@ -36,7 +96,8 @@ WindowTypeLauncher::WindowTypeLauncher()
create_nonresizable_button_(new views::NativeTextButton(
this, L"Create Non-Resizable Window"))),
ALLOW_THIS_IN_INITIALIZER_LIST(bubble_button_(
- new views::NativeTextButton(this, L"Create Pointy Bubble"))) {
+ new views::NativeTextButton(this, L"Create Pointy Bubble"))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
AddChildView(create_button_);
AddChildView(create_nonresizable_button_);
AddChildView(bubble_button_);
@@ -46,6 +107,51 @@ WindowTypeLauncher::WindowTypeLauncher()
WindowTypeLauncher::~WindowTypeLauncher() {
}
+void WindowTypeLauncher::TileWindows() {
+ to_restore_.clear();
+ aura::Window* window_container =
+ aura::Desktop::GetInstance()->toplevel_window_container();
+ const aura::Window::Windows& windows = window_container->children();
+ if (windows.empty())
+ return;
+ float x_scale = 1.0f;
+ float y_scale = 1.0f;
+ std::vector<WindowAndBoundsPair> bounds;
+ CalculateWindowBoundsAndScaleForTiling(window_container->bounds().size(),
+ windows, &x_scale, &y_scale, &bounds);
+ if (bounds.empty())
+ return;
+ ui::Transform transform;
+ transform.SetScale(x_scale, y_scale);
+ for (size_t i = 0; i < bounds.size(); ++i) {
+ to_restore_.push_back(
+ std::make_pair(bounds[i].first, bounds[i].first->bounds()));
+ bounds[i].first->layer()->SetAnimation(
+ aura::Window::CreateDefaultAnimation());
+ bounds[i].first->SetBounds(bounds[i].second);
+ bounds[i].first->layer()->SetTransform(transform);
+ bounds[i].first->layer()->SetOpacity(0.5f);
+ }
+
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, method_factory_.NewRunnableMethod(
+ &WindowTypeLauncher::RestoreTiledWindows), 2000);
+}
+
+void WindowTypeLauncher::RestoreTiledWindows() {
+ aura::Window* window_container =
+ aura::Desktop::GetInstance()->toplevel_window_container();
+ ui::Transform identity_transform;
+ for (size_t i = 0; i < to_restore_.size(); ++i) {
+ to_restore_[i].first->layer()->SetAnimation(
+ aura::Window::CreateDefaultAnimation());
+ to_restore_[i].first->SetBounds(to_restore_[i].second);
+ to_restore_[i].first->layer()->SetTransform(identity_transform);
+ to_restore_[i].first->layer()->SetOpacity(1.0f);
+ }
+ to_restore_.clear();
+}
+
void WindowTypeLauncher::OnPaint(gfx::Canvas* canvas) {
canvas->FillRectInt(SK_ColorWHITE, 0, 0, width(), height());
}
@@ -111,8 +217,16 @@ void WindowTypeLauncher::ButtonPressed(views::Button* sender,
}
void WindowTypeLauncher::ExecuteCommand(int id) {
- DCHECK_EQ(id, COMMAND_NEW_WINDOW);
- InitWindowTypeLauncher();
+ switch (id) {
+ case COMMAND_NEW_WINDOW:
+ InitWindowTypeLauncher();
+ break;
+ case COMMAND_TILE_WINDOWS:
+ TileWindows();
+ break;
+ default:
+ break;
+ }
}
void WindowTypeLauncher::ShowContextMenuForView(views::View* source,
@@ -120,6 +234,8 @@ void WindowTypeLauncher::ShowContextMenuForView(views::View* source,
bool is_mouse_gesture) {
MenuItemView* root = new MenuItemView(this);
root->AppendMenuItem(COMMAND_NEW_WINDOW, L"New Window", MenuItemView::NORMAL);
+ root->AppendMenuItem(COMMAND_TILE_WINDOWS, L"Tile Windows",
+ MenuItemView::NORMAL);
// MenuRunner takes ownership of root.
menu_runner_.reset(new MenuRunner(root));
if (menu_runner_->RunMenuAt(GetWidget(), NULL, gfx::Rect(p, gfx::Size(0, 0)),
diff --git a/ui/aura_shell/examples/window_type_launcher.h b/ui/aura_shell/examples/window_type_launcher.h
index 9fb6eaf..ea39900 100644
--- a/ui/aura_shell/examples/window_type_launcher.h
+++ b/ui/aura_shell/examples/window_type_launcher.h
@@ -6,6 +6,10 @@
#define UI_AURA_SHELL_EXAMPLES_WINDOW_TYPE_LAUNCHER_H_
#pragma once
+#include <utility>
+#include <vector>
+
+#include "base/task.h"
#include "views/context_menu_controller.h"
#include "views/controls/button/button.h"
#include "views/controls/menu/menu_delegate.h"
@@ -30,10 +34,16 @@ class WindowTypeLauncher : public views::WidgetDelegateView,
virtual ~WindowTypeLauncher();
private:
+ typedef std::pair<aura::Window*, gfx::Rect> WindowAndBoundsPair;
+
enum MenuCommands {
COMMAND_NEW_WINDOW = 1,
+ COMMAND_TILE_WINDOWS = 2,
};
+ void TileWindows();
+ void RestoreTiledWindows();
+
// Overridden from views::View:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
virtual void Layout() OVERRIDE;
@@ -61,8 +71,13 @@ class WindowTypeLauncher : public views::WidgetDelegateView,
views::NativeTextButton* create_button_;
views::NativeTextButton* create_nonresizable_button_;
views::NativeTextButton* bubble_button_;
+ views::NativeTextButton* tile_button_;
scoped_ptr<views::MenuRunner> menu_runner_;
+ std::vector<WindowAndBoundsPair> to_restore_;
+
+ ScopedRunnableMethodFactory<WindowTypeLauncher> method_factory_;
+
DISALLOW_COPY_AND_ASSIGN(WindowTypeLauncher);
};
diff --git a/ui/gfx/compositor/compositor.gyp b/ui/gfx/compositor/compositor.gyp
index a0317d7..1c030b6 100644
--- a/ui/gfx/compositor/compositor.gyp
+++ b/ui/gfx/compositor/compositor.gyp
@@ -46,6 +46,7 @@
'layer.h',
'layer_animator.cc',
'layer_animator.h',
+ 'layer_animator_delegate.h',
],
'conditions': [
['os_posix == 1 and OS != "mac"', {
diff --git a/ui/gfx/compositor/layer.cc b/ui/gfx/compositor/layer.cc
index ff5a5ff..9f6b661 100644
--- a/ui/gfx/compositor/layer.cc
+++ b/ui/gfx/compositor/layer.cc
@@ -8,6 +8,8 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "ui/base/animation/animation.h"
+#include "ui/gfx/compositor/layer_animator.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/point3.h"
@@ -86,18 +88,43 @@ bool Layer::Contains(const Layer* other) const {
return false;
}
-void Layer::SetTransform(const ui::Transform& transform) {
- transform_ = transform;
+void Layer::SetAnimation(Animation* animation) {
+ if (animation) {
+ if (!animator_.get())
+ animator_.reset(new LayerAnimator(this));
+ animation->Start();
+ animator_->SetAnimation(animation);
+ } else {
+ animator_.reset();
+ }
+}
- if (parent() && fills_bounds_opaquely_)
- parent()->RecomputeHole();
+void Layer::SetTransform(const ui::Transform& transform) {
+ StopAnimatingIfNecessary(LayerAnimator::TRANSFORM);
+ if (animator_.get() && animator_->IsRunning()) {
+ animator_->AnimateTransform(transform);
+ return;
+ }
+ SetTransformImmediately(transform);
}
void Layer::SetBounds(const gfx::Rect& bounds) {
- bounds_ = bounds;
+ StopAnimatingIfNecessary(LayerAnimator::LOCATION);
+ if (animator_.get() && animator_->IsRunning() &&
+ bounds.size() == bounds_.size()) {
+ animator_->AnimateToPoint(bounds.origin());
+ return;
+ }
+ SetBoundsImmediately(bounds);
+}
- if (parent() && fills_bounds_opaquely_)
- parent()->RecomputeHole();
+void Layer::SetOpacity(float opacity) {
+ StopAnimatingIfNecessary(LayerAnimator::OPACITY);
+ if (animator_.get() && animator_->IsRunning()) {
+ animator_->AnimateOpacity(opacity);
+ return;
+ }
+ SetOpacityImmediately(opacity);
}
void Layer::SetVisible(bool visible) {
@@ -235,28 +262,6 @@ void Layer::DrawTree() {
children_.at(i)->DrawTree();
}
-void Layer::SetOpacity(float alpha) {
- bool was_opaque = GetCombinedOpacity() == 1.0f;
- opacity_ = alpha;
- bool is_opaque = GetCombinedOpacity() == 1.0f;
-
- // If our opacity has changed we need to recompute our hole, our parent's hole
- // and the holes of all our descendants.
- if (was_opaque != is_opaque) {
- if (parent_)
- parent_->RecomputeHole();
- std::queue<Layer*> to_process;
- to_process.push(this);
- while (!to_process.empty()) {
- Layer* current = to_process.front();
- to_process.pop();
- current->RecomputeHole();
- for (size_t i = 0; i < current->children_.size(); ++i)
- to_process.push(current->children_.at(i));
- }
- }
-}
-
float Layer::GetCombinedOpacity() const {
float opacity = opacity_;
Layer* current = this->parent_;
@@ -352,4 +357,75 @@ bool Layer::GetTransformRelativeTo(const Layer* ancestor,
return p == ancestor;
}
+void Layer::StopAnimatingIfNecessary(
+ LayerAnimator::AnimationProperty property) {
+ if (!animator_.get() || !animator_->IsRunning() ||
+ !animator_->got_initial_tick()) {
+ return;
+ }
+
+ if (property != LayerAnimator::LOCATION &&
+ animator_->IsAnimating(LayerAnimator::LOCATION)) {
+ SetBoundsImmediately(
+ gfx::Rect(animator_->GetTargetPoint(), bounds_.size()));
+ }
+ if (property != LayerAnimator::OPACITY &&
+ animator_->IsAnimating(LayerAnimator::OPACITY)) {
+ SetOpacityImmediately(animator_->GetTargetOpacity());
+ }
+ if (property != LayerAnimator::TRANSFORM &&
+ animator_->IsAnimating(LayerAnimator::TRANSFORM)) {
+ SetTransformImmediately(animator_->GetTargetTransform());
+ }
+ animator_.reset();
+}
+
+void Layer::SetBoundsImmediately(const gfx::Rect& bounds) {
+ bounds_ = bounds;
+
+ if (parent() && fills_bounds_opaquely_)
+ parent()->RecomputeHole();
+}
+
+void Layer::SetTransformImmediately(const ui::Transform& transform) {
+ transform_ = transform;
+
+ if (parent() && fills_bounds_opaquely_)
+ parent()->RecomputeHole();
+}
+
+void Layer::SetOpacityImmediately(float opacity) {
+ bool was_opaque = GetCombinedOpacity() == 1.0f;
+ opacity_ = opacity;
+ bool is_opaque = GetCombinedOpacity() == 1.0f;
+
+ // If our opacity has changed we need to recompute our hole, our parent's hole
+ // and the holes of all our descendants.
+ if (was_opaque != is_opaque) {
+ if (parent_)
+ parent_->RecomputeHole();
+ std::queue<Layer*> to_process;
+ to_process.push(this);
+ while (!to_process.empty()) {
+ Layer* current = to_process.front();
+ to_process.pop();
+ current->RecomputeHole();
+ for (size_t i = 0; i < current->children_.size(); ++i)
+ to_process.push(current->children_.at(i));
+ }
+ }
+}
+
+void Layer::SetBoundsFromAnimator(const gfx::Rect& bounds) {
+ SetBoundsImmediately(bounds);
+}
+
+void Layer::SetTransformFromAnimator(const Transform& transform) {
+ SetTransformImmediately(transform);
+}
+
+void Layer::SetOpacityFromAnimator(float opacity) {
+ SetOpacityImmediately(opacity);
+}
+
} // namespace ui
diff --git a/ui/gfx/compositor/layer.h b/ui/gfx/compositor/layer.h
index 9504345..836b63e 100644
--- a/ui/gfx/compositor/layer.h
+++ b/ui/gfx/compositor/layer.h
@@ -8,17 +8,22 @@
#include <vector>
+#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
#include "ui/gfx/compositor/compositor.h"
+#include "ui/gfx/compositor/layer_animator.h"
+#include "ui/gfx/compositor/layer_animator_delegate.h"
#include "ui/gfx/compositor/layer_delegate.h"
class SkCanvas;
namespace ui {
+class Animation;
class Compositor;
class Texture;
@@ -30,7 +35,7 @@ class Texture;
// NOTE: unlike Views, each Layer does *not* own its children views. If you
// delete a Layer and it has children, the parent of each child layer is set to
// NULL, but the children are not deleted.
-class COMPOSITOR_EXPORT Layer {
+class COMPOSITOR_EXPORT Layer : public LayerAnimatorDelegate {
public:
enum LayerType {
LAYER_HAS_NO_TEXTURE = 0,
@@ -70,6 +75,17 @@ class COMPOSITOR_EXPORT Layer {
// Returns true if this Layer contains |other| somewhere in its children.
bool Contains(const Layer* other) const;
+ // Sets the animation to use for changes to opacity, position or transform.
+ // That is, if you invoke this with non-NULL |animation| is started and any
+ // changes to opacity, position or transform are animated between the current
+ // value and target value. If the current animation is NULL or completed,
+ // changes are immediate. If the opacity, transform or bounds are changed
+ // and the animation is part way through, the animation is canceled and
+ // the bounds, opacity and transfrom and set to the target value.
+ // Layer takes ownership of |animation| and installs it's own delegate on the
+ // animation.
+ void SetAnimation(Animation* animation);
+
// The transform, relative to the parent.
void SetTransform(const ui::Transform& transform);
const ui::Transform& transform() const { return transform_; }
@@ -78,6 +94,11 @@ class COMPOSITOR_EXPORT Layer {
void SetBounds(const gfx::Rect& bounds);
const gfx::Rect& bounds() const { return bounds_; }
+ // The opacity of the layer. The opacity is applied to each pixel of the
+ // texture (resulting alpha = opacity * alpha).
+ float opacity() const { return opacity_; }
+ void SetOpacity(float opacity);
+
// Sets |visible_|. The Layer is drawn by Draw() only when visible_ is true.
bool visible() const { return visible_; }
void SetVisible(bool visible);
@@ -146,9 +167,6 @@ class COMPOSITOR_EXPORT Layer {
// (e.g. the GPU process on TOUCH_UI).
bool layer_updated_externally() const { return layer_updated_externally_; }
- float opacity() const { return opacity_; }
- void SetOpacity(float alpha);
-
private:
// TODO(vollick): Eventually, if a non-leaf node has an opacity of less than
// 1.0, we'll render to a separate texture, and then apply the alpha.
@@ -189,6 +207,22 @@ class COMPOSITOR_EXPORT Layer {
// should have valid alpha.
bool has_valid_alpha_channel() const { return !layer_updated_externally_; }
+ // If the animation is running and has progressed, it is stopped and all
+ // properties that are animated (except |property|) are immediately set to
+ // their target value.
+ void StopAnimatingIfNecessary(LayerAnimator::AnimationProperty property);
+
+ // Following are invoked from the animation or if no animation exists to
+ // update the values immediately.
+ void SetBoundsImmediately(const gfx::Rect& bounds);
+ void SetTransformImmediately(const ui::Transform& transform);
+ void SetOpacityImmediately(float opacity);
+
+ // LayerAnimatorDelegate overrides:
+ virtual void SetBoundsFromAnimator(const gfx::Rect& bounds) OVERRIDE;
+ virtual void SetTransformFromAnimator(const Transform& transform) OVERRIDE;
+ virtual void SetOpacityFromAnimator(float opacity) OVERRIDE;
+
const LayerType type_;
Compositor* compositor_;
@@ -218,6 +252,8 @@ class COMPOSITOR_EXPORT Layer {
LayerDelegate* delegate_;
+ scoped_ptr<LayerAnimator> animator_;
+
DISALLOW_COPY_AND_ASSIGN(Layer);
};
diff --git a/ui/gfx/compositor/layer_animator.cc b/ui/gfx/compositor/layer_animator.cc
index e30329c..e7eeaec 100644
--- a/ui/gfx/compositor/layer_animator.cc
+++ b/ui/gfx/compositor/layer_animator.cc
@@ -7,9 +7,11 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "ui/base/animation/animation_container.h"
-#include "ui/base/animation/multi_animation.h"
+#include "ui/base/animation/animation.h"
+#include "ui/base/animation/tween.h"
#include "ui/gfx/compositor/compositor.h"
#include "ui/gfx/compositor/layer.h"
+#include "ui/gfx/compositor/layer_animator_delegate.h"
#include "ui/gfx/transform.h"
#include "ui/gfx/rect.h"
@@ -33,21 +35,24 @@ namespace ui {
LayerAnimator::LayerAnimator(Layer* layer)
: layer_(layer),
- duration_in_ms_(200),
- animation_type_(ui::Tween::EASE_IN) {
+ got_initial_tick_(false) {
}
LayerAnimator::~LayerAnimator() {
- for (Elements::iterator i = elements_.begin(); i != elements_.end(); ++i)
- delete i->second.animation;
- elements_.clear();
}
-void LayerAnimator::SetAnimationDurationAndType(int duration,
- ui::Tween::Type tween_type) {
- DCHECK_GT(duration, 0);
- duration_in_ms_ = duration;
- animation_type_ = tween_type;
+void LayerAnimator::SetAnimation(Animation* animation) {
+ animation_.reset(animation);
+ if (animation_.get()) {
+ static ui::AnimationContainer* container = NULL;
+ if (!container) {
+ container = new AnimationContainer;
+ container->AddRef();
+ }
+ animation_->set_delegate(this);
+ animation_->SetContainer(container);
+ got_initial_tick_ = false;
+ }
}
void LayerAnimator::AnimateToPoint(const gfx::Point& target) {
@@ -56,12 +61,11 @@ void LayerAnimator::AnimateToPoint(const gfx::Point& target) {
if (target == layer_bounds.origin())
return; // Already there.
- Element& element = elements_[LOCATION];
- element.params.location.start_x = layer_bounds.origin().x();
- element.params.location.start_y = layer_bounds.origin().y();
- element.params.location.target_x = target.x();
- element.params.location.target_y = target.y();
- element.animation = CreateAndStartAnimation();
+ Params& element = elements_[LOCATION];
+ element.location.target_x = target.x();
+ element.location.target_y = target.y();
+ element.location.start_x = layer_bounds.origin().x();
+ element.location.start_y = layer_bounds.origin().y();
}
void LayerAnimator::AnimateTransform(const Transform& transform) {
@@ -70,120 +74,113 @@ void LayerAnimator::AnimateTransform(const Transform& transform) {
if (transform == layer_transform)
return; // Already there.
- Element& element = elements_[TRANSFORM];
+ Params& element = elements_[TRANSFORM];
for (int i = 0; i < 16; ++i) {
- element.params.transform.start[i] =
- GetMatrixElement(layer_transform.matrix(), i);
- element.params.transform.target[i] =
- GetMatrixElement(transform.matrix(), i);
+ element.transform.start[i] =
+ GetMatrixElement(layer_transform.matrix(), i);
+ element.transform.target[i] =
+ GetMatrixElement(transform.matrix(), i);
}
- element.animation = CreateAndStartAnimation();
}
-void LayerAnimator::AnimationProgressed(const ui::Animation* animation) {
- Elements::iterator e = GetElementByAnimation(
- static_cast<const ui::MultiAnimation*>(animation));
- DCHECK(e != elements_.end());
- switch (e->first) {
- case LOCATION: {
- const gfx::Rect& current_bounds(layer_->bounds());
- gfx::Rect new_bounds = e->second.animation->CurrentValueBetween(
- gfx::Rect(gfx::Point(e->second.params.location.start_x,
- e->second.params.location.start_y),
- current_bounds.size()),
- gfx::Rect(gfx::Point(e->second.params.location.target_x,
- e->second.params.location.target_y),
- current_bounds.size()));
- layer_->SetBounds(new_bounds);
- break;
- }
+void LayerAnimator::AnimateOpacity(float target_opacity) {
+ StopAnimating(OPACITY);
+ if (layer_->opacity() == target_opacity)
+ return;
- case TRANSFORM: {
- Transform transform;
- for (int i = 0; i < 16; ++i) {
- SkMScalar value = e->second.animation->CurrentValueBetween(
- e->second.params.transform.start[i],
- e->second.params.transform.target[i]);
- SetMatrixElement(transform.matrix(), i, value);
- }
- layer_->SetTransform(transform);
- break;
- }
+ Params& element = elements_[OPACITY];
+ element.opacity.start = layer_->opacity();
+ element.opacity.target = target_opacity;
+}
- default:
- NOTREACHED();
- }
- layer_->GetCompositor()->SchedulePaint();
+gfx::Point LayerAnimator::GetTargetPoint() {
+ return IsAnimating(LOCATION) ?
+ gfx::Point(elements_[LOCATION].location.target_x,
+ elements_[LOCATION].location.target_y) :
+ layer_->bounds().origin();
}
-void LayerAnimator::AnimationEnded(const ui::Animation* animation) {
- Elements::iterator e = GetElementByAnimation(
- static_cast<const ui::MultiAnimation*>(animation));
- DCHECK(e != elements_.end());
- switch (e->first) {
- case LOCATION: {
- gfx::Rect new_bounds(
- gfx::Point(e->second.params.location.target_x,
- e->second.params.location.target_y),
- layer_->bounds().size());
- layer_->SetBounds(new_bounds);
- break;
+float LayerAnimator::GetTargetOpacity() {
+ return IsAnimating(OPACITY) ?
+ elements_[OPACITY].opacity.target : layer_->opacity();
+}
+
+ui::Transform LayerAnimator::GetTargetTransform() {
+ if (IsAnimating(TRANSFORM)) {
+ Transform transform;
+ for (int i = 0; i < 16; ++i) {
+ SetMatrixElement(transform.matrix(), i,
+ elements_[TRANSFORM].transform.target[i]);
}
+ return transform;
+ }
+ return layer_->transform();
+}
- case TRANSFORM: {
- Transform transform;
- for (int i = 0; i < 16; ++i) {
- SetMatrixElement(transform.matrix(),
- i,
- e->second.params.transform.target[i]);
+bool LayerAnimator::IsAnimating(AnimationProperty property) const {
+ return elements_.count(property) > 0;
+}
+
+bool LayerAnimator::IsRunning() const {
+ return animation_.get() && animation_->is_animating();
+}
+
+void LayerAnimator::AnimationProgressed(const ui::Animation* animation) {
+ got_initial_tick_ = true;
+ for (Elements::const_iterator i = elements_.begin(); i != elements_.end();
+ ++i) {
+ switch (i->first) {
+ case LOCATION: {
+ const gfx::Rect& current_bounds(layer_->bounds());
+ gfx::Rect new_bounds = animation_->CurrentValueBetween(
+ gfx::Rect(gfx::Point(i->second.location.start_x,
+ i->second.location.start_y),
+ current_bounds.size()),
+ gfx::Rect(gfx::Point(i->second.location.target_x,
+ i->second.location.target_y),
+ current_bounds.size()));
+ delegate()->SetBoundsFromAnimator(new_bounds);
+ break;
+ }
+
+ case TRANSFORM: {
+ Transform transform;
+ for (int j = 0; j < 16; ++j) {
+ SkMScalar value = animation_->CurrentValueBetween(
+ i->second.transform.start[j],
+ i->second.transform.target[j]);
+ SetMatrixElement(transform.matrix(), j, value);
+ }
+ delegate()->SetTransformFromAnimator(transform);
+ break;
}
- layer_->SetTransform(transform);
- break;
- }
- default:
- NOTREACHED();
+ case OPACITY: {
+ delegate()->SetOpacityFromAnimator(animation_->CurrentValueBetween(
+ i->second.opacity.start, i->second.opacity.target));
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
}
- StopAnimating(e->first);
- // StopAnimating removes from the map, invalidating 'e'.
- e = elements_.end();
layer_->GetCompositor()->SchedulePaint();
}
+void LayerAnimator::AnimationEnded(const ui::Animation* animation) {
+ AnimationProgressed(animation);
+}
+
void LayerAnimator::StopAnimating(AnimationProperty property) {
- if (elements_.count(property) == 0)
+ if (!IsAnimating(property))
return;
- // Reset the delegate so that we don't attempt to update the layer.
- elements_[property].animation->set_delegate(NULL);
- delete elements_[property].animation;
elements_.erase(property);
}
-ui::MultiAnimation* LayerAnimator::CreateAndStartAnimation() {
- static ui::AnimationContainer* container = NULL;
- if (!container) {
- container = new AnimationContainer;
- container->AddRef();
- }
- ui::MultiAnimation::Parts parts;
- parts.push_back(ui::MultiAnimation::Part(duration_in_ms_, animation_type_));
- ui::MultiAnimation* animation = new ui::MultiAnimation(parts);
- animation->SetContainer(container);
- animation->set_delegate(this);
- animation->set_continuous(false);
- animation->Start();
- return animation;
-}
-
-LayerAnimator::Elements::iterator LayerAnimator::GetElementByAnimation(
- const ui::MultiAnimation* animation) {
- for (Elements::iterator i = elements_.begin(); i != elements_.end(); ++i) {
- if (i->second.animation == animation)
- return i;
- }
- NOTREACHED();
- return elements_.end();
+LayerAnimatorDelegate* LayerAnimator::delegate() {
+ return static_cast<LayerAnimatorDelegate*>(layer_);
}
} // namespace ui
diff --git a/ui/gfx/compositor/layer_animator.h b/ui/gfx/compositor/layer_animator.h
index 4570e26..52b8870 100644
--- a/ui/gfx/compositor/layer_animator.h
+++ b/ui/gfx/compositor/layer_animator.h
@@ -10,55 +10,72 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "third_party/skia/include/core/SkScalar.h"
#include "third_party/skia/include/utils/SkMatrix44.h"
#include "ui/base/animation/animation_delegate.h"
-#include "ui/base/animation/tween.h"
#include "ui/gfx/compositor/compositor_export.h"
-#include "ui/gfx/point.h"
+
+namespace gfx {
+class Point;
+}
namespace ui {
+class Animation;
class Layer;
-class MultiAnimation;
+class LayerAnimatorDelegate;
class Transform;
// LayerAnimator manages animating various properties of a Layer.
class COMPOSITOR_EXPORT LayerAnimator : public ui::AnimationDelegate {
public:
+ // Types of properties that can be animated.
+ enum AnimationProperty {
+ LOCATION,
+ OPACITY,
+ TRANSFORM,
+ };
+
explicit LayerAnimator(Layer* layer);
virtual ~LayerAnimator();
- ui::Layer* layer() { return layer_; }
+ // Sets the animation to use. LayerAnimator takes ownership of the animation.
+ void SetAnimation(Animation* animation);
- // Sets the duration (in ms) and type of animation. This does not effect
- // existing animations, only newly created animations.
- void SetAnimationDurationAndType(int duration, ui::Tween::Type tween_type);
+ ui::Layer* layer() { return layer_; }
// Animates the layer to the specified point. The point is relative to the
// parent layer.
void AnimateToPoint(const gfx::Point& target);
- void StopAnimatingToPoint() {
- StopAnimating(LOCATION);
- }
- // Animates the transform from from the current transform to |transform|.
+ // Animates the transform from the current transform to |transform|.
void AnimateTransform(const Transform& transform);
- void StopAnimatingTransform() {
- StopAnimating(TRANSFORM);
- }
+
+ // Animates the opacity from the current opacity to |target_opacity|.
+ void AnimateOpacity(float target_opacity);
+
+ // Returns the target value for the specified type. If the specified property
+ // is not animating, the current value is returned.
+ gfx::Point GetTargetPoint();
+ float GetTargetOpacity();
+ ui::Transform GetTargetTransform();
+
+ // Returns true if animating |property|.
+ bool IsAnimating(AnimationProperty property) const;
+
+ // Returns true if the animation is running.
+ bool IsRunning() const;
+
+ // Returns true if the animation has progressed at least once since
+ // SetAnimation() was invoked.
+ bool got_initial_tick() const { return got_initial_tick_; }
// AnimationDelegate:
virtual void AnimationProgressed(const Animation* animation) OVERRIDE;
virtual void AnimationEnded(const Animation* animation) OVERRIDE;
private:
- // Types of properties that can be animated.
- enum AnimationProperty {
- LOCATION,
- TRANSFORM
- };
-
// Parameters used when animating the location.
struct LocationParams {
int start_x;
@@ -67,35 +84,31 @@ class COMPOSITOR_EXPORT LayerAnimator : public ui::AnimationDelegate {
int target_y;
};
- // Parameters used whe animating the transform.
+ // Parameters used when animating the transform.
struct TransformParams {
- // TODO: make 4x4 whe Transform is updated.
SkMScalar start[16];
SkMScalar target[16];
};
+ // Parameters used when animating the opacity.
+ struct OpacityParams {
+ float start;
+ float target;
+ };
+
union Params {
LocationParams location;
+ OpacityParams opacity;
TransformParams transform;
};
- // Used for tracking the animation of a particular property.
- struct Element {
- Params params;
- ui::MultiAnimation* animation;
- };
-
- typedef std::map<AnimationProperty, Element> Elements;
+ typedef std::map<AnimationProperty, Params> Elements;
// Stops animating the specified property. This does not set the property
// being animated to its final value.
void StopAnimating(AnimationProperty property);
- // Creates an animation.
- ui::MultiAnimation* CreateAndStartAnimation();
-
- // Returns an iterator into |elements_| that matches the specified animation.
- Elements::iterator GetElementByAnimation(const ui::MultiAnimation* animation);
+ LayerAnimatorDelegate* delegate();
// The layer.
Layer* layer_;
@@ -103,11 +116,9 @@ class COMPOSITOR_EXPORT LayerAnimator : public ui::AnimationDelegate {
// Properties being animated.
Elements elements_;
- // Duration in ms for newly created animations.
- int duration_in_ms_;
+ scoped_ptr<ui::Animation> animation_;
- // Type of animation for newly created animations.
- ui::Tween::Type animation_type_;
+ bool got_initial_tick_;
DISALLOW_COPY_AND_ASSIGN(LayerAnimator);
};
diff --git a/ui/gfx/compositor/layer_animator_delegate.h b/ui/gfx/compositor/layer_animator_delegate.h
new file mode 100644
index 0000000..85cbc79
--- /dev/null
+++ b/ui/gfx/compositor/layer_animator_delegate.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef UI_GFX_COMPOSITOR_LAYER_ANIMATOR_DELEGATE_H_
+#define UI_GFX_COMPOSITOR_LAYER_ANIMATOR_DELEGATE_H_
+#pragma once
+
+#include "ui/gfx/compositor/compositor_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+class Transform;
+
+// LayerAnimator modifies the Layer using this interface.
+class COMPOSITOR_EXPORT LayerAnimatorDelegate {
+ public:
+ virtual void SetBoundsFromAnimator(const gfx::Rect& bounds) = 0;
+ virtual void SetTransformFromAnimator(const Transform& transform) = 0;
+ virtual void SetOpacityFromAnimator(float opacity) = 0;
+
+ protected:
+ virtual ~LayerAnimatorDelegate() {}
+};
+
+} // namespace ui
+
+#endif // UI_GFX_COMPOSITOR_LAYER_H_