Bug 1237173 - Part2: Change type of duration to Maybe<StickyTimeDuration>. r=birtles
authorDaisuke Akatsuka <daisuke@mozilla-japan.org>
Wed, 09 Mar 2016 14:14:20 +0900
changeset 311794 8e41986d4724052fc6a6ba1e135c9b2b5b6cd921
parent 311793 75adfcb59f7bc61b7836522394766d28403e1665
child 311795 006e29abfc8ebf0531d932ddcfafea769fe13921
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs1237173
milestone48.0a1
Bug 1237173 - Part2: Change type of duration to Maybe<StickyTimeDuration>. r=birtles
dom/animation/AnimationEffectTiming.cpp
dom/animation/AnimationEffectTimingReadOnly.cpp
dom/animation/AnimationEffectTimingReadOnly.h
dom/animation/KeyframeEffect.cpp
dom/animation/TimingParams.cpp
dom/animation/TimingParams.h
gfx/layers/composite/AsyncCompositionManager.cpp
layout/base/nsDisplayList.cpp
layout/style/nsAnimationManager.cpp
layout/style/nsTransitionManager.cpp
testing/web-platform/tests/web-animations/animatable/animate.html
testing/web-platform/tests/web-animations/keyframe-effect/constructor.html
--- a/dom/animation/AnimationEffectTiming.cpp
+++ b/dom/animation/AnimationEffectTiming.cpp
@@ -36,32 +36,25 @@ AnimationEffectTiming::SetEndDelay(doubl
   mTiming.mEndDelay = endDelay;
 
   NotifyTimingUpdate();
 }
 
 void
 AnimationEffectTiming::SetDuration(const UnrestrictedDoubleOrString& aDuration)
 {
-  if (mTiming.mDuration.IsUnrestrictedDouble() &&
-      aDuration.IsUnrestrictedDouble() &&
-      mTiming.mDuration.GetAsUnrestrictedDouble() ==
-        aDuration.GetAsUnrestrictedDouble()) {
+  Maybe<StickyTimeDuration> newDuration;
+  if (aDuration.IsUnrestrictedDouble()) {
+    newDuration.emplace(StickyTimeDuration::FromMilliseconds(
+                          aDuration.GetAsUnrestrictedDouble()));
+  }
+
+  if (mTiming.mDuration == newDuration) {
     return;
   }
 
-  if (mTiming.mDuration.IsString() && aDuration.IsString() &&
-      mTiming.mDuration.GetAsString() == aDuration.GetAsString()) {
-    return;
-  }
-
-  if (aDuration.IsUnrestrictedDouble()) {
-    mTiming.mDuration.SetAsUnrestrictedDouble() =
-      aDuration.GetAsUnrestrictedDouble();
-  } else {
-    mTiming.mDuration.SetAsString() = aDuration.GetAsString();
-  }
+  mTiming.mDuration = newDuration;
 
   NotifyTimingUpdate();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/animation/AnimationEffectTimingReadOnly.cpp
+++ b/dom/animation/AnimationEffectTimingReadOnly.cpp
@@ -22,16 +22,27 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(A
 
 JSObject*
 AnimationEffectTimingReadOnly::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return AnimationEffectTimingReadOnlyBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
+AnimationEffectTimingReadOnly::GetDuration(
+    OwningUnrestrictedDoubleOrString& aRetVal) const
+{
+  if (mTiming.mDuration) {
+    aRetVal.SetAsUnrestrictedDouble() = mTiming.mDuration->ToMilliseconds();
+  } else {
+    aRetVal.SetAsString().AssignLiteral("auto");
+  }
+}
+
+void
 AnimationEffectTimingReadOnly::GetEasing(nsString& aRetVal) const
 {
   if (mTiming.mFunction.isSome()) {
     mTiming.mFunction->AppendToString(aRetVal);
   } else {
     aRetVal.AssignLiteral("linear");
   }
 }
--- a/dom/animation/AnimationEffectTimingReadOnly.h
+++ b/dom/animation/AnimationEffectTimingReadOnly.h
@@ -36,20 +36,17 @@ public:
   nsISupports* GetParentObject() const { return mParent; }
   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   double Delay() const { return mTiming.mDelay.ToMilliseconds(); }
   double EndDelay() const { return mTiming.mEndDelay.ToMilliseconds(); }
   FillMode Fill() const { return mTiming.mFill; }
   double IterationStart() const { return mTiming.mIterationStart; }
   double Iterations() const { return mTiming.mIterations; }
-  void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const
-  {
-    aRetVal = mTiming.mDuration;
-  }
+  void GetDuration(OwningUnrestrictedDoubleOrString& aRetVal) const;
   PlaybackDirection Direction() const { return mTiming.mDirection; }
   void GetEasing(nsString& aRetVal) const;
 
   const TimingParams& AsTimingParams() const { return mTiming; }
   void SetTimingParams(const TimingParams& aTiming) { mTiming = aTiming; }
 
   virtual void Unlink() { }
 
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -233,22 +233,20 @@ KeyframeEffectReadOnly::GetComputedTimin
                           const Nullable<TimeDuration>& aLocalTime,
                           const TimingParams& aTiming)
 {
   const StickyTimeDuration zeroDuration;
 
   // Always return the same object to benefit from return-value optimization.
   ComputedTiming result;
 
-  if (aTiming.mDuration.IsUnrestrictedDouble()) {
-    double durationMs = aTiming.mDuration.GetAsUnrestrictedDouble();
-    if (!IsNaN(durationMs) && durationMs >= 0.0f) {
-      result.mDuration = StickyTimeDuration::FromMilliseconds(durationMs);
-    }
+  if (aTiming.mDuration && aTiming.mDuration.ref() > zeroDuration) {
+    result.mDuration = aTiming.mDuration.ref();
   }
+
   result.mIterations = IsNaN(aTiming.mIterations) || aTiming.mIterations < 0.0f ?
                        1.0f :
                        aTiming.mIterations;
   result.mIterationStart = std::max(aTiming.mIterationStart, 0.0);
 
   result.mActiveDuration = ActiveDuration(result.mDuration, result.mIterations);
   result.mEndTime = aTiming.mDelay + result.mActiveDuration +
                     aTiming.mEndDelay;
--- a/dom/animation/TimingParams.cpp
+++ b/dom/animation/TimingParams.cpp
@@ -5,30 +5,33 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/TimingParams.h"
 
 namespace mozilla {
 
 TimingParams::TimingParams(const dom::AnimationEffectTimingProperties& aRhs,
                            const dom::Element* aTarget)
-  : mDuration(aRhs.mDuration)
-  , mDelay(TimeDuration::FromMilliseconds(aRhs.mDelay))
+  : mDelay(TimeDuration::FromMilliseconds(aRhs.mDelay))
   , mEndDelay(TimeDuration::FromMilliseconds(aRhs.mEndDelay))
   , mIterations(aRhs.mIterations)
   , mIterationStart(aRhs.mIterationStart)
   , mDirection(aRhs.mDirection)
   , mFill(aRhs.mFill)
 {
+  if (aRhs.mDuration.IsUnrestrictedDouble()) {
+    mDuration.emplace(StickyTimeDuration::FromMilliseconds(
+                        aRhs.mDuration.GetAsUnrestrictedDouble()));
+  }
   mFunction = AnimationUtils::ParseEasing(aTarget, aRhs.mEasing);
 }
 
 TimingParams::TimingParams(double aDuration)
 {
-  mDuration.SetAsUnrestrictedDouble() = aDuration;
+  mDuration.emplace(StickyTimeDuration::FromMilliseconds(aDuration));
 }
 
 template <class OptionsType>
 static const dom::AnimationEffectTimingProperties&
 GetTimingProperties(const OptionsType& aOptions);
 
 template <>
 /* static */ const dom::AnimationEffectTimingProperties&
@@ -90,28 +93,17 @@ TimingParams::FromOptionsUnion(
   const Nullable<dom::ElementOrCSSPseudoElement>& aTarget)
 {
   return TimingParamsFromOptionsUnion(aOptions, aTarget);
 }
 
 bool
 TimingParams::operator==(const TimingParams& aOther) const
 {
-  bool durationEqual;
-  if (mDuration.IsUnrestrictedDouble()) {
-    durationEqual = aOther.mDuration.IsUnrestrictedDouble() &&
-                    (mDuration.GetAsUnrestrictedDouble() ==
-                     aOther.mDuration.GetAsUnrestrictedDouble());
-  } else {
-    // We consider all string values and uninitialized values as meaning "auto".
-    // Since mDuration is either a string or uninitialized, we consider it equal
-    // if aOther.mDuration is also either a string or uninitialized.
-    durationEqual = !aOther.mDuration.IsUnrestrictedDouble();
-  }
-  return durationEqual &&
+  return mDuration == aOther.mDuration &&
          mDelay == aOther.mDelay &&
          mIterations == aOther.mIterations &&
          mIterationStart == aOther.mIterationStart &&
          mDirection == aOther.mDirection &&
          mFill == aOther.mFill &&
          mFunction == aOther.mFunction;
 }
 
--- a/dom/animation/TimingParams.h
+++ b/dom/animation/TimingParams.h
@@ -39,19 +39,18 @@ struct TimingParams
 
   static TimingParams FromOptionsUnion(
     const dom::UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
     const Nullable<dom::ElementOrCSSPseudoElement>& aTarget);
   static TimingParams FromOptionsUnion(
     const dom::UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
     const Nullable<dom::ElementOrCSSPseudoElement>& aTarget);
 
-  // The unitialized state of mDuration represents "auto".
-  // Bug 1237173: We will replace this with Maybe<TimeDuration>.
-  dom::OwningUnrestrictedDoubleOrString mDuration;
+  // mDuration.isNothing() represents the "auto" value
+  Maybe<StickyTimeDuration> mDuration;
   TimeDuration mDelay;      // Initializes to zero
   TimeDuration mEndDelay;
   double mIterations = 1.0; // Can be NaN, negative, +/-Infinity
   double mIterationStart = 0.0;
   dom::PlaybackDirection mDirection = dom::PlaybackDirection::Normal;
   dom::FillMode mFill = dom::FillMode::Auto;
   Maybe<ComputedTimingFunction> mFunction;
 
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -578,18 +578,17 @@ SampleAnimations(Layer* aLayer, TimeStam
     // Since activeAnimations is true, this could mean we keep compositing
     // unnecessarily during the delay, but so long as this only happens while
     // the refresh driver is under test control that should be ok.
     if (elapsedDuration.ToSeconds() < 0) {
       continue;
     }
 
     TimingParams timing;
-    timing.mDuration.SetAsUnrestrictedDouble() =
-      animation.duration().ToMilliseconds();
+    timing.mDuration.emplace(animation.duration());
     // Currently animations run on the compositor have their delay factored
     // into their start time, hence the delay is effectively zero.
     timing.mDelay = TimeDuration(0);
     timing.mIterations = animation.iterations();
     timing.mIterationStart = animation.iterationStart();
     timing.mDirection =
       static_cast<dom::PlaybackDirection>(animation.direction());
     // Animations typically only run on the compositor during their active
@@ -828,17 +827,17 @@ AsyncCompositionManager::ApplyAsyncConte
   // The transform of a mask layer is relative to the masked layer's parent
   // layer. So whenever we apply an async transform to a layer, we need to
   // apply that same transform to the layer's own mask layer.
   // A layer can also have "ancestor" mask layers for any rounded clips from
   // its ancestor scroll frames. A scroll frame mask layer only needs to be
   // async transformed for async scrolls of this scroll frame's ancestor
   // scroll frames, not for async scrolls of this scroll frame itself.
   // In the loop below, we iterate over scroll frames from inside to outside.
-  // At each iteration, this array contains the layer's ancestor mask layers 
+  // At each iteration, this array contains the layer's ancestor mask layers
   // of all scroll frames inside the current one.
   nsTArray<Layer*> ancestorMaskLayers;
 
   for (uint32_t i = 0; i < aLayer->GetFrameMetricsCount(); i++) {
     AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(i);
     if (!controller) {
       continue;
     }
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2468,17 +2468,17 @@ nsDisplayBackgroundImage::AppendBackgrou
 
   if (!bg) {
     aList->AppendToTop(&bgItemList);
     return false;
   }
 
   const DisplayItemScrollClip* scrollClip =
     aBuilder->ClipState().GetCurrentInnermostScrollClip();
- 
+
   bool needBlendContainer = false;
 
   // Passing bg == nullptr in this macro will result in one iteration with
   // i = 0.
   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, bg->mImage) {
     if (bg->mImage.mLayers[i].mImage.IsEmpty()) {
       continue;
     }
@@ -2958,17 +2958,17 @@ nsDisplayBackgroundImage::RenderingMight
 }
 
 static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags)
 {
   nsDisplayItem* nextItem = aItem->GetAbove();
   while (nextItem && nextItem->GetType() == nsDisplayItem::TYPE_BACKGROUND) {
     nextItem = nextItem->GetAbove();
   }
-  if (nextItem && 
+  if (nextItem &&
       nextItem->Frame() == aItem->Frame() &&
       nextItem->GetType() == nsDisplayItem::TYPE_BORDER) {
     aFlags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
   }
 }
 
 void
 nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
@@ -3603,18 +3603,18 @@ nsDisplayBorder::IsInvisibleInRect(const
     // Skip this if there's a border-image (which draws a background
     // too) or if there is a border-radius (which makes the border draw
     // further in).
     return true;
   }
 
   return false;
 }
-  
-nsDisplayItemGeometry* 
+
+nsDisplayItemGeometry*
 nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
 {
   return new nsDisplayBorderGeometry(this, aBuilder);
 }
 
 void
 nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                            const nsDisplayItemGeometry* aGeometry,
@@ -3631,17 +3631,17 @@ nsDisplayBorder::ComputeInvalidationRegi
     aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
   }
 
   if (aBuilder->ShouldSyncDecodeImages() &&
       geometry->ShouldInvalidateToSyncDecodeImages()) {
     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 }
-  
+
 void
 nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
                        nsRenderingContext* aCtx) {
   nsPoint offset = ToReferenceFrame();
 
   PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
                          ? PaintBorderFlags::SYNC_DECODE_IMAGES
                          : PaintBorderFlags();
@@ -3918,17 +3918,17 @@ nsDisplayWrapList::nsDisplayWrapList(nsD
   , mHasZIndexOverride(false)
 {
   MOZ_COUNT_CTOR(nsDisplayWrapList);
 
   mBaseVisibleRect = mVisibleRect;
 
   mList.AppendToTop(aItem);
   UpdateBounds(aBuilder);
-  
+
   if (!aFrame || !aFrame->IsTransformed()) {
     return;
   }
 
   // See the previous nsDisplayWrapList constructor
   if (aItem->Frame() == aFrame) {
     mReferenceFrame = aItem->ReferenceFrame();
     mToReferenceFrame = aItem->ToReferenceFrame();
@@ -4454,17 +4454,17 @@ nsDisplayBlendContainer::BuildLayer(nsDi
   newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
 
   RefPtr<Layer> container = aManager->GetLayerBuilder()->
   BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
                          newContainerParameters, nullptr);
   if (!container) {
     return nullptr;
   }
-  
+
   container->SetForceIsolatedGroup(true);
   return container.forget();
 }
 
 LayerState
 nsDisplayBlendContainer::GetLayerState(nsDisplayListBuilder* aBuilder,
                                        LayerManager* aManager,
                                        const ContainerLayerParameters& aParameters)
@@ -4555,17 +4555,17 @@ nsDisplaySubDocument::BuildLayer(nsDispl
                                  LayerManager* aManager,
                                  const ContainerLayerParameters& aContainerParameters) {
   nsPresContext* presContext = mFrame->PresContext();
   nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
   ContainerLayerParameters params = aContainerParameters;
   if ((mFlags & GENERATE_SCROLLABLE_LAYER) &&
       rootScrollFrame->GetContent() &&
       nsLayoutUtils::HasCriticalDisplayPort(rootScrollFrame->GetContent())) {
-    params.mInLowPrecisionDisplayPort = true; 
+    params.mInLowPrecisionDisplayPort = true;
   }
 
   RefPtr<Layer> layer = nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, params);
   layer->AsContainerLayer()->SetEventRegionsOverride(mForceDispatchToContentRegion
     ? EventRegionsOverride::ForceDispatchToContent
     : EventRegionsOverride::NoOverride);
   return layer.forget();
 }
@@ -4981,17 +4981,17 @@ nsDisplayScrollInfoLayer::GetLayerState(
 
 UniquePtr<FrameMetrics>
 nsDisplayScrollInfoLayer::ComputeFrameMetrics(Layer* aLayer,
                                               const ContainerLayerParameters& aContainerParameters)
 {
   ContainerLayerParameters params = aContainerParameters;
   if (mScrolledFrame->GetContent() &&
       nsLayoutUtils::HasCriticalDisplayPort(mScrolledFrame->GetContent())) {
-    params.mInLowPrecisionDisplayPort = true; 
+    params.mInLowPrecisionDisplayPort = true;
   }
 
   nsRect viewport = mScrollFrame->GetRect() -
                     mScrollFrame->GetPosition() +
                     mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
 
   FrameMetrics metrics = nsLayoutUtils::ComputeFrameMetrics(
       mScrolledFrame, mScrollFrame, mScrollFrame->GetContent(),
@@ -5438,17 +5438,17 @@ nsDisplayTransform::GetResultingTransfor
                                                 float aAppUnitsPerPixel,
                                                 uint32_t aFlags,
                                                 const nsRect* aBoundsOverride,
                                                 nsIFrame** aOutAncestor)
 {
   return GetResultingTransformMatrixInternal(aProperties, aOrigin, aAppUnitsPerPixel,
                                              aFlags, aBoundsOverride, aOutAncestor);
 }
- 
+
 Matrix4x4
 nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
                                                 const nsPoint& aOrigin,
                                                 float aAppUnitsPerPixel,
                                                 uint32_t aFlags,
                                                 const nsRect* aBoundsOverride,
                                                 nsIFrame** aOutAncestor)
 {
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -574,17 +574,18 @@ private:
                     mozilla::css::Declaration* aFromDeclaration,
                     float aToKey, nsStyleContext* aToContext);
 
   static TimingParams TimingParamsFrom(
     const StyleAnimation& aStyleAnimation)
   {
     TimingParams timing;
 
-    timing.mDuration.SetAsUnrestrictedDouble() = aStyleAnimation.GetDuration();
+    timing.mDuration.emplace(StickyTimeDuration::FromMilliseconds(
+			       aStyleAnimation.GetDuration()));
     timing.mDelay = TimeDuration::FromMilliseconds(aStyleAnimation.GetDelay());
     timing.mIterations = aStyleAnimation.GetIterationCount();
     timing.mDirection = aStyleAnimation.GetDirection();
     timing.mFill = aStyleAnimation.GetFillMode();
 
     return timing;
   }
 
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -651,17 +651,17 @@ nsTransitionManager::ConsiderStartingTra
 
     duration *= valuePortion;
 
     startForReversingTest = oldPT->ToValue();
     reversePortion = valuePortion;
   }
 
   TimingParams timing;
-  timing.mDuration.SetAsUnrestrictedDouble() = duration;
+  timing.mDuration.emplace(StickyTimeDuration::FromMilliseconds(duration));
   timing.mDelay = TimeDuration::FromMilliseconds(delay);
   timing.mIterations = 1.0;
   timing.mDirection = dom::PlaybackDirection::Normal;
   timing.mFill = dom::FillMode::Backwards;
 
   RefPtr<ElementPropertyTransition> pt =
     new ElementPropertyTransition(aElement->OwnerDoc(), aElement,
                                   aNewStyleContext->GetPseudoType(), timing,
--- a/testing/web-platform/tests/web-animations/animatable/animate.html
+++ b/testing/web-platform/tests/web-animations/animatable/animate.html
@@ -135,11 +135,10 @@ test(function(t) {
 
 test(function(t) {
   var pseudoTarget = createPseudo(t, 'before');
   var anim = pseudoTarget.animate({ opacity: [ 0, 1 ] }, 2000);
   assert_equals(anim.effect.target, pseudoTarget,
                 'The returned Animation targets to the correct object');
 }, 'CSSPseudoElement.animate() creates an Animation object targeting ' +
    'to the correct CSSPseudoElement object');
-
 </script>
 </body>
--- a/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html
+++ b/testing/web-platform/tests/web-animations/keyframe-effect/constructor.html
@@ -496,29 +496,29 @@ var gKeyframeEffectOptionTests = [
   { desc:     "-Infinity",
     input:    -Infinity,
     expected: { duration: -Infinity } },
   { desc:     "NaN",
     input:    NaN,
     expected: { duration: NaN } },
   { desc:     "a negative value",
     input:    -1,
-    expected: { duration: -1 } },
+    expected: { duration: "auto" } },
   { desc:     "an Infinity duration",
     input:    { duration: Infinity },
     expected: { duration: Infinity } },
   { desc:     "a negative Infinity duration",
     input:    { duration: -Infinity },
     expected: { duration: -Infinity } },
   { desc:     "a NaN duration",
     input:    { duration: NaN },
     expected: { duration: NaN } },
   { desc:     "a negative duration",
     input:    { duration: -1 },
-    expected: { duration: -1 } },
+    expected: { duration: "auto" } },
   { desc:     "a string duration",
     input:    { duration: "merrychristmas" },
     expected: { duration: "merrychristmas" } },
   { desc:     "an auto duration",
     input:    { duration: "auto" },
     expected: { duration: "auto" } },
   { desc:     "an Infinity iterations",
     input:    { iterations: Infinity },