blob: 4378833dd98310dceb1b6598b02c697e633531bd [file] [log] [blame]
/*
* Copyright (C) 2013 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CSS_ANIMATIONS_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CSS_ANIMATIONS_H_
#include "base/check_op.h"
#include "third_party/blink/renderer/core/animation/css/css_animation_data.h"
#include "third_party/blink/renderer/core/animation/css/css_animation_update.h"
#include "third_party/blink/renderer/core/animation/css/css_timeline_map.h"
#include "third_party/blink/renderer/core/animation/css/css_transition_data.h"
#include "third_party/blink/renderer/core/animation/inert_effect.h"
#include "third_party/blink/renderer/core/animation/interpolation.h"
#include "third_party/blink/renderer/core/animation/timeline_offset.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_keyframes_rule.h"
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/properties/css_bitset.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_set.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
namespace blink {
class CSSTransitionData;
class ComputedStyleBuilder;
class Element;
class StylePropertyShorthand;
class StyleResolver;
class StyleTimeline;
class WritingDirectionMode;
class CORE_EXPORT CSSAnimations final {
DISALLOW_NEW();
public:
CSSAnimations();
CSSAnimations(const CSSAnimations&) = delete;
CSSAnimations& operator=(const CSSAnimations&) = delete;
// When |with_discrete| is set to true, this method returns not just
// interpolable properties, but properties which can be transitioned with
// transition-behavior:allow-discrete. |with_discrete| returns almost 3x as
// many properties, which may result in slower style update performance, so
// they are worth separating.
static const StylePropertyShorthand& PropertiesForTransitionAll(
bool with_discrete,
const ExecutionContext* execution_context);
static bool IsAnimationAffectingProperty(const CSSProperty&);
static bool IsAffectedByKeyframesFromScope(const Element&, const TreeScope&);
static bool IsAnimatingCustomProperties(const ElementAnimations*);
static bool IsAnimatingStandardProperties(const ElementAnimations*,
const CSSBitset*,
KeyframeEffect::Priority);
static bool IsAnimatingFontAffectingProperties(const ElementAnimations*);
static bool IsAnimatingLineHeightProperty(const ElementAnimations*);
static bool IsAnimatingRevert(const ElementAnimations*);
static bool IsAnimatingDisplayProperty(const ElementAnimations*);
static void CalculateTimelineUpdate(CSSAnimationUpdate&,
Element& animating_element,
const ComputedStyleBuilder&);
static void CalculateAnimationUpdate(CSSAnimationUpdate&,
Element& animating_element,
Element&,
const ComputedStyleBuilder&,
const ComputedStyle* parent_style,
StyleResolver*,
bool can_trigger_animations);
static void CalculateCompositorAnimationUpdate(
CSSAnimationUpdate&,
const Element& animating_element,
Element&,
const ComputedStyle&,
const ComputedStyle* parent_style,
bool was_viewport_changed,
bool force_update);
static AnimationEffect::EventDelegate* CreateEventDelegate(
Element* element,
const PropertyHandle& property_handle,
const AnimationEffect::EventDelegate* old_event_delegate);
static AnimationEffect::EventDelegate* CreateEventDelegate(
Element* element,
const AtomicString& animation_name,
const AnimationEffect::EventDelegate* old_event_delegate);
static void CalculateTransitionUpdate(CSSAnimationUpdate&,
Element& animating_element,
const ComputedStyleBuilder&,
const ComputedStyle* old_style,
bool can_trigger_animations);
static void SnapshotCompositorKeyframes(Element&,
CSSAnimationUpdate&,
const ComputedStyle&,
const ComputedStyle* parent_style);
static void UpdateAnimationFlags(Element& animating_element,
CSSAnimationUpdate&,
ComputedStyleBuilder&);
const CSSAnimationUpdate& PendingUpdate() const { return pending_update_; }
void SetPendingUpdate(const CSSAnimationUpdate& update) {
ClearPendingUpdate();
pending_update_.Copy(update);
}
void ClearPendingUpdate() { pending_update_.Clear(); }
void MaybeApplyPendingUpdate(Element*);
bool HasPreviousActiveInterpolationsForAnimations() const {
return !previous_active_interpolations_for_animations_.empty();
}
bool IsEmpty() const {
return running_animations_.empty() && transitions_.empty() &&
pending_update_.IsEmpty();
}
bool HasTimelines() const { return !timeline_data_.IsEmpty(); }
void Cancel();
void Trace(Visitor*) const;
private:
friend class CSSAnimationsTest;
class RunningAnimation final : public GarbageCollected<RunningAnimation> {
public:
RunningAnimation(Animation* animation, NewCSSAnimation new_animation)
: animation(animation),
name(new_animation.name),
name_index(new_animation.name_index),
specified_timing(new_animation.timing),
style_rule(new_animation.style_rule),
style_rule_version(new_animation.style_rule_version),
play_state_list(new_animation.play_state_list) {}
AnimationTimeline* Timeline() const {
return animation->TimelineInternal();
}
const std::optional<TimelineOffset>& RangeStart() const {
return animation->GetRangeStartInternal();
}
const std::optional<TimelineOffset>& RangeEnd() const {
return animation->GetRangeEndInternal();
}
void Update(UpdatedCSSAnimation update) {
DCHECK_EQ(update.animation, animation);
style_rule = update.style_rule;
style_rule_version = update.style_rule_version;
play_state_list = update.play_state_list;
specified_timing = update.specified_timing;
}
void Trace(Visitor* visitor) const {
visitor->Trace(animation);
visitor->Trace(style_rule);
}
Member<Animation> animation;
AtomicString name;
size_t name_index;
Timing specified_timing;
Member<StyleRuleKeyframes> style_rule;
unsigned style_rule_version;
Vector<EAnimPlayState> play_state_list;
};
struct RunningTransition : public GarbageCollected<RunningTransition> {
public:
RunningTransition(Animation* animation,
const ComputedStyle* from,
const ComputedStyle* to,
const ComputedStyle* reversing_adjusted_start_value,
double reversing_shortening_factor)
: animation(animation),
from(from),
to(to),
reversing_adjusted_start_value(reversing_adjusted_start_value),
reversing_shortening_factor(reversing_shortening_factor) {}
void Trace(Visitor* visitor) const {
visitor->Trace(animation);
visitor->Trace(from);
visitor->Trace(to);
visitor->Trace(reversing_adjusted_start_value);
}
Member<Animation> animation;
Member<const ComputedStyle> from;
Member<const ComputedStyle> to;
Member<const ComputedStyle> reversing_adjusted_start_value;
double reversing_shortening_factor;
};
class TimelineData {
DISALLOW_NEW();
public:
void SetScrollTimeline(const ScopedCSSName& name, ScrollTimeline*);
const CSSScrollTimelineMap& GetScrollTimelines() const {
return scroll_timelines_;
}
void SetViewTimeline(const ScopedCSSName& name, ViewTimeline*);
const CSSViewTimelineMap& GetViewTimelines() const {
return view_timelines_;
}
void SetDeferredTimeline(const ScopedCSSName& name, DeferredTimeline*);
const CSSDeferredTimelineMap& GetDeferredTimelines() const {
return deferred_timelines_;
}
void SetTimelineAttachment(ScrollSnapshotTimeline*, DeferredTimeline*);
DeferredTimeline* GetTimelineAttachment(ScrollSnapshotTimeline*);
const TimelineAttachmentMap& GetTimelineAttachments() const {
return timeline_attachments_;
}
bool IsEmpty() const {
return scroll_timelines_.empty() && view_timelines_.empty() &&
deferred_timelines_.empty() && timeline_attachments_.empty();
}
void Clear() {
scroll_timelines_.clear();
view_timelines_.clear();
deferred_timelines_.clear();
timeline_attachments_.clear();
}
void Trace(Visitor*) const;
private:
CSSScrollTimelineMap scroll_timelines_;
CSSViewTimelineMap view_timelines_;
CSSDeferredTimelineMap deferred_timelines_;
TimelineAttachmentMap timeline_attachments_;
};
TimelineData timeline_data_;
HeapVector<Member<RunningAnimation>> running_animations_;
using TransitionMap = HeapHashMap<PropertyHandle, Member<RunningTransition>>;
TransitionMap transitions_;
CSSAnimationUpdate pending_update_;
ActiveInterpolationsMap previous_active_interpolations_for_animations_;
struct TransitionUpdateState {
STACK_ALLOCATED();
public:
CSSAnimationUpdate& update;
Element& animating_element;
const ComputedStyle& old_style;
const ComputedStyle& base_style;
const ComputedStyle* before_change_style;
const TransitionMap* active_transitions;
HashSet<PropertyHandle>* listed_properties;
const CSSTransitionData* transition_data;
};
static HeapHashSet<Member<const Animation>> CreateCancelledTransitionsSet(
ElementAnimations*,
CSSAnimationUpdate&);
static void CalculateTransitionUpdateForProperty(
TransitionUpdateState&,
const CSSTransitionData::TransitionProperty&,
wtf_size_t transition_index,
WritingDirectionMode);
static void CalculateTransitionUpdateForCustomProperty(
TransitionUpdateState&,
const CSSTransitionData::TransitionProperty&,
wtf_size_t transition_index);
static void CalculateTransitionUpdateForStandardProperty(
TransitionUpdateState&,
const CSSTransitionData::TransitionProperty&,
wtf_size_t transition_index,
WritingDirectionMode);
static bool CanCalculateTransitionUpdateForProperty(
TransitionUpdateState& state,
const PropertyHandle& property);
static void CalculateTransitionUpdateForPropertyHandle(
TransitionUpdateState&,
const CSSTransitionData::TransitionAnimationType type,
const PropertyHandle&,
wtf_size_t transition_index,
bool animate_all);
static void CalculateAnimationActiveInterpolations(
CSSAnimationUpdate&,
const Element& animating_element);
static void CalculateTransitionActiveInterpolations(
CSSAnimationUpdate&,
const Element& animating_element);
static void CalculateScrollTimelineUpdate(CSSAnimationUpdate&,
Element& animating_element,
const ComputedStyleBuilder&);
static void CalculateViewTimelineUpdate(CSSAnimationUpdate&,
Element& animating_element,
const ComputedStyleBuilder&);
static void CalculateDeferredTimelineUpdate(CSSAnimationUpdate&,
Element& animating_element,
const ComputedStyleBuilder&);
static CSSScrollTimelineMap CalculateChangedScrollTimelines(
Element& animating_element,
const CSSScrollTimelineMap* existing_scroll_timelines,
const ComputedStyleBuilder&);
static CSSViewTimelineMap CalculateChangedViewTimelines(
Element& animating_element,
const CSSViewTimelineMap* existing_view_timelines,
const ComputedStyleBuilder&);
static CSSDeferredTimelineMap CalculateChangedDeferredTimelines(
Element& animating_element,
const CSSDeferredTimelineMap* existing_deferred_timelines,
const ComputedStyleBuilder&);
template <typename MapType>
static const MapType* GetExistingTimelines(const TimelineData*);
template <typename MapType>
static const MapType* GetChangedTimelines(const CSSAnimationUpdate*);
// Invokes `callback` for each timeline, taking both existing timelines
// and pending changes into account.
template <typename TimelineType, typename CallbackFunc>
static void ForEachTimeline(const TimelineData*,
const CSSAnimationUpdate*,
CallbackFunc);
template <typename TimelineType>
static void CalculateChangedTimelineAttachments(
Element& animating_element,
const TimelineData*,
const CSSAnimationUpdate&,
const TimelineAttachmentMap* existing_attachments,
TimelineAttachmentMap& result);
static void CalculateTimelineAttachmentUpdate(CSSAnimationUpdate&,
Element& animating_element);
static const TimelineData* GetTimelineData(const Element&);
static ScrollSnapshotTimeline* FindTimelineForNode(const ScopedCSSName& name,
Node*,
const CSSAnimationUpdate*);
template <typename TimelineType>
static TimelineType* FindTimelineForElement(const ScopedCSSName& name,
const TimelineData*,
const CSSAnimationUpdate*);
static ScrollSnapshotTimeline* FindAncestorTimeline(
const ScopedCSSName& name,
Node*,
const CSSAnimationUpdate*);
static DeferredTimeline* FindDeferredTimeline(const ScopedCSSName& name,
Element*,
const CSSAnimationUpdate*);
static AnimationTimeline* ComputeTimeline(
Element*,
const StyleTimeline& timeline_name,
const CSSAnimationUpdate&,
AnimationTimeline* existing_timeline);
// The before-change style is defined as the computed values of all properties
// on the element as of the previous style change event, except with any
// styles derived from declarative animations updated to the current time.
// https://drafts.csswg.org/css-transitions-1/#before-change-style
static const ComputedStyle* CalculateBeforeChangeStyle(
Element& animating_element,
const ComputedStyle& base_style);
class AnimationEventDelegate final : public AnimationEffect::EventDelegate {
public:
AnimationEventDelegate(
Element* animation_target,
const AtomicString& name,
Timing::Phase previous_phase = Timing::kPhaseNone,
std::optional<double> previous_iteration = std::nullopt)
: animation_target_(animation_target),
name_(name),
previous_phase_(previous_phase),
previous_iteration_(previous_iteration) {}
bool RequiresIterationEvents(const AnimationEffect&) override;
void OnEventCondition(const AnimationEffect&, Timing::Phase) override;
bool IsAnimationEventDelegate() const override { return true; }
Timing::Phase getPreviousPhase() const { return previous_phase_; }
std::optional<double> getPreviousIteration() const {
return previous_iteration_;
}
void Trace(Visitor*) const override;
private:
const Element& AnimationTarget() const { return *animation_target_; }
EventTarget* GetEventTarget() const;
Document& GetDocument() const { return animation_target_->GetDocument(); }
void MaybeDispatch(Document::ListenerType,
const AtomicString& event_name,
const AnimationTimeDelta& elapsed_time);
Member<Element> animation_target_;
const AtomicString name_;
Timing::Phase previous_phase_;
std::optional<double> previous_iteration_;
};
class TransitionEventDelegate final : public AnimationEffect::EventDelegate {
public:
TransitionEventDelegate(Element* transition_target,
const PropertyHandle& property,
Timing::Phase previous_phase = Timing::kPhaseNone)
: property_(property),
transition_target_(transition_target),
previous_phase_(previous_phase) {}
bool RequiresIterationEvents(const AnimationEffect&) override {
return false;
}
void OnEventCondition(const AnimationEffect&, Timing::Phase) override;
bool IsTransitionEventDelegate() const override { return true; }
Timing::Phase getPreviousPhase() const { return previous_phase_; }
void Trace(Visitor*) const override;
private:
void EnqueueEvent(const WTF::AtomicString& type,
const AnimationTimeDelta& elapsed_time);
const Element& TransitionTarget() const { return *transition_target_; }
EventTarget* GetEventTarget() const;
Document& GetDocument() const { return transition_target_->GetDocument(); }
PropertyHandle property_;
Member<Element> transition_target_;
Timing::Phase previous_phase_;
};
};
template <>
struct DowncastTraits<CSSAnimations::AnimationEventDelegate> {
static bool AllowFrom(const AnimationEffect::EventDelegate& delegate) {
return delegate.IsAnimationEventDelegate();
}
};
template <>
struct DowncastTraits<CSSAnimations::TransitionEventDelegate> {
static bool AllowFrom(const AnimationEffect::EventDelegate& delegate) {
return delegate.IsTransitionEventDelegate();
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_CSS_CSS_ANIMATIONS_H_