Bug 1184996 (Part 1) - Create decoders with a DecoderFactory. r=tn

This commit is contained in:
Seth Fowler 2015-07-22 22:39:48 -07:00
parent 9b3b823e97
commit 3b8afe5c2b
9 changed files with 306 additions and 122 deletions

177
image/DecoderFactory.cpp Normal file
View File

@ -0,0 +1,177 @@
/* -*- 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"
#include "nsRefPtr.h"
#include "nsString.h"
#include "Decoder.h"
#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;
}
static already_AddRefed<Decoder>
GetDecoder(DecoderType aType,
RasterImage* aImage,
bool aIsRedecode)
{
nsRefPtr<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::ICO:
decoder = new nsICODecoder(aImage);
break;
case DecoderType::ICON:
decoder = new nsIconDecoder(aImage);
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
}
return decoder.forget();
}
/* static */ already_AddRefed<Decoder>
DecoderFactory::CreateDecoder(DecoderType aType,
RasterImage* aImage,
SourceBuffer* aSourceBuffer,
const Maybe<IntSize>& aTargetSize,
uint32_t aFlags,
bool aIsRedecode,
bool aImageIsTransient,
bool aImageIsLocked)
{
if (aType == DecoderType::UNKNOWN) {
return nullptr;
}
nsRefPtr<Decoder> decoder = GetDecoder(aType, aImage, aIsRedecode);
MOZ_ASSERT(decoder, "Should have a decoder now");
// Initialize the decoder.
decoder->SetSizeDecode(false);
decoder->SetIterator(aSourceBuffer->Iterator());
decoder->SetFlags(aFlags);
decoder->SetSendPartialInvalidations(!aIsRedecode);
decoder->SetImageIsTransient(aImageIsTransient);
if (aImageIsLocked) {
decoder->SetImageIsLocked();
}
// Set a target size for downscale-during-decode if applicable.
if (aTargetSize) {
DebugOnly<nsresult> rv = decoder->SetTargetSize(*aTargetSize);
MOZ_ASSERT(nsresult(rv) != NS_ERROR_NOT_AVAILABLE,
"We're downscale-during-decode but decoder doesn't support it?");
MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
}
decoder->Init();
if (NS_FAILED(decoder->GetDecoderError())) {
return nullptr;
}
return decoder.forget();
}
/* static */ already_AddRefed<Decoder>
DecoderFactory::CreateMetadataDecoder(DecoderType aType,
RasterImage* aImage,
SourceBuffer* aSourceBuffer)
{
if (aType == DecoderType::UNKNOWN) {
return nullptr;
}
nsRefPtr<Decoder> decoder =
GetDecoder(aType, aImage, /* aIsRedecode = */ false);
MOZ_ASSERT(decoder, "Should have a decoder now");
// Initialize the decoder.
decoder->SetSizeDecode(true);
decoder->SetIterator(aSourceBuffer->Iterator());
decoder->Init();
if (NS_FAILED(decoder->GetDecoderError())) {
return nullptr;
}
return decoder.forget();
}
} // namespace image
} // namespace mozilla

103
image/DecoderFactory.h Normal file
View File

@ -0,0 +1,103 @@
/* -*- 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/. */
#ifndef mozilla_image_DecoderFactory_h
#define mozilla_image_DecoderFactory_h
#include "mozilla/Maybe.h"
#include "mozilla/gfx/2D.h"
#include "nsCOMPtr.h"
class nsACString;
namespace mozilla {
namespace image {
class Decoder;
class RasterImage;
class SourceBuffer;
enum class DecoderType
{
PNG,
GIF,
JPEG,
BMP,
ICO,
ICON,
UNKNOWN
};
class DecoderFactory
{
public:
/// @return the type of decoder which is appropriate for @aMimeType.
static DecoderType GetDecoderType(const char* aMimeType);
/**
* Creates and initializes a decoder of type @aType. The decoder will send
* notifications to @aImage.
*
* XXX(seth): @aIsRedecode, @aImageIsTransient, and @aImageIsLocked should
* really be part of @aFlags. This requires changes to the way that decoder
* flags work, though. See bug 1185800.
*
* @param aType Which type of decoder to create - JPEG, PNG, etc.
* @param aImage The image will own the decoder and which should receive
* notifications as decoding progresses.
* @param aSourceBuffer The SourceBuffer which the decoder will read its data
* from.
* @param aTargetSize If not Nothing(), the target size which the image should
* be scaled to during decoding. It's an error to specify
* a target size for a decoder type which doesn't support
* downscale-during-decode.
* @param aFlags Flags specifying what type of output the decoder should
* produce; see GetDecodeFlags() in RasterImage.h.
* @param aIsRedecode Specify 'true' if this image has been decoded before.
* @param aImageIsTransient Specify 'true' if this image is transient.
* @param aImageIsLocked Specify 'true' if this image is locked for the
* lifetime of this decoder, and should be unlocked
* when the decoder finishes.
*/
static already_AddRefed<Decoder>
CreateDecoder(DecoderType aType,
RasterImage* aImage,
SourceBuffer* aSourceBuffer,
const Maybe<gfx::IntSize>& aTargetSize,
uint32_t aFlags,
bool aIsRedecode,
bool aImageIsTransient,
bool aImageIsLocked);
/**
* Creates and initializes a metadata decoder of type @aType. This decoder
* will only decode the image's header, extracting metadata like the size of
* the image. No actual image data will be decoded and no surfaces will be
* allocated. The decoder will send notifications to @aImage.
*
* XXX(seth): A metadata decode is called a "size decode" in most of ImageLib,
* but we are going to move away from that term, as it's both confusing to
* people and increasingly inaccurate.
*
* @param aType Which type of decoder to create - JPEG, PNG, etc.
* @param aImage The image will own the decoder and which should receive
* notifications as decoding progresses.
* @param aSourceBuffer The SourceBuffer which the decoder will read its data
* from.
*/
static already_AddRefed<Decoder>
CreateMetadataDecoder(DecoderType aType,
RasterImage* aImage,
SourceBuffer* aSourceBuffer);
private:
virtual ~DecoderFactory() = 0;
};
} // namespace image
} // namespace mozilla
#endif // mozilla_image_DecoderFactory_h

