Bug 1305325 - Part 11: Store non-animated base value for compositable properties if needed. r?birtles draft
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Sat, 26 Nov 2016 09:08:21 +0900
changeset 444082 d273c9c3e43075a85a21cf90701ba2408052fd50
parent 444081 3bf79073a2e691370c779055e03cc53a28b97ab6
child 444083 00c718b8d9661a32a22b7f739918d912c278cf9d
push id37193
push userhiikezoe@mozilla-japan.org
push dateSat, 26 Nov 2016 03:37:22 +0000
reviewersbirtles
bugs1305325
milestone53.0a1
Bug 1305325 - Part 11: Store non-animated base value for compositable properties if needed. r?birtles This patch adds a hashtable to store the non-animated base value of each property in EffectSet class if the following conditions are met. 1) the property can be run on the compositor 2) the effect is the lowest priority of the effect 3) the effect is additive or accumulative The values are stored as StyleAnimationValue objects since it's handy class to store a CSS value for different properties. MozReview-Commit-ID: 1MZV7MnqzfI
dom/animation/EffectSet.h
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/KeyframeEffectReadOnly.h
--- a/dom/animation/EffectSet.h
+++ b/dom/animation/EffectSet.h
@@ -194,16 +194,29 @@ public:
   {
     return mPropertiesWithImportantRules;
   }
   nsCSSPropertyIDSet& PropertiesForAnimationsLevel()
   {
     return mPropertiesForAnimationsLevel;
   }
 
+  bool GetBaseStyleAnimationValue(nsCSSPropertyID aProperty,
+                                  StyleAnimationValue& aValue) const
+  {
+    return mBaseStyleValues.Get(aProperty, &aValue);
+  }
+
+  typedef nsDataHashtable<nsUint32HashKey, StyleAnimationValue>
+    BaseStyleValueSet;
+  BaseStyleValueSet& GetBaseStyleValues()
+  {
+    return mBaseStyleValues;
+  }
+
 private:
   static nsIAtom* GetEffectSetPropertyAtom(CSSPseudoElementType aPseudoType);
 
   OwningEffectSet mEffects;
 
   // These style rules contain the style data for currently animating
   // values.  They only match when styling with animation.  When we
   // style without animation, we need to not use them so that we can
@@ -242,16 +255,21 @@ private:
   // Specifies the compositor-animatable properties that are overridden by
   // !important rules.
   nsCSSPropertyIDSet mPropertiesWithImportantRules;
   // Specifies the properties for which the result will be added to the
   // animations level of the cascade and hence should be skipped when we are
   // composing the animation style for the transitions level of the cascede.
   nsCSSPropertyIDSet mPropertiesForAnimationsLevel;
 
+  // The non-animated values for properties animated by effects in this set that
+  // contain at least one animation value that is composited with the underlying
+  // value on the compositor if there is an additive or accumulate effect.
+  BaseStyleValueSet mBaseStyleValues;
+
 #ifdef DEBUG
   // Track how many iterators are referencing this effect set when we are
   // destroyed, we can assert that nothing is still pointing to us.
   uint64_t mActiveIterators;
 
   bool mCalledPropertyDtor;
 #endif
 };
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -340,16 +340,17 @@ KeyframeEffectReadOnly::CompositeValue(
   } else {
     // If we are composing with composite operation that is not 'replace'
     // and we have not composed style for the property yet, we have to get
     // the base style for the property.
     RefPtr<nsStyleContext> styleContext = GetTargetStyleContext();
     result = EffectCompositor::GetBaseValue(aProperty,
                                             styleContext,
                                             *mTarget->mElement);
+    MaybeRetainBaseValueForCompositor(aProperty, result);
   }
 
   switch (aCompositeOperation) {
     case dom::CompositeOperation::Add:
       // So far nothing to do since we come to here only in case of missing
       // keyframe, that means we just use the base value as the composited
       // value.
       // FIXME: Bug 1311620: Once we implement additive composition, we need to
@@ -379,16 +380,18 @@ KeyframeEffectReadOnly::ComposeStyle(
   mCurrentIterationOnLastCompose = computedTiming.mCurrentIteration;
 
   // If the progress is null, we don't have fill data for the current
   // time so we shouldn't animate.
   if (computedTiming.mProgress.IsNull()) {
     return;
   }
 
+  mNeedsBaseValueSet.reset();
+
   for (size_t propIdx = 0, propEnd = mProperties.Length();
        propIdx != propEnd; ++propIdx)
   {
     const AnimationProperty& prop = mProperties[propIdx];
 
     MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key");
     MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0,
                "incorrect last to key");
@@ -1499,10 +1502,44 @@ KeyframeEffectReadOnly::HasComputedTimin
   ComputedTiming computedTiming = GetComputedTiming();
   return computedTiming.mProgress != mProgressOnLastCompose ||
          (mEffectOptions.mIterationComposite ==
             IterationCompositeOperation::Accumulate &&
          computedTiming.mCurrentIteration !=
           mCurrentIterationOnLastCompose);
 }
 
+void
+KeyframeEffectReadOnly::MaybeRetainBaseValueForCompositor(
+  nsCSSPropertyID aProperty,
+  const StyleAnimationValue& aBaseValue)
+{
+  for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) {
+    if (LayerAnimationInfo::sRecords[i].mProperty == aProperty) {
+      EffectSet* effectSet =
+        EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
+      MOZ_ASSERT(effectSet, "EffectSet shouldn't be null");
+
+      EffectSet::BaseStyleValueSet& baseStyleValues =
+        effectSet->GetBaseStyleValues();
+      baseStyleValues.Put(aProperty, aBaseValue);
+      mNeedsBaseValueSet.set(i);
+      break;
+    }
+  }
+}
+
+bool
+KeyframeEffectReadOnly::NeedsBaseValue(nsCSSPropertyID aProperty) const
+{
+  for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) {
+    if (LayerAnimationInfo::sRecords[i].mProperty == aProperty) {
+      return mNeedsBaseValueSet[i];
+    }
+  }
+  MOZ_ASSERT_UNREACHABLE(
+    "Shouldn't be called for property that not run on the compositor");
+
+  return false;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -2,16 +2,18 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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_dom_KeyframeEffectReadOnly_h
 #define mozilla_dom_KeyframeEffectReadOnly_h
 
