mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 867183 - Don't recursively notify in FinishedSomeDecoding. r=jlebar
This commit is contained in:
parent
7acb86292c
commit
12db2a480c
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user