Backed out 4 changesets (bug 815471, bug 821023, bug 816374, bug 816362) for reftest failures.

This commit is contained in:
Ryan VanderMeulen 2012-12-16 21:13:35 -05:00
parent acb811dff4
commit 41d18e74d0
23 changed files with 380 additions and 664 deletions

View File

@ -28,6 +28,11 @@
#include "nsBMPEncoder.h"
// objects that just require generic constructors
namespace mozilla {
namespace image {
NS_GENERIC_FACTORY_CONSTRUCTOR(RasterImage)
}
}
using namespace mozilla::image;
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(imgLoader, Init)
@ -40,6 +45,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsBMPEncoder)
NS_DEFINE_NAMED_CID(NS_IMGLOADER_CID);
NS_DEFINE_NAMED_CID(NS_IMGREQUESTPROXY_CID);
NS_DEFINE_NAMED_CID(NS_IMGTOOLS_CID);
NS_DEFINE_NAMED_CID(NS_RASTERIMAGE_CID);
NS_DEFINE_NAMED_CID(NS_ICOENCODER_CID);
NS_DEFINE_NAMED_CID(NS_JPEGENCODER_CID);
NS_DEFINE_NAMED_CID(NS_PNGENCODER_CID);
@ -49,6 +55,7 @@ static const mozilla::Module::CIDEntry kImageCIDs[] = {
{ &kNS_IMGLOADER_CID, false, NULL, imgLoaderConstructor, },
{ &kNS_IMGREQUESTPROXY_CID, false, NULL, imgRequestProxyConstructor, },
{ &kNS_IMGTOOLS_CID, false, NULL, imgToolsConstructor, },
{ &kNS_RASTERIMAGE_CID, false, NULL, RasterImageConstructor, },
{ &kNS_ICOENCODER_CID, false, NULL, nsICOEncoderConstructor, },
{ &kNS_JPEGENCODER_CID, false, NULL, nsJPEGEncoderConstructor, },
{ &kNS_PNGENCODER_CID, false, NULL, nsPNGEncoderConstructor, },
@ -61,6 +68,7 @@ static const mozilla::Module::ContractIDEntry kImageContracts[] = {
{ "@mozilla.org/image/loader;1", &kNS_IMGLOADER_CID },
{ "@mozilla.org/image/request;1", &kNS_IMGREQUESTPROXY_CID },
{ "@mozilla.org/image/tools;1", &kNS_IMGTOOLS_CID },
{ "@mozilla.org/image/rasterimage;1", &kNS_RASTERIMAGE_CID },
{ "@mozilla.org/image/encoder;2?type=image/vnd.microsoft.icon", &kNS_ICOENCODER_CID },
{ "@mozilla.org/image/encoder;2?type=image/jpeg", &kNS_JPEGENCODER_CID },
{ "@mozilla.org/image/encoder;2?type=image/png", &kNS_PNGENCODER_CID },

View File

@ -14,23 +14,9 @@ interface nsIDOMDocument;
interface imgIScriptedNotificationObserver;
interface imgINotificationObserver;
[scriptable, builtinclass, uuid(4c2383a4-931c-484d-8c4a-973590f66e3f)]
[scriptable, builtinclass, uuid(98bd5bf9-87eb-4d92-81b1-4cd10c64f7b2)]
interface imgITools : nsISupports
{
/**
* decodeImage
* Caller provides an input stream and mimetype. We read from the stream
* and decompress it (according to the specified mime type) and return
* the resulting imgIContainer.
*
* @param aStream
* An input stream for an encoded image file.
* @param aMimeType
* Type of image in the stream.
*/
imgIContainer decodeImage(in nsIInputStream aStream,
in ACString aMimeType);
/**
* decodeImageData
* Caller provides an input stream and mimetype. We read from the stream
@ -38,9 +24,6 @@ interface imgITools : nsISupports
* the resulting imgIContainer. (If the caller already has a container,
* it can be provided as input to be reused).
*
* This method is deprecated; new code should use |decodeImage|. Callers
* of |decodeImageData| must provide a |null| aContainer argument.
*
* @param aStream
* An input stream for an encoded image file.
* @param aMimeType
@ -51,9 +34,9 @@ interface imgITools : nsISupports
* be used. It is an error to pass an already-initialized container
* as aContainer.
*/
[deprecated] void decodeImageData(in nsIInputStream aStream,
in ACString aMimeType,
inout imgIContainer aContainer);
void decodeImageData(in nsIInputStream aStream,
in ACString aMimeType,
inout imgIContainer aContainer);
/**
* encodeImage

View File

@ -24,7 +24,6 @@ Decoder::Decoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
, mSizeDecode(false)
, mInFrame(false)
, mIsAnimated(false)
, mFirstWrite(true)
{
}
@ -43,6 +42,10 @@ Decoder::Init()
// No re-initializing
NS_ABORT_IF_FALSE(!mInitialized, "Can't re-initialize a decoder!");
// Fire OnStartDecode at init time to support bug 512435
if (!IsSizeDecode() && mObserver)
mObserver->OnStartDecode();
// Implementation-specific initialization
InitInternal();
mInitialized = true;
@ -56,9 +59,6 @@ Decoder::InitSharedDecoder()
// No re-initializing
NS_ABORT_IF_FALSE(!mInitialized, "Can't re-initialize a decoder!");
// Prevent duplicate notifications.
mFirstWrite = false;
// Implementation-specific initialization
InitInternal();
mInitialized = true;
@ -71,14 +71,6 @@ Decoder::Write(const char* aBuffer, uint32_t aCount)
NS_ABORT_IF_FALSE(!HasDecoderError(),
"Not allowed to make more decoder calls after error!");
// If this is our first write, fire OnStartDecode to support bug 512435.
if (mFirstWrite) {
if (!IsSizeDecode() && mObserver)
mObserver->OnStartDecode();
mFirstWrite = false;
}
// If a data error occured, just ignore future data
if (HasDataError())
return;

View File

@ -192,7 +192,6 @@ private:
bool mSizeDecode;
bool mInFrame;
bool mIsAnimated;
bool mFirstWrite;
};
} // namespace image

View File

@ -9,9 +9,8 @@ namespace mozilla {
namespace image {
// Constructor
Image::Image(imgStatusTracker* aStatusTracker, nsIURI* aURI) :
Image::Image(imgStatusTracker* aStatusTracker) :
mInnerWindowId(0),
mURI(aURI),
mAnimationConsumers(0),
mAnimationMode(kNormalAnimMode),
mInitialized(false),
@ -22,7 +21,7 @@ Image::Image(imgStatusTracker* aStatusTracker, nsIURI* aURI) :
mStatusTracker = aStatusTracker;
mStatusTracker->SetImage(this);
} else {
mStatusTracker = new imgStatusTracker(this);
mStatusTracker = new imgStatusTracker(this, nullptr);
}
}

View File

@ -8,9 +8,6 @@
#include "imgIContainer.h"
#include "imgStatusTracker.h"
#include "nsIURI.h"
#include "nsIRequest.h"
#include "nsIInputStream.h"
namespace mozilla {
namespace image {
@ -50,6 +47,7 @@ public:
*/
virtual nsresult Init(imgIDecoderObserver* aObserver,
const char* aMimeType,
const char* aURIString,
uint32_t aFlags) = 0;
/**
@ -90,51 +88,15 @@ public:
uint32_t GetAnimationConsumers() { return mAnimationConsumers; }
#endif
/**
* Called from OnDataAvailable when the stream associated with the image has
* received new image data. The arguments are the same as OnDataAvailable's,
* but by separating this functionality into a different method we don't
* interfere with subclasses which wish to implement nsIStreamListener.
*
* Images should not do anything that could send out notifications until they
* have received their first OnImageDataAvailable notification; in
* particular, this means that instantiating decoders should be deferred
* until OnImageDataAvailable is called.
*/
virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInStr,
uint64_t aSourceOffset,
uint32_t aCount) = 0;
/**
* Called from OnStopRequest when the image's underlying request completes.
* The arguments are the same as OnStopRequest's, but by separating this
* functionality into a different method we don't interfere with subclasses
* which wish to implement nsIStreamListener.
*/
virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
nsISupports* aContext,
nsresult status) = 0;
/**
* Called for multipart images to allow for any necessary reinitialization
* when there's a new part to add.
*/
virtual nsresult OnNewSourceData() = 0;
void SetInnerWindowID(uint64_t aInnerWindowId) {
mInnerWindowId = aInnerWindowId;
}
uint64_t InnerWindowID() const { return mInnerWindowId; }
bool HasError() { return mError; }
void SetHasError() { mError = true; }
nsIURI* GetURI() { return mURI; }
bool HasError() { return mError; }
protected:
Image(imgStatusTracker* aStatusTracker, nsIURI* aURI);
Image(imgStatusTracker* aStatusTracker);
// Shared functionality for implementors of imgIContainer. Every
// implementation of attribute animationMode should forward here.
@ -153,8 +115,7 @@ protected:
uint64_t mInnerWindowId;
// Member data shared by all implementations of this abstract class
nsRefPtr<imgStatusTracker> mStatusTracker;
nsCOMPtr<nsIURI> mURI;
nsAutoPtr<imgStatusTracker> mStatusTracker;
uint32_t mAnimationConsumers;
uint16_t mAnimationMode; // Enum values in imgIContainer
bool mInitialized:1; // Have we been initalized?

View File

@ -1,200 +0,0 @@
/* -*- 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 "mozilla/Preferences.h"
#include "mozilla/Likely.h"
#include "nsIHttpChannel.h"
#include "nsSimpleURI.h"
#include "RasterImage.h"
#include "VectorImage.h"
#include "ImageFactory.h"
namespace mozilla {
namespace image {
const char* SVG_MIMETYPE = "image/svg+xml";
// Global preferences related to image containers.
static bool gInitializedPrefCaches = false;
static bool gDecodeOnDraw = false;
static bool gDiscardable = false;
static void
InitPrefCaches()
{
Preferences::AddBoolVarCache(&gDiscardable, "image.mem.discardable");
Preferences::AddBoolVarCache(&gDecodeOnDraw, "image.mem.decodeondraw");
gInitializedPrefCaches = true;
}
static uint32_t
ComputeImageFlags(nsIURI* uri, bool isMultiPart)
{
nsresult rv;
// We default to the static globals
bool isDiscardable = gDiscardable;
bool doDecodeOnDraw = gDecodeOnDraw;
// We want UI to be as snappy as possible and not to flicker. Disable discarding
// and decode-on-draw for chrome URLS
bool isChrome = false;
rv = uri->SchemeIs("chrome", &isChrome);
if (NS_SUCCEEDED(rv) && isChrome)
isDiscardable = doDecodeOnDraw = false;
// We don't want resources like the "loading" icon to be discardable or
// decode-on-draw either.
bool isResource = false;
rv = uri->SchemeIs("resource", &isResource);
if (NS_SUCCEEDED(rv) && isResource)
isDiscardable = doDecodeOnDraw = false;
// For multipart/x-mixed-replace, we basically want a direct channel to the
// decoder. Disable both for this case as well.
if (isMultiPart)
isDiscardable = doDecodeOnDraw = false;
// We have all the information we need
uint32_t imageFlags = Image::INIT_FLAG_NONE;
if (isDiscardable)
imageFlags |= Image::INIT_FLAG_DISCARDABLE;
if (doDecodeOnDraw)
imageFlags |= Image::INIT_FLAG_DECODE_ON_DRAW;
if (isMultiPart)
imageFlags |= Image::INIT_FLAG_MULTIPART;
return imageFlags;
}
/* static */ already_AddRefed<Image>
ImageFactory::CreateImage(nsIRequest* aRequest,
imgStatusTracker* aStatusTracker,
const nsCString& aMimeType,
nsIURI* aURI,
bool aIsMultiPart,
uint32_t aInnerWindowId)
{
// Register our pref observers if we haven't yet.
if (MOZ_UNLIKELY(!gInitializedPrefCaches))
InitPrefCaches();
// Compute the image's initialization flags.
uint32_t imageFlags = ComputeImageFlags(aURI, aIsMultiPart);
// Select the type of image to create based on MIME type.
if (aMimeType.Equals(SVG_MIMETYPE)) {
return CreateVectorImage(aRequest, aStatusTracker, aMimeType,
aURI, imageFlags, aInnerWindowId);
} else {
return CreateRasterImage(aRequest, aStatusTracker, aMimeType,
aURI, imageFlags, aInnerWindowId);
}
}
// Marks an image as having an error before returning it. Used with macros like
// NS_ENSURE_SUCCESS, since we guarantee to always return an image even if an
// error occurs, but callers need to be able to tell that this happened.
template <typename T>
static already_AddRefed<Image>
BadImage(nsRefPtr<T>& image)
{
image->SetHasError();
return image.forget();
}
/* static */ already_AddRefed<Image>
ImageFactory::CreateAnonymousImage(const nsCString& aMimeType)
{
nsresult rv;
nsRefPtr<RasterImage> newImage = new RasterImage();
rv = newImage->Init(nullptr, aMimeType.get(), Image::INIT_FLAG_NONE);
NS_ENSURE_SUCCESS(rv, BadImage(newImage));
return newImage.forget();
}
/* static */ already_AddRefed<Image>
ImageFactory::CreateRasterImage(nsIRequest* aRequest,
imgStatusTracker* aStatusTracker,
const nsCString& aMimeType,
nsIURI* aURI,
uint32_t aImageFlags,
uint32_t aInnerWindowId)
{
nsresult rv;
nsRefPtr<RasterImage> newImage = new RasterImage(aStatusTracker, aURI);
rv = newImage->Init(aStatusTracker->GetDecoderObserver(),
aMimeType.get(), aImageFlags);
NS_ENSURE_SUCCESS(rv, BadImage(newImage));
newImage->SetInnerWindowID(aInnerWindowId);
// Use content-length as a size hint for http channels.
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
nsAutoCString contentLength;
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-length"),
contentLength);
if (NS_SUCCEEDED(rv)) {
int32_t len = contentLength.ToInteger(&rv);
// Pass anything usable on so that the RasterImage can preallocate
// its source buffer
if (len > 0) {
uint32_t sizeHint = (uint32_t) len;
sizeHint = NS_MIN<uint32_t>(sizeHint, 20000000); // Bound by something reasonable
rv = newImage->SetSourceSizeHint(sizeHint);
if (NS_FAILED(rv)) {
// Flush memory, try to get some back, and try again
rv = nsMemory::HeapMinimize(true);
nsresult rv2 = newImage->SetSourceSizeHint(sizeHint);
// If we've still failed at this point, things are going downhill
if (NS_FAILED(rv) || NS_FAILED(rv2)) {
NS_WARNING("About to hit OOM in imagelib!");
}
}
}
}
}
return newImage.forget();
}
/* static */ already_AddRefed<Image>
ImageFactory::CreateVectorImage(nsIRequest* aRequest,
imgStatusTracker* aStatusTracker,
const nsCString& aMimeType,
nsIURI* aURI,
uint32_t aImageFlags,
uint32_t aInnerWindowId)
{
nsresult rv;
nsRefPtr<VectorImage> newImage = new VectorImage(aStatusTracker, aURI);
rv = newImage->Init(aStatusTracker->GetDecoderObserver(),
aMimeType.get(), aImageFlags);
NS_ENSURE_SUCCESS(rv, BadImage(newImage));
newImage->SetInnerWindowID(aInnerWindowId);
rv = newImage->OnStartRequest(aRequest, nullptr);
NS_ENSURE_SUCCESS(rv, BadImage(newImage));
return newImage.forget();
}
} // namespace image
} // namespace mozilla

