Bug 1305325 - Part 14: Compose base values on the compositor. r?birtles draft
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Sun, 04 Dec 2016 08:07:40 +0900
changeset 447349 cccd11f36543ca937c4c645169fb8c5983b3bdbc
parent 447348 a07714983b759d9c00e660bf145108c453f7bb09
child 447350 6941df906f2d1a00b44e047f42159c5e47bea120
push id38039
push userhiikezoe@mozilla-japan.org
push dateSat, 03 Dec 2016 23:26:35 +0000
reviewersbirtles
bugs1305325
milestone53.0a1
Bug 1305325 - Part 14: Compose base values on the compositor. r?birtles MozReview-Commit-ID: EWumBqQ82RT
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/KeyframeEffectReadOnly.h
gfx/layers/Layers.h
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/ipc/LayersMessages.ipdlh
layout/painting/nsDisplayList.cpp
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -300,16 +300,44 @@ KeyframeEffectReadOnly::UpdateProperties
     CalculateCumulativeChangeHint(aStyleContext);
   }
 
   MarkCascadeNeedsUpdate();
 
   RequestRestyle(EffectCompositor::RestyleType::Layer);
 }
 
+/* static */ StyleAnimationValue
+KeyframeEffectReadOnly::CompositeValue(
+  nsCSSPropertyID aProperty,
+  const StyleAnimationValue& aValueToComposite,
+  const StyleAnimationValue& aUnderlyingValue,
+  CompositeOperation aCompositeOperation)
+{
+  switch (aCompositeOperation) {
+    case dom::CompositeOperation::Replace:
+      return aValueToComposite;
+    case dom::CompositeOperation::Add:
+      // So far nothing to do since we come to here only in case of missing
+      // keyframe, that means we have only to use the base value or the
+      // underlying value as the composited value.
+      // FIXME: Bug 1311620: Once we implement additive operation, we need to
+      // calculate it here.
+      return aUnderlyingValue;
+    case dom::CompositeOperation::Accumulate:
+      // FIXME: Bug 1291468: Implement accumulate operation.
+      MOZ_ASSERT_UNREACHABLE("Not implemented yet");
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown compisite operation type");
+      break;
+  }
+  return StyleAnimationValue();
+}
+
 StyleAnimationValue
 KeyframeEffectReadOnly::CompositeValue(
   nsCSSPropertyID aProperty,
   const RefPtr<AnimValuesStyleRule>& aAnimationRule,
   const StyleAnimationValue& aValueToComposite,
   CompositeOperation aCompositeOperation)
 {
   MOZ_ASSERT(mTarget, "CompositeValue should be called with target element");
@@ -345,36 +373,20 @@ KeyframeEffectReadOnly::CompositeValue(
     result = EffectCompositor::GetBaseStyle(aProperty,
                                             styleContext,
                                             *mTarget->mElement,
                                             mTarget->mPseudoType);
     MOZ_ASSERT(!result.IsNull(), "The base style should be set");
     SetNeedsBaseStyle(aProperty);
   }
 
-  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
-      // use it here only if |aValueToCompose| is not null.
-      return result;
-    case dom::CompositeOperation::Accumulate:
-      // FIXME: Bug 1291468: Implement accumulate operation.
-      MOZ_ASSERT_UNREACHABLE("Not implemented yet");
-      break;
-    case dom::CompositeOperation::Replace:
-      MOZ_ASSERT_UNREACHABLE("Replace should have already handled");
-      break;
-    default:
-      MOZ_ASSERT_UNREACHABLE("Unknown compisite operation type");
-      break;
-  }
-  return result;
+  return CompositeValue(aProperty,
+                        aValueToComposite,
+                        result,
+                        aCompositeOperation);
 }
 
 void
 KeyframeEffectReadOnly::ComposeStyle(
   RefPtr<AnimValuesStyleRule>& aStyleRule,
   const nsCSSPropertyIDSet& aPropertiesToSkip)
 {
   ComputedTiming computedTiming = GetComputedTiming();
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -284,16 +284,26 @@ public:
   // |aStyleContext| to resolve specified values.
   void UpdateProperties(nsStyleContext* aStyleContext);
 
   // Updates |aStyleRule| with the animation values produced by this
   // AnimationEffect for the current time except any properties contained
   // in |aPropertiesToSkip|.
   void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
                     const nsCSSPropertyIDSet& aPropertiesToSkip);
