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; }
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; }
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; }
/** * @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; }
// // 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; }