diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-29 15:38:12 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-29 15:38:12 +0000 |
commit | 7fca53d420d201e1ec5a637ad236056c61e4e4b1 (patch) | |
tree | 8489ef482f21b5a0250582aa2dabff1c4335b270 /ui | |
parent | 79a5004a179fc12eb4e7ed6d1d12bd8b454fde6b (diff) | |
download | chromium_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.cc | 6 | ||||
-rw-r--r-- | ui/aura/desktop.cc | 4 | ||||
-rw-r--r-- | ui/aura/toplevel_window_event_filter.cc | 2 | ||||
-rw-r--r-- | ui/aura/window.cc | 29 | ||||
-rw-r--r-- | ui/aura/window.h | 12 | ||||
-rw-r--r-- | ui/aura/window_unittest.cc | 4 | ||||
-rw-r--r-- | ui/aura_shell/desktop_layout_manager.cc | 2 | ||||
-rw-r--r-- | ui/aura_shell/examples/window_type_launcher.cc | 122 | ||||
-rw-r--r-- | ui/aura_shell/examples/window_type_launcher.h | 15 | ||||
-rw-r--r-- | ui/gfx/compositor/compositor.gyp | 1 | ||||
-rw-r--r-- | ui/gfx/compositor/layer.cc | 134 | ||||
-rw-r--r-- | ui/gfx/compositor/layer.h | 44 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animator.cc | 215 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animator.h | 87 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animator_delegate.h | 32 |
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_ |