+
+  // Composite |aValueToComposite| on |aUnderlyingValue| with
+  // |aCompositeOperation|.
+  // Returns |aValueToComposite| if |aCompositeOperation| is Replace.
+  static StyleAnimationValue CompositeValue(
+    nsCSSPropertyID aProperty,
+    const StyleAnimationValue& aValueToComposite,
+    const StyleAnimationValue& aUnderlyingValue,
+    CompositeOperation aCompositeOperation);
+
   // Returns true if at least one property is being animated on compositor.
   bool IsRunningOnCompositor() const;
   void SetIsRunningOnCompositor(nsCSSPropertyID aProperty, bool aIsRunning);
   void ResetIsRunningOnCompositor();
 
   // Returns true if this effect, applied to |aFrame|, contains properties
   // that mean we shouldn't run transform compositor animations on this element.
   //
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1413,16 +1413,21 @@ public:
   AnimationArray& GetAnimations() { return mAnimations; }
   InfallibleTArray<AnimData>& GetAnimationData() { return mAnimationData; }
 
   uint64_t GetAnimationGeneration() { return mAnimationGeneration; }
   void SetAnimationGeneration(uint64_t aCount) { mAnimationGeneration = aCount; }
 
   bool HasTransformAnimation() const;
 
+  StyleAnimationValue GetBaseAnimationStyle() const
+  {
+    return mBaseAnimationStyle;
+  }
+
   /**
    * Returns the local transform for this layer: either mTransform or,
    * for shadow layers, GetShadowBaseTransform(), in either case with the
    * pre- and post-scales applied.
    */
   gfx::Matrix4x4 GetLocalTransform();
 
   /**
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -571,28 +571,45 @@ AsyncCompositionManager::AlignFixedAndSt
       AlignFixedAndStickyLayers(aTransformedSubtreeRoot, child, aTransformScrollId,
           aPreviousTransformForRoot, newTransform, aFixedLayerMargins, aClipPartsCache);
     }
   }
 
   return;
 }
 
+struct StyleAnimationValueCompositePair {
+  StyleAnimationValue mValue;
+  dom::CompositeOperation mComposite;
+};
+
 static StyleAnimationValue
-SampleValue(float aPortion, Animation& aAnimation,
-            const StyleAnimationValue& aStart, const StyleAnimationValue& aEnd,
-            const StyleAnimationValue& aLastValue, uint64_t aCurrentIteration)
+SampleValue(float aPortion, const Animation& aAnimation,
+            const StyleAnimationValueCompositePair& aStart,
+            const StyleAnimationValueCompositePair& aEnd,
+            const StyleAnimationValue& aLastValue,
+            uint64_t aCurrentIteration,
+            const StyleAnimationValue& aUnderlyingValue)
 {
-  NS_ASSERTION(aStart.GetUnit() == aEnd.GetUnit() ||
-               aStart.GetUnit() == StyleAnimationValue::eUnit_None ||
-               aEnd.GetUnit() == StyleAnimationValue::eUnit_None,
+  NS_ASSERTION(aStart.mValue.GetUnit() == aEnd.mValue.GetUnit() ||
+               aStart.mValue.GetUnit() == StyleAnimationValue::eUnit_None ||
+               aEnd.mValue.GetUnit() == StyleAnimationValue::eUnit_None,
                "Must have same unit");
 
-  StyleAnimationValue startValue = aStart;
-  StyleAnimationValue endValue = aEnd;
+  StyleAnimationValue startValue =
+    dom::KeyframeEffectReadOnly::CompositeValue(aAnimation.property(),
+                                                aStart.mValue,
+                                                aUnderlyingValue,
+                                                aStart.mComposite);
+  StyleAnimationValue endValue =
+    dom::KeyframeEffectReadOnly::CompositeValue(aAnimation.property(),
+                                                aEnd.mValue,
+                                                aUnderlyingValue,
+                                                aEnd.mComposite);
+
   // Iteration composition for accumulate
   if (static_cast<dom::IterationCompositeOperation>
         (aAnimation.iterationComposite()) ==
           dom::IterationCompositeOperation::Accumulate &&
       aCurrentIteration > 0) {
     // FIXME: Bug 1293492: Add a utility function to calculate both of
     // below StyleAnimationValues.
     startValue =
@@ -683,17 +700,19 @@ SampleAnimations(Layer* aLayer, TimeStam
       {
         AnimationArray& animations = layer->GetAnimations();
         if (animations.IsEmpty()) {
           return;
         }
 
         InfallibleTArray<AnimData>& animationData = layer->GetAnimationData();
 
-        StyleAnimationValue interpolatedValue;
+        StyleAnimationValue animationValue = layer->GetBaseAnimationStyle();
+        bool hasInEffectAnimations = false;
+
         // Process in order, since later animations override earlier ones.
         for (size_t i = 0, iEnd = animations.Length(); i < iEnd; ++i) {
           Animation& animation = animations[i];
           AnimData& animData = animationData[i];
 
           activeAnimations = true;
 
           MOZ_ASSERT(!animation.startTime().IsNull() ||
@@ -740,23 +759,32 @@ SampleAnimations(Layer* aLayer, TimeStam
             (computedTiming.mProgress.Value() - segment->startPortion()) /
             (segment->endPortion() - segment->startPortion());
 
           double portion =
             ComputedTimingFunction::GetPortion(animData.mFunctions[segmentIndex],
                                                positionInSegment,
                                            computedTiming.mBeforeFlag);
 
+          StyleAnimationValueCompositePair from {
+            animData.mStartValues[segmentIndex],
+            static_cast<dom::CompositeOperation>(segment->startComposite())
+          };
+          StyleAnimationValueCompositePair to {
+            animData.mEndValues[segmentIndex],
+            static_cast<dom::CompositeOperation>(segment->endComposite())
+          };
           // interpolate the property
-          interpolatedValue =
-            SampleValue(portion, animation,
-                        animData.mStartValues[segmentIndex],
-                        animData.mEndValues[segmentIndex],
-                        animData.mEndValues.LastElement(),
-                        computedTiming.mCurrentIteration);
+          animationValue = SampleValue(portion,
+                                       animation,
+                                       from, to,
+                                       animData.mEndValues.LastElement(),
+                                       computedTiming.mCurrentIteration,
+                                       animationValue);
+          hasInEffectAnimations = true;
         }
 
 #ifdef DEBUG
         // Sanity check that all of animation data are the same.
         const AnimationData& lastData = animations.LastElement().data();
         for (const Animation& animation : animations) {
           const AnimationData& data = animation.data();
           MOZ_ASSERT(data.type() == lastData.type(),
@@ -772,22 +800,23 @@ SampleAnimations(Layer* aLayer, TimeStam
                      transformData.transformOrigin() ==
                        lastTransformData.transformOrigin() &&
                      transformData.bounds() == lastTransformData.bounds() &&
                      transformData.appUnitsPerDevPixel() ==
                        lastTransformData.appUnitsPerDevPixel(),
                      "All of members of TransformData should be the same");
         }
 #endif
-        if (!interpolatedValue.IsNull()) {
+        // If all of animations are 
+        if (hasInEffectAnimations) {
           Animation& animation = animations.LastElement();
           ApplyAnimatedValue(layer,
                              animation.property(),
                              animation.data(),
-                             interpolatedValue);
+                             animationValue);
         }
       });
   return activeAnimations;
 }
 
 static bool
 SampleAPZAnimations(const LayerMetricsWrapper& aLayer, TimeStamp aSampleTime)
 {
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -165,16 +165,18 @@ union BaseAnimationStyle {
   Animatable;
 };
 
 struct AnimationSegment {
   Animatable startState;
   Animatable endState;
   float startPortion;
   float endPortion;
+  uint8_t startComposite;
+  uint8_t endComposite;
   TimingFunction sampleFn;
 };
 
 // Transforms need extra information to correctly convert the list of transform
 // functions to a Matrix4x4 that can be applied directly to the layer.
 struct TransformData {
   // the origin of the frame being transformed in app units
   nsPoint origin;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -532,16 +532,20 @@ AddAnimationForProperty(nsIFrame* aFrame
                   animSegment->startState());
     SetAnimatable(aProperty.mProperty,
                   segment.mToValue,
                   aFrame, refBox,
                   animSegment->endState());
 
     animSegment->startPortion() = segment.mFromKey;
     animSegment->endPortion() = segment.mToKey;
+    animSegment->startComposite() =
+      static_cast<uint8_t>(segment.mFromComposite);
+    animSegment->endComposite() =
+      static_cast<uint8_t>(segment.mToComposite);
     animSegment->sampleFn() = ToTimingFunction(segment.mTimingFunction);
   }
 }
 
 static void
 AddAnimationsForProperty(nsIFrame* aFrame, nsCSSPropertyID aProperty,
                          nsTArray<RefPtr<dom::Animation>>& aAnimations,
                          Layer* aLayer, AnimationData& aData,