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