View File

@ -3,8 +3,6 @@
* 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 "nsMimeTypes.h"
#include "Image.h"
#include "nsRefreshDriver.h"
#include "mozilla/TimeStamp.h"
@ -69,52 +67,6 @@ ImageResource::~ImageResource()
mProgressTracker->ResetImage();
}
// Translates a mimetype into a concrete decoder
Image::eDecoderType
Image::GetDecoderType(const char* aMimeType)
{
// By default we don't know
eDecoderType rv = eDecoderType_unknown;
// PNG
if (!strcmp(aMimeType, IMAGE_PNG)) {
rv = eDecoderType_png;
} else if (!strcmp(aMimeType, IMAGE_X_PNG)) {
rv = eDecoderType_png;
// GIF
} else if (!strcmp(aMimeType, IMAGE_GIF)) {
rv = eDecoderType_gif;
// JPEG
} else if (!strcmp(aMimeType, IMAGE_JPEG)) {
rv = eDecoderType_jpeg;
} else if (!strcmp(aMimeType, IMAGE_PJPEG)) {
rv = eDecoderType_jpeg;
} else if (!strcmp(aMimeType, IMAGE_JPG)) {
rv = eDecoderType_jpeg;
// BMP
} else if (!strcmp(aMimeType, IMAGE_BMP)) {
rv = eDecoderType_bmp;
} else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
rv = eDecoderType_bmp;
// ICO
} else if (!strcmp(aMimeType, IMAGE_ICO)) {
rv = eDecoderType_ico;
} else if (!strcmp(aMimeType, IMAGE_ICO_MS)) {
rv = eDecoderType_ico;
// Icon
} else if (!strcmp(aMimeType, IMAGE_ICON_MS)) {
rv = eDecoderType_icon;
}
return rv;
}
void
ImageResource::IncrementAnimationConsumers()
{

View File

@ -129,18 +129,6 @@ private:
class Image : public imgIContainer
{
public:
// Mimetype translation
enum eDecoderType {
eDecoderType_png = 0,
eDecoderType_gif = 1,
eDecoderType_jpeg = 2,
eDecoderType_bmp = 3,
eDecoderType_ico = 4,
eDecoderType_icon = 5,
eDecoderType_unknown = 6
};
static eDecoderType GetDecoderType(const char* aMimeType);
/**
* Flags for Image initialization.
*

View File

@ -21,18 +21,12 @@
#include "ImageRegion.h"
#include "Layers.h"
#include "LookupResult.h"
#include "nsIInputStream.h"
#include "nsPresContext.h"
#include "SourceBuffer.h"
#include "SurfaceCache.h"
#include "FrameAnimator.h"
#include "nsPNGDecoder.h"
#include "nsGIFDecoder2.h"
#include "nsJPEGDecoder.h"
#include "nsBMPDecoder.h"
#include "nsICODecoder.h"
#include "nsIconDecoder.h"
#include "gfxContext.h"
#include "mozilla/gfx/2D.h"
@ -282,8 +276,8 @@ RasterImage::Init(const char* aMimeType,
// Use the MIME type to select a decoder type, and make sure there *is* a
// decoder for this MIME type.
NS_ENSURE_ARG_POINTER(aMimeType);
mDecoderType = GetDecoderType(aMimeType);
if (mDecoderType == eDecoderType_unknown) {
mDecoderType = DecoderFactory::GetDecoderType(aMimeType);
if (mDecoderType == DecoderType::UNKNOWN) {
return NS_ERROR_FAILURE;
}
@ -1339,64 +1333,28 @@ RasterImage::CreateDecoder(const Maybe<IntSize>& aSize, uint32_t aFlags)
MOZ_ASSERT(!mHasSize, "Should not do unnecessary size decodes");
}
// Instantiate the appropriate decoder.
nsRefPtr<Decoder> decoder;
switch (mDecoderType) {
case eDecoderType_png:
decoder = new nsPNGDecoder(this);
break;
case eDecoderType_gif:
decoder = new nsGIFDecoder2(this);
break;
case eDecoderType_jpeg:
// If we have all the data we don't want to waste cpu time doing
// a progressive decode.
decoder = new nsJPEGDecoder(this,
mHasBeenDecoded ? Decoder::SEQUENTIAL :
Decoder::PROGRESSIVE);
break;
case eDecoderType_bmp:
decoder = new nsBMPDecoder(this);
break;
case eDecoderType_ico:
decoder = new nsICODecoder(this);
break;
case eDecoderType_icon:
decoder = new nsIconDecoder(this);
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown decoder type");
}
MOZ_ASSERT(decoder, "Should have a decoder now");
// Initialize the decoder.
decoder->SetSizeDecode(!aSize);
decoder->SetSendPartialInvalidations(!mHasBeenDecoded);
decoder->SetImageIsTransient(mTransient);
decoder->SetFlags(aFlags);
bool imageIsLocked = false;
if (!mHasBeenDecoded && aSize) {
// Lock the image while we're decoding, so that it doesn't get evicted from
// the SurfaceCache before we have a chance to realize that it's animated.
// The corresponding unlock happens in FinalizeDecoder.
LockImage();
decoder->SetImageIsLocked();
imageIsLocked = true;
}
decoder->SetIterator(mSourceBuffer->Iterator());
// Set a target size for downscale-during-decode if applicable.
if (mDownscaleDuringDecode && aSize && *aSize != mSize) {
DebugOnly<nsresult> rv = decoder->SetTargetSize(*aSize);
MOZ_ASSERT(nsresult(rv) != NS_ERROR_NOT_AVAILABLE,
"We're downscale-during-decode but decoder doesn't support it?");
MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
nsRefPtr<Decoder> decoder;
if (aSize) {
Maybe<IntSize> targetSize = mSize != *aSize ? aSize : Nothing();
decoder = DecoderFactory::CreateDecoder(mDecoderType, this, mSourceBuffer,
targetSize, aFlags, mHasBeenDecoded,
mTransient, imageIsLocked);
} else {
decoder = DecoderFactory::CreateMetadataDecoder(mDecoderType, this,
mSourceBuffer);
}
decoder->Init();
if (NS_FAILED(decoder->GetDecoderError())) {
// Make sure DecoderFactory was able to create a decoder successfully.
if (!decoder) {
return nullptr;
}

View File

@ -26,6 +26,7 @@
#include "LookupResult.h"
#include "nsThreadUtils.h"
#include "DecodePool.h"
#include "DecoderFactory.h"
#include "Orientation.h"
#include "nsIObserver.h"
#include "mozilla/Attributes.h"
@ -376,7 +377,7 @@ private: // data
uint32_t mLockCount;
// The type of decoder this image needs. Computed from the MIME type in Init().
eDecoderType mDecoderType;
DecoderType mDecoderType;
// How many times we've decoded this image.
// This is currently only used for statistics

View File

@ -32,9 +32,11 @@
// undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
#undef GetCurrentTime
using namespace mozilla::dom;
namespace mozilla {
using namespace dom;
using namespace gfx;
namespace image {
NS_IMPL_ISUPPORTS(SVGDocumentWrapper,

View File

@ -41,6 +41,7 @@
#include "nsIApplicationCacheContainer.h"
#include "nsIMemoryReporter.h"
#include "DecoderFactory.h"
#include "Image.h"
#include "gfxPrefs.h"
#include "prtime.h"
@ -2475,7 +2476,8 @@ imgLoader::SupportImageWithMimeType(const char* aMimeType,
return true;
}
return Image::GetDecoderType(mimeType.get()) != Image::eDecoderType_unknown;
DecoderType type = DecoderFactory::GetDecoderType(mimeType.get());
return type != DecoderType::UNKNOWN;
}
NS_IMETHODIMP

View File

@ -50,6 +50,7 @@ UNIFIED_SOURCES += [
'ClippedImage.cpp',
'DecodePool.cpp',
'Decoder.cpp',
'DecoderFactory.cpp',
'DynamicImage.cpp',
'FrameAnimator.cpp',
'FrozenImage.cpp',