+#include <bitset>
+
 #include "nsChangeHint.h"
 #include "nsCSSPropertyID.h"
 #include "nsCSSValue.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
@@ -325,16 +327,20 @@ public:
   void CalculateCumulativeChangeHint(nsStyleContext* aStyleContext);
 
   // Returns true if all of animation properties' change hints
   // can ignore painting if the animation is not visible.
   // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
   // in detail which change hint can be ignored.
   bool CanIgnoreIfNotVisible() const;
 
+  // Returns true if the effect needs base values for |aProperty| runnable on
+  // the compositor.
+  bool NeedsBaseValue(nsCSSPropertyID aProperty) const;
+
 protected:
   KeyframeEffectReadOnly(nsIDocument* aDocument,
                          const Maybe<OwningAnimationTarget>& aTarget,
                          AnimationEffectTimingReadOnly* aTiming,
                          const KeyframeEffectParams& aOptions);
 
   ~KeyframeEffectReadOnly() override = default;
 
@@ -399,16 +405,22 @@ protected:
   // |aAnimationRule|, uses the base value for the property recorded on the
   // target element's EffectSet.
   StyleAnimationValue CompositeValue(
     nsCSSPropertyID aProperty,
     const RefPtr<AnimValuesStyleRule>& aAnimationRule,
     const StyleAnimationValue& aValueToComposite,
     CompositeOperation aCompositeOperation);
 
+  // Retain the base value if |aProperty| can be run on the compositor so that
+  // we can pass the base value to the compositor when we send this effect to
+  // the compositor.
+  void MaybeRetainBaseValueForCompositor(nsCSSPropertyID aProperty,
+                                         const StyleAnimationValue& aBaseValue);
+
   Maybe<OwningAnimationTarget> mTarget;
 
   KeyframeEffectParams mEffectOptions;
 
   // The specified keyframes.
   nsTArray<Keyframe>          mKeyframes;
 
   // A set of per-property value arrays, derived from |mKeyframes|.
@@ -423,16 +435,21 @@ protected:
   // this is used to detect when the current iteration is not changing
   // in the case when iterationComposite is accumulate.
   uint64_t mCurrentIterationOnLastCompose = 0;
 
   // We need to track when we go to or from being "in effect" since
   // we need to re-evaluate the cascade of animations when that changes.
   bool mInEffectOnLastAnimationTimingUpdate;
 
+  // A bit set that each bit represents that corresponding property needs the
+  // base value or not. The bit order matches to the order of
+  // LayerAnimationInfo::sRecords.
+  std::bitset<LayerAnimationInfo::kRecords> mNeedsBaseValueSet;
+
 private:
   nsChangeHint mCumulativeChangeHint;
 
   nsIFrame* GetAnimationFrame() const;
 
   bool CanThrottle() const;
   bool CanThrottleTransformChanges(nsIFrame& aFrame) const;