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 /* Code to start and animate CSS transitions. */
8 #ifndef nsTransitionManager_h_
9 #define nsTransitionManager_h_
11 #include "mozilla/Attributes.h"
12 #include "mozilla/MemoryReporting.h"
13 #include "AnimationCommon.h"
14 #include "nsCSSPseudoElements.h"
16 class nsStyleContext;
17 class nsPresContext;
18 class nsCSSPropertySet;
19 struct nsTransition;
20 struct ElementDependentRuleProcessorData;
22 /*****************************************************************************
23 * Per-Element data *
24 *****************************************************************************/
26 struct ElementPropertyTransition : public mozilla::StyleAnimation
27 {
28 // This is the start value to be used for a check for whether a
29 // transition is being reversed. Normally the same as
30 // mProperties[0].mSegments[0].mFromValue, except when this transition
31 // started as the reversal of another in-progress transition.
32 // Needed so we can handle two reverses in a row.
33 nsStyleAnimation::Value mStartForReversingTest;
34 // Likewise, the portion (in value space) of the "full" reversed
35 // transition that we're actually covering. For example, if a :hover
36 // effect has a transition that moves the element 10px to the right
37 // (by changing 'left' from 0px to 10px), and the mouse moves in to
38 // the element (starting the transition) but then moves out after the
39 // transition has advanced 4px, the second transition (from 10px/4px
40 // to 0px) will have mReversePortion of 0.4. (If the mouse then moves
41 // in again when the transition is back to 2px, the mReversePortion
42 // for the third transition (from 0px/2px to 10px) will be 0.8.
43 double mReversePortion;
45 // Compute the portion of the *value* space that we should be through
46 // at the given time. (The input to the transition timing function
47 // has time units, the output has value units.)
48 double ValuePortionFor(mozilla::TimeStamp aRefreshTime) const;
50 bool IsRemovedSentinel() const
51 {
52 // Note that mozilla::StyleAnimation::IsRunningAt depends on removed
53 // sentinels being represented by a null mStartTime.
54 return mStartTime.IsNull();
55 }
57 void SetRemovedSentinel()
58 {
59 // assign the null time stamp
60 mStartTime = mozilla::TimeStamp();
61 }
62 };
64 struct ElementTransitions MOZ_FINAL
65 : public mozilla::css::CommonElementAnimationData
66 {
67 ElementTransitions(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
68 nsTransitionManager *aTransitionManager,
69 mozilla::TimeStamp aNow);
71 void EnsureStyleRuleFor(mozilla::TimeStamp aRefreshTime);
73 virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE;
75 // If aFlags contains CanAnimate_AllowPartial, returns whether the
76 // state of this element's transitions at the current refresh driver
77 // time contains transition data that can be done on the compositor
78 // thread. (This is useful for determining whether a layer should be
79 // active, or whether to send data to the layer.)
80 // If aFlags does not contain CanAnimate_AllowPartial, returns whether
81 // the state of this element's transitions at the current refresh driver
82 // time can be fully represented by data sent to the compositor.
83 // (This is useful for determining whether throttle the transition
84 // (suppress main-thread style updates).)
85 // Note that when CanPerformOnCompositorThread returns true, it also,
86 // as a side-effect, notifies the ActiveLayerTracker. FIXME: This
87 // should probably move to the relevant callers.
88 virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE;
90 // Either zero or one for each CSS property:
91 nsTArray<ElementPropertyTransition> mPropertyTransitions;
92 };
96 class nsTransitionManager MOZ_FINAL
97 : public mozilla::css::CommonAnimationManager
98 {
99 public:
100 nsTransitionManager(nsPresContext *aPresContext)
101 : mozilla::css::CommonAnimationManager(aPresContext)
102 {
103 }
105 static ElementTransitions* GetTransitions(nsIContent* aContent) {
106 return static_cast<ElementTransitions*>
107 (aContent->GetProperty(nsGkAtoms::transitionsProperty));
108 }
110 // Returns true if aContent or any of its ancestors has a transition.
111 static bool ContentOrAncestorHasTransition(nsIContent* aContent) {
112 do {
113 if (GetTransitions(aContent)) {
114 return true;
115 }
116 } while ((aContent = aContent->GetParent()));
118 return false;
119 }
121 typedef mozilla::css::CommonElementAnimationData CommonElementAnimationData;
123 static ElementTransitions*
124 GetTransitionsForCompositor(nsIContent* aContent,
125 nsCSSProperty aProperty)
126 {
127 if (!aContent->MayHaveAnimations()) {
128 return nullptr;
129 }
130 ElementTransitions* transitions = GetTransitions(aContent);
131 if (!transitions ||
132 !transitions->HasAnimationOfProperty(aProperty) ||
133 !transitions->CanPerformOnCompositorThread(
134 CommonElementAnimationData::CanAnimate_AllowPartial)) {
135 return nullptr;
136 }
137 return transitions;
138 }
140 /**
141 * StyleContextChanged
142 *
143 * To be called from nsFrameManager::ReResolveStyleContext when the
144 * style of an element has changed, to initiate transitions from
145 * that style change. For style contexts with :before and :after
146 * pseudos, aElement is expected to be the generated before/after
147 * element.
148 *
149 * It may return a "cover rule" (see CoverTransitionStartStyleRule) to
150 * cover up some of the changes for the duration of the restyling of
151 * descendants. If it does, this function will take care of causing
152 * the necessary restyle afterwards, but the caller must restyle the
153 * element *again* with the original sequence of rules plus the
154 * returned cover rule as the most specific rule.
155 */
156 already_AddRefed<nsIStyleRule>
157 StyleContextChanged(mozilla::dom::Element *aElement,
158 nsStyleContext *aOldStyleContext,
159 nsStyleContext *aNewStyleContext);
161 // nsIStyleRuleProcessor (parts)
162 virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE;
163 virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE;
164 virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE;
165 #ifdef MOZ_XUL
166 virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE;
167 #endif
168 virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
169 MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
170 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
171 MOZ_MUST_OVERRIDE MOZ_OVERRIDE;
173 // nsARefreshObserver
174 virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE;
176 void FlushTransitions(FlushFlags aFlags);
178 // Performs a 'mini-flush' to make styles from throttled transitions
179 // up-to-date prior to processing an unrelated style change, so that
180 // any transitions triggered by that style change produce correct
181 // results.
182 //
183 // In more detail: when we're able to run animations on the
184 // compositor, we sometimes "throttle" these animations by skipping
185 // updating style data on the main thread. However, whenever we
186 // process a normal (non-animation) style change, any changes in
187 // computed style on elements that have transition-* properties set
188 // may need to trigger new transitions; this process requires knowing
189 // both the old and new values of the property. To do this correctly,
190 // we need to have an up-to-date *old* value of the property on the
191 // primary frame. So the purpose of the mini-flush is to update the
192 // style for all throttled transitions and animations to the current
193 // animation state without making any other updates, so that when we
194 // process the queued style updates we'll have correct old data to
195 // compare against. When we do this, we don't bother touching frames
196 // other than primary frames.
197 void UpdateAllThrottledStyles();
199 ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement,
200 nsCSSPseudoElements::Type aPseudoType,
201 bool aCreateIfNeeded);
203 protected:
204 virtual void ElementDataRemoved() MOZ_OVERRIDE;
205 virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE;
207 private:
208 void ConsiderStartingTransition(nsCSSProperty aProperty,
209 const nsTransition& aTransition,
210 mozilla::dom::Element *aElement,
211 ElementTransitions *&aElementTransitions,
212 nsStyleContext *aOldStyleContext,
213 nsStyleContext *aNewStyleContext,
214 bool *aStartedAny,
215 nsCSSPropertySet *aWhichStarted);
216 void WalkTransitionRule(ElementDependentRuleProcessorData* aData,
217 nsCSSPseudoElements::Type aPseudoType);
218 // Update the animated styles of an element and its descendants.
219 // If the element has a transition, it is flushed back to its primary frame.
220 // If the element does not have a transition, then its style is reparented.
221 void UpdateThrottledStylesForSubtree(nsIContent* aContent,
222 nsStyleContext* aParentStyle,
223 nsStyleChangeList &aChangeList);
224 void UpdateAllThrottledStylesInternal();
225 };
227 #endif /* !defined(nsTransitionManager_h_) */