コード例 #1
0
nsresult
nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
                                     const nsISMILAnimationElement* aSrcElement,
                                     nsSMILValue& aValue,
                                     PRBool& aPreventCachingOfSandwich) const
{
  NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
  NS_ASSERTION(aValue.IsNull(),
    "aValue should have been cleared before calling ValueFromString");

  const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
  const nsIAtom* transformType = nsGkAtoms::translate;
  if (typeAttr) {
    if (typeAttr->Type() != nsAttrValue::eAtom) {
      // Recognized values of |type| are parsed as an atom -- so if we have
      // something other than an atom, then it means our |type| was invalid.
      return NS_ERROR_FAILURE;
    }
    transformType = typeAttr->GetAtomValue();
  }

  ParseValue(aStr, transformType, aValue);
  aPreventCachingOfSandwich = PR_FALSE;
  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
コード例 #2
0
nsresult
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ValueFromString(
  const nsAString& aStr,
  const dom::SVGAnimationElement* aSrcElement,
  nsSMILValue& aValue,
  bool& aPreventCachingOfSandwich) const
{
  NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
  MOZ_ASSERT(aValue.IsNull(),
             "aValue should have been cleared before calling ValueFromString");

  const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
  const nsIAtom* transformType = nsGkAtoms::translate; // default val
  if (typeAttr) {
    if (typeAttr->Type() != nsAttrValue::eAtom) {
      // Recognized values of |type| are parsed as an atom -- so if we have
      // something other than an atom, then we know already our |type| is
      // invalid.
      return NS_ERROR_FAILURE;
    }
    transformType = typeAttr->GetAtomValue();
  }

  ParseValue(aStr, transformType, aValue);
  aPreventCachingOfSandwich = false;
  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
コード例 #3
0
void
nsSMILFloatType::Init(nsSMILValue& aValue) const
{
  NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");
  aValue.mU.mDouble = 0.0;
  aValue.mType = this;
}
コード例 #4
0
ファイル: SMILEnumType.cpp プロジェクト: AOSC-Dev/Pale-Moon
void
SMILEnumType::Init(nsSMILValue& aValue) const
{
  NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");
  aValue.mU.mUint = 0;
  aValue.mType = this;
}
コード例 #5
0
void
SMILStringType::Init(nsSMILValue& aValue) const
{
  NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");
  aValue.mU.mPtr = new nsString();
  aValue.mType = this;
}
コード例 #6
0
void
SMILBoolType::Init(nsSMILValue& aValue) const
{
  NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");
  aValue.mU.mBool = false;
  aValue.mType = this;
}
コード例 #7
0
// static
void
nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
                                    Element* aTargetElement,
                                    const nsAString& aString,
                                    nsSMILValue& aValue,
                                    bool* aIsContextSensitive)
{
  MOZ_ASSERT(aValue.IsNull(), "Outparam should be null-typed");
  nsPresContext* presContext = GetPresContextForElement(aTargetElement);
  if (!presContext) {
    NS_WARNING("Not parsing animation value; unable to get PresContext");
    return;
  }

  nsIDocument* doc = aTargetElement->GetUncomposedDoc();
  if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
                                                doc->NodePrincipal(),
                                                doc->GetDocumentURI(),
                                                0, aString, nullptr)) {
    return;
  }

  StyleAnimationValue parsedValue;
  if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
                            aString, parsedValue, aIsContextSensitive)) {
    sSingleton.Init(aValue);
    aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue);
  }
}
コード例 #8
0
void
SMILIntegerType::Init(nsSMILValue& aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");
  aValue.mU.mInt = 0;
  aValue.mType = this;
}
コード例 #9
0
void
SMILIntegerType::Init(nsSMILValue& aValue) const
{
  MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
  aValue.mU.mInt = 0;
  aValue.mType = this;
}
コード例 #10
0
// Class methods
// -------------
void
nsSMILCSSValueType::Init(nsSMILValue& aValue) const
{
  MOZ_ASSERT(aValue.IsNull(), "Unexpected SMIL value type");

  aValue.mU.mPtr = nullptr;
  aValue.mType = this;
}
コード例 #11
0
// Class methods
// -------------
void
nsSMILCSSValueType::Init(nsSMILValue& aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected SMIL value type");

  aValue.mU.mPtr = nsnull;
  aValue.mType = this;
}
コード例 #12
0
void
SVGMotionSMILType::Init(nsSMILValue& aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected SMIL type");

  aValue.mType = this;
  aValue.mU.mPtr = new MotionSegmentArray(1);
}
コード例 #13
0
ファイル: SVGMotionSMILType.cpp プロジェクト: 70599/Waterfox
void
SVGMotionSMILType::Init(nsSMILValue& aValue) const
{
  MOZ_ASSERT(aValue.IsNull(), "Unexpected SMIL type");

  aValue.mType = this;
  aValue.mU.mPtr = new MotionSegmentArray(1);
}
コード例 #14
0
void
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ParseValue(
  const nsAString& aSpec,
  const nsIAtom* aTransformType,
  nsSMILValue& aResult)
{
  MOZ_ASSERT(aResult.IsNull(), "Unexpected type for SMIL value");

  static_assert(SVGTransformSMILData::NUM_SIMPLE_PARAMS == 3,
                "nsSVGSMILTransform constructor should be expecting array "
                "with 3 params");

  float params[3] = { 0.f };
  int32_t numParsed = ParseParameterList(aSpec, params, 3);
  uint16_t transformType;

  if (aTransformType == nsGkAtoms::translate) {
    // tx [ty=0]
    if (numParsed != 1 && numParsed != 2)
      return;
    transformType = SVG_TRANSFORM_TRANSLATE;
  } else if (aTransformType == nsGkAtoms::scale) {
    // sx [sy=sx]
    if (numParsed != 1 && numParsed != 2)
      return;
    if (numParsed == 1) {
      params[1] = params[0];
    }
    transformType = SVG_TRANSFORM_SCALE;
  } else if (aTransformType == nsGkAtoms::rotate) {
    // r [cx=0 cy=0]
    if (numParsed != 1 && numParsed != 3)
      return;
    transformType = SVG_TRANSFORM_ROTATE;
  } else if (aTransformType == nsGkAtoms::skewX) {
    // x-angle
    if (numParsed != 1)
      return;
    transformType = SVG_TRANSFORM_SKEWX;
  } else if (aTransformType == nsGkAtoms::skewY) {
    // y-angle
    if (numParsed != 1)
      return;
    transformType = SVG_TRANSFORM_SKEWY;
  } else {
    return;
  }

  nsSMILValue val(SVGTransformListSMILType::Singleton());
  SVGTransformSMILData transform(transformType, params);
  if (NS_FAILED(SVGTransformListSMILType::AppendTransform(transform, val))) {
    return; // OOM
  }

  // Success! Populate our outparam with parsed value.
  aResult.Swap(val);
}
コード例 #15
0
void
SVGNumberPairSMILType::Init(nsSMILValue& aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");

  aValue.mU.mNumberPair[0] = 0;
  aValue.mU.mNumberPair[1] = 0;
  aValue.mType = this;
}
コード例 #16
0
void
SVGViewBoxSMILType::Init(nsSMILValue& aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");

  nsSVGViewBoxRect* viewBox = new nsSVGViewBoxRect();
  aValue.mU.mPtr = viewBox;
  aValue.mType = this;
}
コード例 #17
0
nsresult
nsSMILFloatType::Init(nsSMILValue& aValue) const
{
  NS_PRECONDITION(aValue.mType == this || aValue.IsNull(),
    "Unexpected value type");
  aValue.mU.mDouble = 0.0;
  aValue.mType = this;
  return NS_OK;
}
コード例 #18
0
void
SVGTransformListSMILType::Init(nsSMILValue &aValue) const
{
  NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");

  TransformArray* transforms = new TransformArray(1);
  aValue.mU.mPtr = transforms;
  aValue.mType = this;
}
コード例 #19
0
void
SVGOrientSMILType::Init(nsSMILValue& aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");

  aValue.mU.mOrient.mAngle = 0.0f;
  aValue.mU.mOrient.mUnit = SVG_ANGLETYPE_UNSPECIFIED;
  aValue.mU.mOrient.mOrientType = dom::SVG_MARKER_ORIENT_ANGLE;
  aValue.mType = this;
}
コード例 #20
0
nsresult
nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
                                     const nsISMILAnimationElement* aSrcElement,
                                     nsSMILValue& aValue,
                                     PRBool& aCanCache) const
{
  NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
  NS_ASSERTION(aValue.IsNull(),
    "aValue should have been cleared before calling ValueFromString");

  const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
  const nsIAtom* transformType = typeAttr
                               ? typeAttr->GetAtomValue()
                               : nsGkAtoms::translate;

  ParseValue(aStr, transformType, aValue);
  aCanCache = PR_TRUE;
  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
コード例 #21
0
void
SVGPointListSMILType::Init(nsSMILValue &aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");

  SVGPointListAndInfo* pointList = new SVGPointListAndInfo();

  aValue.mU.mPtr = pointList;
  aValue.mType = this;
}
コード例 #22
0
void
nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
                                   const nsIAtom* aTransformType,
                                   nsSMILValue& aResult)
{
  NS_ASSERTION(aResult.IsNull(), "Unexpected type for SMIL value");

  // nsSVGSMILTransform constructor should be expecting array with 3 params
  PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_SIMPLE_PARAMS == 3);

  float params[3] = { 0.f };
  PRInt32 numParsed = ParseParameterList(aSpec, params, 3);
  nsSVGSMILTransform::TransformType transformType;

  if (aTransformType == nsGkAtoms::translate) {
    // tx [ty=0]
    if (numParsed != 1 && numParsed != 2)
      return;
    transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE;
  } else if (aTransformType == nsGkAtoms::scale) {
    // sx [sy=sx]
    if (numParsed != 1 && numParsed != 2)
      return;
    if (numParsed == 1) {
      params[1] = params[0];
    }
    transformType = nsSVGSMILTransform::TRANSFORM_SCALE;
  } else if (aTransformType == nsGkAtoms::rotate) {
    // r [cx=0 cy=0]
    if (numParsed != 1 && numParsed != 3)
      return;
    transformType = nsSVGSMILTransform::TRANSFORM_ROTATE;
  } else if (aTransformType == nsGkAtoms::skewX) {
    // x-angle
    if (numParsed != 1)
      return;
    transformType = nsSVGSMILTransform::TRANSFORM_SKEWX;
  } else if (aTransformType == nsGkAtoms::skewY) {
    // y-angle
    if (numParsed != 1)
      return;
    transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
  } else {
    return;
  }

  nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
  nsSVGSMILTransform transform(transformType, params);
  if (NS_FAILED(nsSVGTransformSMILType::AppendTransform(transform, val))) {
    return;
  }

  // Success! Initialize our outparam with parsed value.
  aResult = val;
}
コード例 #23
0
// static
void
nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
                                    Element* aTargetElement,
                                    const nsAString& aString,
                                    nsSMILValue& aValue,
                                    bool* aIsContextSensitive)
{
  MOZ_ASSERT(aValue.IsNull(), "Outparam should be null-typed");
  nsPresContext* presContext = GetPresContextForElement(aTargetElement);
  if (!presContext) {
    NS_WARNING("Not parsing animation value; unable to get PresContext");
    return;
  }

  nsIDocument* doc = aTargetElement->GetUncomposedDoc();
  if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
                                                doc->NodePrincipal(),
                                                doc->GetDocumentURI(),
                                                0, aString, nullptr)) {
    return;
  }

  RefPtr<nsStyleContext> styleContext =
    nsComputedDOMStyle::GetStyleContext(aTargetElement, nullptr,
                                        presContext->PresShell());
  if (!styleContext) {
    return;
  }

  if (styleContext->IsServo()) {
    ServoAnimationValues parsedValues =
      ValueFromStringHelper(aPropID, aTargetElement, presContext,
                            styleContext, aString);
    if (aIsContextSensitive) {
      // FIXME: Bug 1358955 - detect context-sensitive values and set this value
      // appropriately.
      *aIsContextSensitive = false;
    }

    if (!parsedValues.IsEmpty()) {
      sSingleton.Init(aValue);
      aValue.mU.mPtr = new ValueWrapper(aPropID, Move(parsedValues));
    }
    return;
  }

  StyleAnimationValue parsedValue;
  if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
                            styleContext->AsGecko(), aString, parsedValue,
                            aIsContextSensitive)) {
    sSingleton.Init(aValue);
    aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue);
  }
}
コード例 #24
0
nsresult
nsSMILMappedAttribute::ValueFromString(const nsAString& aStr,
                                       const mozilla::dom::SVGAnimationElement* aSrcElement,
                                       nsSMILValue& aValue,
                                       bool& aPreventCachingOfSandwich) const
{
  NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);

  nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
                                      &aPreventCachingOfSandwich);
  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
