mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 596796 - SVG SMIL: Fix inconsistent state when resetting current interval; r=dholbert; a=roc
This commit is contained in:
parent
66c9a936a3
commit
98fd010267
15
content/smil/crashtests/596796-1.svg
Normal file
15
content/smil/crashtests/596796-1.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
|
||||
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
document.documentElement.appendChild(document.getElementById("a"));
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
window.addEventListener("load", boom, false);
|
||||
</script>
|
||||
|
||||
<animate end="a.begin" id="a"/>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 313 B |
@ -20,3 +20,4 @@ load 588287-1.svg
|
||||
load 588287-2.svg
|
||||
load 592477-1.xhtml
|
||||
load 594653-1.svg
|
||||
load 596796-1.svg
|
||||
|
@ -202,9 +202,6 @@ nsSMILTimedElement::nsSMILTimedElement()
|
||||
|
||||
nsSMILTimedElement::~nsSMILTimedElement()
|
||||
{
|
||||
// Put us in a consistent state in case we get any callbacks
|
||||
mElementState = STATE_POSTACTIVE;
|
||||
|
||||
// Unlink all instance times from dependent intervals
|
||||
for (PRUint32 i = 0; i < mBeginInstances.Length(); ++i) {
|
||||
mBeginInstances[i]->Unlink();
|
||||
@ -218,10 +215,8 @@ nsSMILTimedElement::~nsSMILTimedElement()
|
||||
// Notify anyone listening to our intervals that they're gone
|
||||
// (We shouldn't get any callbacks from this because all our instance times
|
||||
// are now disassociated with any intervals)
|
||||
if (mCurrentInterval) {
|
||||
mCurrentInterval->Unlink();
|
||||
mCurrentInterval = nsnull;
|
||||
}
|
||||
mElementState = STATE_POSTACTIVE;
|
||||
ResetCurrentInterval();
|
||||
|
||||
for (PRInt32 i = mOldIntervals.Length() - 1; i >= 0; --i) {
|
||||
mOldIntervals[i]->Unlink();
|
||||
@ -703,14 +698,7 @@ nsSMILTimedElement::Rewind()
|
||||
mSeekState == SEEK_BACKWARD_FROM_ACTIVE,
|
||||
"Rewind in the middle of a forwards seek?");
|
||||
|
||||
// Set the STARTUP state first so that if we get any callbacks we won't waste
|
||||
// time recalculating the current interval
|
||||
mElementState = STATE_STARTUP;
|
||||
mCurrentRepeatIteration = 0;
|
||||
|
||||
// Clear the intervals and instance times except those instance times we can't
|
||||
// regenerate (DOM calls etc.)
|
||||
RewindTiming();
|
||||
ClearIntervalProgress();
|
||||
|
||||
UnsetBeginSpec(RemoveNonDynamic);
|
||||
UnsetEndSpec(RemoveNonDynamic);
|
||||
@ -1116,6 +1104,13 @@ nsSMILTimedElement::IsTimeDependent(const nsSMILTimedElement& aOther) const
|
||||
void
|
||||
nsSMILTimedElement::BindToTree(nsIContent* aContextNode)
|
||||
{
|
||||
// If we were already active then clear all our timing information and start
|
||||
// afresh
|
||||
if (mElementState != STATE_STARTUP) {
|
||||
mSeekState = SEEK_NOT_SEEKING;
|
||||
Rewind();
|
||||
}
|
||||
|
||||
// Resolve references to other parts of the tree
|
||||
PRUint32 count = mBeginSpecs.Length();
|
||||
for (PRUint32 i = 0; i < count; ++i) {
|
||||
@ -1127,23 +1122,9 @@ nsSMILTimedElement::BindToTree(nsIContent* aContextNode)
|
||||
mEndSpecs[j]->ResolveReferences(aContextNode);
|
||||
}
|
||||
|
||||
// If this element was already in play then we may need to do a local rewind.
|
||||
nsSMILTime containerTime = GetTimeContainer()->GetCurrentTime();
|
||||
PRBool localRewind =
|
||||
mElementState != STATE_STARTUP && mCurrentInterval &&
|
||||
mCurrentInterval->Begin()->Time().GetMillis() > containerTime;
|
||||
|
||||
if (localRewind) {
|
||||
Rewind();
|
||||
// Put the time container in the seeking state -- this is necessary so we
|
||||
// don't generate unnecessary events whilst doing the backwards seek.
|
||||
GetTimeContainer()->SetCurrentTime(containerTime);
|
||||
} else {
|
||||
// Otherwise, re-register any previous milestone since it might be been
|
||||
// processed whilst we were not bound to the tree.
|
||||
mPrevRegisteredMilestone = sMaxMilestone;
|
||||
RegisterMilestone();
|
||||
}
|
||||
// Register new milestone
|
||||
mPrevRegisteredMilestone = sMaxMilestone;
|
||||
RegisterMilestone();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1269,13 +1250,13 @@ nsSMILTimedElement::ClearSpecs(TimeValueSpecList& aSpecs,
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::RewindTiming()
|
||||
nsSMILTimedElement::ClearIntervalProgress()
|
||||
{
|
||||
if (mCurrentInterval) {
|
||||
mCurrentInterval->Unlink();
|
||||
mCurrentInterval = nsnull;
|
||||
}
|
||||
mElementState = STATE_STARTUP;
|
||||
mCurrentRepeatIteration = 0;
|
||||
ResetCurrentInterval();
|
||||
|
||||
// Remove old intervals
|
||||
for (PRInt32 i = mOldIntervals.Length() - 1; i >= 0; --i) {
|
||||
mOldIntervals[i]->Unlink();
|
||||
}
|
||||
@ -1893,8 +1874,7 @@ nsSMILTimedElement::UpdateCurrentInterval(PRBool aForceChangeNotice)
|
||||
|
||||
if (mElementState == STATE_ACTIVE || mElementState == STATE_WAITING) {
|
||||
mElementState = STATE_POSTACTIVE;
|
||||
mCurrentInterval->Unlink();
|
||||
mCurrentInterval = nsnull;
|
||||
ResetCurrentInterval();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ protected:
|
||||
void ClearSpecs(TimeValueSpecList& aSpecs,
|
||||
InstanceTimeList& aInstances,
|
||||
RemovalTestFunction aRemove);
|
||||
void RewindTiming();
|
||||
void ClearIntervalProgress();
|
||||
void DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly);
|
||||
|
||||
/**
|
||||
@ -513,6 +513,18 @@ protected:
|
||||
PRBool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
|
||||
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) {
|
||||
// Transfer ownership to temp var. (This sets mCurrentInterval to null.)
|
||||
nsAutoPtr<nsSMILInterval> interval(mCurrentInterval);
|
||||
interval->Unlink();
|
||||
}
|
||||
}
|
||||
|
||||
// Hashtable callback methods
|
||||
PR_STATIC_CALLBACK(PLDHashOperator) NotifyNewIntervalCallback(
|
||||
TimeValueSpecPtrKey* aKey, void* aData);
|
||||
|
Loading…
Reference in New Issue
Block a user