Bug 678847 part 2 - SMIL: Fix recursion with self-referential end conditions on open intervals; r=dholbert
authorBrian Birtles <birtles@gmail.com>
Fri, 02 Sep 2011 08:14:58 +0900
changeset 76428 246f74de583c9715c01e94e4450102078f87ff14
parent 76427 7a01e603335dc905ddda0e6690d09a1e45e1f7bb
child 76429 b6608d4de5f7f225c43cb637e324eb34f190533f
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersdholbert
bugs678847
milestone9.0a1
Bug 678847 part 2 - SMIL: Fix recursion with self-referential end conditions on open intervals; r=dholbert
content/smil/nsSMILTimedElement.cpp
content/smil/nsSMILTimedElement.h
--- a/content/smil/nsSMILTimedElement.cpp
+++ b/content/smil/nsSMILTimedElement.cpp
@@ -1679,24 +1679,25 @@ nsSMILTimedElement::GetNextInterval(cons
           prevIntervalWasZeroDur) {
         tempEnd = GetNextGreater(mEndInstances, tempBegin->Time(), endPos);
       }
 
       // If all the ends are before the beginning we have a bad interval UNLESS:
       // a) We never had any end attribute to begin with (and hence we should
       //    just use the active duration after allowing for the possibility of
       //    an end instance provided by a DOM call), OR
-      // b) We have an end attribute but no end instances--this is a special
-      //    case that is needed for syncbase timing so that animations of the
-      //    following sort: <animate id="a" end="a.begin+1s" ... /> can be
-      //    resolved (see SVGT 1.2 Test Suite animate-elem-221-t.svg) by first
-      //    establishing an interval of unresolved duration, OR
+      // b) We have no resolved (not incl. indefinite) end instances
+      //    (SMIL only says "if the instance list is empty"--but if we have
+      //    indefinite/unresolved instance times then there must be a good
+      //    reason we haven't used them (since they'll be >= tempBegin) such as
+      //    avoiding creating a self-referential loop. In any case, the interval
+      //    should be allowed to be open.), OR
       // c) We have end events which leave the interval open-ended.
       PRBool openEndedIntervalOk = mEndSpecs.IsEmpty() ||
-                                   mEndInstances.IsEmpty() ||
+                                   !HaveResolvedEndTimes() ||
                                    EndHasEventConditions();
       if (!tempEnd && !openEndedIntervalOk)
         return PR_FALSE; // Bad interval
 
       nsSMILTimeValue intervalEnd = tempEnd
                                   ? tempEnd->Time() : nsSMILTimeValue();
       nsSMILTimeValue activeEnd = CalcActiveEnd(tempBegin->Time(), intervalEnd);
 
@@ -2244,16 +2245,27 @@ const nsSMILInterval*
 nsSMILTimedElement::GetPreviousInterval() const
 {
   return mOldIntervals.IsEmpty()
     ? nsnull
     : mOldIntervals[mOldIntervals.Length()-1].get();
 }
 
 PRBool
+nsSMILTimedElement::HaveResolvedEndTimes() const
+{
+  if (mEndInstances.IsEmpty())
+    return PR_FALSE;
+
+  // mEndInstances is sorted so if the first time is not resolved then none of
+  // them are
+  return mEndInstances[0]->Time().IsResolved();
+}
+
+PRBool
 nsSMILTimedElement::EndHasEventConditions() const
 {
   for (PRUint32 i = 0; i < mEndSpecs.Length(); ++i) {
     if (mEndSpecs[i]->IsEventBased())
       return PR_TRUE;
   }
   return PR_FALSE;
 }
--- a/content/smil/nsSMILTimedElement.h
+++ b/content/smil/nsSMILTimedElement.h
@@ -520,16 +520,17 @@ protected:
   void              NotifyChangedInterval(nsSMILInterval* aInterval,
                                           PRBool aBeginObjectChanged,
                                           PRBool aEndObjectChanged);
 
   void              FireTimeEventAsync(PRUint32 aMsg, PRInt32 aDetail);
   const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
   const nsSMILInterval* GetPreviousInterval() const;
   PRBool            HasPlayed() const { return !mOldIntervals.IsEmpty(); }
+  PRBool            HaveResolvedEndTimes() const;
   PRBool            EndHasEventConditions() const;
 
   // Reset the current interval by first passing ownership to a temporary
   // variable so that if Unlink() results in us receiving a callback,
   // mCurrentInterval will be nsnull and we will be in a consistent state.
   void ResetCurrentInterval()
   {
     if (mCurrentInterval) {