コード例 #25
0
void
SVGLengthListSMILType::Init(nsSMILValue &aValue) const
{
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");

  SVGLengthListAndInfo* lengthList = new SVGLengthListAndInfo();

  // See the comment documenting Init() in our header file:
  lengthList->SetCanZeroPadList(true);

  aValue.mU.mPtr = lengthList;
  aValue.mType = this;
}
コード例 #26
0
nsresult
nsSMILMappedAttribute::ValueFromString(const nsAString& aStr,
                                       const nsISMILAnimationElement* aSrcElement,
                                       nsSMILValue& aValue,
                                       PRBool& aPreventCachingOfSandwich) const
{
  NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);

  nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
  if (aValue.IsNull()) {
    return NS_ERROR_FAILURE;
  }

  // XXXdholbert: For simplicity, just assume that all CSS values have to
  // reparsed every sample. See note in nsSMILCSSProperty::ValueFromString.
  aPreventCachingOfSandwich = PR_TRUE;
  return NS_OK;
}
コード例 #27
0
nsresult
nsSMILCSSProperty::ValueFromString(const nsAString& aStr,
                                   const nsISMILAnimationElement* aSrcElement,
                                   nsSMILValue& aValue,
                                   PRBool& aPreventCachingOfSandwich) const
{
  NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);

  nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue,
      &aPreventCachingOfSandwich);

  // XXX Due to bug 536660 (or at least that seems to be the most likely
  // culprit), when we have animation setting display:none on a <use> element,
  // if we DON'T set the property every sample, chaos ensues.
  if (!aPreventCachingOfSandwich && mPropID == eCSSProperty_display) {
    aPreventCachingOfSandwich = PR_TRUE;
  }

  return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
