diff -r 000000000000 -r 6474c204b198 layout/style/AnimationCommon.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layout/style/AnimationCommon.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,387 @@ +/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_css_AnimationCommon_h +#define mozilla_css_AnimationCommon_h + +#include "nsIStyleRuleProcessor.h" +#include "nsIStyleRule.h" +#include "nsRefreshDriver.h" +#include "prclist.h" +#include "nsStyleAnimation.h" +#include "nsCSSProperty.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/dom/Element.h" +#include "nsSMILKeySpline.h" +#include "nsStyleStruct.h" +#include "mozilla/Attributes.h" +#include "nsCSSPseudoElements.h" + +class nsPresContext; +class nsIFrame; + + +namespace mozilla { +namespace css { + +bool IsGeometricProperty(nsCSSProperty aProperty); + +struct CommonElementAnimationData; + +class CommonAnimationManager : public nsIStyleRuleProcessor, + public nsARefreshObserver { +public: + CommonAnimationManager(nsPresContext *aPresContext); + virtual ~CommonAnimationManager(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIStyleRuleProcessor (parts) + virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData) MOZ_OVERRIDE; + virtual nsRestyleHint HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) MOZ_OVERRIDE; + virtual bool HasDocumentStateDependentStyle(StateRuleProcessorData* aData) MOZ_OVERRIDE; + virtual nsRestyleHint + HasAttributeDependentStyle(AttributeRuleProcessorData* aData) MOZ_OVERRIDE; + virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) MOZ_OVERRIDE; + virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) + const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; + virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) + const MOZ_MUST_OVERRIDE MOZ_OVERRIDE; + + /** + * Notify the manager that the pres context is going away. + */ + void Disconnect(); + + enum FlushFlags { + Can_Throttle, + Cannot_Throttle + }; + + static bool ExtractComputedValueForTransition( + nsCSSProperty aProperty, + nsStyleContext* aStyleContext, + nsStyleAnimation::Value& aComputedValue); +protected: + friend struct CommonElementAnimationData; // for ElementDataRemoved + + virtual void AddElementData(CommonElementAnimationData* aData) = 0; + virtual void ElementDataRemoved() = 0; + void RemoveAllElementData(); + + // Update the style on aElement from the transition stored in this manager and + // the new parent style - aParentStyle. aElement must be transitioning or + // animated. Returns the updated style. + nsStyleContext* UpdateThrottledStyle(mozilla::dom::Element* aElement, + nsStyleContext* aParentStyle, + nsStyleChangeList &aChangeList); + // Reparent the style of aContent and any :before and :after pseudo-elements. + already_AddRefed ReparentContent(nsIContent* aContent, + nsStyleContext* aParentStyle); + // reparent :before and :after pseudo elements of aElement + static void ReparentBeforeAndAfter(dom::Element* aElement, + nsIFrame* aPrimaryFrame, + nsStyleContext* aNewStyle, + nsStyleSet* aStyleSet); + + PRCList mElementData; + nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect) +}; + +// The internals of UpdateAllThrottledStyles, used by nsAnimationManager and +// nsTransitionManager, see the comments in the declaration of the latter. +#define IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(class_, animations_getter_) \ +void \ +class_::UpdateAllThrottledStylesInternal() \ +{ \ + TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); \ + \ + nsStyleChangeList changeList; \ + \ + /* update each transitioning element by finding its root-most ancestor + with a transition, and flushing the style on that ancestor and all + its descendants*/ \ + PRCList *next = PR_LIST_HEAD(&mElementData); \ + while (next != &mElementData) { \ + CommonElementAnimationData* ea = \ + static_cast(next); \ + next = PR_NEXT_LINK(next); \ + \ + if (ea->mFlushGeneration == now) { \ + /* this element has been ticked already */ \ + continue; \ + } \ + \ + /* element is initialised to the starting element (i.e., one we know has + an animation) and ends up with the root-most animated ancestor, + that is, the element where we begin updates. */ \ + dom::Element* element = ea->mElement; \ + /* make a list of ancestors */ \ + nsTArray ancestors; \ + do { \ + ancestors.AppendElement(element); \ + } while ((element = element->GetParentElement())); \ + \ + /* walk down the ancestors until we find one with a throttled transition */\ + for (int32_t i = ancestors.Length() - 1; i >= 0; --i) { \ + if (animations_getter_(ancestors[i], \ + nsCSSPseudoElements::ePseudo_NotPseudoElement, \ + false)) { \ + element = ancestors[i]; \ + break; \ + } \ + } \ + \ + nsIFrame* primaryFrame; \ + if (element && \ + (primaryFrame = nsLayoutUtils::GetStyleFrame(element))) { \ + UpdateThrottledStylesForSubtree(element, \ + primaryFrame->StyleContext()->GetParent(), changeList); \ + } \ + } \ + \ + RestyleManager* restyleManager = mPresContext->RestyleManager(); \ + restyleManager->ProcessRestyledFrames(changeList); \ + restyleManager->FlushOverflowChangedTracker(); \ +} + +/** + * A style rule that maps property-nsStyleAnimation::Value pairs. + */ +class AnimValuesStyleRule MOZ_FINAL : public nsIStyleRule +{ +public: + // nsISupports implementation + NS_DECL_ISUPPORTS + + // nsIStyleRule implementation + virtual void MapRuleInfoInto(nsRuleData* aRuleData) MOZ_OVERRIDE; +#ifdef DEBUG + virtual void List(FILE* out = stdout, int32_t aIndent = 0) const MOZ_OVERRIDE; +#endif + + void AddValue(nsCSSProperty aProperty, nsStyleAnimation::Value &aStartValue) + { + PropertyValuePair v = { aProperty, aStartValue }; + mPropertyValuePairs.AppendElement(v); + } + + // Caller must fill in returned value. + nsStyleAnimation::Value* AddEmptyValue(nsCSSProperty aProperty) + { + PropertyValuePair *p = mPropertyValuePairs.AppendElement(); + p->mProperty = aProperty; + return &p->mValue; + } + + struct PropertyValuePair { + nsCSSProperty mProperty; + nsStyleAnimation::Value mValue; + }; + +private: + InfallibleTArray mPropertyValuePairs; +}; + +class ComputedTimingFunction { +public: + typedef nsTimingFunction::Type Type; + void Init(const nsTimingFunction &aFunction); + double GetValue(double aPortion) const; + const nsSMILKeySpline* GetFunction() const { + NS_ASSERTION(mType == nsTimingFunction::Function, "Type mismatch"); + return &mTimingFunction; + } + Type GetType() const { return mType; } + uint32_t GetSteps() const { return mSteps; } +private: + Type mType; + nsSMILKeySpline mTimingFunction; + uint32_t mSteps; +}; + +} /* end css sub-namespace */ + +struct AnimationPropertySegment +{ + float mFromKey, mToKey; + nsStyleAnimation::Value mFromValue, mToValue; + mozilla::css::ComputedTimingFunction mTimingFunction; +}; + +struct AnimationProperty +{ + nsCSSProperty mProperty; + InfallibleTArray mSegments; +}; + +/** + * Data about one animation (i.e., one of the values of + * 'animation-name') running on an element. + */ +struct StyleAnimation +{ + StyleAnimation() + : mIsRunningOnCompositor(false) + , mLastNotification(LAST_NOTIFICATION_NONE) + { + } + + nsString mName; // empty string for 'none' + float mIterationCount; // NS_IEEEPositiveInfinity() means infinite + uint8_t mDirection; + uint8_t mFillMode; + uint8_t mPlayState; + + bool FillsForwards() const { + return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH || + mFillMode == NS_STYLE_ANIMATION_FILL_MODE_FORWARDS; + } + bool FillsBackwards() const { + return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH || + mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BACKWARDS; + } + + bool IsPaused() const { + return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED; + } + + bool HasAnimationOfProperty(nsCSSProperty aProperty) const; + bool IsRunningAt(mozilla::TimeStamp aTime) const; + + // Return the duration, at aTime (or, if paused, mPauseStart), since + // the *end* of the delay period. May be negative. + mozilla::TimeDuration ElapsedDurationAt(mozilla::TimeStamp aTime) const { + NS_ABORT_IF_FALSE(!IsPaused() || aTime >= mPauseStart, + "if paused, aTime must be at least mPauseStart"); + return (IsPaused() ? mPauseStart : aTime) - mStartTime - mDelay; + } + + // The beginning of the delay period. This is also used by + // ElementPropertyTransition in its IsRemovedSentinel and + // SetRemovedSentinel methods. + mozilla::TimeStamp mStartTime; + mozilla::TimeStamp mPauseStart; + mozilla::TimeDuration mDelay; + mozilla::TimeDuration mIterationDuration; + bool mIsRunningOnCompositor; + + enum { + LAST_NOTIFICATION_NONE = uint32_t(-1), + LAST_NOTIFICATION_END = uint32_t(-2) + }; + // One of the above constants, or an integer for the iteration + // whose start we last notified on. + uint32_t mLastNotification; + + InfallibleTArray mProperties; +}; + +namespace css { + +struct CommonElementAnimationData : public PRCList +{ + CommonElementAnimationData(dom::Element *aElement, nsIAtom *aElementProperty, + CommonAnimationManager *aManager, TimeStamp aNow) + : mElement(aElement) + , mElementProperty(aElementProperty) + , mManager(aManager) + , mAnimationGeneration(0) + , mFlushGeneration(aNow) +#ifdef DEBUG + , mCalledPropertyDtor(false) +#endif + { + MOZ_COUNT_CTOR(CommonElementAnimationData); + PR_INIT_CLIST(this); + } + ~CommonElementAnimationData() + { + NS_ABORT_IF_FALSE(mCalledPropertyDtor, + "must call destructor through element property dtor"); + MOZ_COUNT_DTOR(CommonElementAnimationData); + PR_REMOVE_LINK(this); + mManager->ElementDataRemoved(); + } + + void Destroy() + { + // This will call our destructor. + mElement->DeleteProperty(mElementProperty); + } + + bool CanThrottleTransformChanges(mozilla::TimeStamp aTime); + + bool CanThrottleAnimation(mozilla::TimeStamp aTime); + + enum CanAnimateFlags { + // Testing for width, height, top, right, bottom, or left. + CanAnimate_HasGeometricProperty = 1, + // Allow the case where OMTA is allowed in general, but not for the + // specified property. + CanAnimate_AllowPartial = 2 + }; + + static bool + CanAnimatePropertyOnCompositor(const dom::Element *aElement, + nsCSSProperty aProperty, + CanAnimateFlags aFlags); + + static bool IsCompositorAnimationDisabledForFrame(nsIFrame* aFrame); + + // True if this animation can be performed on the compositor thread. + // Do not pass CanAnimate_AllowPartial to make sure that all properties of this + // animation are supported by the compositor. + virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const = 0; + virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const = 0; + + static void LogAsyncAnimationFailure(nsCString& aMessage, + const nsIContent* aContent = nullptr); + + dom::Element *mElement; + + // the atom we use in mElement's prop table (must be a static atom, + // i.e., in an atom list) + nsIAtom *mElementProperty; + + CommonAnimationManager *mManager; + + // This style rule contains the style data for currently animating + // values. It only matches when styling with animation. When we + // style without animation, we need to not use it so that we can + // detect any new changes; if necessary we restyle immediately + // afterwards with animation. + // NOTE: If we don't need to apply any styles, mStyleRule will be + // null, but mStyleRuleRefreshTime will still be valid. + nsRefPtr mStyleRule; + + // RestyleManager keeps track of the number of animation + // 'mini-flushes' (see nsTransitionManager::UpdateAllThrottledStyles()). + // mAnimationGeneration is the sequence number of the last flush where a + // transition/animation changed. We keep a similar count on the + // corresponding layer so we can check that the layer is up to date with + // the animation manager. + uint64_t mAnimationGeneration; + // Update mAnimationGeneration to nsCSSFrameConstructor's count + void UpdateAnimationGeneration(nsPresContext* aPresContext); + + // The refresh time associated with mStyleRule. + TimeStamp mStyleRuleRefreshTime; + + // Generation counter for flushes of throttled animations. + // Used to prevent updating the styles twice for a given element during + // UpdateAllThrottledStyles. + TimeStamp mFlushGeneration; + +#ifdef DEBUG + bool mCalledPropertyDtor; +#endif +}; + +} +} + +#endif /* !defined(mozilla_css_AnimationCommon_h) */