Bug 1389988 - Handle a data race between a new sync decode request and a pending decoder. r=tnikkel

If there is an active provider which has yet to produce a frame, any
calls to SurfaceCache::Lookup will return MatchType::PENDING. If
RasterImage::Lookup gets the above result while given FLAG_SYNC_DECODE,
it will attempt to start a new decoder. It is entirely possible that
when we try to insert the new provider into the SurfaceCache, it cannot
because the original provider finally did produce something. In that
case we should abandon attempting to redecode and retry our lookup.
This commit is contained in:
Andrew Osmond
2018-02-09 08:51:28 -05:00
parent c068ba453b
commit a2da8f23eb
3 changed files with 74 additions and 29 deletions

View File

@@ -109,17 +109,18 @@ DecoderFactory::GetDecoder(DecoderType aType,
return decoder.forget();
}
/* static */ already_AddRefed<IDecodingTask>
/* static */ nsresult
DecoderFactory::CreateDecoder(DecoderType aType,
NotNull<RasterImage*> aImage,
NotNull<SourceBuffer*> aSourceBuffer,
const IntSize& aIntrinsicSize,
const IntSize& aOutputSize,
DecoderFlags aDecoderFlags,
SurfaceFlags aSurfaceFlags)
SurfaceFlags aSurfaceFlags,
IDecodingTask** aOutTask)
{
if (aType == DecoderType::UNKNOWN) {
return nullptr;
return NS_ERROR_INVALID_ARG;
}
// Create an anonymous decoder. Interaction with the SurfaceCache and the
@@ -135,8 +136,9 @@ DecoderFactory::CreateDecoder(DecoderType aType,
decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
decoder->SetSurfaceFlags(aSurfaceFlags);
if (NS_FAILED(decoder->Init())) {
return nullptr;
nsresult rv = decoder->Init();
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Create a DecodedSurfaceProvider which will manage the decoding process and
@@ -151,25 +153,32 @@ DecoderFactory::CreateDecoder(DecoderType aType,
// Attempt to insert the surface provider into the surface cache right away so
// we won't trigger any more decoders with the same parameters.
if (SurfaceCache::Insert(provider) != InsertOutcome::SUCCESS) {
return nullptr;
switch (SurfaceCache::Insert(provider)) {
case InsertOutcome::SUCCESS:
break;
case InsertOutcome::FAILURE_ALREADY_PRESENT:
return NS_ERROR_ALREADY_INITIALIZED;
default:
return NS_ERROR_FAILURE;
}
// Return the surface provider in its IDecodingTask guise.
RefPtr<IDecodingTask> task = provider.get();
return task.forget();
task.forget(aOutTask);
return NS_OK;
}
/* static */ already_AddRefed<IDecodingTask>
/* static */ nsresult
DecoderFactory::CreateAnimationDecoder(DecoderType aType,
NotNull<RasterImage*> aImage,
NotNull<SourceBuffer*> aSourceBuffer,
const IntSize& aIntrinsicSize,
DecoderFlags aDecoderFlags,
SurfaceFlags aSurfaceFlags)
SurfaceFlags aSurfaceFlags,
IDecodingTask** aOutTask)
{
if (aType == DecoderType::UNKNOWN) {
return nullptr;
return NS_ERROR_INVALID_ARG;
}
MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG,
@@ -186,8 +195,9 @@ DecoderFactory::CreateAnimationDecoder(DecoderType aType,
decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
decoder->SetSurfaceFlags(aSurfaceFlags);
if (NS_FAILED(decoder->Init())) {
return nullptr;
nsresult rv = decoder->Init();
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Create an AnimationSurfaceProvider which will manage the decoding process
@@ -199,13 +209,19 @@ DecoderFactory::CreateAnimationDecoder(DecoderType aType,
// Attempt to insert the surface provider into the surface cache right away so
// we won't trigger any more decoders with the same parameters.
if (SurfaceCache::Insert(provider) != InsertOutcome::SUCCESS) {
return nullptr;
switch (SurfaceCache::Insert(provider)) {
case InsertOutcome::SUCCESS:
break;
case InsertOutcome::FAILURE_ALREADY_PRESENT:
return NS_ERROR_ALREADY_INITIALIZED;
default:
return NS_ERROR_FAILURE;
}
// Return the surface provider in its IDecodingTask guise.
RefPtr<IDecodingTask> task = provider.get();
return task.forget();
task.forget(aOutTask);
return NS_OK;
}
/* static */ already_AddRefed<IDecodingTask>