nsSMILTimeValue
nsSMILTimeValueSpec::ConvertBetweenTimeContainers(
    const nsSMILTimeValue& aSrcTime,
    const nsSMILTimeContainer* aSrcContainer)
{
    // If the source time is either indefinite or unresolved the result is going
    // to be the same
    if (!aSrcTime.IsDefinite())
        return aSrcTime;

    // Convert from source time container to our parent time container
    const nsSMILTimeContainer* dstContainer = mOwner->GetTimeContainer();
    if (dstContainer == aSrcContainer)
        return aSrcTime;

    // If one of the elements is not attached to a time container then we can't do
    // any meaningful conversion
    if (!aSrcContainer || !dstContainer)
        return nsSMILTimeValue(); // unresolved

    nsSMILTimeValue docTime =
        aSrcContainer->ContainerToParentTime(aSrcTime.GetMillis());

    if (docTime.IsIndefinite())
        // This will happen if the source container is paused and we have a future
        // time. Just return the indefinite time.
        return docTime;

    NS_ABORT_IF_FALSE(docTime.IsDefinite(),
                      "ContainerToParentTime gave us an unresolved or indefinite time");

    return dstContainer->ParentToContainerTime(docTime.GetMillis());
}
bool
nsSMILTimeValueSpec::ApplyOffset(nsSMILTimeValue& aTime) const
{
    // indefinite + offset = indefinite. Likewise for unresolved times.
    if (!aTime.IsDefinite()) {
        return true;
    }

    double resultAsDouble =
        (double)aTime.GetMillis() + mParams.mOffset.GetMillis();
    if (resultAsDouble > std::numeric_limits<nsSMILTime>::max() ||
            resultAsDouble < std::numeric_limits<nsSMILTime>::min()) {
        return false;
    }
    aTime.SetMillis(aTime.GetMillis() + mParams.mOffset.GetMillis());
    return true;
}
Esempio n. 3
0
PRBool
nsSMILTimedElement::GetNextGreater(
    const nsTArray<nsSMILInstanceTime>& aList,
    const nsSMILTimeValue& aBase,
    PRInt32 &aPosition,
    nsSMILTimeValue& aResult)
{
  PRBool found;
  while ((found = GetNextGreaterOrEqual(aList, aBase, aPosition, aResult))
         && aResult.CompareTo(aBase) == 0);
  return found;
}
Esempio n. 4
0
nsSMILTimeValue
nsSMILTimedElement::ApplyMinAndMax(const nsSMILTimeValue& aDuration)
{
  if (!aDuration.IsResolved() && !aDuration.IsIndefinite()) {
    return aDuration;
  }

  if (mMax.CompareTo(mMin) < 0) {
    return aDuration;
  }

  nsSMILTimeValue result;

  if (aDuration.CompareTo(mMax) > 0) {
    result = mMax;
  } else if (aDuration.CompareTo(mMin) < 0) {
    nsSMILTimeValue repeatDur = GetRepeatDuration();
    result = (mMin.CompareTo(repeatDur) > 0) ? repeatDur : mMin;
  } else {
    result = aDuration;
  }

  return result;
}
Esempio n. 5
0
/**
 * @see SMILANIM 3.3.4
 */
