NotNull<AllocPolicy*> GlobalAllocPolicy::Instance(TrackType aTrack) { StaticMutexAutoLock lock(sMutex); if (aTrack == TrackType::kAudioTrack) { static RefPtr<AllocPolicyImpl> sAudioPolicy = []() { SystemGroup::Dispatch( TaskCategory::Other, NS_NewRunnableFunction( "GlobalAllocPolicy::GlobalAllocPolicy:Audio", []() { ClearOnShutdown(&sAudioPolicy, ShutdownPhase::ShutdownThreads); })); return new AllocPolicyImpl(MediaDecoderLimitDefault()); }(); return WrapNotNull(sAudioPolicy.get()); } static RefPtr<AllocPolicyImpl> sVideoPolicy = []() { SystemGroup::Dispatch( TaskCategory::Other, NS_NewRunnableFunction( "GlobalAllocPolicy::GlobalAllocPolicy:Audio", []() { ClearOnShutdown(&sVideoPolicy, ShutdownPhase::ShutdownThreads); })); return new AllocPolicyImpl(MediaDecoderLimitDefault()); }(); return WrapNotNull(sVideoPolicy.get()); }
/* static */ already_AddRefed<IDecodingTask> DecoderFactory::CreateMetadataDecoder(DecoderType aType, NotNull<RasterImage*> aImage, NotNull<SourceBuffer*> aSourceBuffer, int aSampleSize) { if (aType == DecoderType::UNKNOWN) { return nullptr; } RefPtr<Decoder> decoder = GetDecoder(aType, aImage, /* aIsRedecode = */ false); MOZ_ASSERT(decoder, "Should have a decoder now"); // Initialize the decoder. decoder->SetMetadataDecode(true); decoder->SetIterator(aSourceBuffer->Iterator()); decoder->SetSampleSize(aSampleSize); decoder->Init(); if (NS_FAILED(decoder->GetDecoderError())) { return nullptr; } RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder)); return task.forget(); }
void AnimationDecodingTask::Run() { while (true) { LexerResult result = mDecoder->Decode(WrapNotNull(this)); if (result.is<TerminalState>()) { NotifyDecodeComplete(mDecoder->GetImage(), mDecoder); return; // We're done. } MOZ_ASSERT(result.is<Yield>()); // Notify for the progress we've made so far. if (mDecoder->HasProgress()) { NotifyProgress(mDecoder->GetImage(), mDecoder); } if (result == LexerResult(Yield::NEED_MORE_DATA)) { // We can't make any more progress right now. The decoder itself will // ensure that we get reenqueued when more data is available; just return // for now. return; } // Right now we don't do anything special for other kinds of yields, so just // keep working. } }
/* static */ already_AddRefed<IDecodingTask> DecoderFactory::CreateAnimationDecoder(DecoderType aType, NotNull<RasterImage*> aImage, NotNull<SourceBuffer*> aSourceBuffer, DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags) { if (aType == DecoderType::UNKNOWN) { return nullptr; } MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG, "Calling CreateAnimationDecoder for non-animating DecoderType"); RefPtr<Decoder> decoder = GetDecoder(aType, aImage, /* aIsRedecode = */ true); MOZ_ASSERT(decoder, "Should have a decoder now"); // Initialize the decoder. decoder->SetMetadataDecode(false); decoder->SetIterator(aSourceBuffer->Iterator()); decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE); decoder->SetSurfaceFlags(aSurfaceFlags); decoder->Init(); if (NS_FAILED(decoder->GetDecoderError())) { return nullptr; } RefPtr<IDecodingTask> task = new DecodingTask(WrapNotNull(decoder)); return task.forget(); }
HRESULT AccessibleHandler::ReadHandlerPayload(IStream* aStream, REFIID aIid) { if (!aStream) { return E_INVALIDARG; } mscom::StructFromStream deserializer(aStream); if (!deserializer) { return E_FAIL; } if (deserializer.IsEmpty()) { return S_FALSE; } if (!deserializer.Read(&mCachedData, &IA2Payload_Decode)) { return E_FAIL; } if (!mCachedData.mGeckoBackChannel) { return S_OK; } RefPtr<AccessibleHandlerControl> ctl(gControlFactory.GetOrCreateSingleton()); if (!ctl) { return E_OUTOFMEMORY; } return ctl->Register(WrapNotNull(mCachedData.mGeckoBackChannel)); }
static void AnnotateTypelibRegistrationForHive(JSONWriter& aJson, HKEY aHive, const nsAString& aTypelibId, const nsAString& aTypelibVersion, const JSONWriter::CollectionStyle aStyle) { nsAutoString typelibSubKey; typelibSubKey.AppendLiteral(kSoftwareClasses); typelibSubKey.AppendLiteral(kTypeLib); typelibSubKey.AppendLiteral(kBackslash); typelibSubKey.Append(aTypelibId); typelibSubKey.AppendLiteral(kBackslash); typelibSubKey.Append(aTypelibVersion); nsAutoString typelibDesc; if (GetStringValue(aHive, typelibSubKey, kDefaultValue, typelibDesc)) { aJson.StringProperty("Description", NS_ConvertUTF16toUTF8(typelibDesc).get()); } nsAutoString flagsSubKey(typelibSubKey); flagsSubKey.AppendLiteral(kBackslash); flagsSubKey.AppendLiteral(kFlags); nsAutoString typelibFlags; if (GetStringValue(aHive, flagsSubKey, kDefaultValue, typelibFlags)) { aJson.StringProperty("Flags", NS_ConvertUTF16toUTF8(typelibFlags).get()); } HKEY rawTypelibKey; LONG result = RegOpenKeyEx(aHive, typelibSubKey.get(), 0, KEY_READ, &rawTypelibKey); if (result != ERROR_SUCCESS) { return; } nsAutoRegKey typelibKey(rawTypelibKey); const size_t kMaxLcidCharLen = 9; WCHAR keyName[kMaxLcidCharLen]; for (DWORD index = 0; result == ERROR_SUCCESS; ++index) { DWORD keyNameLength = ArrayLength(keyName); result = RegEnumKeyEx(typelibKey, index, keyName, &keyNameLength, nullptr, nullptr, nullptr, nullptr); unsigned long lcid; if (result == ERROR_SUCCESS && ConvertLCID(keyName, WrapNotNull(&lcid))) { nsDependentString strLcid(keyName, keyNameLength); aJson.StartObjectProperty(NS_ConvertUTF16toUTF8(strLcid).get(), aStyle); AnnotateTypelibPlatform(aJson, typelibKey, strLcid, kWin32, aStyle); #if defined(HAVE_64BIT_BUILD) AnnotateTypelibPlatform(aJson, typelibKey, strLcid, kWin64, aStyle); #endif aJson.EndObject(); } } }
void AnimationSurfaceProvider::Run() { MutexAutoLock lock(mDecodingMutex); if (!mDecoder || !mImage) { MOZ_ASSERT_UNREACHABLE("Running after decoding finished?"); return; } while (true) { // Run the decoder. LexerResult result = mDecoder->Decode(WrapNotNull(this)); if (result.is<TerminalState>()) { // We may have a new frame now, but it's not guaranteed - a decoding // failure or truncated data may mean that no new frame got produced. // Since we're not sure, rather than call CheckForNewFrameAtYield() here // we call CheckForNewFrameAtTerminalState(), which handles both of these // possibilities. CheckForNewFrameAtTerminalState(); // We're done! FinishDecoding(); return; } // Notify for the progress we've made so far. if (mDecoder->HasProgress()) { NotifyProgress(WrapNotNull(mImage), WrapNotNull(mDecoder)); } if (result == LexerResult(Yield::NEED_MORE_DATA)) { // We can't make any more progress right now. The decoder itself will ensure // that we get reenqueued when more data is available; just return for now. return; } // There's new output available - a new frame! Grab it. MOZ_ASSERT(result == LexerResult(Yield::OUTPUT_AVAILABLE)); CheckForNewFrameAtYield(); } }
void AnimationSurfaceProvider::FinishDecoding() { mDecodingMutex.AssertCurrentThreadOwns(); MOZ_ASSERT(mImage); MOZ_ASSERT(mDecoder); // Send notifications. NotifyDecodeComplete(WrapNotNull(mImage), WrapNotNull(mDecoder)); // Destroy our decoder; we don't need it anymore. mDecoder = nullptr; // We don't need a reference to our image anymore, either, and we don't want // one. We may be stored in the surface cache for a long time after decoding // finishes. If we don't drop our reference to the image, we'll end up // keeping it alive as long as we remain in the surface cache, which could // greatly extend the image's lifetime - in fact, if the image isn't // discardable, it'd result in a leak! DropImageReference(); }
void AnimationSurfaceProvider::AnnounceSurfaceAvailable() { mFramesMutex.AssertNotCurrentThreadOwns(); MOZ_ASSERT(mImage); // We just got the first frame; let the surface cache know. We deliberately do // this outside of mFramesMutex to avoid a potential deadlock with // AddSizeOfExcludingThis(), since otherwise we'd be acquiring mFramesMutex // and then the surface cache lock, while the memory reporting code would // acquire the surface cache lock and then mFramesMutex. SurfaceCache::SurfaceAvailable(WrapNotNull(this)); }
void DecodedSurfaceProvider::Run() { MutexAutoLock lock(mMutex); if (!mDecoder || !mImage) { MOZ_ASSERT_UNREACHABLE("Running after decoding finished?"); return; } // Run the decoder. LexerResult result = mDecoder->Decode(WrapNotNull(this)); // If there's a new surface available, announce it to the surface cache. CheckForNewSurface(); if (result.is<TerminalState>()) { FinishDecoding(); return; // We're done. } // Notify for the progress we've made so far. if (mDecoder->HasProgress()) { NotifyProgress(WrapNotNull(mImage), WrapNotNull(mDecoder)); } MOZ_ASSERT(result.is<Yield>()); if (result == LexerResult(Yield::NEED_MORE_DATA)) { // We can't make any more progress right now. The decoder itself will ensure // that we get reenqueued when more data is available; just return for now. return; } // Single-frame images shouldn't yield for any reason except NEED_MORE_DATA. MOZ_ASSERT_UNREACHABLE("Unexpected yield for single-frame image"); mDecoder->TerminateFailure(); FinishDecoding(); }
/* static */ already_AddRefed<IDecodingTask> DecoderFactory::CreateDecoder(DecoderType aType, NotNull<RasterImage*> aImage, NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize, const IntSize& aOutputSize, DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags) { if (aType == DecoderType::UNKNOWN) { return nullptr; } // Create an anonymous decoder. Interaction with the SurfaceCache and the // owning RasterImage will be mediated by DecodedSurfaceProvider. RefPtr<Decoder> decoder = GetDecoder(aType, nullptr, bool(aDecoderFlags & DecoderFlags::IS_REDECODE)); MOZ_ASSERT(decoder, "Should have a decoder now"); // Initialize the decoder. decoder->SetMetadataDecode(false); decoder->SetIterator(aSourceBuffer->Iterator()); decoder->SetOutputSize(aOutputSize); decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY); decoder->SetSurfaceFlags(aSurfaceFlags); if (NS_FAILED(decoder->Init())) { return nullptr; } // Create a DecodedSurfaceProvider which will manage the decoding process and // make this decoder's output available in the surface cache. SurfaceKey surfaceKey = RasterSurfaceKey(aOutputSize, aSurfaceFlags, PlaybackType::eStatic); auto provider = MakeNotNull<RefPtr<DecodedSurfaceProvider>>( aImage, surfaceKey, WrapNotNull(decoder)); if (aDecoderFlags & DecoderFlags::CANNOT_SUBSTITUTE) { provider->Availability().SetCannotSubstitute(); } // 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; } // Return the surface provider in its IDecodingTask guise. RefPtr<IDecodingTask> task = provider.get(); return task.forget(); }
nsresult MediaDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, nsILoadGroup* aLoadGroup, nsISupports* aContainer, nsIStreamListener** aDocListener, bool aReset, nsIContentSink* aSink) { nsresult rv = nsDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, aDocListener, aReset, aSink); if (NS_FAILED(rv)) { return rv; } // We try to set the charset of the current document to that of the // 'genuine' (as opposed to an intervening 'chrome') parent document // that may be in a different window/tab. Even if we fail here, // we just return NS_OK because another attempt is made in // |UpdateTitleAndCharset| and the worst thing possible is a mangled // filename in the titlebar and the file picker. // Note that we // exclude UTF-8 as 'invalid' because UTF-8 is likely to be the charset // of a chrome document that has nothing to do with the actual content // whose charset we want to know. Even if "the actual content" is indeed // in UTF-8, we don't lose anything because the default empty value is // considered synonymous with UTF-8. nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer)); // not being able to set the charset is not critical. NS_ENSURE_TRUE(docShell, NS_OK); const Encoding* encoding; int32_t source; nsCOMPtr<nsIPrincipal> principal; // opening in a new tab docShell->GetParentCharset(encoding, &source, getter_AddRefs(principal)); if (encoding && encoding != UTF_8_ENCODING && NodePrincipal()->Equals(principal)) { SetDocumentCharacterSetSource(source); SetDocumentCharacterSet(WrapNotNull(encoding)); } return NS_OK; }
void MetadataDecodingTask::Run() { nsresult rv = mDecoder->Decode(WrapNotNull(this)); if (NS_SUCCEEDED(rv) && !mDecoder->GetDecodeDone()) { // It's important that metadata decode results are delivered atomically, so // we'll wait until NotifyDecodeComplete() to report any progress. We don't // need to do anything else for this case. The decoder itself will ensure // that we get reenqueued when more data is available. return; } NotifyDecodeComplete(mDecoder); }
/* static */ already_AddRefed<IDecodingTask> DecoderFactory::CreateAnimationDecoder(DecoderType aType, NotNull<RasterImage*> aImage, NotNull<SourceBuffer*> aSourceBuffer, const IntSize& aIntrinsicSize, DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags) { if (aType == DecoderType::UNKNOWN) { return nullptr; } MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG, "Calling CreateAnimationDecoder for non-animating DecoderType"); // Create an anonymous decoder. Interaction with the SurfaceCache and the // owning RasterImage will be mediated by AnimationSurfaceProvider. RefPtr<Decoder> decoder = GetDecoder(aType, nullptr, /* aIsRedecode = */ true); MOZ_ASSERT(decoder, "Should have a decoder now"); // Initialize the decoder. decoder->SetMetadataDecode(false); decoder->SetIterator(aSourceBuffer->Iterator()); decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE); decoder->SetSurfaceFlags(aSurfaceFlags); if (NS_FAILED(decoder->Init())) { return nullptr; } // Create an AnimationSurfaceProvider which will manage the decoding process // and make this decoder's output available in the surface cache. SurfaceKey surfaceKey = RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, PlaybackType::eAnimated); auto provider = MakeNotNull<RefPtr<AnimationSurfaceProvider>>( aImage, surfaceKey, WrapNotNull(decoder)); // 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; } // Return the surface provider in its IDecodingTask guise. RefPtr<IDecodingTask> task = provider.get(); return task.forget(); }
void DecodingTask::Run() { nsresult rv = mDecoder->Decode(WrapNotNull(this)); if (NS_SUCCEEDED(rv) && !mDecoder->GetDecodeDone()) { // Notify for the progress we've made so far. if (mDecoder->HasProgress()) { NotifyProgress(mDecoder); } // We don't need to do anything else for this case. The decoder itself will // ensure that we get reenqueued when more data is available. return; } NotifyDecodeComplete(mDecoder); }
void MetadataDecodingTask::Run() { LexerResult result = mDecoder->Decode(WrapNotNull(this)); if (result.is<TerminalState>()) { NotifyDecodeComplete(mDecoder->GetImage(), mDecoder); return; // We're done. } if (result == LexerResult(Yield::NEED_MORE_DATA)) { // We can't make any more progress right now. We also don't want to report // any progress, because it's important that metadata decode results are // delivered atomically. The decoder itself will ensure that we get // reenqueued when more data is available; just return for now. return; } MOZ_ASSERT_UNREACHABLE("Metadata decode yielded for an unexpected reason"); }
HRESULT AccessibleTextTearoff::get_oldText(IA2TextSegment *oldText) { if (!oldText) { return E_INVALIDARG; } RefPtr<AccessibleHandlerControl> ctl(gControlFactory.GetSingleton()); MOZ_ASSERT(ctl); if (!ctl) { return S_OK; } long id; HRESULT hr = mHandler->get_uniqueID(&id); if (FAILED(hr)) { return hr; } return ctl->GetOldText(id, WrapNotNull(oldText)); }
void AnonymousDecodingTask::Run() { while (true) { LexerResult result = mDecoder->Decode(WrapNotNull(this)); if (result.is<TerminalState>()) { return; // We're done. } if (result == LexerResult(Yield::NEED_MORE_DATA)) { // We can't make any more progress right now. Let the caller decide how to // handle it. return; } // Right now we don't do anything special for other kinds of yields, so just // keep working. MOZ_ASSERT(result.is<Yield>()); } }
/* static */ already_AddRefed<IDecodingTask> DecoderFactory::CreateDecoder(DecoderType aType, NotNull<RasterImage*> aImage, NotNull<SourceBuffer*> aSourceBuffer, const Maybe<IntSize>& aTargetSize, DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags, int aSampleSize) { if (aType == DecoderType::UNKNOWN) { return nullptr; } RefPtr<Decoder> decoder = GetDecoder(aType, aImage, bool(aDecoderFlags & DecoderFlags::IS_REDECODE)); MOZ_ASSERT(decoder, "Should have a decoder now"); // Initialize the decoder. decoder->SetMetadataDecode(false); decoder->SetIterator(aSourceBuffer->Iterator()); decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY); decoder->SetSurfaceFlags(aSurfaceFlags); decoder->SetSampleSize(aSampleSize); // Set a target size for downscale-during-decode if applicable. if (aTargetSize) { DebugOnly<nsresult> rv = decoder->SetTargetSize(*aTargetSize); MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?"); } decoder->Init(); if (NS_FAILED(decoder->GetDecoderError())) { return nullptr; } RefPtr<IDecodingTask> task = new DecodingTask(WrapNotNull(decoder)); return task.forget(); }
NS_IMETHODIMP RasterImage::DecodeMetadata(uint32_t aFlags) { if (mError) { return NS_ERROR_FAILURE; } MOZ_ASSERT(!mHasSize, "Should not do unnecessary metadata decodes"); // Create a decoder. RefPtr<IDecodingTask> task = DecoderFactory::CreateMetadataDecoder(mDecoderType, WrapNotNull(this), mSourceBuffer, mRequestedSampleSize); // Make sure DecoderFactory was able to create a decoder successfully. if (!task) { return NS_ERROR_FAILURE; } // We're ready to decode; start the decoder. LaunchDecodingTask(task, this, aFlags, mHasSourceData); return NS_OK; }
void DecodedSurfaceProvider::CheckForNewSurface() { mMutex.AssertCurrentThreadOwns(); MOZ_ASSERT(mDecoder); if (mSurface) { // Single-frame images should produce no more than one surface, so if we // have one, it should be the same one the decoder is working on. MOZ_ASSERT(mSurface.get() == mDecoder->GetCurrentFrameRef().get(), "DecodedSurfaceProvider and Decoder have different surfaces?"); return; } // We don't have a surface yet; try to get one from the decoder. mSurface = mDecoder->GetCurrentFrameRef().get(); if (!mSurface) { return; // No surface yet. } // We just got a surface for the first time; let the surface cache know. MOZ_ASSERT(mImage); SurfaceCache::SurfaceAvailable(WrapNotNull(this)); }
void AnonymousDecodingTask::Run() { mDecoder->Decode(WrapNotNull(this)); }
void VectorImage::CreateSurfaceAndShow(const SVGDrawingParameters& aParams) { mSVGDocumentWrapper->UpdateViewportBounds(aParams.viewportSize); mSVGDocumentWrapper->FlushImageTransformInvalidation(); RefPtr<gfxDrawingCallback> cb = new SVGDrawingCallback(mSVGDocumentWrapper, IntRect(IntPoint(0, 0), aParams.viewportSize), aParams.size, aParams.flags); RefPtr<gfxDrawable> svgDrawable = new gfxCallbackDrawable(cb, aParams.size); bool bypassCache = bool(aParams.flags & FLAG_BYPASS_SURFACE_CACHE) || // Refuse to cache animated images: // XXX(seth): We may remove this restriction in bug 922893. mHaveAnimations || // The image is too big to fit in the cache: !SurfaceCache::CanHold(aParams.size); if (bypassCache) { return Show(svgDrawable, aParams); } // We're about to rerasterize, which may mean that some of the previous // surfaces we've rasterized aren't useful anymore. We can allow them to // expire from the cache by unlocking them here, and then sending out an // invalidation. If this image is locked, any surfaces that are still useful // will become locked again when Draw touches them, and the remainder will // eventually expire. SurfaceCache::UnlockEntries(ImageKey(this)); // Try to create an imgFrame, initializing the surface it contains by drawing // our gfxDrawable into it. (We use FILTER_NEAREST since we never scale here.) NotNull<RefPtr<imgFrame>> frame = WrapNotNull(new imgFrame); nsresult rv = frame->InitWithDrawable(svgDrawable, aParams.size, SurfaceFormat::B8G8R8A8, SamplingFilter::POINT, aParams.flags); // If we couldn't create the frame, it was probably because it would end // up way too big. Generally it also wouldn't fit in the cache, but the prefs // could be set such that the cache isn't the limiting factor. if (NS_FAILED(rv)) { return Show(svgDrawable, aParams); } // Take a strong reference to the frame's surface and make sure it hasn't // already been purged by the operating system. RefPtr<SourceSurface> surface = frame->GetSourceSurface(); if (!surface) { return Show(svgDrawable, aParams); } // Attempt to cache the frame. SurfaceKey surfaceKey = VectorSurfaceKey(aParams.size, aParams.svgContext); NotNull<RefPtr<ISurfaceProvider>> provider = WrapNotNull(new SimpleSurfaceProvider(ImageKey(this), surfaceKey, frame)); SurfaceCache::Insert(provider); // Draw. RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(surface, aParams.size); Show(drawable, aParams); // Send out an invalidation so that surfaces that are still in use get // re-locked. See the discussion of the UnlockSurfaces call above. mProgressTracker->SyncNotifyProgress(FLAG_FRAME_COMPLETE, GetMaxSizedIntRect()); }
NS_IMETHODIMP RasterImage::Decode(const IntSize& aSize, uint32_t aFlags, PlaybackType aPlaybackType) { MOZ_ASSERT(NS_IsMainThread()); if (mError) { return NS_ERROR_FAILURE; } // If we don't have a size yet, we can't do any other decoding. if (!mHasSize) { mWantFullDecode = true; return NS_OK; } // We're about to decode again, which may mean that some of the previous sizes // we've decoded at aren't useful anymore. We can allow them to expire from // the cache by unlocking them here. When the decode finishes, it will send an // invalidation that will cause all instances of this image to redraw. If this // image is locked, any surfaces that are still useful will become locked // again when LookupFrame touches them, and the remainder will eventually // expire. SurfaceCache::UnlockEntries(ImageKey(this)); // Determine which flags we need to decode this image with. DecoderFlags decoderFlags = DefaultDecoderFlags(); if (aFlags & FLAG_ASYNC_NOTIFY) { decoderFlags |= DecoderFlags::ASYNC_NOTIFY; } if (mTransient) { decoderFlags |= DecoderFlags::IMAGE_IS_TRANSIENT; } if (mHasBeenDecoded) { decoderFlags |= DecoderFlags::IS_REDECODE; } SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags); if (IsOpaque()) { // If there's no transparency, it doesn't matter whether we premultiply // alpha or not. surfaceFlags &= ~SurfaceFlags::NO_PREMULTIPLY_ALPHA; } // Create a decoder. RefPtr<IDecodingTask> task; if (mAnimationState && aPlaybackType == PlaybackType::eAnimated) { task = DecoderFactory::CreateAnimationDecoder(mDecoderType, WrapNotNull(this), mSourceBuffer, mSize, decoderFlags, surfaceFlags); } else { task = DecoderFactory::CreateDecoder(mDecoderType, WrapNotNull(this), mSourceBuffer, mSize, aSize, decoderFlags, surfaceFlags, mRequestedSampleSize); } // Make sure DecoderFactory was able to create a decoder successfully. if (!task) { return NS_ERROR_FAILURE; } mDecodeCount++; // We're ready to decode; start the decoder. LaunchDecodingTask(task, this, aFlags, mHasSourceData); return NS_OK; }