コード例 #28
0
// static
void
nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
                                    nsIContent* aTargetElement,
                                    const nsAString& aString,
                                    nsSMILValue& aValue)
{
  // XXXbz aTargetElement should be an Element
  NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
  nsPresContext* presContext = GetPresContextForElement(aTargetElement);
  if (!presContext) {
    NS_WARNING("Not parsing animation value; unable to get PresContext");
    return;
  }

  nsStyleAnimation::Value parsedValue;
  if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
                            aString, parsedValue)) {
    sSingleton.Init(aValue);
    aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
  }
}
コード例 #29
0
nsresult
nsSMILAnimationFunction::InterpolateResult(const nsSMILValueArray& aValues,
                                           nsSMILValue& aResult,
                                           nsSMILValue& aBaseValue)
{
  // Sanity check animation values
  if ((!IsToAnimation() && aValues.Length() < 2) ||
      (IsToAnimation()  && aValues.Length() != 1)) {
    NS_ERROR("Unexpected number of values");
    return NS_ERROR_FAILURE;
  }

  if (IsToAnimation() && aBaseValue.IsNull()) {
    return NS_ERROR_FAILURE;
  }

  // Get the normalised progress through the simple duration.
  //
  // If we have an indefinite simple duration, just set the progress to be
  // 0 which will give us the expected behaviour of the animation being fixed at
  // its starting point.
  double simpleProgress = 0.0;

  if (mSimpleDuration.IsDefinite()) {
    nsSMILTime dur = mSimpleDuration.GetMillis();

    MOZ_ASSERT(dur >= 0, "Simple duration should not be negative");
    MOZ_ASSERT(mSampleTime >= 0, "Sample time should not be negative");

    if (mSampleTime >= dur || mSampleTime < 0) {
      NS_ERROR("Animation sampled outside interval");
      return NS_ERROR_FAILURE;
    }

    if (dur > 0) {
      simpleProgress = (double)mSampleTime / dur;
    } // else leave simpleProgress at 0.0 (e.g. if mSampleTime == dur == 0)
  }

  nsresult rv = NS_OK;
  nsSMILCalcMode calcMode = GetCalcMode();

  // Force discrete calcMode for visibility since StyleAnimationValue will
  // try to interpolate it using the special clamping behavior defined for
  // CSS.
  if (nsSMILCSSValueType::PropertyFromValue(aValues[0])
        == eCSSProperty_visibility) {
    calcMode = CALC_DISCRETE;
  }

  if (calcMode != CALC_DISCRETE) {
    // Get the normalised progress between adjacent values
    const nsSMILValue* from = nullptr;
    const nsSMILValue* to = nullptr;
    // Init to -1 to make sure that if we ever forget to set this, the
    // MOZ_ASSERT that tests that intervalProgress is in range will fail.
    double intervalProgress = -1.f;
    if (IsToAnimation()) {
      from = &aBaseValue;
      to = &aValues[0];
      if (calcMode == CALC_PACED) {
        // Note: key[Times/Splines/Points] are ignored for calcMode="paced"
        intervalProgress = simpleProgress;
      } else {
        double scaledSimpleProgress =
          ScaleSimpleProgress(simpleProgress, calcMode);
        intervalProgress = ScaleIntervalProgress(scaledSimpleProgress, 0);
      }
    } else if (calcMode == CALC_PACED) {
      rv = ComputePacedPosition(aValues, simpleProgress,
                                intervalProgress, from, to);
      // Note: If the above call fails, we'll skip the "from->Interpolate"
      // call below, and we'll drop into the CALC_DISCRETE section
      // instead. (as the spec says we should, because our failure was
      // presumably due to the values being non-additive)
    } else { // calcMode == CALC_LINEAR or calcMode == CALC_SPLINE
      double scaledSimpleProgress =
        ScaleSimpleProgress(simpleProgress, calcMode);
      uint32_t index = (uint32_t)floor(scaledSimpleProgress *
                                       (aValues.Length() - 1));
      from = &aValues[index];
      to = &aValues[index + 1];
      intervalProgress =
        scaledSimpleProgress * (aValues.Length() - 1) - index;
      intervalProgress = ScaleIntervalProgress(intervalProgress, index);
    }

    if (NS_SUCCEEDED(rv)) {
      MOZ_ASSERT(from, "NULL from-value during interpolation");
      MOZ_ASSERT(to, "NULL to-value during interpolation");
      MOZ_ASSERT(0.0f <= intervalProgress && intervalProgress < 1.0f,
                 "Interval progress should be in the range [0, 1)");
      rv = from->Interpolate(*to, intervalProgress, aResult);
    }
  }

  // Discrete-CalcMode case
  // Note: If interpolation failed (isn't supported for this type), the SVG
  // spec says to force discrete mode.
  if (calcMode == CALC_DISCRETE || NS_FAILED(rv)) {
    double scaledSimpleProgress =
      ScaleSimpleProgress(simpleProgress, CALC_DISCRETE);

    // Floating-point errors can mean that, for example, a sample time of 29s in
    // a 100s duration animation gives us a simple progress of 0.28999999999
    // instead of the 0.29 we'd expect. Normally this isn't a noticeable
    // problem, but when we have sudden jumps in animation values (such as is
    // the case here with discrete animation) we can get unexpected results.
    //
    // To counteract this, before we perform a floor() on the animation
    // progress, we add a tiny fudge factor to push us into the correct interval
    // in cases where floating-point errors might cause us to fall short.
    static const double kFloatingPointFudgeFactor = 1.0e-16;
    if (scaledSimpleProgress + kFloatingPointFudgeFactor <= 1.0) {
      scaledSimpleProgress += kFloatingPointFudgeFactor;
    }

    if (IsToAnimation()) {
      // We don't follow SMIL 3, 12.6.4, where discrete to animations
      // are the same as <set> animations.  Instead, we treat it as a
      // discrete animation with two values (the underlying value and
      // the to="" value), and honor keyTimes="" as well.
      uint32_t index = (uint32_t)floor(scaledSimpleProgress * 2);
      aResult = index == 0 ? aBaseValue : aValues[0];
    } else {
      uint32_t index = (uint32_t)floor(scaledSimpleProgress * aValues.Length());
      aResult = aValues[index];
    }
    rv = NS_OK;
  }
  return rv;
}
コード例 #30
0
void
nsSMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
                                       nsSMILValue& aResult)
{
  mHasChanged = false;
  mPrevSampleWasSingleValueAnimation = false;
  mWasSkippedInPrevSample = false;

  // Skip animations that are inactive or in error
  if (!IsActiveOrFrozen() || mErrorFlags != 0)
    return;

  // Get the animation values
  nsSMILValueArray values;
  nsresult rv = GetValues(aSMILAttr, values);
  if (NS_FAILED(rv))
    return;

  // Check that we have the right number of keySplines and keyTimes
  CheckValueListDependentAttrs(values.Length());
  if (mErrorFlags != 0)
    return;

  // If this interval is active, we must have a non-negative mSampleTime
  MOZ_ASSERT(mSampleTime >= 0 || !mIsActive,
             "Negative sample time for active animation");
  MOZ_ASSERT(mSimpleDuration.IsResolved() || mLastValue,
             "Unresolved simple duration for active or frozen animation");

  // If we want to add but don't have a base value then just fail outright.
  // This can happen when we skipped getting the base value because there's an
  // animation function in the sandwich that should replace it but that function
  // failed unexpectedly.
  bool isAdditive = IsAdditive();
  if (isAdditive && aResult.IsNull())
    return;

  nsSMILValue result;

  if (values.Length() == 1 && !IsToAnimation()) {

    // Single-valued animation
    result = values[0];
    mPrevSampleWasSingleValueAnimation = true;

  } else if (mLastValue) {

    // Sampling last value
    const nsSMILValue& last = values[values.Length() - 1];
    result = last;

    // See comment in AccumulateResult: to-animation does not accumulate
    if (!IsToAnimation() && GetAccumulate() && mRepeatIteration) {
      // If the target attribute type doesn't support addition Add will
      // fail leaving result = last
      result.Add(last, mRepeatIteration);
    }

  } else {

    // Interpolation
    if (NS_FAILED(InterpolateResult(values, result, aResult)))
      return;

    if (NS_FAILED(AccumulateResult(values, result)))
      return;
  }

  // If additive animation isn't required or isn't supported, set the value.
  if (!isAdditive || NS_FAILED(aResult.SandwichAdd(result))) {
    aResult = Move(result);
  }
}