void
nsSMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
                                       nsSMILValue& aResult)
{
  mHasChanged = PR_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
  NS_ABORT_IF_FALSE(mSampleTime >= 0 || !mIsActive,
      "Negative sample time for active animation");
  NS_ABORT_IF_FALSE(mSimpleDuration.IsResolved() ||
      mSimpleDuration.IsIndefinite() || mLastValue,
      "Unresolved simple duration for active or frozen animation");

  nsSMILValue result(aResult.mType);

  if (mSimpleDuration.IsIndefinite() ||
      (values.Length() == 1 && TreatSingleValueAsStatic())) {
    // Indefinite duration or only one value set: Always set the first value
    result = values[0];

  } 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 if (!mFrozenValue.IsNull() && !mHasChanged) {

    // Frozen to animation
    result = mFrozenValue;

  } else {

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

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

    if (IsToAnimation() && mIsFrozen) {
      mFrozenValue = result;
    }
  }

  // If additive animation isn't required or isn't supported, set the value.
  if (!IsAdditive() || NS_FAILED(aResult.SandwichAdd(result))) {
    aResult.Swap(result);
    // Note: The old value of aResult is now in |result|, and it will get
    // cleaned up when |result| goes out of scope, when this function returns.
  }
}
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
    NS_ABORT_IF_FALSE(mSampleTime >= 0 || !mIsActive,
                      "Negative sample time for active animation");
    NS_ABORT_IF_FALSE(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.Swap(result);
        // Note: The old value of aResult is now in |result|, and it will get
        // cleaned up when |result| goes out of scope, when this function returns.
    }
}