1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsTransitionManager.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,227 @@ 1.4 +/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* Code to start and animate CSS transitions. */ 1.10 + 1.11 +#ifndef nsTransitionManager_h_ 1.12 +#define nsTransitionManager_h_ 1.13 + 1.14 +#include "mozilla/Attributes.h" 1.15 +#include "mozilla/MemoryReporting.h" 1.16 +#include "AnimationCommon.h" 1.17 +#include "nsCSSPseudoElements.h" 1.18 + 1.19 +class nsStyleContext; 1.20 +class nsPresContext; 1.21 +class nsCSSPropertySet; 1.22 +struct nsTransition; 1.23 +struct ElementDependentRuleProcessorData; 1.24 + 1.25 +/***************************************************************************** 1.26 + * Per-Element data * 1.27 + *****************************************************************************/ 1.28 + 1.29 +struct ElementPropertyTransition : public mozilla::StyleAnimation 1.30 +{ 1.31 + // This is the start value to be used for a check for whether a 1.32 + // transition is being reversed. Normally the same as 1.33 + // mProperties[0].mSegments[0].mFromValue, except when this transition 1.34 + // started as the reversal of another in-progress transition. 1.35 + // Needed so we can handle two reverses in a row. 1.36 + nsStyleAnimation::Value mStartForReversingTest; 1.37 + // Likewise, the portion (in value space) of the "full" reversed 1.38 + // transition that we're actually covering. For example, if a :hover 1.39 + // effect has a transition that moves the element 10px to the right 1.40 + // (by changing 'left' from 0px to 10px), and the mouse moves in to 1.41 + // the element (starting the transition) but then moves out after the 1.42 + // transition has advanced 4px, the second transition (from 10px/4px 1.43 + // to 0px) will have mReversePortion of 0.4. (If the mouse then moves 1.44 + // in again when the transition is back to 2px, the mReversePortion 1.45 + // for the third transition (from 0px/2px to 10px) will be 0.8. 1.46 + double mReversePortion; 1.47 + 1.48 + // Compute the portion of the *value* space that we should be through 1.49 + // at the given time. (The input to the transition timing function 1.50 + // has time units, the output has value units.) 1.51 + double ValuePortionFor(mozilla::TimeStamp aRefreshTime) const; 1.52 + 1.53 + bool IsRemovedSentinel() const 1.54 + { 1.55 + // Note that mozilla::StyleAnimation::IsRunningAt depends on removed 1.56 + // sentinels being represented by a null mStartTime. 1.57 + return mStartTime.IsNull(); 1.58 + } 1.59 + 1.60 + void SetRemovedSentinel() 1.61 + { 1.62 + // assign the null time stamp 1.63 + mStartTime = mozilla::TimeStamp(); 1.64 + } 1.65 +}; 1.66 + 1.67 +struct ElementTransitions MOZ_FINAL 1.68 + : public mozilla::css::CommonElementAnimationData 1.69 +{ 1.70 + ElementTransitions(mozilla::dom::Element *aElement, nsIAtom *aElementProperty, 1.71 + nsTransitionManager *aTransitionManager, 1.72 + mozilla::TimeStamp aNow); 1.73 + 1.74 + void EnsureStyleRuleFor(mozilla::TimeStamp aRefreshTime); 1.75 + 1.76 + virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE; 1.77 + 1.78 + // If aFlags contains CanAnimate_AllowPartial, returns whether the 1.79 + // state of this element's transitions at the current refresh driver 1.80 + // time contains transition data that can be done on the compositor 1.81 + // thread. (This is useful for determining whether a layer should be 1.82 + // active, or whether to send data to the layer.) 1.83 + // If aFlags does not contain CanAnimate_AllowPartial, returns whether 1.84 + // the state of this element's transitions at the current refresh driver 1.85 + // time can be fully represented by data sent to the compositor. 1.86 + // (This is useful for determining whether throttle the transition 1.87 + // (suppress main-thread style updates).) 1.88 + // Note that when CanPerformOnCompositorThread returns true, it also, 1.89 + // as a side-effect, notifies the ActiveLayerTracker. FIXME: This 1.90 + // should probably move to the relevant callers. 1.91 + virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE; 1.92 + 1.93 + // Either zero or one for each CSS property: 1.94 + nsTArray<ElementPropertyTransition> mPropertyTransitions; 1.95 +}; 1.96 + 1.97 + 1.98 + 1.99 +class nsTransitionManager MOZ_FINAL 1.100 + : public mozilla::css::CommonAnimationManager 1.101 +{ 1.102 +public: 1.103 + nsTransitionManager(nsPresContext *aPresContext) 1.104 + : mozilla::css::CommonAnimationManager(aPresContext) 1.105 + { 1.106 + } 1.107 + 1.108 + static ElementTransitions* GetTransitions(nsIContent* aContent) { 1.109 + return static_cast<ElementTransitions*> 1.110 + (aContent->GetProperty(nsGkAtoms::transitionsProperty)); 1.111 + } 1.112 + 1.113 + // Returns true if aContent or any of its ancestors has a transition. 1.114 + static bool ContentOrAncestorHasTransition(nsIContent* aContent) { 1.115 + do { 1.116 + if (GetTransitions(aContent)) { 1.117 + return true; 1.118 + } 1.119 + } while ((aContent = aContent->GetParent())); 1.120 + 1.121 + return false; 1.122 + } 1.123 + 1.124 + typedef mozilla::css::CommonElementAnimationData CommonElementAnimationData; 1.125 + 1.126 + static ElementTransitions* 1.127 + GetTransitionsForCompositor(nsIContent* aContent, 1.128 + nsCSSProperty aProperty) 1.129 + { 1.130 + if (!aContent->MayHaveAnimations()) { 1.131 + return nullptr; 1.132 + } 1.133 + ElementTransitions* transitions = GetTransitions(aContent); 1.134 + if (!transitions || 1.135 + !transitions->HasAnimationOfProperty(aProperty) || 1.136 + !transitions->CanPerformOnCompositorThread( 1.137 + CommonElementAnimationData::CanAnimate_AllowPartial)) { 1.138 + return nullptr; 1.139 + } 1.140 + return transitions; 1.141 + } 1.142 + 1.143 + /** 1.144 + * StyleContextChanged 1.145 + * 1.146 + * To be called from nsFrameManager::ReResolveStyleContext when the 1.147 + * style of an element has changed, to initiate transitions from 1.148 + * that style change. For style contexts with :before and :after 1.149 + * pseudos, aElement is expected to be the generated before/after 1.150 + * element. 1.151 + * 1.152 + * It may return a "cover rule" (see CoverTransitionStartStyleRule) to 1.153 + * cover up some of the changes for the duration of the restyling of 1.154 + * descendants. If it does, this function will take care of causing 1.155 + * the necessary restyle afterwards, but the caller must restyle the 1.156 + * element *again* with the original sequence of rules plus the 1.157 + * returned cover rule as the most specific rule. 1.158 + */ 1.159 + already_AddRefed<nsIStyleRule> 1.160 + StyleContextChanged(mozilla::dom::Element *aElement, 1.161 + nsStyleContext *aOldStyleContext, 1.162 + nsStyleContext *aNewStyleContext); 1.163 + 1.164 + // nsIStyleRuleProcessor (parts) 1.165 + virtual void RulesMatching(ElementRuleProcessorData* aData) MOZ_OVERRIDE; 1.166 + virtual void RulesMatching(PseudoElementRuleProcessorData* aData) MOZ_OVERRIDE; 1.167 + virtual void RulesMatching(AnonBoxRuleProcessorData* aData) MOZ_OVERRIDE; 1.168 +#ifdef MOZ_XUL 1.169 + virtual void RulesMatching(XULTreeRuleProcessorData* aData) MOZ_OVERRIDE; 1.170 +#endif 1.171 + virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.172 + MOZ_MUST_OVERRIDE MOZ_OVERRIDE; 1.173 + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.174 + MOZ_MUST_OVERRIDE MOZ_OVERRIDE; 1.175 + 1.176 + // nsARefreshObserver 1.177 + virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE; 1.178 + 1.179 + void FlushTransitions(FlushFlags aFlags); 1.180 + 1.181 + // Performs a 'mini-flush' to make styles from throttled transitions 1.182 + // up-to-date prior to processing an unrelated style change, so that 1.183 + // any transitions triggered by that style change produce correct 1.184 + // results. 1.185 + // 1.186 + // In more detail: when we're able to run animations on the 1.187 + // compositor, we sometimes "throttle" these animations by skipping 1.188 + // updating style data on the main thread. However, whenever we 1.189 + // process a normal (non-animation) style change, any changes in 1.190 + // computed style on elements that have transition-* properties set 1.191 + // may need to trigger new transitions; this process requires knowing 1.192 + // both the old and new values of the property. To do this correctly, 1.193 + // we need to have an up-to-date *old* value of the property on the 1.194 + // primary frame. So the purpose of the mini-flush is to update the 1.195 + // style for all throttled transitions and animations to the current 1.196 + // animation state without making any other updates, so that when we 1.197 + // process the queued style updates we'll have correct old data to 1.198 + // compare against. When we do this, we don't bother touching frames 1.199 + // other than primary frames. 1.200 + void UpdateAllThrottledStyles(); 1.201 + 1.202 + ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement, 1.203 + nsCSSPseudoElements::Type aPseudoType, 1.204 + bool aCreateIfNeeded); 1.205 + 1.206 +protected: 1.207 + virtual void ElementDataRemoved() MOZ_OVERRIDE; 1.208 + virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE; 1.209 + 1.210 +private: 1.211 + void ConsiderStartingTransition(nsCSSProperty aProperty, 1.212 + const nsTransition& aTransition, 1.213 + mozilla::dom::Element *aElement, 1.214 + ElementTransitions *&aElementTransitions, 1.215 + nsStyleContext *aOldStyleContext, 1.216 + nsStyleContext *aNewStyleContext, 1.217 + bool *aStartedAny, 1.218 + nsCSSPropertySet *aWhichStarted); 1.219 + void WalkTransitionRule(ElementDependentRuleProcessorData* aData, 1.220 + nsCSSPseudoElements::Type aPseudoType); 1.221 + // Update the animated styles of an element and its descendants. 1.222 + // If the element has a transition, it is flushed back to its primary frame. 1.223 + // If the element does not have a transition, then its style is reparented. 1.224 + void UpdateThrottledStylesForSubtree(nsIContent* aContent, 1.225 + nsStyleContext* aParentStyle, 1.226 + nsStyleChangeList &aChangeList); 1.227 + void UpdateAllThrottledStylesInternal(); 1.228 +}; 1.229 + 1.230 +#endif /* !defined(nsTransitionManager_h_) */