forked from Floorp-Projects/Floorp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnsAnimationManager.h
309 lines (263 loc) · 11.1 KB
/
nsAnimationManager.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsAnimationManager_h_
#define nsAnimationManager_h_
#include "mozilla/Attributes.h"
#include "mozilla/ContentEvents.h"
#include "AnimationCommon.h"
#include "nsCSSPseudoElements.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/TimeStamp.h"
class nsCSSKeyframesRule;
class nsStyleContext;
namespace mozilla {
namespace css {
class Declaration;
}
}
struct AnimationEventInfo {
nsRefPtr<mozilla::dom::Element> mElement;
mozilla::InternalAnimationEvent mEvent;
AnimationEventInfo(mozilla::dom::Element *aElement,
const nsString& aAnimationName,
uint32_t aMessage, mozilla::TimeDuration aElapsedTime,
const nsAString& aPseudoElement)
: mElement(aElement),
mEvent(true, aMessage, aAnimationName, aElapsedTime.ToSeconds(),
aPseudoElement)
{
}
// InternalAnimationEvent doesn't support copy-construction, so we need
// to ourselves in order to work with nsTArray
AnimationEventInfo(const AnimationEventInfo &aOther)
: mElement(aOther.mElement),
mEvent(true, aOther.mEvent.message,
aOther.mEvent.animationName, aOther.mEvent.elapsedTime,
aOther.mEvent.pseudoElement)
{
}
};
typedef InfallibleTArray<AnimationEventInfo> EventArray;
struct AnimationPropertySegment
{
float mFromKey, mToKey;
nsStyleAnimation::Value mFromValue, mToValue;
mozilla::css::ComputedTimingFunction mTimingFunction;
};
struct AnimationProperty
{
nsCSSProperty mProperty;
InfallibleTArray<AnimationPropertySegment> mSegments;
};
/**
* Data about one animation (i.e., one of the values of
* 'animation-name') running on an element.
*/
struct ElementAnimation
{
ElementAnimation()
: mLastNotification(LAST_NOTIFICATION_NONE)
{
}
nsString mName; // empty string for 'none'
float mIterationCount; // NS_IEEEPositiveInfinity() means infinite
uint8_t mDirection;
uint8_t mFillMode;
uint8_t mPlayState;
bool FillsForwards() const {
return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH ||
mFillMode == NS_STYLE_ANIMATION_FILL_MODE_FORWARDS;
}
bool FillsBackwards() const {
return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH ||
mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BACKWARDS;
}
bool IsPaused() const {
return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED;
}
virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
bool IsRunningAt(mozilla::TimeStamp aTime) const;
// Return the duration, at aTime (or, if paused, mPauseStart), since
// the *end* of the delay period. May be negative.
mozilla::TimeDuration ElapsedDurationAt(mozilla::TimeStamp aTime) const {
NS_ABORT_IF_FALSE(!IsPaused() || aTime >= mPauseStart,
"if paused, aTime must be at least mPauseStart");
return (IsPaused() ? mPauseStart : aTime) - mStartTime - mDelay;
}
mozilla::TimeStamp mStartTime; // the beginning of the delay period
mozilla::TimeStamp mPauseStart;
mozilla::TimeDuration mDelay;
mozilla::TimeDuration mIterationDuration;
enum {
LAST_NOTIFICATION_NONE = uint32_t(-1),
LAST_NOTIFICATION_END = uint32_t(-2)
};
// One of the above constants, or an integer for the iteration
// whose start we last notified on.
uint32_t mLastNotification;
InfallibleTArray<AnimationProperty> mProperties;
};
/**
* Data about all of the animations running on an element.
*/
struct ElementAnimations MOZ_FINAL
: public mozilla::css::CommonElementAnimationData
{
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::TimeDuration TimeDuration;
ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
nsAnimationManager *aAnimationManager);
// This function takes as input the start time, duration, and direction of an
// animation and returns the position in the current iteration. Note that
// this only works when we know that the animation is currently running.
// This way of calling the function can be used from the compositor. Note
// that if the animation has not started yet, has already ended, or is paused,
// it should not be run from the compositor. When this function is called
// from the main thread, we need the actual ElementAnimation* in order to
// get correct animation-fill behavior and to fire animation events.
// This function returns -1 for the position if the animation should not be
// run (because it is not currently active and has no fill behavior), but
// only does so if aAnimation is non-null; with a null aAnimation it is an
// error to give aCurrentTime < aStartTime, and fill-forwards is assumed.
// After calling GetPositionInIteration with non-null aAnimation and aEa, be
// sure to call CheckNeedsRefresh on the animation manager afterwards.
static double GetPositionInIteration(TimeDuration aElapsedDuration,
TimeDuration aIterationDuration,
double aIterationCount,
uint32_t aDirection,
ElementAnimation* aAnimation = nullptr,
ElementAnimations* aEa = nullptr,
EventArray* aEventsToDispatch = nullptr);
void EnsureStyleRuleFor(TimeStamp aRefreshTime,
EventArray &aEventsToDispatch,
bool aIsThrottled);
bool IsForElement() const { // rather than for a pseudo-element
return mElementProperty == nsGkAtoms::animationsProperty;
}
nsString PseudoElement()
{
return mElementProperty == nsGkAtoms::animationsProperty ?
EmptyString() :
mElementProperty == nsGkAtoms::animationsOfBeforeProperty ?
NS_LITERAL_STRING("::before") :
NS_LITERAL_STRING("::after");
}
void PostRestyleForAnimation(nsPresContext *aPresContext) {
nsRestyleHint styleHint = IsForElement() ? eRestyle_Self : eRestyle_Subtree;
aPresContext->PresShell()->RestyleForAnimation(mElement, styleHint);
}
// True if this animation can be performed on the compositor thread.
virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE;
virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE;
// False when we know that our current style rule is valid
// indefinitely into the future (because all of our animations are
// either completed or paused). May be invalidated by a style change.
bool mNeedsRefreshes;
InfallibleTArray<ElementAnimation> mAnimations;
};
class nsAnimationManager MOZ_FINAL
: public mozilla::css::CommonAnimationManager
{
public:
nsAnimationManager(nsPresContext *aPresContext)
: mozilla::css::CommonAnimationManager(aPresContext)
, mObservingRefreshDriver(false)
{
}
static ElementAnimations* GetAnimationsForCompositor(nsIContent* aContent,
nsCSSProperty aProperty)
{
if (!aContent->MayHaveAnimations())
return nullptr;
ElementAnimations* animations = static_cast<ElementAnimations*>(
aContent->GetProperty(nsGkAtoms::animationsProperty));
if (!animations)
return nullptr;
bool propertyMatches = animations->HasAnimationOfProperty(aProperty);
return (propertyMatches &&
animations->CanPerformOnCompositorThread(
mozilla::css::CommonElementAnimationData::CanAnimate_AllowPartial))
? animations
: nullptr;
}
// Returns true if aContent or any of its ancestors has an animation.
static bool ContentOrAncestorHasAnimation(nsIContent* aContent) {
do {
if (aContent->GetProperty(nsGkAtoms::animationsProperty)) {
return true;
}
} while ((aContent = aContent->GetParent()));
return false;
}
void EnsureStyleRuleFor(ElementAnimations* aET);
// nsIStyleRuleProcessor (parts)
virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE;
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE;
virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE;
#ifdef MOZ_XUL
virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE;
#endif
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
const MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
const MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
// nsARefreshObserver
virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE;
void FlushAnimations(FlushFlags aFlags);
/**
* Return the style rule that RulesMatching should add for
* aStyleContext. This might be different from what RulesMatching
* actually added during aStyleContext's construction because the
* element's animation-name may have changed. (However, this does
* return null during the non-animation restyling phase, as
* RulesMatching does.)
*
* aStyleContext may be a style context for aElement or for its
* :before or :after pseudo-element.
*/
nsIStyleRule* CheckAnimationRule(nsStyleContext* aStyleContext,
mozilla::dom::Element* aElement);
/**
* Dispatch any pending events. We accumulate animationend and
* animationiteration events only during refresh driver notifications
* (and dispatch them at the end of such notifications), but we
* accumulate animationstart events at other points when style
* contexts are created.
*/
void DispatchEvents() {
// Fast-path the common case: no events
if (!mPendingEvents.IsEmpty()) {
DoDispatchEvents();
}
}
ElementAnimations* GetElementAnimations(mozilla::dom::Element *aElement,
nsCSSPseudoElements::Type aPseudoType,
bool aCreateIfNeeded);
protected:
virtual void ElementDataRemoved() MOZ_OVERRIDE
{
CheckNeedsRefresh();
}
virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE;
/**
* Check to see if we should stop or start observing the refresh driver
*/
void CheckNeedsRefresh();
private:
void BuildAnimations(nsStyleContext* aStyleContext,
InfallibleTArray<ElementAnimation>& aAnimations);
bool BuildSegment(InfallibleTArray<AnimationPropertySegment>& aSegments,
nsCSSProperty aProperty, const nsAnimation& aAnimation,
float aFromKey, nsStyleContext* aFromContext,
mozilla::css::Declaration* aFromDeclaration,
float aToKey, nsStyleContext* aToContext);
nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType);
// The guts of DispatchEvents
void DoDispatchEvents();
EventArray mPendingEvents;
bool mObservingRefreshDriver;
};
#endif /* !defined(nsAnimationManager_h_) */