diff --git a/content/smil/crashtests/554202-1.svg b/content/smil/crashtests/554202-1.svg
new file mode 100644
index 00000000000..f3d692ca029
--- /dev/null
+++ b/content/smil/crashtests/554202-1.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/content/smil/crashtests/554202-2.svg b/content/smil/crashtests/554202-2.svg
new file mode 100644
index 00000000000..a3bbb3195cb
--- /dev/null
+++ b/content/smil/crashtests/554202-2.svg
@@ -0,0 +1,19 @@
+
diff --git a/content/smil/crashtests/crashtests.list b/content/smil/crashtests/crashtests.list
index 6d1f24401f0..25b994300df 100644
--- a/content/smil/crashtests/crashtests.list
+++ b/content/smil/crashtests/crashtests.list
@@ -10,6 +10,8 @@ load 537157-1.svg
load 541297-1.svg
load 547333-1.svg
load 548899-1.svg
+load 554202-1.svg
+load 554202-2.svg
load 554141-1.svg
load 555026-1.svg
load 556841-1.svg
diff --git a/content/smil/nsSMILInstanceTime.cpp b/content/smil/nsSMILInstanceTime.cpp
index 98b2f5a39db..f77b3d25446 100644
--- a/content/smil/nsSMILInstanceTime.cpp
+++ b/content/smil/nsSMILInstanceTime.cpp
@@ -163,11 +163,10 @@ nsSMILInstanceTime::HandleDeletedInterval()
}
PRBool
-nsSMILInstanceTime::IsDependent(const nsSMILInstanceTime& aOther,
- PRUint32 aRecursionDepth) const
+nsSMILInstanceTime::IsDependent(const nsSMILInstanceTime& aOther) const
{
- NS_ABORT_IF_FALSE(aRecursionDepth < 1000,
- "We seem to have created a cycle between instance times");
+ if (mVisited || mChainEnd)
+ return PR_FALSE;
const nsSMILInstanceTime* myBaseTime = GetBaseTime();
if (!myBaseTime)
@@ -176,7 +175,9 @@ nsSMILInstanceTime::IsDependent(const nsSMILInstanceTime& aOther,
if (myBaseTime == &aOther)
return PR_TRUE;
- return myBaseTime->IsDependent(aOther, ++aRecursionDepth);
+ // mVisited is mutable
+ AutoBoolSetter setVisited(const_cast(this)->mVisited);
+ return myBaseTime->IsDependent(aOther);
}
void
@@ -185,8 +186,6 @@ nsSMILInstanceTime::SetBaseInterval(nsSMILInterval* aBaseInterval)
NS_ABORT_IF_FALSE(!mBaseInterval,
"Attempting to reassociate an instance time with a different interval.");
- // Make sure we don't end up creating a cycle between the dependent time
- // pointers.
if (aBaseInterval) {
NS_ABORT_IF_FALSE(mCreator,
"Attempting to create a dependent instance time without reference "
@@ -194,10 +193,6 @@ nsSMILInstanceTime::SetBaseInterval(nsSMILInterval* aBaseInterval)
if (!mCreator)
return;
- const nsSMILInstanceTime* dependentTime = mCreator->DependsOnBegin() ?
- aBaseInterval->Begin() :
- aBaseInterval->End();
- dependentTime->BreakPotentialCycle(this);
aBaseInterval->AddDependentTime(*this);
}
@@ -219,21 +214,3 @@ nsSMILInstanceTime::GetBaseTime() const
return mCreator->DependsOnBegin() ? mBaseInterval->Begin() :
mBaseInterval->End();
}
-
-void
-nsSMILInstanceTime::BreakPotentialCycle(
- const nsSMILInstanceTime* aNewTail) const
-{
- const nsSMILInstanceTime* myBaseTime = GetBaseTime();
- if (!myBaseTime)
- return;
-
- if (myBaseTime == aNewTail) {
- // Making aNewTail the new tail of the chain would create a cycle so we
- // prevent this by unlinking the pointer to aNewTail.
- mBaseInterval->RemoveDependentTime(*this);
- return;
- }
-
- myBaseTime->BreakPotentialCycle(aNewTail);
-}
diff --git a/content/smil/nsSMILInstanceTime.h b/content/smil/nsSMILInstanceTime.h
index 9a010c57c13..14e4f71a52f 100644
--- a/content/smil/nsSMILInstanceTime.h
+++ b/content/smil/nsSMILInstanceTime.h
@@ -109,8 +109,7 @@ public:
mTime = aNewTime;
}
- PRBool IsDependent(const nsSMILInstanceTime& aOther,
- PRUint32 aRecursionDepth = 0) const;
+ PRBool IsDependent(const nsSMILInstanceTime& aOther) const;
PRBool SameTimeAndBase(const nsSMILInstanceTime& aOther) const
{
@@ -126,7 +125,6 @@ public:
protected:
void SetBaseInterval(nsSMILInterval* aBaseInterval);
- void BreakPotentialCycle(const nsSMILInstanceTime* aNewTail) const;
const nsSMILInstanceTime* GetBaseTime() const;
nsSMILTimeValue mTime;
@@ -155,8 +153,11 @@ protected:
PRUint32 mSerial; // A serial number used by the containing class to
// specify the sort order for instance times with the
// same mTime.
- PRPackedBool mVisited;
- PRPackedBool mChainEnd;
+ PRPackedBool mVisited; // (mutable) Cycle tracking
+ PRPackedBool mChainEnd; // Flag to indicate that this instance time is part
+ // of some cyclic dependency and that in order to
+ // avoid infinite recursion the cycle should not be
+ // followed any further than this point.
nsSMILTimeValueSpec* mCreator; // The nsSMILTimeValueSpec object that created
// us. (currently only needed for syncbase
diff --git a/layout/reftests/svg/smil/syncbase/reftest.list b/layout/reftests/svg/smil/syncbase/reftest.list
index e9a25e851e0..effd37fa737 100644
--- a/layout/reftests/svg/smil/syncbase/reftest.list
+++ b/layout/reftests/svg/smil/syncbase/reftest.list
@@ -83,6 +83,7 @@
== sandwich-priority-9.svg green-box-ref.svg
== sandwich-priority-10.svg green-box-ref.svg
== sandwich-priority-11.svg green-box-ref.svg
+== sandwich-priority-12.svg green-box-ref.svg
# Cross-time container dependencies
== cross-container-1.xhtml green-box-ref.xhtml
diff --git a/layout/reftests/svg/smil/syncbase/sandwich-priority-12.svg b/layout/reftests/svg/smil/syncbase/sandwich-priority-12.svg
new file mode 100644
index 00000000000..8164e56fa8f
--- /dev/null
+++ b/layout/reftests/svg/smil/syncbase/sandwich-priority-12.svg
@@ -0,0 +1,24 @@
+