nsSMILTimeValue
nsSMILTimedElement::CalcActiveEnd(const nsSMILTimeValue& aBegin,
                                  const nsSMILTimeValue& aEnd)
{
  nsSMILTimeValue result;

  NS_ASSERTION(mSimpleDur.IsResolved() || mSimpleDur.IsIndefinite(),
    "Unresolved simple duration in CalcActiveEnd.");

  if (!aBegin.IsResolved() && !aBegin.IsIndefinite()) {
    NS_ERROR("Unresolved begin time passed to CalcActiveEnd.");
    result.SetIndefinite();
    return result;
  }

  if (mRepeatDur.IsIndefinite() || aBegin.IsIndefinite()) {
    result.SetIndefinite();
  } else {
    result = GetRepeatDuration();
  }

  if (aEnd.IsResolved() && aBegin.IsResolved()) {
    nsSMILTime activeDur = aEnd.GetMillis() - aBegin.GetMillis();

    if (result.IsResolved()) {
      result.SetMillis(PR_MIN(result.GetMillis(), activeDur));
    } else {
      result.SetMillis(activeDur);
    }
  }

  result = ApplyMinAndMax(result);

  if (result.IsResolved()) {
    nsSMILTime activeEnd = result.GetMillis() + aBegin.GetMillis();
    result.SetMillis(activeEnd);
  }

  return result;
}
Esempio n. 6
0
//
// This method is based on the pseudocode given in the SMILANIM spec.
//
// See:
// http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LC-Start
//
nsresult
nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
                                    nsSMILInterval& aResult)
{
  static nsSMILTimeValue zeroTime;
  zeroTime.SetMillis(0L);

  if (mRestartMode == RESTART_NEVER && aPrevInterval)
    return NS_ERROR_FAILURE;

  // Calc starting point
  nsSMILTimeValue beginAfter;
  PRBool prevIntervalWasZeroDur = PR_FALSE;
  if (aPrevInterval) {
    beginAfter = aPrevInterval->mEnd;
    prevIntervalWasZeroDur
      = (aPrevInterval->mEnd.CompareTo(aPrevInterval->mBegin) == 0);
  } else {
    beginAfter.SetMillis(LL_MININT);
  }

  nsSMILTimeValue tempBegin;
  nsSMILTimeValue tempEnd;

  nsSMILInstanceTime::Comparator comparator;
  mBeginInstances.Sort(comparator);
  mEndInstances.Sort(comparator);

  while (PR_TRUE) {
    if (!mBeginSpecSet && beginAfter.CompareTo(zeroTime) <= 0) {
      tempBegin.SetMillis(0);
    } else {
      PRInt32 beginPos = 0;
      PRBool beginFound = GetNextGreaterOrEqual(mBeginInstances, beginAfter,
                                                beginPos, tempBegin);
      if (!beginFound)
        return NS_ERROR_FAILURE;
    }

    if (mEndInstances.Length() == 0) {
      nsSMILTimeValue indefiniteEnd;
      indefiniteEnd.SetIndefinite();

      tempEnd = CalcActiveEnd(tempBegin, indefiniteEnd);
    } else {
      PRInt32 endPos = 0;
      PRBool endFound = GetNextGreaterOrEqual(mEndInstances, tempBegin,
                                              endPos, tempEnd);

      // If the last interval ended at the same point and was zero-duration and
      // this one is too, look for another end to use instead
      if (tempEnd.CompareTo(tempBegin) == 0 && prevIntervalWasZeroDur) {
        endFound = GetNextGreater(mEndInstances, tempBegin, endPos, tempEnd);
      }

      if (!endFound) {
        if (mEndHasEventConditions || mEndInstances.Length() == 0) {
          tempEnd.SetUnresolved();
        } else {
          //
          // This is a little counter-intuitive but according to SMILANIM, if
          // all the ends are before the begin, we _don't_ just assume an
          // infinite end, it's actually a bad interval. ASV however will just
          // use an infinite end.
          //
          return NS_ERROR_FAILURE;
        }
      }

      tempEnd = CalcActiveEnd(tempBegin, tempEnd);
    }

    // If we get two zero-length intervals in a row we will potentially have an
    // infinite loop so we break it here by searching for the next begin time
    // greater than tempEnd on the next time around.
    if (tempEnd.IsResolved() && tempBegin.CompareTo(tempEnd) == 0) {
      if (prevIntervalWasZeroDur) {
        beginAfter.SetMillis(tempEnd.GetMillis()+1);
        prevIntervalWasZeroDur = PR_FALSE;
        continue;
      }
      prevIntervalWasZeroDur = PR_TRUE;
    }

    if (tempEnd.CompareTo(zeroTime) > 0 ||
     (tempBegin.CompareTo(zeroTime) == 0 && tempEnd.CompareTo(zeroTime) == 0)) {
      aResult.mBegin = tempBegin;
      aResult.mEnd = tempEnd;
      return NS_OK;
    } else if (mRestartMode == RESTART_NEVER) {
      // tempEnd <= 0 so we're going to loop which effectively means restarting
      return NS_ERROR_FAILURE;
    } else {
      beginAfter = tempEnd;
    }
  }
  NS_NOTREACHED("Hmm... we really shouldn't be here");

  return NS_ERROR_FAILURE;
}