mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Just linearly search for keyframes in the set of stylesheets. Components rarely have many sheets, and sheets rarely have many keyframes so this should be quite fast. It's also much simpler than having to collect all the keyframes from all the rulesets. R=ojan@chromium.org, rafaelw@chromium.org Review URL: https://codereview.chromium.org/839473005
236 lines
10 KiB
C++
236 lines
10 KiB
C++
/*
|
|
* 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 SKY_ENGINE_CORE_ANIMATION_CSS_CSSANIMATIONS_H_
|
|
#define SKY_ENGINE_CORE_ANIMATION_CSS_CSSANIMATIONS_H_
|
|
|
|
#include "sky/engine/core/animation/Animation.h"
|
|
#include "sky/engine/core/animation/AnimationPlayer.h"
|
|
#include "sky/engine/core/animation/InertAnimation.h"
|
|
#include "sky/engine/core/animation/Interpolation.h"
|
|
#include "sky/engine/core/css/StylePropertySet.h"
|
|
#include "sky/engine/core/dom/Document.h"
|
|
#include "sky/engine/core/rendering/style/RenderStyleConstants.h"
|
|
#include "sky/engine/wtf/HashMap.h"
|
|
#include "sky/engine/wtf/Vector.h"
|
|
#include "sky/engine/wtf/text/AtomicString.h"
|
|
|
|
namespace blink {
|
|
|
|
class CSSTransitionData;
|
|
class Element;
|
|
class StylePropertyShorthand;
|
|
class StyleResolver;
|
|
class StyleRuleKeyframes;
|
|
|
|
// This class stores the CSS Animations/Transitions information we use during a style recalc.
|
|
// This includes updates to animations/transitions as well as the Interpolations to be applied.
|
|
class CSSAnimationUpdate final {
|
|
public:
|
|
void startAnimation(AtomicString& animationName, PassRefPtr<InertAnimation> animation)
|
|
{
|
|
NewAnimation newAnimation;
|
|
newAnimation.name = animationName;
|
|
newAnimation.animation = animation;
|
|
m_newAnimations.append(newAnimation);
|
|
}
|
|
// Returns whether player has been cancelled and should be filtered during style application.
|
|
bool isCancelledAnimation(const AnimationPlayer* player) const { return m_cancelledAnimationPlayers.contains(player); }
|
|
void cancelAnimation(const AtomicString& name, AnimationPlayer& player)
|
|
{
|
|
m_cancelledAnimationNames.append(name);
|
|
m_cancelledAnimationPlayers.add(&player);
|
|
}
|
|
void toggleAnimationPaused(const AtomicString& name)
|
|
{
|
|
m_animationsWithPauseToggled.append(name);
|
|
}
|
|
|
|
void startTransition(CSSPropertyID id, CSSPropertyID eventId, const AnimatableValue* from, const AnimatableValue* to, PassRefPtr<InertAnimation> animation)
|
|
{
|
|
NewTransition newTransition;
|
|
newTransition.id = id;
|
|
newTransition.eventId = eventId;
|
|
newTransition.from = from;
|
|
newTransition.to = to;
|
|
newTransition.animation = animation;
|
|
m_newTransitions.set(id, newTransition);
|
|
}
|
|
bool isCancelledTransition(CSSPropertyID id) const { return m_cancelledTransitions.contains(id); }
|
|
void cancelTransition(CSSPropertyID id) { m_cancelledTransitions.add(id); }
|
|
|
|
struct NewAnimation {
|
|
ALLOW_ONLY_INLINE_ALLOCATION();
|
|
public:
|
|
AtomicString name;
|
|
RefPtr<InertAnimation> animation;
|
|
};
|
|
const Vector<NewAnimation>& newAnimations() const { return m_newAnimations; }
|
|
const Vector<AtomicString>& cancelledAnimationNames() const { return m_cancelledAnimationNames; }
|
|
const HashSet<RawPtr<const AnimationPlayer> >& cancelledAnimationAnimationPlayers() const { return m_cancelledAnimationPlayers; }
|
|
const Vector<AtomicString>& animationsWithPauseToggled() const { return m_animationsWithPauseToggled; }
|
|
|
|
struct NewTransition {
|
|
ALLOW_ONLY_INLINE_ALLOCATION();
|
|
public:
|
|
CSSPropertyID id;
|
|
CSSPropertyID eventId;
|
|
RawPtr<const AnimatableValue> from;
|
|
RawPtr<const AnimatableValue> to;
|
|
RefPtr<InertAnimation> animation;
|
|
};
|
|
typedef HashMap<CSSPropertyID, NewTransition> NewTransitionMap;
|
|
const NewTransitionMap& newTransitions() const { return m_newTransitions; }
|
|
const HashSet<CSSPropertyID>& cancelledTransitions() const { return m_cancelledTransitions; }
|
|
|
|
void adoptActiveInterpolationsForAnimations(HashMap<CSSPropertyID, RefPtr<Interpolation> >& newMap) { newMap.swap(m_activeInterpolationsForAnimations); }
|
|
void adoptActiveInterpolationsForTransitions(HashMap<CSSPropertyID, RefPtr<Interpolation> >& newMap) { newMap.swap(m_activeInterpolationsForTransitions); }
|
|
const HashMap<CSSPropertyID, RefPtr<Interpolation> >& activeInterpolationsForAnimations() const { return m_activeInterpolationsForAnimations; }
|
|
const HashMap<CSSPropertyID, RefPtr<Interpolation> >& activeInterpolationsForTransitions() const { return m_activeInterpolationsForTransitions; }
|
|
HashMap<CSSPropertyID, RefPtr<Interpolation> >& activeInterpolationsForAnimations() { return m_activeInterpolationsForAnimations; }
|
|
|
|
bool isEmpty() const
|
|
{
|
|
return m_newAnimations.isEmpty()
|
|
&& m_cancelledAnimationNames.isEmpty()
|
|
&& m_cancelledAnimationPlayers.isEmpty()
|
|
&& m_animationsWithPauseToggled.isEmpty()
|
|
&& m_newTransitions.isEmpty()
|
|
&& m_cancelledTransitions.isEmpty()
|
|
&& m_activeInterpolationsForAnimations.isEmpty()
|
|
&& m_activeInterpolationsForTransitions.isEmpty();
|
|
}
|
|
|
|
private:
|
|
// Order is significant since it defines the order in which new animations
|
|
// will be started. Note that there may be multiple animations present
|
|
// with the same name, due to the way in which we split up animations with
|
|
// incomplete keyframes.
|
|
Vector<NewAnimation> m_newAnimations;
|
|
Vector<AtomicString> m_cancelledAnimationNames;
|
|
HashSet<RawPtr<const AnimationPlayer> > m_cancelledAnimationPlayers;
|
|
Vector<AtomicString> m_animationsWithPauseToggled;
|
|
|
|
NewTransitionMap m_newTransitions;
|
|
HashSet<CSSPropertyID> m_cancelledTransitions;
|
|
|
|
HashMap<CSSPropertyID, RefPtr<Interpolation> > m_activeInterpolationsForAnimations;
|
|
HashMap<CSSPropertyID, RefPtr<Interpolation> > m_activeInterpolationsForTransitions;
|
|
};
|
|
|
|
class CSSAnimations final {
|
|
WTF_MAKE_NONCOPYABLE(CSSAnimations);
|
|
DISALLOW_ALLOCATION();
|
|
public:
|
|
CSSAnimations();
|
|
|
|
// FIXME: This method is only used here and in the legacy animations
|
|
// implementation. It should be made private or file-scope when the legacy
|
|
// engine is removed.
|
|
static const StyleRuleKeyframes* matchScopedKeyframesRule(StyleResolver*, const Element*, String animationName);
|
|
|
|
static const StylePropertyShorthand& animatableProperties();
|
|
static bool isAllowedAnimation(CSSPropertyID);
|
|
// FIXME: We should change the Element* to a const Element*
|
|
static PassOwnPtr<CSSAnimationUpdate> calculateUpdate(Element*, const Element& parentElement, const RenderStyle&, RenderStyle* parentStyle, StyleResolver*);
|
|
|
|
void setPendingUpdate(PassOwnPtr<CSSAnimationUpdate> update) { m_pendingUpdate = update; }
|
|
void maybeApplyPendingUpdate(Element*);
|
|
bool isEmpty() const { return m_animations.isEmpty() && m_transitions.isEmpty() && !m_pendingUpdate; }
|
|
void cancel();
|
|
|
|
private:
|
|
struct RunningTransition {
|
|
ALLOW_ONLY_INLINE_ALLOCATION();
|
|
public:
|
|
RefPtr<AnimationPlayer> player;
|
|
RawPtr<const AnimatableValue> from;
|
|
RawPtr<const AnimatableValue> to;
|
|
};
|
|
|
|
typedef HashMap<AtomicString, RefPtr<AnimationPlayer> > AnimationMap;
|
|
AnimationMap m_animations;
|
|
|
|
typedef HashMap<CSSPropertyID, RunningTransition> TransitionMap;
|
|
TransitionMap m_transitions;
|
|
|
|
OwnPtr<CSSAnimationUpdate> m_pendingUpdate;
|
|
|
|
HashMap<CSSPropertyID, RefPtr<Interpolation> > m_previousActiveInterpolationsForAnimations;
|
|
|
|
static void calculateAnimationUpdate(CSSAnimationUpdate*, Element*, const Element& parentElement, const RenderStyle&, RenderStyle* parentStyle, StyleResolver*);
|
|
static void calculateTransitionUpdate(CSSAnimationUpdate*, const Element*, const RenderStyle&);
|
|
static void calculateTransitionUpdateForProperty(CSSPropertyID, CSSPropertyID eventId, const CSSTransitionData&, size_t transitionIndex, const RenderStyle& oldStyle, const RenderStyle&, const TransitionMap* activeTransitions, CSSAnimationUpdate*, const Element*);
|
|
|
|
static void calculateAnimationActiveInterpolations(CSSAnimationUpdate*, const Element*, double timelineCurrentTime);
|
|
static void calculateTransitionActiveInterpolations(CSSAnimationUpdate*, const Element*, double timelineCurrentTime);
|
|
|
|
class AnimationEventDelegate final : public AnimationNode::EventDelegate {
|
|
public:
|
|
AnimationEventDelegate(Element* target, const AtomicString& name)
|
|
: m_target(target)
|
|
, m_name(name)
|
|
, m_previousPhase(AnimationNode::PhaseNone)
|
|
, m_previousIteration(nullValue())
|
|
{
|
|
}
|
|
virtual void onEventCondition(const AnimationNode*) override;
|
|
|
|
private:
|
|
void maybeDispatch(Document::ListenerType, const AtomicString& eventName, double elapsedTime);
|
|
RawPtr<Element> m_target;
|
|
const AtomicString m_name;
|
|
AnimationNode::Phase m_previousPhase;
|
|
double m_previousIteration;
|
|
};
|
|
|
|
class TransitionEventDelegate final : public AnimationNode::EventDelegate {
|
|
public:
|
|
TransitionEventDelegate(Element* target, CSSPropertyID property)
|
|
: m_target(target)
|
|
, m_property(property)
|
|
, m_previousPhase(AnimationNode::PhaseNone)
|
|
{
|
|
}
|
|
virtual void onEventCondition(const AnimationNode*) override;
|
|
|
|
private:
|
|
RawPtr<Element> m_target;
|
|
const CSSPropertyID m_property;
|
|
AnimationNode::Phase m_previousPhase;
|
|
};
|
|
};
|
|
|
|
} // namespace blink
|
|
|
|
WTF_ALLOW_INIT_WITH_MEM_FUNCTIONS(blink::CSSAnimationUpdate::NewAnimation);
|
|
|
|
#endif // SKY_ENGINE_CORE_ANIMATION_CSS_CSSANIMATIONS_H_
|