2015-07-23 08:39:48 +03:00
|
|
|
/* -*- 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 "nsMimeTypes.h"
|
2015-10-18 08:24:48 +03:00
|
|
|
#include "mozilla/RefPtr.h"
|
2015-07-23 08:39:48 +03:00
|
|
|
|
|
|
|
#include "Decoder.h"
|
2016-06-26 10:09:24 +03:00
|
|
|
#include "IDecodingTask.h"
|
2015-07-23 08:39:48 +03:00
|
|
|
#include "nsPNGDecoder.h"
|
|
|
|
#include "nsGIFDecoder2.h"
|
|
|
|
#include "nsJPEGDecoder.h"
|
|
|
|
#include "nsBMPDecoder.h"
|
|
|
|
#include "nsICODecoder.h"
|
|
|
|
#include "nsIconDecoder.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;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2015-07-23 08:39:56 +03:00
|
|
|
/* static */ already_AddRefed<Decoder>
|
|
|
|
DecoderFactory::GetDecoder(DecoderType aType,
|
|
|
|
RasterImage* aImage,
|
|
|
|
bool aIsRedecode)
|
2015-07-23 08:39:48 +03:00
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Decoder> decoder;
|
2015-07-23 08:39:48 +03:00
|
|
|
|
|
|
|
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::ICO:
|
|
|
|
decoder = new nsICODecoder(aImage);
|
|
|
|
break;
|
|
|
|
case DecoderType::ICON:
|
|
|
|
decoder = new nsIconDecoder(aImage);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return decoder.forget();
|
|
|
|
}
|
|
|
|
|
2016-06-26 10:09:24 +03:00
|
|
|
/* static */ already_AddRefed<IDecodingTask>
|
2015-07-23 08:39:48 +03:00
|
|
|
DecoderFactory::CreateDecoder(DecoderType aType,
|
2016-06-27 07:50:43 +03:00
|
|
|
NotNull<RasterImage*> aImage,
|
|
|
|
NotNull<SourceBuffer*> aSourceBuffer,
|
2016-06-27 08:05:58 +03:00
|
|
|
const IntSize& aIntrinsicSize,
|
2015-07-23 08:39:48 +03:00
|
|
|
const Maybe<IntSize>& aTargetSize,
|
2015-08-15 03:56:44 +03:00
|
|
|
DecoderFlags aDecoderFlags,
|
|
|
|
SurfaceFlags aSurfaceFlags,
|
2015-10-01 03:00:52 +03:00
|
|
|
int aSampleSize)
|
2015-07-23 08:39:48 +03:00
|
|
|
{
|
|
|
|
if (aType == DecoderType::UNKNOWN) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Decoder> decoder =
|
2015-08-15 03:56:44 +03:00
|
|
|
GetDecoder(aType, aImage, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
|
2015-07-23 08:39:48 +03:00
|
|
|
MOZ_ASSERT(decoder, "Should have a decoder now");
|
|
|
|
|
|
|
|
// Initialize the decoder.
|
2015-07-23 08:39:54 +03:00
|
|
|
decoder->SetMetadataDecode(false);
|
2015-07-23 08:39:48 +03:00
|
|
|
decoder->SetIterator(aSourceBuffer->Iterator());
|
2015-08-15 03:56:44 +03:00
|
|
|
decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
|
|
|
|
decoder->SetSurfaceFlags(aSurfaceFlags);
|
2015-07-31 17:29:03 +03:00
|
|
|
decoder->SetSampleSize(aSampleSize);
|
2015-07-23 08:39:48 +03:00
|
|
|
|
|
|
|
// 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?");
|
|
|
|
}
|
|
|
|
|
2016-07-11 10:34:50 +03:00
|
|
|
if (NS_FAILED(decoder->Init())) {
|
2015-07-23 08:39:48 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-06-27 08:05:58 +03:00
|
|
|
// Add a placeholder to the SurfaceCache so we won't trigger any more decoders
|
|
|
|
// with the same parameters.
|
|
|
|
IntSize surfaceSize = aTargetSize.valueOr(aIntrinsicSize);
|
|
|
|
SurfaceKey surfaceKey =
|
|
|
|
RasterSurfaceKey(surfaceSize, aSurfaceFlags, /* aFrameNum = */ 0);
|
|
|
|
InsertOutcome outcome =
|
|
|
|
SurfaceCache::InsertPlaceholder(ImageKey(aImage.get()), surfaceKey);
|
|
|
|
if (outcome != InsertOutcome::SUCCESS) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-06-26 10:09:24 +03:00
|
|
|
RefPtr<IDecodingTask> task = new DecodingTask(WrapNotNull(decoder));
|
|
|
|
return task.forget();
|
2015-07-23 08:39:48 +03:00
|
|
|
}
|
|
|
|
|
2016-06-26 10:09:24 +03:00
|
|
|
/* static */ already_AddRefed<IDecodingTask>
|
2015-08-14 10:37:13 +03:00
|
|
|
DecoderFactory::CreateAnimationDecoder(DecoderType aType,
|
2016-06-27 07:50:43 +03:00
|
|
|
NotNull<RasterImage*> aImage,
|
|
|
|
NotNull<SourceBuffer*> aSourceBuffer,
|
2016-06-27 08:05:58 +03:00
|
|
|
const IntSize& aIntrinsicSize,
|
2015-08-15 03:56:44 +03:00
|
|
|
DecoderFlags aDecoderFlags,
|
2015-10-01 03:00:52 +03:00
|
|
|
SurfaceFlags aSurfaceFlags)
|
2015-08-14 10:37:13 +03:00
|
|
|
{
|
|
|
|
if (aType == DecoderType::UNKNOWN) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(aType == DecoderType::GIF || aType == DecoderType::PNG,
|
|
|
|
"Calling CreateAnimationDecoder for non-animating DecoderType");
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Decoder> decoder =
|
2015-08-14 10:37:13 +03:00
|
|
|
GetDecoder(aType, aImage, /* aIsRedecode = */ true);
|
|
|
|
MOZ_ASSERT(decoder, "Should have a decoder now");
|
|
|
|
|
|
|
|
// Initialize the decoder.
|
|
|
|
decoder->SetMetadataDecode(false);
|
|
|
|
decoder->SetIterator(aSourceBuffer->Iterator());
|
2015-08-15 03:56:44 +03:00
|
|
|
decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
|
|
|
|
decoder->SetSurfaceFlags(aSurfaceFlags);
|
2015-08-14 10:37:13 +03:00
|
|
|
|
2016-07-11 10:34:50 +03:00
|
|
|
if (NS_FAILED(decoder->Init())) {
|
2015-08-14 10:37:13 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-06-27 08:05:58 +03:00
|
|
|
// Add a placeholder for the first frame to the SurfaceCache so we won't
|
|
|
|
// trigger any more decoders with the same parameters.
|
|
|
|
SurfaceKey surfaceKey =
|
|
|
|
RasterSurfaceKey(aIntrinsicSize, aSurfaceFlags, /* aFrameNum = */ 0);
|
|
|
|
InsertOutcome outcome =
|
|
|
|
SurfaceCache::InsertPlaceholder(ImageKey(aImage.get()), surfaceKey);
|
|
|
|
if (outcome != InsertOutcome::SUCCESS) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-06-26 10:09:24 +03:00
|
|
|
RefPtr<IDecodingTask> task = new DecodingTask(WrapNotNull(decoder));
|
|
|
|
return task.forget();
|
2015-08-14 10:37:13 +03:00
|
|
|
}
|
|
|
|
|
2016-06-26 10:09:24 +03:00
|
|
|
/* static */ already_AddRefed<IDecodingTask>
|
2015-07-23 08:39:48 +03:00
|
|
|
DecoderFactory::CreateMetadataDecoder(DecoderType aType,
|
2016-06-27 07:50:43 +03:00
|
|
|
NotNull<RasterImage*> aImage,
|
|
|
|
NotNull<SourceBuffer*> aSourceBuffer,
|
2015-10-01 03:00:52 +03:00
|
|
|
int aSampleSize)
|
2015-07-23 08:39:48 +03:00
|
|
|
{
|
|
|
|
if (aType == DecoderType::UNKNOWN) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Decoder> decoder =
|
2015-07-23 08:39:48 +03:00
|
|
|
GetDecoder(aType, aImage, /* aIsRedecode = */ false);
|
|
|
|
MOZ_ASSERT(decoder, "Should have a decoder now");
|
|
|
|
|
|
|
|
// Initialize the decoder.
|
2015-07-23 08:39:54 +03:00
|
|
|
decoder->SetMetadataDecode(true);
|
2015-07-23 08:39:48 +03:00
|
|
|
decoder->SetIterator(aSourceBuffer->Iterator());
|
2015-07-31 17:29:03 +03:00
|
|
|
decoder->SetSampleSize(aSampleSize);
|
2015-07-23 08:39:48 +03:00
|
|
|
|
2016-07-11 10:34:50 +03:00
|
|
|
if (NS_FAILED(decoder->Init())) {
|
2015-07-23 08:39:48 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-06-26 10:09:24 +03:00
|
|
|
RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
|
|
|
|
return task.forget();
|
2015-07-23 08:39:48 +03:00
|
|
|
}
|
|
|
|
|
2016-07-03 06:20:55 +03:00
|
|
|
/* 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.
|
|
|
|
decoder->SetMetadataDecode(aICODecoder->IsMetadataDecode());
|
|
|
|
decoder->SetIterator(aSourceBuffer->Iterator());
|
|
|
|
decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
|
|
|
|
decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
|
|
|
|
|
|
|
|
// Set a target size for downscale-during-decode if applicable.
|
|
|
|
const Maybe<IntSize> targetSize = aICODecoder->GetTargetSize();
|
|
|
|
if (targetSize) {
|
|
|
|
DebugOnly<nsresult> rv = decoder->SetTargetSize(*targetSize);
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
|
|
|
|
}
|
|
|
|
|
2016-07-11 10:34:50 +03:00
|
|
|
if (NS_FAILED(decoder->Init())) {
|
2016-07-03 06:20:55 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return decoder.forget();
|
|
|
|
}
|
|
|
|
|
2015-08-01 04:10:31 +03:00
|
|
|
/* static */ already_AddRefed<Decoder>
|
|
|
|
DecoderFactory::CreateAnonymousDecoder(DecoderType aType,
|
2016-06-27 07:50:43 +03:00
|
|
|
NotNull<SourceBuffer*> aSourceBuffer,
|
2016-05-27 22:59:19 +03:00
|
|
|
const Maybe<IntSize>& aTargetSize,
|
2015-08-15 03:56:44 +03:00
|
|
|
SurfaceFlags aSurfaceFlags)
|
2015-08-01 04:10:31 +03:00
|
|
|
{
|
|
|
|
if (aType == DecoderType::UNKNOWN) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Decoder> decoder =
|
2015-08-01 04:10:31 +03:00
|
|
|
GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
|
|
|
|
MOZ_ASSERT(decoder, "Should have a decoder now");
|
|
|
|
|
|
|
|
// Initialize the decoder.
|
|
|
|
decoder->SetMetadataDecode(false);
|
|
|
|
decoder->SetIterator(aSourceBuffer->Iterator());
|
2015-08-15 03:56:44 +03:00
|
|
|
|
|
|
|
// 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;
|
2015-08-01 04:10:31 +03:00
|
|
|
|
|
|
|
// 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.
|
2015-08-15 03:56:44 +03:00
|
|
|
decoderFlags |= DecoderFlags::FIRST_FRAME_ONLY;
|
|
|
|
|
|
|
|
decoder->SetDecoderFlags(decoderFlags);
|
|
|
|
decoder->SetSurfaceFlags(aSurfaceFlags);
|
2015-08-01 04:10:31 +03:00
|
|
|
|
2016-05-27 22:59:19 +03:00
|
|
|
// 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?");
|
|
|
|
}
|
|
|
|
|
2016-07-11 10:34:50 +03:00
|
|
|
if (NS_FAILED(decoder->Init())) {
|
2015-08-01 04:10:31 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return decoder.forget();
|
|
|
|
}
|
|
|
|
|
2015-08-12 20:41:05 +03:00
|
|
|
/* static */ already_AddRefed<Decoder>
|
|
|
|
DecoderFactory::CreateAnonymousMetadataDecoder(DecoderType aType,
|
2016-06-27 07:50:43 +03:00
|
|
|
NotNull<SourceBuffer*> aSourceBuffer)
|
2015-08-12 20:41:05 +03:00
|
|
|
{
|
|
|
|
if (aType == DecoderType::UNKNOWN) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Decoder> decoder =
|
2015-08-12 20:41:05 +03:00
|
|
|
GetDecoder(aType, /* aImage = */ nullptr, /* aIsRedecode = */ false);
|
|
|
|
MOZ_ASSERT(decoder, "Should have a decoder now");
|
|
|
|
|
|
|
|
// Initialize the decoder.
|
|
|
|
decoder->SetMetadataDecode(true);
|
|
|
|
decoder->SetIterator(aSourceBuffer->Iterator());
|
2015-08-15 03:56:44 +03:00
|
|
|
decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
|
2015-08-12 20:41:05 +03:00
|
|
|
|
2016-07-11 10:34:50 +03:00
|
|
|
if (NS_FAILED(decoder->Init())) {
|
2015-08-12 20:41:05 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return decoder.forget();
|
|
|
|
}
|
|
|
|
|
2015-07-23 08:39:48 +03:00
|
|
|
} // namespace image
|
|
|
|
} // namespace mozilla
|