Bug 867183 - Don't recursively notify in FinishedSomeDecoding. r=jlebar

This commit is contained in:
Seth Fowler 2013-11-26 17:22:44 -08:00
parent 293eb0cabf
commit f210c6be6f
2 changed files with 65 additions and 27 deletions

View File

@ -394,6 +394,8 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
mDecoder(nullptr),
mBytesDecoded(0),
mInDecoder(false),
mStatusDiff(ImageStatusDiff::NoChange()),
mNotifying(false),
mHasSize(false),
mDecodeOnDraw(false),
mMultipart(false),
@ -2924,6 +2926,33 @@ RasterImage::GetFramesNotified(uint32_t *aFramesNotified)
}
#endif
nsresult
RasterImage::RequestDecodeIfNeeded(nsresult aStatus,
eShutdownIntent aIntent,
bool aDone,
bool aWasSize)
{
MOZ_ASSERT(NS_IsMainThread());
// If we were a size decode and a full decode was requested, now's the time.
if (NS_SUCCEEDED(aStatus) &&
aIntent != eShutdownIntent_Error &&
aDone &&
aWasSize &&
mWantFullDecode) {
mWantFullDecode = false;
// If we're not meant to be storing source data and we just got the size,
// we need to synchronously flush all the data we got to a full decoder.
// When that decoder is shut down, we'll also clear our source data.
return StoringSourceData() ? RequestDecode()
: SyncDecode();
}
// We don't need a full decode right now, so just return the existing status.
return aStatus;
}
nsresult
RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_Done */,
DecodeRequest* aRequest /* = nullptr */)
@ -2992,39 +3021,40 @@ RasterImage::FinishedSomeDecoding(eShutdownIntent aIntent /* = eShutdownIntent_D
}
}
ImageStatusDiff diff;
if (request) {
diff = image->mStatusTracker->Difference(request->mStatusTracker);
image->mStatusTracker->ApplyDifference(diff);
ImageStatusDiff diff =
request ? image->mStatusTracker->Difference(request->mStatusTracker)
: image->mStatusTracker->DecodeStateAsDifference();
image->mStatusTracker->ApplyDifference(diff);
// Notifications can't go out with the decoding lock held, nor can we call
// RequestDecodeIfNeeded, so unlock for the rest of the function.
MutexAutoUnlock unlock(mDecodingMutex);
if (mNotifying) {
// Accumulate the status changes. We don't permit recursive notifications
// because they cause subtle concurrency bugs, so we'll delay sending out
// the notifications until we pop back to the lowest invocation of
// FinishedSomeDecoding on the stack.
NS_WARNING("Recursively notifying in RasterImage::FinishedSomeDecoding!");
mStatusDiff.Combine(diff);
} else {
diff = image->mStatusTracker->DecodeStateAsDifference();
}
MOZ_ASSERT(mStatusDiff.IsNoChange(), "Shouldn't have an accumulated change at this point");
{
// Notifications can't go out with the decoding lock held.
MutexAutoUnlock unlock(mDecodingMutex);
while (!diff.IsNoChange()) {
// Tell the observers what happened.
mNotifying = true;
image->mStatusTracker->SyncNotifyDifference(diff);
mNotifying = false;
// Then, tell the observers what has happened.
image->mStatusTracker->SyncNotifyDifference(diff);
// If we were a size decode and a full decode was requested, now's the time.
if (NS_SUCCEEDED(rv) && aIntent != eShutdownIntent_Error && done &&
wasSize && image->mWantFullDecode) {
image->mWantFullDecode = false;
// If we're not meant to be storing source data and we just got the size,
// we need to synchronously flush all the data we got to a full decoder.
// When that decoder is shut down, we'll also clear our source data.
if (!image->StoringSourceData()) {
rv = image->SyncDecode();
} else {
rv = image->RequestDecode();
}
// Gather any status changes that may have occurred as a result of sending
// out the previous notifications. If there were any, we'll send out
// notifications for them next.
diff = mStatusDiff;
mStatusDiff = ImageStatusDiff::NoChange();
}
}
return rv;
return RequestDecodeIfNeeded(rv, aIntent, done, wasSize);
}
NS_IMPL_ISUPPORTS1(RasterImage::DecodePool,

View File

@ -657,6 +657,10 @@ private: // data
bool mInDecoder;
// END LOCKED MEMBER VARIABLES
// Notification state. Used to avoid recursive notifications.
ImageStatusDiff mStatusDiff;
bool mNotifying:1;
// Boolean flags (clustered together to conserve space):
bool mHasSize:1; // Has SetSize() been called?
bool mDecodeOnDraw:1; // Decoding on draw?
@ -688,6 +692,10 @@ private: // data
bool mPendingError:1;
// Decoding
nsresult RequestDecodeIfNeeded(nsresult aStatus,
eShutdownIntent aIntent,
bool aDone,
bool aWasSize);
nsresult WantDecodedFrames();
nsresult SyncDecode();
nsresult InitDecoder(bool aDoSizeDecode);