View File

@ -1,68 +0,0 @@
/* -*- 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 "nsIURI.h"
#include "nsIRequest.h"
#include "imgIContainer.h"
#include "imgStatusTracker.h"
#include "Image.h"
namespace mozilla {
namespace image {
extern const char* SVG_MIMETYPE;
struct ImageFactory
{
/**
* Creates a new image with the given properties.
*
* @param aRequest The associated request.
* @param aStatusTracker A status tracker for the image to use.
* @param aMimeType The mimetype of the image.
* @param aURI The URI of the image.
* @param aIsMultiPart Whether the image is part of a multipart request.
* @param aInnerWindowId The window this image belongs to.
*/
static already_AddRefed<Image> CreateImage(nsIRequest* aRequest,
imgStatusTracker* aStatusTracker,
const nsCString& aMimeType,
nsIURI* aURI,
bool aIsMultiPart,
uint32_t aInnerWindowId);
/**
* Creates a new image which isn't associated with a URI or loaded through
* the usual image loading mechanism.
*
* @param aMimeType The mimetype of the image.
*/
static already_AddRefed<Image> CreateAnonymousImage(const nsCString& aMimeType);
private:
// Factory functions that create specific types of image containers.
static already_AddRefed<Image> CreateRasterImage(nsIRequest* aRequest,
imgStatusTracker* aStatusTracker,
const nsCString& aMimeType,
nsIURI* aURI,
uint32_t aImageFlags,
uint32_t aInnerWindowId);
static already_AddRefed<Image> CreateVectorImage(nsIRequest* aRequest,
imgStatusTracker* aStatusTracker,
const nsCString& aMimeType,
nsIURI* aURI,
uint32_t aImageFlags,
uint32_t aInnerWindowId);
// This is a static factory class, so disallow instantiation.
virtual ~ImageFactory() = 0;
};
} // namespace image
} // namespace mozilla

