|
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 |
|
6 /* Code to start and animate CSS transitions. */ |
|
7 |
|
8 #ifndef nsTransitionManager_h_ |
|
9 #define nsTransitionManager_h_ |
|
10 |
|
11 #include "mozilla/Attributes.h" |
|
12 #include "mozilla/MemoryReporting.h" |
|
13 #include "AnimationCommon.h" |
|
14 #include "nsCSSPseudoElements.h" |
|
15 |
|
16 class nsStyleContext; |
|
17 class nsPresContext; |
|
18 class nsCSSPropertySet; |
|
19 struct nsTransition; |
|
20 struct ElementDependentRuleProcessorData; |
|
21 |
|
22 /***************************************************************************** |
|
23 * Per-Element data * |
|
24 *****************************************************************************/ |
|
25 |
|
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; |
|
44 |
|
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; |
|
49 |
|
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 } |
|
56 |
|
57 void SetRemovedSentinel() |
|
58 { |
|
59 // assign the null time stamp |
|
60 mStartTime = mozilla::TimeStamp(); |
|
61 } |
|
62 }; |
|
63 |
|
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); |
|
70 |
|
71 void EnsureStyleRuleFor(mozilla::TimeStamp aRefreshTime); |
|
72 |
|
73 virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE; |
|
74 |
|
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; |
|
89 |
|
90 // Either zero or one for each CSS property: |
|
91 nsTArray<ElementPropertyTransition> mPropertyTransitions; |
|
92 }; |
|
93 |
|
94 |
|
95 |
|
96 class nsTransitionManager MOZ_FINAL |
|
97 : public mozilla::css::CommonAnimationManager |
|
98 { |
|
99 public: |
|
100 nsTransitionManager(nsPresContext *aPresContext) |
|
101 : mozilla::css::CommonAnimationManager(aPresContext) |
|
102 { |
|
103 } |
|
104 |
|
105 static ElementTransitions* GetTransitions(nsIContent* aContent) { |
|
106 return static_cast<ElementTransitions*> |
|
107 (aContent->GetProperty(nsGkAtoms::transitionsProperty)); |
|
108 } |
|
109 |
|
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())); |
|
117 |
|
118 return false; |
|
119 } |
|
120 |
|
121 typedef mozilla::css::CommonElementAnimationData CommonElementAnimationData; |
|
122 |
|
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 } |
|
139 |
|
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); |
|
160 |
|
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; |
|
172 |
|
173 // nsARefreshObserver |
|
174 virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE; |
|
175 |
|
176 void FlushTransitions(FlushFlags aFlags); |
|
177 |
|
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(); |
|
198 |
|
199 ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement, |
|
200 nsCSSPseudoElements::Type aPseudoType, |
|
201 bool aCreateIfNeeded); |
|
202 |
|
203 protected: |
|
204 virtual void ElementDataRemoved() MOZ_OVERRIDE; |
|
205 virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE; |
|
206 |
|
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 }; |
|
226 |
|
227 #endif /* !defined(nsTransitionManager_h_) */ |