Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
1 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef nsAnimationManager_h_
6 #define nsAnimationManager_h_
8 #include "mozilla/Attributes.h"
9 #include "mozilla/ContentEvents.h"
10 #include "AnimationCommon.h"
11 #include "nsCSSPseudoElements.h"
12 #include "mozilla/MemoryReporting.h"
13 #include "mozilla/TimeStamp.h"
15 class nsCSSKeyframesRule;
16 class nsStyleContext;
18 namespace mozilla {
19 namespace css {
20 class Declaration;
21 }
22 }
24 struct AnimationEventInfo {
25 nsRefPtr<mozilla::dom::Element> mElement;
26 mozilla::InternalAnimationEvent mEvent;
28 AnimationEventInfo(mozilla::dom::Element *aElement,
29 const nsString& aAnimationName,
30 uint32_t aMessage, mozilla::TimeDuration aElapsedTime,
31 const nsAString& aPseudoElement)
32 : mElement(aElement), mEvent(true, aMessage)
33 {
34 // XXX Looks like nobody initialize WidgetEvent::time
35 mEvent.animationName = aAnimationName;
36 mEvent.elapsedTime = aElapsedTime.ToSeconds();
37 mEvent.pseudoElement = aPseudoElement;
38 }
40 // InternalAnimationEvent doesn't support copy-construction, so we need
41 // to ourselves in order to work with nsTArray
42 AnimationEventInfo(const AnimationEventInfo &aOther)
43 : mElement(aOther.mElement), mEvent(true, aOther.mEvent.message)
44 {
45 mEvent.AssignAnimationEventData(aOther.mEvent, false);
46 }
47 };
49 typedef InfallibleTArray<AnimationEventInfo> EventArray;
51 /**
52 * Data about all of the animations running on an element.
53 */
54 struct ElementAnimations MOZ_FINAL
55 : public mozilla::css::CommonElementAnimationData
56 {
57 typedef mozilla::TimeStamp TimeStamp;
58 typedef mozilla::TimeDuration TimeDuration;
60 ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
61 nsAnimationManager *aAnimationManager, TimeStamp aNow);
63 // This function takes as input the start time, duration, and direction of an
64 // animation and returns the position in the current iteration. Note that
65 // this only works when we know that the animation is currently running.
66 // This way of calling the function can be used from the compositor. Note
67 // that if the animation has not started yet, has already ended, or is paused,
68 // it should not be run from the compositor. When this function is called
69 // from the main thread, we need the actual StyleAnimation* in order to
70 // get correct animation-fill behavior and to fire animation events.
71 // This function returns -1 for the position if the animation should not be
72 // run (because it is not currently active and has no fill behavior), but
73 // only does so if aAnimation is non-null; with a null aAnimation it is an
74 // error to give aElapsedDuration < 0, and fill-forwards is assumed.
75 // After calling GetPositionInIteration with non-null aAnimation and aEa, be
76 // sure to call CheckNeedsRefresh on the animation manager afterwards.
77 static double GetPositionInIteration(TimeDuration aElapsedDuration,
78 TimeDuration aIterationDuration,
79 double aIterationCount,
80 uint32_t aDirection,
81 mozilla::StyleAnimation* aAnimation =
82 nullptr,
83 ElementAnimations* aEa = nullptr,
84 EventArray* aEventsToDispatch = nullptr);
86 void EnsureStyleRuleFor(TimeStamp aRefreshTime,
87 EventArray &aEventsToDispatch,
88 bool aIsThrottled);
90 bool IsForElement() const { // rather than for a pseudo-element
91 return mElementProperty == nsGkAtoms::animationsProperty;
92 }
94 nsString PseudoElement()
95 {
96 return mElementProperty == nsGkAtoms::animationsProperty ?
97 EmptyString() :
98 mElementProperty == nsGkAtoms::animationsOfBeforeProperty ?
99 NS_LITERAL_STRING("::before") :
100 NS_LITERAL_STRING("::after");
101 }
103 void PostRestyleForAnimation(nsPresContext *aPresContext) {
104 nsRestyleHint styleHint = IsForElement() ? eRestyle_Self : eRestyle_Subtree;
105 aPresContext->PresShell()->RestyleForAnimation(mElement, styleHint);
106 }
108 // If aFlags contains CanAnimate_AllowPartial, returns whether the
109 // state of this element's animations at the current refresh driver
110 // time contains animation data that can be done on the compositor
111 // thread. (This is useful for determining whether a layer should be
112 // active, or whether to send data to the layer.)
113 // If aFlags does not contain CanAnimate_AllowPartial, returns whether
114 // the state of this element's animations at the current refresh driver
115 // time can be fully represented by data sent to the compositor.
116 // (This is useful for determining whether throttle the animation
117 // (suppress main-thread style updates).)
118 // Note that when CanPerformOnCompositorThread returns true, it also,
119 // as a side-effect, notifies the ActiveLayerTracker. FIXME: This
120 // should probably move to the relevant callers.
121 virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE;
123 virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE;
125 // False when we know that our current style rule is valid
126 // indefinitely into the future (because all of our animations are
127 // either completed or paused). May be invalidated by a style change.
128 bool mNeedsRefreshes;
130 InfallibleTArray<mozilla::StyleAnimation> mAnimations;
131 };
133 class nsAnimationManager MOZ_FINAL
134 : public mozilla::css::CommonAnimationManager
135 {
136 public:
137 nsAnimationManager(nsPresContext *aPresContext)
138 : mozilla::css::CommonAnimationManager(aPresContext)
139 , mObservingRefreshDriver(false)
140 {
141 }
143 static ElementAnimations* GetAnimationsForCompositor(nsIContent* aContent,
144 nsCSSProperty aProperty)
145 {
146 if (!aContent->MayHaveAnimations())
147 return nullptr;
148 ElementAnimations* animations = static_cast<ElementAnimations*>(
149 aContent->GetProperty(nsGkAtoms::animationsProperty));
150 if (!animations)
151 return nullptr;
152 bool propertyMatches = animations->HasAnimationOfProperty(aProperty);
153 return (propertyMatches &&
154 animations->CanPerformOnCompositorThread(
155 mozilla::css::CommonElementAnimationData::CanAnimate_AllowPartial))
156 ? animations
157 : nullptr;
158 }
160 // Returns true if aContent or any of its ancestors has an animation.
161 static bool ContentOrAncestorHasAnimation(nsIContent* aContent) {
162 do {
163 if (aContent->GetProperty(nsGkAtoms::animationsProperty)) {
164 return true;
165 }
166 } while ((aContent = aContent->GetParent()));
168 return false;
169 }
171 void EnsureStyleRuleFor(ElementAnimations* aET);
173 // nsIStyleRuleProcessor (parts)
174 virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE;
175 virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE;
176 virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE;
177 #ifdef MOZ_XUL
178 virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE;
179 #endif
180 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
181 const MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
182 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
183 const MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
185 // nsARefreshObserver
186 virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE;
188 void FlushAnimations(FlushFlags aFlags);
190 /**
191 * Return the style rule that RulesMatching should add for
192 * aStyleContext. This might be different from what RulesMatching
193 * actually added during aStyleContext's construction because the
194 * element's animation-name may have changed. (However, this does
195 * return null during the non-animation restyling phase, as
196 * RulesMatching does.)
197 *
198 * aStyleContext may be a style context for aElement or for its
199 * :before or :after pseudo-element.
200 */
201 nsIStyleRule* CheckAnimationRule(nsStyleContext* aStyleContext,
202 mozilla::dom::Element* aElement);
204 /**
205 * Dispatch any pending events. We accumulate animationend and
206 * animationiteration events only during refresh driver notifications
207 * (and dispatch them at the end of such notifications), but we
208 * accumulate animationstart events at other points when style
209 * contexts are created.
210 */
211 void DispatchEvents() {
212 // Fast-path the common case: no events
213 if (!mPendingEvents.IsEmpty()) {
214 DoDispatchEvents();
215 }
216 }
218 ElementAnimations* GetElementAnimations(mozilla::dom::Element *aElement,
219 nsCSSPseudoElements::Type aPseudoType,
220 bool aCreateIfNeeded);
222 // Updates styles on throttled animations. See note on nsTransitionManager
223 void UpdateAllThrottledStyles();
225 protected:
226 virtual void ElementDataRemoved() MOZ_OVERRIDE
227 {
228 CheckNeedsRefresh();
229 }
230 virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE;
232 /**
233 * Check to see if we should stop or start observing the refresh driver
234 */
235 void CheckNeedsRefresh();
237 private:
238 void BuildAnimations(nsStyleContext* aStyleContext,
239 InfallibleTArray<mozilla::StyleAnimation>& aAnimations);
240 bool BuildSegment(InfallibleTArray<mozilla::AnimationPropertySegment>&
241 aSegments,
242 nsCSSProperty aProperty, const nsAnimation& aAnimation,
243 float aFromKey, nsStyleContext* aFromContext,
244 mozilla::css::Declaration* aFromDeclaration,
245 float aToKey, nsStyleContext* aToContext);
246 nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement,
247 nsCSSPseudoElements::Type aPseudoType);
249 // Update the animated styles of an element and its descendants.
250 // If the element has an animation, it is flushed back to its primary frame.
251 // If the element does not have an animation, then its style is reparented.
252 void UpdateThrottledStylesForSubtree(nsIContent* aContent,
253 nsStyleContext* aParentStyle,
254 nsStyleChangeList &aChangeList);
255 void UpdateAllThrottledStylesInternal();
257 // The guts of DispatchEvents
258 void DoDispatchEvents();
260 EventArray mPendingEvents;
262 bool mObservingRefreshDriver;
263 };
265 #endif /* !defined(nsAnimationManager_h_) */