123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "DecoderFactory.h"
- #include "gfxPrefs.h"
- #include "nsMimeTypes.h"
- #include "mozilla/RefPtr.h"
- #include "AnimationSurfaceProvider.h"
- #include "Decoder.h"
- #include "IDecodingTask.h"
- #include "nsPNGDecoder.h"
- #include "nsGIFDecoder2.h"
- #include "nsJPEGDecoder.h"
- #include "nsBMPDecoder.h"
- #include "nsICODecoder.h"
- #include "nsIconDecoder.h"
- #include "nsWebPDecoder.h"
- namespace mozilla {
- using namespace gfx;
- namespace image {
- /* static */ DecoderType
- DecoderFactory::GetDecoderType(const char* aMimeType)
- {
- // By default we don't know.
- DecoderType type = DecoderType::UNKNOWN;
- // PNG
- if (!strcmp(aMimeType, IMAGE_PNG)) {
- type = DecoderType::PNG;
- } else if (!strcmp(aMimeType, IMAGE_X_PNG)) {
- type = DecoderType::PNG;
- } else if (!strcmp(aMimeType, IMAGE_APNG)) {
- type = DecoderType::PNG;
- // GIF
- } else if (!strcmp(aMimeType, IMAGE_GIF)) {
- type = DecoderType::GIF;
- // JPEG
- } else if (!strcmp(aMimeType, IMAGE_JPEG)) {
- type = DecoderType::JPEG;
- } else if (!strcmp(aMimeType, IMAGE_PJPEG)) {
- type = DecoderType::JPEG;
- } else if (!strcmp(aMimeType, IMAGE_JPG)) {
- type = DecoderType::JPEG;
- // BMP
- } else if (!strcmp(aMimeType, IMAGE_BMP)) {
- type = DecoderType::BMP;
- } else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
- type = DecoderType::BMP;
- // BMP_CLIPBOARD
- } else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) {
- type = DecoderType::BMP_CLIPBOARD;
- // ICO
- } else if (!strcmp(aMimeType, IMAGE_ICO)) {
- type = DecoderType::ICO;
- } else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
- type = DecoderType::ICO;
- // Icon
- } else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
- type = DecoderType::ICON;
- // WebP
- } else if (!strcmp(aMimeType, IMAGE_WEBP) &&
- gfxPrefs::ImageWebPEnabled()) {
- type = DecoderType::WEBP;
- }
- return type;
- }
- /* static */ already_AddRefed<Decoder>
- DecoderFactory::GetDecoder(DecoderType aType,
- RasterImage* aImage,
- bool aIsRedecode)
- {
- RefPtr<Decoder> decoder;
- switch (aType) {
- case DecoderType::PNG:
- decoder = new nsPNGDecoder(aImage);
- break;
- case DecoderType::GIF:
- decoder = new nsGIFDecoder2(aImage);
- break;
- case DecoderType::JPEG:
- // If we have all the data we don't want to waste cpu time doing
- // a progressive decode.
- decoder = new nsJPEGDecoder(aImage,
- aIsRedecode ? Decoder::SEQUENTIAL
- : Decoder::PROGRESSIVE);
- break;
- case DecoderType::BMP:
- decoder = new nsBMPDecoder(aImage);
- break;
- case DecoderType::BMP_CLIPBOARD:
- decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true);
- break;
- case DecoderType::ICO:
- decoder = new nsICODecoder(aImage);
- break;
- case DecoderType::ICON:
- decoder = new nsIconDecoder(aImage);
- break;
- case DecoderType::WEBP:
- decoder = new nsWebPDecoder(aImage);
- break;
- default:
- MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
- }
- return decoder.forget();
- }
- /* static */ already_AddRefed<IDecodingTask>
- DecoderFactory::CreateDecoder(DecoderType aType,
- NotNull<RasterImage*> aImage,
- NotNull<SourceBuffer*> aSourceBuffer,
- const IntSize& aIntrinsicSize,
- const IntSize& aOutputSize,
- DecoderFlags aDecoderFlags,
- SurfaceFlags aSurfaceFlags,
- int aSampleSize)
- {
- 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);
- decoder->SetSampleSize(aSampleSize);
- 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);
- NotNull<RefPtr<DecodedSurfaceProvider>> provider =
- WrapNotNull(new DecodedSurfaceProvider(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();
- }
- /* 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 ||
- aType == DecoderType::WEBP,
- "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);
- NotNull<RefPtr<AnimationSurfaceProvider>> provider =
- WrapNotNull(new 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();
- }
- /* 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);
- if (NS_FAILED(decoder->Init())) {
- return nullptr;
- }
- RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
- return task.forget();
- }
- /* static */ already_AddRefed<Decoder>
- DecoderFactory::CreateDecoderForICOResource(DecoderType aType,
- NotNull<SourceBuffer*> aSourceBuffer,
- NotNull<nsICODecoder*> aICODecoder,
- const Maybe<uint32_t>& aDataOffset
- /* = Nothing() */)
- {
- // Create the decoder.
- RefPtr<Decoder> decoder;
- switch (aType) {
- case DecoderType::BMP:
- MOZ_ASSERT(aDataOffset);
- decoder = new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
- break;
- case DecoderType::PNG:
- MOZ_ASSERT(!aDataOffset);
- decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
- break;
- default:
- MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
- return nullptr;
- }
- MOZ_ASSERT(decoder);
- // Initialize the decoder, copying settings from @aICODecoder.
- MOZ_ASSERT(!aICODecoder->IsMetadataDecode());
- decoder->SetMetadataDecode(aICODecoder->IsMetadataDecode());
- decoder->SetIterator(aSourceBuffer->Iterator());
- decoder->SetOutputSize(aICODecoder->OutputSize());
- decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
- decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
- if (NS_FAILED(decoder->Init())) {
- return nullptr;
- }
- return decoder.forget();
- }
- /* static */ already_AddRefed<Decoder>
- DecoderFactory::CreateAnonymousDecoder(DecoderType aType,
- NotNull<SourceBuffer*> aSourceBuffer,
- const Maybe<IntSize>& aOutputSize,
- SurfaceFlags aSurfaceFlags)
- {
- if (aType == DecoderType::UNKNOWN) {
- return nullptr;
- }
- RefPtr<Decoder> decoder =
- GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
- MOZ_ASSERT(decoder, "Should have a decoder now");
- // Initialize the decoder.
- decoder->SetMetadataDecode(false);
- decoder->SetIterator(aSourceBuffer->Iterator());
- // Anonymous decoders are always transient; we don't want to optimize surfaces
- // or do any other expensive work that might be wasted.
- DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
- // Without an image, the decoder can't store anything in the SurfaceCache, so
- // callers will only be able to retrieve the most recent frame via
- // Decoder::GetCurrentFrame(). That means that anonymous decoders should
- // always be first-frame-only decoders, because nobody ever wants the *last*
- // frame.
- decoderFlags |= DecoderFlags::FIRST_FRAME_ONLY;
- decoder->SetDecoderFlags(decoderFlags);
- decoder->SetSurfaceFlags(aSurfaceFlags);
- // Set an output size for downscale-during-decode if requested.
- if (aOutputSize) {
- decoder->SetOutputSize(*aOutputSize);
- }
- if (NS_FAILED(decoder->Init())) {
- return nullptr;
- }
- return decoder.forget();
- }
- /* static */ already_AddRefed<Decoder>
- DecoderFactory::CreateAnonymousMetadataDecoder(DecoderType aType,
- NotNull<SourceBuffer*> aSourceBuffer)
- {
- if (aType == DecoderType::UNKNOWN) {
- return nullptr;
- }
- RefPtr<Decoder> decoder =
- GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
- MOZ_ASSERT(decoder, "Should have a decoder now");
- // Initialize the decoder.
- decoder->SetMetadataDecode(true);
- decoder->SetIterator(aSourceBuffer->Iterator());
- decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
- if (NS_FAILED(decoder->Init())) {
- return nullptr;
- }
- return decoder.forget();
- }
- } // namespace image
- } // namespace mozilla
|