Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
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/. */
6 #ifndef mozilla_css_AnimationCommon_h
7 #define mozilla_css_AnimationCommon_h
9 #include "nsIStyleRuleProcessor.h"
10 #include "nsIStyleRule.h"
11 #include "nsRefreshDriver.h"
12 #include "prclist.h"
13 #include "nsStyleAnimation.h"
14 #include "nsCSSProperty.h"
15 #include "mozilla/MemoryReporting.h"
16 #include "mozilla/dom/Element.h"
17 #include "nsSMILKeySpline.h"
18 #include "nsStyleStruct.h"
19 #include "mozilla/Attributes.h"
20 #include "nsCSSPseudoElements.h"
22 class nsPresContext;
23 class nsIFrame;
26 namespace mozilla {
27 namespace css {
29 bool IsGeometricProperty(nsCSSProperty aProperty);
31 struct CommonElementAnimationData;
33 class CommonAnimationManager : public nsIStyleRuleProcessor,
34 public nsARefreshObserver {
35 public:
36 CommonAnimationManager(nsPresContext *aPresContext);
37 virtual ~CommonAnimationManager();
39 // nsISupports
40 NS_DECL_ISUPPORTS
42 // nsIStyleRuleProcessor (parts)
43 virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData) MOZ_OVERRIDE;
44 virtual nsRestyleHint HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) MOZ_OVERRIDE;
45 virtual bool HasDocumentStateDependentStyle(StateRuleProcessorData* aData) MOZ_OVERRIDE;
46 virtual nsRestyleHint
47 HasAttributeDependentStyle(AttributeRuleProcessorData* aData) MOZ_OVERRIDE;
48 virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) MOZ_OVERRIDE;
49 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
50 const MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
51 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
52 const MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
54 /**
55 * Notify the manager that the pres context is going away.
56 */
57 void Disconnect();
59 enum FlushFlags {
60 Can_Throttle,
61 Cannot_Throttle
62 };
64 static bool ExtractComputedValueForTransition(
65 nsCSSProperty aProperty,
66 nsStyleContext* aStyleContext,
67 nsStyleAnimation::Value& aComputedValue);
68 protected:
69 friend struct CommonElementAnimationData; // for ElementDataRemoved
71 virtual void AddElementData(CommonElementAnimationData* aData) = 0;
72 virtual void ElementDataRemoved() = 0;
73 void RemoveAllElementData();
75 // Update the style on aElement from the transition stored in this manager and
76 // the new parent style - aParentStyle. aElement must be transitioning or
77 // animated. Returns the updated style.
78 nsStyleContext* UpdateThrottledStyle(mozilla::dom::Element* aElement,
79 nsStyleContext* aParentStyle,
80 nsStyleChangeList &aChangeList);
81 // Reparent the style of aContent and any :before and :after pseudo-elements.
82 already_AddRefed<nsStyleContext> ReparentContent(nsIContent* aContent,
83 nsStyleContext* aParentStyle);
84 // reparent :before and :after pseudo elements of aElement
85 static void ReparentBeforeAndAfter(dom::Element* aElement,
86 nsIFrame* aPrimaryFrame,
87 nsStyleContext* aNewStyle,
88 nsStyleSet* aStyleSet);
90 PRCList mElementData;
91 nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
92 };
94 // The internals of UpdateAllThrottledStyles, used by nsAnimationManager and
95 // nsTransitionManager, see the comments in the declaration of the latter.
96 #define IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(class_, animations_getter_) \
97 void \
98 class_::UpdateAllThrottledStylesInternal() \
99 { \
100 TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); \
101 \
102 nsStyleChangeList changeList; \
103 \
104 /* update each transitioning element by finding its root-most ancestor
105 with a transition, and flushing the style on that ancestor and all
106 its descendants*/ \
107 PRCList *next = PR_LIST_HEAD(&mElementData); \
108 while (next != &mElementData) { \
109 CommonElementAnimationData* ea = \
110 static_cast<CommonElementAnimationData*>(next); \
111 next = PR_NEXT_LINK(next); \
112 \
113 if (ea->mFlushGeneration == now) { \
114 /* this element has been ticked already */ \
115 continue; \
116 } \
117 \
118 /* element is initialised to the starting element (i.e., one we know has
119 an animation) and ends up with the root-most animated ancestor,
120 that is, the element where we begin updates. */ \
121 dom::Element* element = ea->mElement; \
122 /* make a list of ancestors */ \
123 nsTArray<dom::Element*> ancestors; \
124 do { \
125 ancestors.AppendElement(element); \
126 } while ((element = element->GetParentElement())); \
127 \
128 /* walk down the ancestors until we find one with a throttled transition */\
129 for (int32_t i = ancestors.Length() - 1; i >= 0; --i) { \
130 if (animations_getter_(ancestors[i], \
131 nsCSSPseudoElements::ePseudo_NotPseudoElement, \
132 false)) { \
133 element = ancestors[i]; \
134 break; \
135 } \
136 } \
137 \
138 nsIFrame* primaryFrame; \
139 if (element && \
140 (primaryFrame = nsLayoutUtils::GetStyleFrame(element))) { \
141 UpdateThrottledStylesForSubtree(element, \
142 primaryFrame->StyleContext()->GetParent(), changeList); \
143 } \
144 } \
145 \
146 RestyleManager* restyleManager = mPresContext->RestyleManager(); \
147 restyleManager->ProcessRestyledFrames(changeList); \
148 restyleManager->FlushOverflowChangedTracker(); \
149 }
151 /**
152 * A style rule that maps property-nsStyleAnimation::Value pairs.
153 */
154 class AnimValuesStyleRule MOZ_FINAL : public nsIStyleRule
155 {
156 public:
157 // nsISupports implementation
158 NS_DECL_ISUPPORTS
160 // nsIStyleRule implementation
161 virtual void MapRuleInfoInto(nsRuleData* aRuleData) MOZ_OVERRIDE;
162 #ifdef DEBUG
163 virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE;
164 #endif
166 void AddValue(nsCSSProperty aProperty, nsStyleAnimation::Value &aStartValue)
167 {
168 PropertyValuePair v = { aProperty, aStartValue };
169 mPropertyValuePairs.AppendElement(v);
170 }
172 // Caller must fill in returned value.
173 nsStyleAnimation::Value* AddEmptyValue(nsCSSProperty aProperty)
174 {
175 PropertyValuePair *p = mPropertyValuePairs.AppendElement();
176 p->mProperty = aProperty;
177 return &p->mValue;
178 }
180 struct PropertyValuePair {
181 nsCSSProperty mProperty;
182 nsStyleAnimation::Value mValue;
183 };
185 private:
186 InfallibleTArray<PropertyValuePair> mPropertyValuePairs;
187 };
189 class ComputedTimingFunction {
190 public:
191 typedef nsTimingFunction::Type Type;
192 void Init(const nsTimingFunction &aFunction);
193 double GetValue(double aPortion) const;
194 const nsSMILKeySpline* GetFunction() const {
195 NS_ASSERTION(mType == nsTimingFunction::Function, "Type mismatch");
196 return &mTimingFunction;
197 }
198 Type GetType() const { return mType; }
199 uint32_t GetSteps() const { return mSteps; }
200 private:
201 Type mType;
202 nsSMILKeySpline mTimingFunction;
203 uint32_t mSteps;
204 };
206 } /* end css sub-namespace */
208 struct AnimationPropertySegment
209 {
210 float mFromKey, mToKey;
211 nsStyleAnimation::Value mFromValue, mToValue;
212 mozilla::css::ComputedTimingFunction mTimingFunction;
213 };
215 struct AnimationProperty
216 {
217 nsCSSProperty mProperty;
218 InfallibleTArray<AnimationPropertySegment> mSegments;
219 };
221 /**
222 * Data about one animation (i.e., one of the values of
223 * 'animation-name') running on an element.
224 */
225 struct StyleAnimation
226 {
227 StyleAnimation()
228 : mIsRunningOnCompositor(false)
229 , mLastNotification(LAST_NOTIFICATION_NONE)
230 {
231 }
233 nsString mName; // empty string for 'none'
234 float mIterationCount; // NS_IEEEPositiveInfinity() means infinite
235 uint8_t mDirection;
236 uint8_t mFillMode;
237 uint8_t mPlayState;
239 bool FillsForwards() const {
240 return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH ||
241 mFillMode == NS_STYLE_ANIMATION_FILL_MODE_FORWARDS;
242 }
243 bool FillsBackwards() const {
244 return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH ||
245 mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BACKWARDS;
246 }
248 bool IsPaused() const {
249 return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED;
250 }
252 bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
253 bool IsRunningAt(mozilla::TimeStamp aTime) const;
255 // Return the duration, at aTime (or, if paused, mPauseStart), since
256 // the *end* of the delay period. May be negative.
257 mozilla::TimeDuration ElapsedDurationAt(mozilla::TimeStamp aTime) const {
258 NS_ABORT_IF_FALSE(!IsPaused() || aTime >= mPauseStart,
259 "if paused, aTime must be at least mPauseStart");
260 return (IsPaused() ? mPauseStart : aTime) - mStartTime - mDelay;
261 }
263 // The beginning of the delay period. This is also used by
264 // ElementPropertyTransition in its IsRemovedSentinel and
265 // SetRemovedSentinel methods.
266 mozilla::TimeStamp mStartTime;
267 mozilla::TimeStamp mPauseStart;
268 mozilla::TimeDuration mDelay;
269 mozilla::TimeDuration mIterationDuration;
270 bool mIsRunningOnCompositor;
272 enum {
273 LAST_NOTIFICATION_NONE = uint32_t(-1),
274 LAST_NOTIFICATION_END = uint32_t(-2)
275 };
276 // One of the above constants, or an integer for the iteration
277 // whose start we last notified on.
278 uint32_t mLastNotification;
280 InfallibleTArray<AnimationProperty> mProperties;
281 };
283 namespace css {
285 struct CommonElementAnimationData : public PRCList
286 {
287 CommonElementAnimationData(dom::Element *aElement, nsIAtom *aElementProperty,
288 CommonAnimationManager *aManager, TimeStamp aNow)
289 : mElement(aElement)
290 , mElementProperty(aElementProperty)
291 , mManager(aManager)
292 , mAnimationGeneration(0)
293 , mFlushGeneration(aNow)
294 #ifdef DEBUG
295 , mCalledPropertyDtor(false)
296 #endif
297 {
298 MOZ_COUNT_CTOR(CommonElementAnimationData);
299 PR_INIT_CLIST(this);
300 }
301 ~CommonElementAnimationData()
302 {
303 NS_ABORT_IF_FALSE(mCalledPropertyDtor,
304 "must call destructor through element property dtor");
305 MOZ_COUNT_DTOR(CommonElementAnimationData);
306 PR_REMOVE_LINK(this);
307 mManager->ElementDataRemoved();
308 }
310 void Destroy()
311 {
312 // This will call our destructor.
313 mElement->DeleteProperty(mElementProperty);
314 }
316 bool CanThrottleTransformChanges(mozilla::TimeStamp aTime);
318 bool CanThrottleAnimation(mozilla::TimeStamp aTime);
320 enum CanAnimateFlags {
321 // Testing for width, height, top, right, bottom, or left.
322 CanAnimate_HasGeometricProperty = 1,
323 // Allow the case where OMTA is allowed in general, but not for the
324 // specified property.
325 CanAnimate_AllowPartial = 2
326 };
328 static bool
329 CanAnimatePropertyOnCompositor(const dom::Element *aElement,
330 nsCSSProperty aProperty,
331 CanAnimateFlags aFlags);
333 static bool IsCompositorAnimationDisabledForFrame(nsIFrame* aFrame);
335 // True if this animation can be performed on the compositor thread.
336 // Do not pass CanAnimate_AllowPartial to make sure that all properties of this
337 // animation are supported by the compositor.
338 virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const = 0;
339 virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const = 0;
341 static void LogAsyncAnimationFailure(nsCString& aMessage,
342 const nsIContent* aContent = nullptr);
344 dom::Element *mElement;
346 // the atom we use in mElement's prop table (must be a static atom,
347 // i.e., in an atom list)
348 nsIAtom *mElementProperty;
350 CommonAnimationManager *mManager;
352 // This style rule contains the style data for currently animating
353 // values. It only matches when styling with animation. When we
354 // style without animation, we need to not use it so that we can
355 // detect any new changes; if necessary we restyle immediately
356 // afterwards with animation.
357 // NOTE: If we don't need to apply any styles, mStyleRule will be
358 // null, but mStyleRuleRefreshTime will still be valid.
359 nsRefPtr<mozilla::css::AnimValuesStyleRule> mStyleRule;
361 // RestyleManager keeps track of the number of animation
362 // 'mini-flushes' (see nsTransitionManager::UpdateAllThrottledStyles()).
363 // mAnimationGeneration is the sequence number of the last flush where a
364 // transition/animation changed. We keep a similar count on the
365 // corresponding layer so we can check that the layer is up to date with
366 // the animation manager.
367 uint64_t mAnimationGeneration;
368 // Update mAnimationGeneration to nsCSSFrameConstructor's count
369 void UpdateAnimationGeneration(nsPresContext* aPresContext);
371 // The refresh time associated with mStyleRule.
372 TimeStamp mStyleRuleRefreshTime;
374 // Generation counter for flushes of throttled animations.
375 // Used to prevent updating the styles twice for a given element during
376 // UpdateAllThrottledStyles.
377 TimeStamp mFlushGeneration;
379 #ifdef DEBUG
380 bool mCalledPropertyDtor;
381 #endif
382 };
384 }
385 }
387 #endif /* !defined(mozilla_css_AnimationCommon_h) */