blob: a91c67b41ce11e363037e2753e8d434d7c5b292e [file] [log] [blame]
// Copyright 2021 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 "ui/views/animation/animation_builder.h"
#include <algorithm>
#include <tuple>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/check_op.h"
#include "base/ranges/algorithm.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_element.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/layer_owner.h"
#include "ui/views/animation/animation_key.h"
#include "ui/views/animation/animation_sequence_block.h"
namespace views {
class AnimationBuilder::Observer : public ui::LayerAnimationObserver {
public:
Observer() = default;
Observer(const Observer&) = delete;
Observer& operator=(const Observer&) = delete;
~Observer() override = default;
void SetOnStarted(base::OnceClosure callback);
void SetOnEnded(base::OnceClosure callback);
void SetOnWillRepeat(base::RepeatingClosure callback);
void SetOnAborted(base::OnceClosure callback);
void SetOnScheduled(base::OnceClosure callback);
// ui::LayerAnimationObserver:
void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationWillRepeat(
ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override;
void OnLayerAnimationScheduled(ui::LayerAnimationSequence* sequence) override;
protected:
void OnDetachedFromSequence(ui::LayerAnimationSequence* sequence) override;
private:
using RepeatMap = base::flat_map<ui::LayerAnimationSequence*, int>;
RepeatMap repeat_map_;
base::OnceClosure on_started_;
base::OnceClosure on_ended_;
base::RepeatingClosure on_will_repeat_;
base::OnceClosure on_aborted_;
base::OnceClosure on_scheduled_;
};
void AnimationBuilder::Observer::SetOnStarted(base::OnceClosure callback) {
DCHECK(!on_started_);
on_started_ = std::move(callback);
}
void AnimationBuilder::Observer::SetOnEnded(base::OnceClosure callback) {
DCHECK(!on_ended_);
on_ended_ = std::move(callback);
}
void AnimationBuilder::Observer::SetOnWillRepeat(
base::RepeatingClosure callback) {
DCHECK(!on_will_repeat_);
on_will_repeat_ = std::move(callback);
}
void AnimationBuilder::Observer::SetOnAborted(base::OnceClosure callback) {
DCHECK(!on_aborted_);
on_aborted_ = std::move(callback);
}
void AnimationBuilder::Observer::SetOnScheduled(base::OnceClosure callback) {
DCHECK(!on_scheduled_);
on_scheduled_ = std::move(callback);
}
void AnimationBuilder::Observer::OnLayerAnimationStarted(
ui::LayerAnimationSequence* sequence) {
if (on_started_)
std::move(on_started_).Run();
}
void AnimationBuilder::Observer::OnLayerAnimationEnded(
ui::LayerAnimationSequence* sequence) {
const auto running =
base::ranges::count_if(attached_sequences(), [](auto* sequence) {
return !sequence->IsFinished(base::TimeTicks::Now());
});
if (running <= 1) {
if (on_ended_)
std::move(on_ended_).Run();
}
}
void AnimationBuilder::Observer::OnLayerAnimationWillRepeat(
ui::LayerAnimationSequence* sequence) {
if (!on_will_repeat_)
return;
// First time through, initialize the repeat_map_ with the sequences.
if (repeat_map_.empty()) {
for (auto* seq : attached_sequences())
repeat_map_[seq] = 0;
}
// Only trigger the repeat callback on the last LayerAnimationSequence on
// which this observer is attached.
const int next_cycle = ++repeat_map_[sequence];
if (base::ranges::none_of(
repeat_map_, [next_cycle](int count) { return count < next_cycle; },
&RepeatMap::value_type::second)) {
on_will_repeat_.Run();
}
}
void AnimationBuilder::Observer::OnLayerAnimationAborted(
ui::LayerAnimationSequence* sequence) {
if (on_aborted_)
std::move(on_aborted_).Run();
}
void AnimationBuilder::Observer::OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) {
if (on_scheduled_)
std::move(on_scheduled_).Run();
}
void AnimationBuilder::Observer::OnDetachedFromSequence(
ui::LayerAnimationSequence* sequence) {
if (attached_sequences().empty())
delete this;
}
struct AnimationBuilder::Value {
base::TimeDelta start;
std::unique_ptr<ui::LayerAnimationElement> element;
bool operator<(const Value& key) const {
return std::tie(start, element) < std::tie(key.start, key.element);
}
};
AnimationBuilder::AnimationBuilder() = default;
AnimationBuilder::~AnimationBuilder() {
for (auto it = layer_animation_sequences_.begin();
it != layer_animation_sequences_.end();) {
auto* const target = it->first;
auto end_it = layer_animation_sequences_.upper_bound(target);
std::vector<ui::LayerAnimationSequence*> sequences;
std::transform(it, end_it, std::back_inserter(sequences),
[](auto& it) { return it.second.release(); });
DCHECK(target->layer()) << "Animation targets must paint to a layer.";
target->layer()->GetAnimator()->StartTogether(std::move(sequences));
it = end_it;
}
}
AnimationSequenceBlock AnimationBuilder::Once() {
repeating_ = false;
return NewSequence();
}
AnimationSequenceBlock AnimationBuilder::Repeatedly() {
repeating_ = true;
return NewSequence();
}
void AnimationBuilder::SetOnStarted(base::OnceClosure callback) {
GetObserver()->SetOnStarted(std::move(callback));
}
void AnimationBuilder::SetOnEnded(base::OnceClosure callback) {
GetObserver()->SetOnEnded(std::move(callback));
}
void AnimationBuilder::SetOnWillRepeat(base::RepeatingClosure callback) {
GetObserver()->SetOnWillRepeat(std::move(callback));
}
void AnimationBuilder::SetOnAborted(base::OnceClosure callback) {
GetObserver()->SetOnAborted(std::move(callback));
}
void AnimationBuilder::SetOnScheduled(base::OnceClosure callback) {
GetObserver()->SetOnScheduled(std::move(callback));
}
void AnimationBuilder::AddLayerAnimationElement(
base::PassKey<AnimationSequenceBlock>,
AnimationKey key,
base::TimeDelta start,
std::unique_ptr<ui::LayerAnimationElement> element) {
auto& values = values_[key];
Value value = {start, std::move(element)};
auto it = base::ranges::upper_bound(values, value);
values.insert(it, std::move(value));
}
void AnimationBuilder::BlockEndedAt(base::PassKey<AnimationSequenceBlock>,
base::TimeDelta end) {
end_ = std::max(end_, end);
}
void AnimationBuilder::TerminateSequence(
base::PassKey<AnimationSequenceBlock>) {
for (auto& pair : values_) {
auto sequence = std::make_unique<ui::LayerAnimationSequence>();
sequence->set_is_repeating(repeating_);
if (animation_observer_)
sequence->AddObserver(animation_observer_.get());
base::TimeDelta start;
ui::LayerAnimationElement::AnimatableProperties properties =
ui::LayerAnimationElement::UNKNOWN;
for (auto& value : pair.second) {
DCHECK_GE(value.start, start)
<< "Do not overlap animations of the same property on the same view.";
properties = value.element->properties();
if (value.start > start) {
sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
properties, value.start - start));
start = value.start;
}
start += value.element->duration();
sequence->AddElement(std::move(value.element));
}
if (start < end_) {
sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
properties, end_ - start));
}
layer_animation_sequences_.insert({pair.first.target, std::move(sequence)});
}
values_.clear();
animation_observer_.release();
}
AnimationBuilder::Observer* AnimationBuilder::GetObserver() {
if (!animation_observer_)
animation_observer_ = std::make_unique<Observer>();
return animation_observer_.get();
}
AnimationSequenceBlock AnimationBuilder::NewSequence() {
end_ = base::TimeDelta();
return AnimationSequenceBlock(base::PassKey<AnimationBuilder>(), this,
base::TimeDelta());
}
} // namespace views