コード例 #1
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
    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.
    }
}
コード例 #2
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.IsResolved()) {
    nsSMILTime dur = mSimpleDuration.GetMillis();

    NS_ABORT_IF_FALSE(dur >= 0, "Simple duration should not be negative");
    NS_ABORT_IF_FALSE(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();
  if (calcMode != CALC_DISCRETE) {
    // Get the normalised progress between adjacent values
    const nsSMILValue* from = nsnull;
    const nsSMILValue* to = nsnull;
    // Init to -1 to make sure that if we ever forget to set this, the
    // NS_ABORT_IF_FALSE 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);
      PRUint32 index = (PRUint32)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)) {
      NS_ABORT_IF_FALSE(from, "NULL from-value during interpolation");
      NS_ABORT_IF_FALSE(to, "NULL to-value during interpolation");
      NS_ABORT_IF_FALSE(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);
    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.
      PRUint32 index = (PRUint32)floor(scaledSimpleProgress * 2);
      aResult = index == 0 ? aBaseValue : aValues[0];
    } else {
      PRUint32 index = (PRUint32)floor(scaledSimpleProgress * aValues.Length());
      aResult = aValues[index];
    }
    rv = NS_OK;
  }
  return rv;
}