View File

@ -26,7 +26,6 @@ EXPORTS = imgLoader.h \
CPPSRCS = \
Image.cpp \
ImageFactory.cpp \
Decoder.cpp \
DiscardTracker.cpp \
RasterImage.cpp \
@ -44,9 +43,6 @@ CPPSRCS = \
# We need to instantiate the decoders
LOCAL_INCLUDES += -I$(topsrcdir)/image/decoders
# For URI-related functionality
LOCAL_INCLUDES += -I$(topsrcdir)/netwerk/base/src
# Because SVGDocumentWrapper.cpp includes "nsSVGSVGElement.h"
LOCAL_INCLUDES += \
-I$(topsrcdir)/content/svg/content/src \

View File

@ -352,9 +352,8 @@ NS_IMPL_ISUPPORTS3(RasterImage, imgIContainer, nsIProperties,
#endif
//******************************************************************************
RasterImage::RasterImage(imgStatusTracker* aStatusTracker,
nsIURI* aURI /* = nullptr */) :
Image(aStatusTracker, aURI), // invoke superclass's constructor
RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
Image(aStatusTracker), // invoke superclass's constructor
mSize(0,0),
mFrameDecodeFlags(DECODE_FLAGS_DEFAULT),
mAnim(nullptr),
@ -442,6 +441,7 @@ RasterImage::Initialize()
nsresult
RasterImage::Init(imgIDecoderObserver *aObserver,
const char* aMimeType,
const char* aURIString,
uint32_t aFlags)
{
// We don't support re-initialization
@ -464,6 +464,7 @@ RasterImage::Init(imgIDecoderObserver *aObserver,
// Store initialization data
mObserver = do_GetWeakReference(aObserver);
mSourceDataMimeType.Assign(aMimeType);
mURIString.Assign(aURIString);
mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
mDecodeOnDraw = !!(aFlags & INIT_FLAG_DECODE_ON_DRAW);
mMultipart = !!(aFlags & INIT_FLAG_MULTIPART);
@ -687,7 +688,7 @@ RasterImage::ExtractFrame(uint32_t aWhichFrame,
// We don't actually have a mimetype in this case. The empty string tells the
// init routine not to try to instantiate a decoder. This should be fixed in
// bug 505959.
img->Init(nullptr, "", INIT_FLAG_NONE);
img->Init(nullptr, "", "", INIT_FLAG_NONE);
img->SetSize(aRegion.width, aRegion.height);
img->mDecoded = true; // Also, we need to mark the image as decoded
img->mHasBeenDecoded = true;
@ -1804,7 +1805,7 @@ get_header_str (char *buf, char *data, size_t data_len)
}
nsresult
RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult)
RasterImage::SourceDataComplete()
{
if (mError)
return NS_ERROR_FAILURE;
@ -1866,27 +1867,7 @@ RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult)
}
nsresult
RasterImage::OnImageDataAvailable(nsIRequest*,
nsISupports*,
nsIInputStream* aInStr,
uint64_t,
uint32_t aCount)
{
nsresult rv;
// WriteToRasterImage always consumes everything it gets
// if it doesn't run out of memory
uint32_t bytesRead;
rv = aInStr->ReadSegments(WriteToRasterImage, this, aCount, &bytesRead);
NS_ABORT_IF_FALSE(bytesRead == aCount || HasError(),
"WriteToRasterImage should consume everything or the image must be in error!");
return rv;
}
nsresult
RasterImage::OnNewSourceData()
RasterImage::NewSourceData()
{
nsresult rv;

View File

@ -23,7 +23,6 @@
#include "imgIContainer.h"
#include "nsIProperties.h"
#include "nsITimer.h"
#include "nsIRequest.h"
#include "nsWeakReference.h"
#include "nsTArray.h"
#include "imgFrame.h"
@ -153,7 +152,7 @@ public:
NS_DECL_IMGICONTAINERDEBUG
#endif
// (no public constructor - use ImageFactory)
RasterImage(imgStatusTracker* aStatusTracker = nullptr);
virtual ~RasterImage();
virtual nsresult StartAnimation();
@ -162,8 +161,9 @@ public:
// Methods inherited from Image
nsresult Init(imgIDecoderObserver* aObserver,
const char* aMimeType,
const char* aURIString,
uint32_t aFlags);
virtual void GetCurrentFrameRect(nsIntRect& aRect) MOZ_OVERRIDE;
void GetCurrentFrameRect(nsIntRect& aRect);
// Raster-specific methods
static NS_METHOD WriteToRasterImage(nsIInputStream* aIn, void* aClosure,
@ -249,15 +249,11 @@ public:
*/
nsresult AddSourceData(const char *aBuffer, uint32_t aCount);
virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInStr,
uint64_t aSourceOffset,
uint32_t aCount) MOZ_OVERRIDE;
virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aResult) MOZ_OVERRIDE;
virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
/* Called after the all the source data has been added with addSourceData. */
nsresult SourceDataComplete();
/* Called for multipart images when there's a new source image to add. */
nsresult NewSourceData();
/**
* A hint of the number of bytes of source data that the image contains. If
@ -732,11 +728,7 @@ private: // data
bool StoringSourceData() const;
protected:
RasterImage(imgStatusTracker* aStatusTracker = nullptr, nsIURI* aURI = nullptr);
bool ShouldAnimate();
friend class ImageFactory;
};
inline NS_IMETHODIMP RasterImage::GetAnimationMode(uint16_t *aAnimationMode) {

View File

@ -169,9 +169,8 @@ NS_IMPL_ISUPPORTS3(VectorImage,
//------------------------------------------------------------------------------
// Constructor / Destructor
VectorImage::VectorImage(imgStatusTracker* aStatusTracker,
nsIURI* aURI /* = nullptr */) :
Image(aStatusTracker, aURI), // invoke superclass's constructor
VectorImage::VectorImage(imgStatusTracker* aStatusTracker) :
Image(aStatusTracker), // invoke superclass's constructor
mRestrictedRegion(0, 0, 0, 0),
mIsInitialized(false),
mIsFullyLoaded(false),
@ -191,6 +190,7 @@ VectorImage::~VectorImage()
nsresult
VectorImage::Init(imgIDecoderObserver* aObserver,
const char* aMimeType,
const char* aURIString,
uint32_t aFlags)
{
// We don't support re-initialization
@ -243,30 +243,6 @@ VectorImage::OutOfProcessSizeOfDecoded() const
return 0;
}
nsresult
VectorImage::OnImageDataComplete(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aStatus)
{
return OnStopRequest(aRequest, aContext, aStatus);
}
nsresult
VectorImage::OnImageDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInStr,
uint64_t aSourceOffset,
uint32_t aCount)
{
return OnDataAvailable(aRequest, aContext, aInStr, aSourceOffset, aCount);
}
nsresult
VectorImage::OnNewSourceData()
{
return NS_OK;
}
nsresult
VectorImage::StartAnimation()
{

View File

@ -8,7 +8,6 @@
#include "Image.h"
#include "nsIStreamListener.h"
#include "nsIRequest.h"
#include "nsWeakReference.h"
#include "mozilla/TimeStamp.h"
@ -33,36 +32,25 @@ public:
NS_DECL_NSISTREAMLISTENER
NS_DECL_IMGICONTAINER
// (no public constructor - use ImageFactory)
VectorImage(imgStatusTracker* aStatusTracker = nullptr);
virtual ~VectorImage();
// Methods inherited from Image
nsresult Init(imgIDecoderObserver* aObserver,
const char* aMimeType,
const char* aURIString,
uint32_t aFlags);
virtual void GetCurrentFrameRect(nsIntRect& aRect) MOZ_OVERRIDE;
void GetCurrentFrameRect(nsIntRect& aRect);
virtual size_t HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
virtual size_t HeapSizeOfDecodedWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const;
virtual size_t NonHeapSizeOfDecoded() const;
virtual size_t OutOfProcessSizeOfDecoded() const;
virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInStr,
uint64_t aSourceOffset,
uint32_t aCount) MOZ_OVERRIDE;
virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
nsISupports* aContext,
nsresult status) MOZ_OVERRIDE;
virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
// Callback for SVGRootRenderingObserver
void InvalidateObserver();
protected:
VectorImage(imgStatusTracker* aStatusTracker = nullptr, nsIURI* aURI = nullptr);
virtual nsresult StartAnimation();
virtual nsresult StopAnimation();
virtual bool ShouldAnimate();
@ -84,8 +72,6 @@ private:
// (Only set after mIsFullyLoaded.)
bool mHaveRestrictedRegion:1; // Are we a restricted-region clone
// created via ExtractFrame?
friend class ImageFactory;
};
inline NS_IMETHODIMP VectorImage::GetAnimationMode(uint16_t *aAnimationMode) {

View File

@ -703,8 +703,7 @@ nsresult imgLoader::CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup
aRequest->GetURI(getter_AddRefs(uri));
// init adds itself to imgRequest's list of observers
nsresult rv = proxyRequest->Init(aRequest, &aRequest->GetStatusTracker(),
aLoadGroup, uri, aObserver);
nsresult rv = proxyRequest->Init(&aRequest->GetStatusTracker(), aLoadGroup, uri, aObserver);
if (NS_FAILED(rv)) {
NS_RELEASE(proxyRequest);
return rv;

View File

@ -17,7 +17,8 @@
#include "imgLoader.h"
#include "imgRequestProxy.h"
#include "ImageFactory.h"
#include "RasterImage.h"
#include "VectorImage.h"
#include "imgILoader.h"
@ -46,12 +47,29 @@
#include "nsNetUtil.h"
#include "nsIProtocolHandler.h"
#include "mozilla/Preferences.h"
#include "mozilla/Likely.h"
#include "DiscardTracker.h"
#include "nsAsyncRedirectVerifyHelper.h"
#define SVG_MIMETYPE "image/svg+xml"
using namespace mozilla;
using namespace mozilla::image;
static bool gInitializedPrefCaches = false;
static bool gDecodeOnDraw = false;
static bool gDiscardable = false;
static void
InitPrefCaches()
{
Preferences::AddBoolVarCache(&gDiscardable, "image.mem.discardable");
Preferences::AddBoolVarCache(&gDecodeOnDraw, "image.mem.decodeondraw");
gInitializedPrefCaches = true;
}
#if defined(PR_LOGGING)
PRLogModuleInfo *
GetImgLog()
@ -71,7 +89,7 @@ NS_IMPL_ISUPPORTS5(imgRequest,
imgRequest::imgRequest(imgLoader* aLoader)
: mLoader(aLoader)
, mStatusTracker(new imgStatusTracker(nullptr))
, mStatusTracker(new imgStatusTracker(nullptr, this))
, mValidator(nullptr)
, mInnerWindowId(0)
, mCORSMode(imgIRequest::CORS_NONE)
@ -80,10 +98,18 @@ imgRequest::imgRequest(imgLoader* aLoader)
, mGotData(false)
, mIsInCache(false)
, mResniffMimeType(false)
{ }
{
// Register our pref observers if we haven't yet.
if (MOZ_UNLIKELY(!gInitializedPrefCaches)) {
InitPrefCaches();
}
}
imgRequest::~imgRequest()
{
// The status tracker can outlive this request, and needs to know it's dying.
GetStatusTracker().ClearRequest();
if (mURI) {
nsAutoCString spec;
mURI->GetSpec(spec);
@ -527,10 +553,8 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
// Figure out if we're multipart
nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
if (mpchan) {
mIsMultiPartChannel = true;
GetStatusTracker().SetIsMultipart();
}
if (mpchan)
mIsMultiPartChannel = true;
// If we're not multipart, we shouldn't have an image yet
NS_ABORT_IF_FALSE(mIsMultiPartChannel || !mImage,
@ -540,13 +564,14 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
// detect the mime type in OnDataAvailable.
if (mIsMultiPartChannel && mImage) {
mResniffMimeType = true;
// Tell the image to reinitialize itself. We have to do this in
// OnStartRequest so that its state machine is always in a consistent
// state.
// Note that if our MIME type changes, mImage will be replaced with a
// new object.
mImage->OnNewSourceData();
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
// Tell the RasterImage to reinitialize itself. We have to do this in
// OnStartRequest so that its state machine is always in a consistent
// state.
// Note that if our MIME type changes, mImage will be replaced with a
// new object.
static_cast<RasterImage*>(mImage.get())->NewSourceData();
}
}
/*
@ -625,12 +650,21 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt,
// trigger a failure, since the image might be waiting for more non-optional
// data and this is the point where we break the news that it's not coming.
if (mImage) {
nsresult rv = mImage->OnImageDataComplete(aRequest, ctxt, status);
nsresult rv;
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
// Notify the image
rv = static_cast<RasterImage*>(mImage.get())->SourceDataComplete();
} else { // imageType == imgIContainer::TYPE_VECTOR
nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
NS_ABORT_IF_FALSE(imageAsStream,
"SVG-typed Image failed QI to nsIStreamListener");
rv = imageAsStream->OnStopRequest(aRequest, ctxt, status);
}
// If we got an error in the OnImageDataComplete() call, we don't want to
// proceed as if nothing bad happened. However, we also want to give
// precedence to failure status codes from necko, since presumably they're
// more meaningful.
// If we got an error in the SourceDataComplete() / OnStopRequest() call,
// we don't want to proceed as if nothing bad happened. However, we also
// want to give precedence to failure status codes from necko, since
// presumably they're more meaningful.
if (NS_FAILED(rv) && NS_SUCCEEDED(status))
status = rv;
}
@ -726,7 +760,7 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
// type and decoder.
// We always reinitialize for SVGs, because they have no way of
// reinitializing themselves.
if (mContentType != newType || newType.Equals(SVG_MIMETYPE)) {
if (mContentType != newType || newType.EqualsLiteral(SVG_MIMETYPE)) {
mContentType = newType;
// If we've resniffed our MIME type and it changed, we need to create a
@ -734,14 +768,23 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
// our own any more.
if (mResniffMimeType) {
NS_ABORT_IF_FALSE(mIsMultiPartChannel, "Resniffing a non-multipart image");
imgStatusTracker* freshTracker = new imgStatusTracker(nullptr);
imgStatusTracker* freshTracker = new imgStatusTracker(nullptr, this);
freshTracker->AdoptConsumers(&GetStatusTracker());
mStatusTracker = freshTracker;
mResniffMimeType = false;
}
mResniffMimeType = false;
/* now we have mimetype, so we can infer the image type that we want */
if (mContentType.EqualsLiteral(SVG_MIMETYPE)) {
mImage = new VectorImage(mStatusTracker.forget());
} else {
mImage = new RasterImage(mStatusTracker.forget());
}
mImage->SetInnerWindowID(mInnerWindowId);
GetStatusTracker().OnDataAvailable();
/* set our mimetype as a property */
nsCOMPtr<nsISupportsCString> contentType(do_CreateInstance("@mozilla.org/supports-cstring;1"));
if (contentType) {
@ -764,37 +807,121 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
LOG_MSG_WITH_PARAM(GetImgLog(), "imgRequest::OnDataAvailable", "content type", mContentType.get());
// Now we can create a new image to hold the data. If we don't have a decoder
//
// Figure out our Image initialization flags
//
// We default to the static globals
bool isDiscardable = gDiscardable;
bool doDecodeOnDraw = gDecodeOnDraw;
// We want UI to be as snappy as possible and not to flicker. Disable discarding
// and decode-on-draw for chrome URLS
bool isChrome = false;
rv = mURI->SchemeIs("chrome", &isChrome);
if (NS_SUCCEEDED(rv) && isChrome)
isDiscardable = doDecodeOnDraw = false;
// We don't want resources like the "loading" icon to be discardable or
// decode-on-draw either.
bool isResource = false;
rv = mURI->SchemeIs("resource", &isResource);
if (NS_SUCCEEDED(rv) && isResource)
isDiscardable = doDecodeOnDraw = false;
// For multipart/x-mixed-replace, we basically want a direct channel to the
// decoder. Disable both for this case as well.
if (mIsMultiPartChannel)
isDiscardable = doDecodeOnDraw = false;
// We have all the information we need
uint32_t imageFlags = Image::INIT_FLAG_NONE;
if (isDiscardable)
imageFlags |= Image::INIT_FLAG_DISCARDABLE;
if (doDecodeOnDraw)
imageFlags |= Image::INIT_FLAG_DECODE_ON_DRAW;
if (mIsMultiPartChannel)
imageFlags |= Image::INIT_FLAG_MULTIPART;
// Get our URI string
nsAutoCString uriString;
rv = mURI->GetSpec(uriString);
if (NS_FAILED(rv))
uriString.Assign("<unknown image URI>");
// Initialize the image that we created above. For RasterImages, this
// instantiates a decoder behind the scenes, so if we don't have a decoder
// for this mimetype we'll find out about it here.
mImage = ImageFactory::CreateImage(aRequest, mStatusTracker, mContentType,
mURI, mIsMultiPartChannel, mInnerWindowId);
rv = mImage->Init(GetStatusTracker().GetDecoderObserver(),
mContentType.get(), uriString.get(), imageFlags);
// Release our copy of the status tracker since the image owns it now.
mStatusTracker = nullptr;
// We allow multipart images to fail to initialize without cancelling the
// load because subsequent images might be fine.
if (NS_FAILED(rv) && !mIsMultiPartChannel) { // Probably bad mimetype
// Notify listeners that we have an image.
// XXX(seth): The name of this notification method is pretty misleading.
GetStatusTracker().OnDataAvailable();
if (mImage->HasError() && !mIsMultiPartChannel) { // Probably bad mimetype
// We allow multipart images to fail to initialize without cancelling the
// load because subsequent images might be fine; thus only single part
// images end up here.
this->Cancel(NS_ERROR_FAILURE);
this->Cancel(rv);
return NS_BINDING_ABORTED;
}
NS_ABORT_IF_FALSE(!!GetStatusTracker().GetImage(), "Status tracker should have an image!");
NS_ABORT_IF_FALSE(mImage, "imgRequest should have an image!");
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
/* Use content-length as a size hint for http channels. */
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
nsAutoCString contentLength;
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-length"),
contentLength);
if (NS_SUCCEEDED(rv)) {
int32_t len = contentLength.ToInteger(&rv);
if (mDecodeRequested)
mImage->StartDecoding();
// Pass anything usable on so that the RasterImage can preallocate
// its source buffer
if (len > 0) {
uint32_t sizeHint = (uint32_t) len;
sizeHint = NS_MIN<uint32_t>(sizeHint, 20000000); /* Bound by something reasonable */
RasterImage* rasterImage = static_cast<RasterImage*>(mImage.get());
rv = rasterImage->SetSourceSizeHint(sizeHint);
if (NS_FAILED(rv)) {
// Flush memory, try to get some back, and try again
rv = nsMemory::HeapMinimize(true);
nsresult rv2 = rasterImage->SetSourceSizeHint(sizeHint);
// If we've still failed at this point, things are going downhill
if (NS_FAILED(rv) || NS_FAILED(rv2)) {
NS_WARNING("About to hit OOM in imagelib!");
}
}
}
}
}
}
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
// If we were waiting on the image to do something, now's our chance.
if (mDecodeRequested) {
mImage->StartDecoding();
}
} else { // mImage->GetType() == imgIContainer::TYPE_VECTOR
nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
NS_ABORT_IF_FALSE(imageAsStream,
"SVG-typed Image failed QI to nsIStreamListener");
imageAsStream->OnStartRequest(aRequest, nullptr);
}
}
}
// Notify the image that it has new data.
rv = mImage->OnImageDataAvailable(aRequest, ctxt, inStr, sourceOffset, count);
if (mImage->GetType() == imgIContainer::TYPE_RASTER) {
// WriteToRasterImage always consumes everything it gets
// if it doesn't run out of memory
uint32_t bytesRead;
rv = inStr->ReadSegments(RasterImage::WriteToRasterImage,
static_cast<void*>(mImage),
count, &bytesRead);
NS_ABORT_IF_FALSE(bytesRead == count || mImage->HasError(),
"WriteToRasterImage should consume everything or the image must be in error!");
} else { // mImage->GetType() == imgIContainer::TYPE_VECTOR
nsCOMPtr<nsIStreamListener> imageAsStream = do_QueryInterface(mImage);
rv = imageAsStream->OnDataAvailable(aRequest, ctxt, inStr,
sourceOffset, count);
}
if (NS_FAILED(rv)) {
PR_LOG(GetImgLog(), PR_LOG_WARNING,
("[this=%p] imgRequest::OnDataAvailable -- "

View File

@ -198,7 +198,7 @@ private:
// The principal of this image.
nsCOMPtr<nsIPrincipal> mPrincipal;
// Status-tracker -- transferred to mImage, when it gets instantiated
nsRefPtr<imgStatusTracker> mStatusTracker;
nsAutoPtr<imgStatusTracker> mStatusTracker;
nsRefPtr<mozilla::image::Image> mImage;
nsCOMPtr<nsIProperties> mProperties;
nsCOMPtr<nsISupports> mSecurityInfo;

View File

@ -148,19 +148,17 @@ imgRequestProxy::~imgRequestProxy()
}
}
nsresult imgRequestProxy::Init(imgRequest* aOwner,
imgStatusTracker* aStatusTracker,
nsresult imgRequestProxy::Init(imgStatusTracker* aStatusTracker,
nsILoadGroup* aLoadGroup,
nsIURI* aURI,
imgINotificationObserver* aObserver)
nsIURI* aURI, imgINotificationObserver* aObserver)
{
NS_PRECONDITION(!GetOwner() && !mListener, "imgRequestProxy is already initialized");
LOG_SCOPE_WITH_PARAM(GetImgLog(), "imgRequestProxy::Init", "request", aOwner);
LOG_SCOPE_WITH_PARAM(GetImgLog(), "imgRequestProxy::Init", "request", aStatusTracker->GetRequest());
NS_ABORT_IF_FALSE(mAnimationConsumers == 0, "Cannot have animation before Init");
mBehaviour->SetOwner(aOwner);
mBehaviour->SetOwner(aStatusTracker->GetRequest());
mListener = aObserver;
// Make sure to addref mListener before the AddProxy call below, since
// that call might well want to release it if the imgRequest has
@ -586,8 +584,7 @@ nsresult imgRequestProxy::PerformClone(imgINotificationObserver* aObserver,
// XXXldb That's not true anymore. Stuff from imgLoader adds the
// request to the loadgroup.
clone->SetLoadFlags(mLoadFlags);
nsresult rv = clone->Init(mBehaviour->GetOwner(), &GetStatusTracker(),
mLoadGroup, mURI, aObserver);
nsresult rv = clone->Init(&GetStatusTracker(), mLoadGroup, mURI, aObserver);
if (NS_FAILED(rv))
return rv;
@ -682,20 +679,6 @@ NS_IMETHODIMP imgRequestProxy::GetHasTransferredData(bool* hasData)
/** imgIDecoderObserver methods **/
void imgRequestProxy::OnStartDecode()
{
// This notification is deliberately not propagated since there are no
// listeners who care about it.
if (GetOwner()) {
// In the case of streaming jpegs, it is possible to get multiple
// OnStartDecodes which indicates the beginning of a new decode. The cache
// entry's size therefore needs to be reset to 0 here. If we do not do
// this, the code in imgStatusTrackerObserver::OnStopFrame will continue to
// increase the data size cumulatively.
GetOwner()->ResetCacheEntry();
}
}
void imgRequestProxy::OnStartContainer()
{
LOG_FUNC(GetImgLog(), "imgRequestProxy::OnStartContainer");
@ -740,15 +723,9 @@ void imgRequestProxy::OnStopDecode()
mListener->Notify(this, imgINotificationObserver::DECODE_COMPLETE, nullptr);
}
if (GetOwner()) {
// We finished the decode, and thus have the decoded frames. Update the cache
// entry size to take this into account.
GetOwner()->UpdateCacheEntrySize();
// Multipart needs reset for next OnStartContainer.
if (GetOwner()->GetMultipart())
mSentStartContainer = false;
}
// Multipart needs reset for next OnStartContainer
if (GetOwner() && GetOwner()->GetMultipart())
mSentStartContainer = false;
}
void imgRequestProxy::OnDiscard()
@ -760,10 +737,6 @@ void imgRequestProxy::OnDiscard()
nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->Notify(this, imgINotificationObserver::DISCARD, nullptr);
}
if (GetOwner()) {
// Update the cache entry size, since we just got rid of frame data.
GetOwner()->UpdateCacheEntrySize();
}
}
void imgRequestProxy::OnImageIsAnimated()
@ -913,7 +886,7 @@ imgRequestProxy::GetStaticRequest(imgRequestProxy** aReturn)
nsCOMPtr<nsIPrincipal> currentPrincipal;
GetImagePrincipal(getter_AddRefs(currentPrincipal));
nsRefPtr<imgRequestProxy> req = new imgRequestProxyStatic(frame, currentPrincipal);
req->Init(nullptr, &frame->GetStatusTracker(), nullptr, mURI, nullptr);
req->Init(&frame->GetStatusTracker(), nullptr, mURI, nullptr);
NS_ADDREF(*aReturn = req);
@ -929,7 +902,7 @@ void imgRequestProxy::NotifyListener()
if (GetOwner()) {
// Send the notifications to our listener asynchronously.
GetStatusTracker().Notify(this);
GetStatusTracker().Notify(GetOwner(), this);
} else {
// We don't have an imgRequest, so we can only notify the clone of our
// current state, but we still have to do that asynchronously.

View File

@ -58,11 +58,9 @@ public:
// Callers to Init or ChangeOwner are required to call NotifyListener after
// (although not immediately after) doing so.
nsresult Init(imgRequest* aOwner,
imgStatusTracker* aStatusTracker,
nsresult Init(imgStatusTracker* aStatusTracker,
nsILoadGroup *aLoadGroup,
nsIURI* aURI,
imgINotificationObserver *aObserver);
nsIURI* aURI, imgINotificationObserver *aObserver);
nsresult ChangeOwner(imgRequest *aNewOwner); // this will change mOwner. Do not call this if the previous
// owner has already sent notifications out!
@ -138,7 +136,6 @@ protected:
// notifications.
/* non-virtual imgIDecoderObserver methods */
void OnStartDecode ();
void OnStartContainer ();
void OnFrameUpdate (const nsIntRect * aRect);
void OnStopFrame ();

View File

@ -6,6 +6,7 @@
#include "imgStatusTracker.h"
#include "imgRequest.h"
#include "imgIContainer.h"
#include "imgRequestProxy.h"
#include "Image.h"
@ -51,14 +52,7 @@ NS_IMETHODIMP imgStatusTrackerObserver::OnStartDecode()
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStartDecode callback before we've created our image");
mTracker->RecordStartDecode();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendStartDecode(iter.GetNext());
}
if (mTracker->IsMultipart()) {
if (mTracker->GetRequest() && !mTracker->GetRequest()->GetMultipart()) {
MOZ_ASSERT(!mTracker->mBlockingOnload);
mTracker->mBlockingOnload = true;
@ -70,6 +64,15 @@ NS_IMETHODIMP imgStatusTrackerObserver::OnStartDecode()
}
}
/* In the case of streaming jpegs, it is possible to get multiple OnStartDecodes which
indicates the beginning of a new decode.
The cache entry's size therefore needs to be reset to 0 here. If we do not do this,
the code in imgStatusTrackerObserver::OnStopFrame will continue to increase the data size cumulatively.
*/
if (mTracker->GetRequest()) {
mTracker->GetRequest()->ResetCacheEntry();
}
return NS_OK;
}
@ -132,6 +135,20 @@ NS_IMETHODIMP imgStatusTrackerObserver::OnStopFrame()
return NS_OK;
}
static void
FireFailureNotification(imgRequest* aRequest)
{
// Some kind of problem has happened with image decoding.
// Report the URI to net:failed-to-process-uri-conent observers.
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
nsCOMPtr<nsIURI> uri;
aRequest->GetURI(getter_AddRefs(uri));
os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
}
}
/* void onStopDecode (in nsresult status); */
NS_IMETHODIMP imgStatusTrackerObserver::OnStopDecode(nsresult aStatus)
{
@ -139,6 +156,12 @@ NS_IMETHODIMP imgStatusTrackerObserver::OnStopDecode(nsresult aStatus)
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStopDecode callback before we've created our image");
// We finished the decode, and thus have the decoded frames. Update the cache
// entry size to take this into account.
if (mTracker->GetRequest()) {
mTracker->GetRequest()->UpdateCacheEntrySize();
}
bool preexistingError = mTracker->GetImageStatus() == imgIRequest::STATUS_ERROR;
mTracker->RecordStopDecode(aStatus);
@ -152,8 +175,8 @@ NS_IMETHODIMP imgStatusTrackerObserver::OnStopDecode(nsresult aStatus)
// block onload, but then hit an error before we get to our first frame.
mTracker->MaybeUnblockOnload();
if (NS_FAILED(aStatus) && !preexistingError) {
mTracker->FireFailureNotification();
if (NS_FAILED(aStatus) && !preexistingError && mTracker->GetRequest()) {
FireFailureNotification(mTracker->GetRequest());
}
return NS_OK;
@ -173,6 +196,11 @@ NS_IMETHODIMP imgStatusTrackerObserver::OnDiscard()
mTracker->RecordDiscard();
// Update the cache entry size, since we just got rid of frame data
if (mTracker->GetRequest()) {
mTracker->GetRequest()->UpdateCacheEntrySize();
}
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendDiscard(iter.GetNext());
@ -197,21 +225,21 @@ NS_IMETHODIMP imgStatusTrackerObserver::OnImageIsAnimated()
// imgStatusTracker methods
imgStatusTracker::imgStatusTracker(Image* aImage)
imgStatusTracker::imgStatusTracker(Image* aImage, imgRequest* aRequest)
: mImage(aImage),
mTrackerObserver(new imgStatusTrackerObserver(this)),
mRequest(aRequest),
mState(0),
mImageStatus(imgIRequest::STATUS_NONE),
mIsMultipart(false),
mHadLastPart(false),
mBlockingOnload(false)
mBlockingOnload(false),
mTrackerObserver(new imgStatusTrackerObserver(this))
{}
imgStatusTracker::imgStatusTracker(const imgStatusTracker& aOther)
: mImage(aOther.mImage),
mRequest(aOther.mRequest),
mState(aOther.mState),
mImageStatus(aOther.mImageStatus),
mIsMultipart(aOther.mIsMultipart),
mHadLastPart(aOther.mHadLastPart),
mBlockingOnload(aOther.mBlockingOnload)
// Note: we explicitly don't copy mRequestRunnable, because it won't be
@ -246,20 +274,22 @@ imgStatusTracker::GetImageStatus() const
class imgRequestNotifyRunnable : public nsRunnable
{
public:
imgRequestNotifyRunnable(imgStatusTracker* aTracker, imgRequestProxy* aRequestProxy)
: mTracker(aTracker)
imgRequestNotifyRunnable(imgRequest* request, imgRequestProxy* requestproxy)
: mRequest(request)
{
mProxies.AppendElement(aRequestProxy);
mProxies.AppendElement(requestproxy);
}
NS_IMETHOD Run()
{
imgStatusTracker& statusTracker = mRequest->GetStatusTracker();
for (uint32_t i = 0; i < mProxies.Length(); ++i) {
mProxies[i]->SetNotificationsDeferred(false);
mTracker->SyncNotify(mProxies[i]);
statusTracker.SyncNotify(mProxies[i]);
}
mTracker->mRequestRunnable = nullptr;
statusTracker.mRequestRunnable = nullptr;
return NS_OK;
}
@ -271,22 +301,19 @@ class imgRequestNotifyRunnable : public nsRunnable
private:
friend class imgStatusTracker;
nsRefPtr<imgStatusTracker> mTracker;
nsTArray< nsRefPtr<imgRequestProxy> > mProxies;
nsRefPtr<imgRequest> mRequest;
nsTArray<nsRefPtr<imgRequestProxy> > mProxies;
};
void
imgStatusTracker::Notify(imgRequestProxy* proxy)
imgStatusTracker::Notify(imgRequest* request, imgRequestProxy* proxy)
{
#ifdef PR_LOGGING
if (GetImage() && GetImage()->GetURI()) {
nsCOMPtr<nsIURI> uri(GetImage()->GetURI());
nsAutoCString spec;
uri->GetSpec(spec);
LOG_FUNC_WITH_PARAM(GetImgLog(), "imgStatusTracker::Notify async", "uri", spec.get());
} else {
LOG_FUNC_WITH_PARAM(GetImgLog(), "imgStatusTracker::Notify async", "uri", "<unknown>");
}
nsCOMPtr<nsIURI> uri;
request->GetURI(getter_AddRefs(uri));
nsAutoCString spec;
uri->GetSpec(spec);
LOG_FUNC_WITH_PARAM(GetImgLog(), "imgStatusTracker::Notify async", "uri", spec.get());
#endif
proxy->SetNotificationsDeferred(true);
@ -295,10 +322,13 @@ imgStatusTracker::Notify(imgRequestProxy* proxy)
// to its list of proxies to be notified. This ensures we don't unnecessarily
// delay onload.
imgRequestNotifyRunnable* runnable = static_cast<imgRequestNotifyRunnable*>(mRequestRunnable.get());
if (runnable) {
if (runnable && runnable->mRequest == request) {
runnable->AddProxy(proxy);
} else {
mRequestRunnable = new imgRequestNotifyRunnable(this, proxy);
// It's okay to overwrite an existing mRequestRunnable, because adding a
// new proxy is strictly a performance optimization. The notification will
// always happen, regardless of whether we hold a reference to a runnable.
mRequestRunnable = new imgRequestNotifyRunnable(request, proxy);
NS_DispatchToCurrentThread(mRequestRunnable);
}
}
@ -368,29 +398,26 @@ imgStatusTracker::SyncNotify(imgRequestProxy* proxy)
if (mState & stateHasSize)
proxy->OnStartContainer();
// OnStartDecode
if (mState & stateDecodeStarted)
proxy->OnStartDecode();
// BlockOnload
if (mState & stateBlockingOnload)
proxy->BlockOnload();
if (mImage) {
// OnDataAvailable
// XXX - Should only send partial rects here, but that needs to
// wait until we fix up the observer interface
nsIntRect r;
mImage->GetCurrentFrameRect(r);
int16_t imageType = mImage->GetType();
// Send frame messages (OnDataAvailable, OnStopFrame)
if (imageType == imgIContainer::TYPE_VECTOR ||
static_cast<RasterImage*>(mImage)->GetNumFrames() > 0) {
// If there's any content in this frame at all (always true for
// vector images, true for raster images that have decoded at
// least one frame) then send OnFrameUpdate.
if (!r.IsEmpty())
// OnDataAvailable
// XXX - Should only send partial rects here, but that needs to
// wait until we fix up the observer interface
nsIntRect r;
mImage->GetCurrentFrameRect(r);
proxy->OnFrameUpdate(&r);
if (mState & stateFrameStopped)
proxy->OnStopFrame();
if (mState & stateFrameStopped)
proxy->OnStopFrame();
}
// OnImageIsAnimated
bool isAnimated = false;
@ -472,24 +499,10 @@ void
imgStatusTracker::RecordDecoded()
{
NS_ABORT_IF_FALSE(mImage, "RecordDecoded called before we have an Image");
mState |= stateDecodeStarted | stateDecodeStopped | stateFrameStopped;
mState |= stateDecodeStopped | stateFrameStopped;
mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE | imgIRequest::STATUS_DECODE_COMPLETE;
}
void
imgStatusTracker::RecordStartDecode()
{
NS_ABORT_IF_FALSE(mImage, "RecordStartDecode without an Image");
mState |= stateDecodeStarted;
}
void
imgStatusTracker::SendStartDecode(imgRequestProxy* aProxy)
{
if (!aProxy->NotificationsDeferred())
aProxy->OnStartDecode();
}
void
imgStatusTracker::RecordStartContainer(imgIContainer* aContainer)
{
@ -631,7 +644,6 @@ imgStatusTracker::RecordStartRequest()
mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE;
mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE;
mState &= ~stateRequestStarted;
mState &= ~stateDecodeStarted;
mState &= ~stateDecodeStopped;
mState &= ~stateRequestStopped;
mState &= ~stateBlockingOnload;
@ -693,8 +705,8 @@ imgStatusTracker::OnStopRequest(bool aLastPart,
SendStopRequest(srIter.GetNext(), aLastPart, aStatus);
}
if (NS_FAILED(aStatus) && !preexistingError) {
FireFailureNotification();
if (NS_FAILED(aStatus) && !preexistingError && GetRequest()) {
FireFailureNotification(GetRequest());
}
}
@ -756,15 +768,7 @@ imgStatusTracker::MaybeUnblockOnload()
}
void
imgStatusTracker::FireFailureNotification()
imgStatusTracker::ClearRequest()
{
// Some kind of problem has happened with image decoding.
// Report the URI to net:failed-to-process-uri-conent observers.
nsIURI* uri = GetImage()->GetURI();
if (uri) {
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
}
}
mRequest = nullptr;
}

View File

@ -8,6 +8,7 @@
#define imgStatusTracker_h__
class imgIContainer;
class imgRequest;
class imgRequestProxy;
class imgStatusNotifyRunnable;
class imgRequestNotifyRunnable;
@ -20,7 +21,6 @@ class Image;
} // namespace mozilla
#include "mozilla/RefPtr.h"
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsTObserverArray.h"
@ -32,7 +32,6 @@ class Image;
enum {
stateRequestStarted = 1u << 0,
stateHasSize = 1u << 1,
stateDecodeStarted = 1u << 2,
stateDecodeStopped = 1u << 3,
stateFrameStopped = 1u << 4,
stateRequestStopped = 1u << 5,
@ -71,13 +70,13 @@ private:
* and the notifications will be replayed to the proxy asynchronously.
*/
class imgStatusTracker : public mozilla::RefCounted<imgStatusTracker>
class imgStatusTracker
{
public:
// aImage is the image that this status tracker will pass to the
// imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be
// alive as long as this instance is, because we hold a weak reference to it.
imgStatusTracker(mozilla::image::Image* aImage);
imgStatusTracker(mozilla::image::Image* aImage, imgRequest* aRequest);
imgStatusTracker(const imgStatusTracker& aOther);
// Image-setter, for imgStatusTrackers created by imgRequest::Init, which
@ -86,15 +85,12 @@ public:
// without an image.
void SetImage(mozilla::image::Image* aImage);
// Inform this status tracker that it is associated with a multipart image.
void SetIsMultipart() { mIsMultipart = true; }
// Schedule an asynchronous "replaying" of all the notifications that would
// have to happen to put us in the current state.
// We will also take note of any notifications that happen between the time
// Notify() is called and when we call SyncNotify on |proxy|, and replay them
// as well.
void Notify(imgRequestProxy* proxy);
void Notify(imgRequest* request, imgRequestProxy* proxy);
// Schedule an asynchronous "replaying" of all the notifications that would
// have to happen to put us in the state we are in right now.
@ -152,8 +148,6 @@ public:
void RecordDecoded();
/* non-virtual imgIDecoderObserver methods */
void RecordStartDecode();
void SendStartDecode(imgRequestProxy* aProxy);
void RecordStartContainer(imgIContainer* aContainer);
void SendStartContainer(imgRequestProxy* aProxy);
void RecordDataAvailable();
@ -192,10 +186,12 @@ public:
void MaybeUnblockOnload();
bool IsMultipart() const { return mIsMultipart; }
// Null out any reference to an associated image request
void ClearRequest();
// Weak pointer getters - no AddRefs.
inline mozilla::image::Image* GetImage() const { return mImage; }
inline imgRequest* GetRequest() const { return mRequest; }
inline imgIDecoderObserver* GetDecoderObserver() { return mTrackerObserver.get(); }
@ -204,24 +200,22 @@ private:
friend class imgRequestNotifyRunnable;
friend class imgStatusTrackerObserver;
void FireFailureNotification();
nsCOMPtr<nsIRunnable> mRequestRunnable;
// Weak pointer to the image. The image owns the status tracker.
// Weak pointers to the image and request. The request owns the image, and
// the image (or the request, if there's no image) owns the status tracker.
mozilla::image::Image* mImage;
imgRequest* mRequest;
uint32_t mState;
uint32_t mImageStatus;
bool mHadLastPart;
bool mBlockingOnload;
// List of proxies attached to the image. Each proxy represents a consumer
// using the image.
nsTObserverArray<imgRequestProxy*> mConsumers;
nsRefPtr<imgStatusTrackerObserver> mTrackerObserver;
uint32_t mState;
uint32_t mImageStatus;
bool mIsMultipart : 1;
bool mHadLastPart : 1;
bool mBlockingOnload : 1;
};
#endif

View File

@ -22,7 +22,7 @@
#include "nsStreamUtils.h"
#include "nsNetUtil.h"
#include "nsContentUtils.h"
#include "ImageFactory.h"
#include "RasterImage.h"
#include "ScriptedNotificationObserver.h"
#include "imgIScriptedNotificationObserver.h"
@ -47,33 +47,32 @@ imgTools::~imgTools()
/* destructor code */
}
NS_IMETHODIMP imgTools::DecodeImageData(nsIInputStream* aInStr,
const nsACString& aMimeType,
imgIContainer **aContainer)
{
NS_ABORT_IF_FALSE(*aContainer == nullptr,
"Cannot provide an existing image container to DecodeImageData");
return DecodeImage(aInStr, aMimeType, aContainer);
}
NS_IMETHODIMP imgTools::DecodeImage(nsIInputStream* aInStr,
const nsACString& aMimeType,
imgIContainer **aContainer)
{
nsresult rv;
nsRefPtr<Image> image;
RasterImage* image; // convenience alias for *aContainer
NS_ENSURE_ARG_POINTER(aInStr);
// Create a new image container to hold the decoded data.
nsAutoCString mimeType(aMimeType);
image = ImageFactory::CreateAnonymousImage(mimeType);
// If the caller didn't provide an imgIContainer, create one.
if (*aContainer) {
NS_ABORT_IF_FALSE((*aContainer)->GetType() == imgIContainer::TYPE_RASTER,
"wrong type of imgIContainer for decoding into");
image = static_cast<RasterImage*>(*aContainer);
} else {
*aContainer = image = new RasterImage();
NS_ADDREF(image);
}
if (image->HasError())
return NS_ERROR_FAILURE;
// Initialize the Image. If we're using the one from the caller, we
// require that it not be initialized.
nsCString mimeType(aMimeType);
rv = image->Init(nullptr, mimeType.get(), "<unknown>", Image::INIT_FLAG_NONE);
NS_ENSURE_SUCCESS(rv, rv);
// Prepare the input stream.
nsCOMPtr<nsIInputStream> inStream = aInStr;
if (!NS_InputStreamIsBuffered(aInStr)) {
nsCOMPtr<nsIInputStream> bufStream;
@ -82,21 +81,27 @@ NS_IMETHODIMP imgTools::DecodeImage(nsIInputStream* aInStr,
inStream = bufStream;
}
// Figure out how much data we've been passed.
// Figure out how much data we've been passed
uint64_t length;
rv = inStream->Available(&length);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(length <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
// Send the source data to the Image.
rv = image->OnImageDataAvailable(nullptr, nullptr, inStream, 0, uint32_t(length));
// Send the source data to the Image. WriteToRasterImage always
// consumes everything it gets if it doesn't run out of memory.
uint32_t bytesRead;
rv = inStream->ReadSegments(RasterImage::WriteToRasterImage,
static_cast<void*>(image),
(uint32_t)length, &bytesRead);
NS_ENSURE_SUCCESS(rv, rv);
// Let the Image know we've sent all the data.
rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK);
NS_ABORT_IF_FALSE(bytesRead == length || image->HasError(),
"WriteToRasterImage should consume everything or the image must be in error!");
// Let the Image know we've sent all the data
rv = image->SourceDataComplete();
NS_ENSURE_SUCCESS(rv, rv);
// All done.
NS_ADDREF(*aContainer = image.get());
// All done
return NS_OK;
}

View File

@ -8,11 +8,11 @@
#include "gfxContext.h"
#define NS_IMGTOOLS_CID \
{ /* 4c2383a4-931c-484d-8c4a-973590f66e3f */ \
0x4c2383a4, \
0x931c, \
0x484d, \
{0x8c, 0x4a, 0x97, 0x35, 0x90, 0xf6, 0x6e, 0x3f} \
{ /* fd9a9e8a-a77b-496a-b7bb-263df9715149 */ \
0xfd9a9e8a, \
0xa77b, \
0x496a, \
{0xb7, 0xbb, 0x26, 0x3d, 0xf9, 0x71, 0x51, 0x49} \
}
class imgTools : public imgITools

View File

@ -149,8 +149,6 @@ var imgFile = do_get_file(imgName);
var istream = getFileInputStream(imgFile);
do_check_eq(istream.available(), 8415);
// Use decodeImageData for this test even though it's deprecated to ensure that
// it correctly forwards to decodeImage and continues to work.
var outParam = { value: null };
imgTools.decodeImageData(istream, inMimeType, outParam);
var container = outParam.value;
@ -211,7 +209,9 @@ imgFile = do_get_file(imgName);
istream = getFileInputStream(imgFile);
do_check_eq(istream.available(), 3494);
container = imgTools.decodeImage(istream, inMimeType);
outParam = {};
imgTools.decodeImageData(istream, inMimeType, outParam);
container = outParam.value;
// It's not easy to look at the pixel values from JS, so just
// check the container's size.
@ -273,7 +273,9 @@ imgFile = do_get_file(imgName);
istream = getFileInputStream(imgFile);
do_check_eq(istream.available(), 1406);
container = imgTools.decodeImage(istream, inMimeType);
outParam = { value: null };
imgTools.decodeImageData(istream, inMimeType, outParam);
container = outParam.value;
// It's not easy to look at the pixel values from JS, so just
// check the container's size.
@ -331,7 +333,9 @@ imgFile = do_get_file(imgName);
istream = getFileInputStream(imgFile);
do_check_eq(istream.available(), 1809);
container = imgTools.decodeImage(istream, inMimeType);
outParam = { value: null };
imgTools.decodeImageData(istream, inMimeType, outParam);
container = outParam.value;
// It's not easy to look at the pixel values from JS, so just
// check the container's size.
@ -439,7 +443,9 @@ imgFile = do_get_file(imgName);
istream = getFileInputStream(imgFile);
do_check_eq(istream.available(), 3494);
container = imgTools.decodeImage(istream, inMimeType);
outParam = {};
imgTools.decodeImageData(istream, inMimeType, outParam);
container = outParam.value;
// It's not easy to look at the pixel values from JS, so just
// check the container's size.
@ -657,7 +663,9 @@ for(var i=0; i<testData.length; ++i) {
imgFile = do_get_file(dict["preImage"]);
istream = getFileInputStream(imgFile);
var container = imgTools.decodeImage(istream, dict["preImageMimeType"]);
var outParam = { value: null };
imgTools.decodeImageData(istream, dict["preImageMimeType"], outParam);
var container = outParam.value;
istream = imgTools.encodeImage(container, dict["refImageMimeType"]);
@ -693,9 +701,11 @@ do_check_eq(istream.available(), 17759);
var errsrc = "none";
try {
container = imgTools.decodeImage(istream, inMimeType);
outParam = { value: null };
imgTools.decodeImageData(istream, inMimeType, outParam);
container = outParam.value;
// We should never hit this - decodeImage throws an assertion because the
// We should never hit this - decodeImageData throws an assertion because the
// image decoded doesn't have enough frames.
try {
istream = imgTools.encodeImage(container, "image/png");
@ -723,7 +733,9 @@ imgFile = do_get_file(imgName);
istream = getFileInputStream(imgFile);
do_check_eq(istream.available(), 4286);
container = imgTools.decodeImage(istream, inMimeType);
outParam = { value: null };
imgTools.decodeImageData(istream, inMimeType, outParam);
container = outParam.value;
var props = container.QueryInterface(Ci.nsIProperties);