mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out 4 changesets (bug 815471, bug 821023, bug 816374, bug 816362) for reftest failures.
This commit is contained in:
parent
acb811dff4
commit
41d18e74d0
@ -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 },
|
||||
|
@ -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,7 +34,7 @@ interface imgITools : nsISupports
|
||||
* be used. It is an error to pass an already-initialized container
|
||||
* as aContainer.
|
||||
*/
|
||||
[deprecated] void decodeImageData(in nsIInputStream aStream,
|
||||
void decodeImageData(in nsIInputStream aStream,
|
||||
in ACString aMimeType,
|
||||
inout imgIContainer aContainer);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -192,7 +192,6 @@ private:
|
||||
bool mSizeDecode;
|
||||
bool mInFrame;
|
||||
bool mIsAnimated;
|
||||
bool mFirstWrite;
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
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?
|
||||
|
@ -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
|
@ -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
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
if (mpchan)
|
||||
mIsMultiPartChannel = true;
|
||||
GetStatusTracker().SetIsMultipart();
|
||||
}
|
||||
|
||||
// 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
|
||||
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.
|
||||
mImage->OnNewSourceData();
|
||||
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,13 +768,22 @@ 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;
|
||||
|
||||
/* 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"));
|
||||
@ -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;
|
||||
|
||||
// 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);
|
||||
// load because subsequent images might be fine.
|
||||
if (NS_FAILED(rv) && !mIsMultiPartChannel) { // Probably bad mimetype
|
||||
|
||||
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)
|
||||
// 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 -- "
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
// 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.
|
||||
|
@ -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 ();
|
||||
|
@ -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());
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
request->GetURI(getter_AddRefs(uri));
|
||||
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>");
|
||||
}
|
||||
#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) {
|
||||
int16_t imageType = mImage->GetType();
|
||||
// Send frame messages (OnDataAvailable, OnStopFrame)
|
||||
if (imageType == imgIContainer::TYPE_VECTOR ||
|
||||
static_cast<RasterImage*>(mImage)->GetNumFrames() > 0) {
|
||||
|
||||
// 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);
|
||||
|
||||
// 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())
|
||||
proxy->OnFrameUpdate(&r);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user