mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 505385 - Part 9: Hoist decoder and container observer out of imgRequest into imgStatusTracker. r=joe
This commit is contained in:
parent
d14b24720d
commit
575c6923d4
@ -71,10 +71,8 @@ InitPrefCaches()
|
||||
PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest");
|
||||
#endif
|
||||
|
||||
NS_IMPL_ISUPPORTS8(imgRequest,
|
||||
imgIDecoderObserver, imgIContainerObserver,
|
||||
NS_IMPL_ISUPPORTS5(imgRequest,
|
||||
nsIStreamListener, nsIRequestObserver,
|
||||
nsISupportsWeakReference,
|
||||
nsIChannelEventSink,
|
||||
nsIInterfaceRequestor,
|
||||
nsIAsyncVerifyRedirectCallback)
|
||||
@ -90,7 +88,6 @@ imgRequest::imgRequest(imgLoader* aLoader)
|
||||
, mIsMultiPartChannel(false)
|
||||
, mGotData(false)
|
||||
, mIsInCache(false)
|
||||
, mBlockingOnload(false)
|
||||
, mResniffMimeType(false)
|
||||
{
|
||||
// Register our pref observers if we haven't yet.
|
||||
@ -175,6 +172,13 @@ bool imgRequest::HasCacheEntry() const
|
||||
return mCacheEntry != nullptr;
|
||||
}
|
||||
|
||||
void imgRequest::ResetCacheEntry()
|
||||
{
|
||||
if (HasCacheEntry()) {
|
||||
mCacheEntry->SetDataSize(0);
|
||||
}
|
||||
}
|
||||
|
||||
void imgRequest::AddProxy(imgRequestProxy *proxy)
|
||||
{
|
||||
NS_PRECONDITION(proxy, "null imgRequestProxy passed in");
|
||||
@ -270,16 +274,7 @@ void imgRequest::Cancel(nsresult aStatus)
|
||||
|
||||
imgStatusTracker& statusTracker = GetStatusTracker();
|
||||
|
||||
if (mBlockingOnload) {
|
||||
mBlockingOnload = false;
|
||||
|
||||
statusTracker.RecordUnblockOnload();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
statusTracker.SendUnblockOnload(iter.GetNext());
|
||||
}
|
||||
}
|
||||
statusTracker.MaybeUnblockOnload();
|
||||
|
||||
statusTracker.RecordCancel();
|
||||
|
||||
@ -477,289 +472,6 @@ imgRequest::StartDecoding()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** imgIContainerObserver methods **/
|
||||
|
||||
/* [noscript] void frameChanged (in imgIRequest request,
|
||||
in imgIContainer container,
|
||||
in nsIntRect dirtyRect); */
|
||||
NS_IMETHODIMP imgRequest::FrameChanged(imgIRequest *request,
|
||||
imgIContainer *container,
|
||||
const nsIntRect *dirtyRect)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::FrameChanged");
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"FrameChanged callback before we've created our image");
|
||||
|
||||
mImage->GetStatusTracker().RecordFrameChanged(container, dirtyRect);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendFrameChanged(iter.GetNext(), container, dirtyRect);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/** imgIDecoderObserver methods **/
|
||||
|
||||
/* void onStartDecode (in imgIRequest request); */
|
||||
NS_IMETHODIMP imgRequest::OnStartDecode(imgIRequest *request)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStartDecode");
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnStartDecode callback before we've created our image");
|
||||
|
||||
|
||||
imgStatusTracker& tracker = mImage->GetStatusTracker();
|
||||
tracker.RecordStartDecode();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
tracker.SendStartDecode(iter.GetNext());
|
||||
}
|
||||
|
||||
if (!mIsMultiPartChannel) {
|
||||
MOZ_ASSERT(!mBlockingOnload);
|
||||
mBlockingOnload = true;
|
||||
|
||||
tracker.RecordBlockOnload();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
tracker.SendBlockOnload(iter.GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 imgRequest::OnStopFrame will continue to increase the data size cumulatively.
|
||||
*/
|
||||
if (mCacheEntry)
|
||||
mCacheEntry->SetDataSize(0);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP imgRequest::OnStartRequest(imgIRequest *aRequest)
|
||||
{
|
||||
NS_NOTREACHED("imgRequest(imgIDecoderObserver)::OnStartRequest");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStartContainer (in imgIRequest request, in imgIContainer image); */
|
||||
NS_IMETHODIMP imgRequest::OnStartContainer(imgIRequest *request, imgIContainer *image)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStartContainer");
|
||||
|
||||
NS_ASSERTION(image, "imgRequest::OnStartContainer called with a null image!");
|
||||
if (!image) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnStartContainer callback before we've created our image");
|
||||
NS_ABORT_IF_FALSE(image == mImage,
|
||||
"OnStartContainer callback from an image we don't own");
|
||||
mImage->GetStatusTracker().RecordStartContainer(image);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendStartContainer(iter.GetNext(), image);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStartFrame (in imgIRequest request, in unsigned long frame); */
|
||||
NS_IMETHODIMP imgRequest::OnStartFrame(imgIRequest *request,
|
||||
uint32_t frame)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStartFrame");
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnStartFrame callback before we've created our image");
|
||||
|
||||
mImage->GetStatusTracker().RecordStartFrame(frame);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendStartFrame(iter.GetNext(), frame);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* [noscript] void onDataAvailable (in imgIRequest request, in boolean aCurrentFrame, [const] in nsIntRect rect); */
|
||||
NS_IMETHODIMP imgRequest::OnDataAvailable(imgIRequest *request,
|
||||
bool aCurrentFrame,
|
||||
const nsIntRect * rect)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable");
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnDataAvailable callback before we've created our image");
|
||||
|
||||
mImage->GetStatusTracker().RecordDataAvailable(aCurrentFrame, rect);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendDataAvailable(iter.GetNext(), aCurrentFrame, rect);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStopFrame (in imgIRequest request, in unsigned long frame); */
|
||||
NS_IMETHODIMP imgRequest::OnStopFrame(imgIRequest *request,
|
||||
uint32_t frame)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStopFrame");
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnStopFrame callback before we've created our image");
|
||||
|
||||
imgStatusTracker& tracker = mImage->GetStatusTracker();
|
||||
tracker.RecordStopFrame(frame);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
tracker.SendStopFrame(iter.GetNext(), frame);
|
||||
}
|
||||
|
||||
if (mBlockingOnload) {
|
||||
mBlockingOnload = false;
|
||||
|
||||
tracker.RecordUnblockOnload();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
tracker.SendUnblockOnload(iter.GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStopContainer (in imgIRequest request, in imgIContainer image); */
|
||||
NS_IMETHODIMP imgRequest::OnStopContainer(imgIRequest *request,
|
||||
imgIContainer *image)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStopContainer");
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnDataContainer callback before we've created our image");
|
||||
|
||||
imgStatusTracker& tracker = mImage->GetStatusTracker();
|
||||
tracker.RecordStopContainer(image);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
tracker.SendStopContainer(iter.GetNext(), image);
|
||||
}
|
||||
|
||||
// This is really hacky. We need to handle the case where we start decoding,
|
||||
// block onload, but then hit an error before we get to our first frame. In
|
||||
// theory we would just hook in at OnStopDecode, but OnStopDecode is broken
|
||||
// until we fix bug 505385. OnStopContainer is actually going away at that
|
||||
// point. So for now we take advantage of the fact that OnStopContainer is
|
||||
// always fired in the decoders at the same time as OnStopDecode.
|
||||
if (mBlockingOnload) {
|
||||
mBlockingOnload = false;
|
||||
|
||||
tracker.RecordUnblockOnload();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
tracker.SendUnblockOnload(iter.GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStopDecode (in imgIRequest request, in nsresult status, in wstring statusArg); */
|
||||
NS_IMETHODIMP imgRequest::OnStopDecode(imgIRequest *aRequest,
|
||||
nsresult aStatus,
|
||||
const PRUnichar *aStatusArg)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStopDecode");
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnDataDecode 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.
|
||||
UpdateCacheEntrySize();
|
||||
|
||||
mImage->GetStatusTracker().RecordStopDecode(aStatus, aStatusArg);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendStopDecode(iter.GetNext(), aStatus,
|
||||
aStatusArg);
|
||||
}
|
||||
|
||||
if (NS_FAILED(aStatus)) {
|
||||
// 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)
|
||||
os->NotifyObservers(mURI, "net:failed-to-process-uri-content", nullptr);
|
||||
}
|
||||
|
||||
// RasterImage and everything below it is completely correct and
|
||||
// bulletproof about its handling of decoder notifications.
|
||||
// Unfortunately, here and above we have to make some gross and
|
||||
// inappropriate use of things to get things to work without
|
||||
// completely overhauling the decoder observer interface (this will,
|
||||
// thankfully, happen in bug 505385). From imgRequest and above (for
|
||||
// the time being), OnStopDecode is just a companion to OnStopRequest
|
||||
// that signals success or failure of the _load_ (not the _decode_).
|
||||
// Within imgStatusTracker, we ignore OnStopDecode notifications from the
|
||||
// decoder and RasterImage and generate our own every time we send
|
||||
// OnStopRequest. From within SendStopDecode, we actually send
|
||||
// OnStopContainer. For more information, see bug 435296.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP imgRequest::OnStopRequest(imgIRequest *aRequest,
|
||||
bool aLastPart)
|
||||
{
|
||||
NS_NOTREACHED("imgRequest(imgIDecoderObserver)::OnStopRequest");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onDiscard (in imgIRequest request); */
|
||||
NS_IMETHODIMP imgRequest::OnDiscard(imgIRequest *aRequest)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnDiscard callback before we've created our image");
|
||||
|
||||
mImage->GetStatusTracker().RecordDiscard();
|
||||
|
||||
// Update the cache entry size, since we just got rid of frame data
|
||||
UpdateCacheEntrySize();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendDiscard(iter.GetNext());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP imgRequest::OnImageIsAnimated(imgIRequest *aRequest)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"OnImageIsAnimated callback before we've created our image");
|
||||
mImage->GetStatusTracker().RecordImageIsAnimated();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(GetStatusTracker().GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendImageIsAnimated(iter.GetNext());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/** nsIRequestObserver methods **/
|
||||
|
||||
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
|
||||
@ -1082,7 +794,8 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
|
||||
// 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.
|
||||
rv = mImage->Init(this, mContentType.get(), uriString.get(), imageFlags);
|
||||
rv = mImage->Init(GetStatusTracker().GetDecoderObserver(),
|
||||
mContentType.get(), uriString.get(), imageFlags);
|
||||
|
||||
// We allow multipart images to fail to initialize without cancelling the
|
||||
// load because subsequent images might be fine.
|
||||
|
@ -7,8 +7,6 @@
|
||||
#ifndef imgRequest_h__
|
||||
#define imgRequest_h__
|
||||
|
||||
#include "imgIDecoderObserver.h"
|
||||
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIContentSniffer.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
@ -22,7 +20,6 @@
|
||||
#include "nsCategoryCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsError.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
@ -41,9 +38,7 @@ class Image;
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
||||
class imgRequest : public imgIDecoderObserver,
|
||||
public nsIStreamListener,
|
||||
public nsSupportsWeakReference,
|
||||
class imgRequest : public nsIStreamListener,
|
||||
public nsIChannelEventSink,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsIAsyncVerifyRedirectCallback
|
||||
@ -117,6 +112,14 @@ public:
|
||||
// Get the current principal of the image. No AddRefing.
|
||||
inline nsIPrincipal* GetPrincipal() const { return mPrincipal.get(); };
|
||||
|
||||
// Resize the cache entry to 0 if it exists
|
||||
void ResetCacheEntry();
|
||||
|
||||
// Update the cache entry size based on the image container
|
||||
void UpdateCacheEntrySize();
|
||||
|
||||
nsresult GetURI(nsIURI **aURI);
|
||||
|
||||
private:
|
||||
friend class imgCacheEntry;
|
||||
friend class imgRequestProxy;
|
||||
@ -132,7 +135,6 @@ private:
|
||||
void Cancel(nsresult aStatus);
|
||||
void RemoveFromCache();
|
||||
|
||||
nsresult GetURI(nsIURI **aURI);
|
||||
nsresult GetSecurityInfo(nsISupports **aSecurityInfo);
|
||||
|
||||
inline const char *GetMimeType() const {
|
||||
@ -166,12 +168,10 @@ private:
|
||||
// try to update or modify the image cache.
|
||||
void SetIsInCache(bool cacheable);
|
||||
|
||||
// Update the cache entry size based on the image container
|
||||
void UpdateCacheEntrySize();
|
||||
bool IsBlockingOnload() const;
|
||||
void SetBlockingOnload(bool block) const;
|
||||
|
||||
public:
|
||||
NS_DECL_IMGIDECODEROBSERVER
|
||||
NS_DECL_IMGICONTAINEROBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSICHANNELEVENTSINK
|
||||
|
@ -98,10 +98,8 @@ nsresult imgRequestProxy::Init(imgStatusTracker* aStatusTracker,
|
||||
|
||||
NS_ABORT_IF_FALSE(mAnimationConsumers == 0, "Cannot have animation before Init");
|
||||
|
||||
mStatusTracker = aStatusTracker;
|
||||
mOwner = aStatusTracker->GetRequest();
|
||||
mOwnerHasImage = !!aStatusTracker->GetImage();
|
||||
MOZ_ASSERT_IF(mOwner, mStatusTracker == &mOwner->GetStatusTracker());
|
||||
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
|
||||
@ -136,7 +134,6 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
|
||||
|
||||
nsRefPtr<imgRequest> oldOwner = mOwner;
|
||||
mOwner = aNewOwner;
|
||||
mStatusTracker = &aNewOwner->GetStatusTracker();
|
||||
|
||||
// If we were locked, apply the locks here
|
||||
for (uint32_t i = 0; i < oldLockCount; i++)
|
||||
@ -501,7 +498,7 @@ NS_IMETHODIMP imgRequestProxy::Clone(imgIDecoderObserver* aObserver,
|
||||
// XXXldb That's not true anymore. Stuff from imgLoader adds the
|
||||
// request to the loadgroup.
|
||||
clone->SetLoadFlags(mLoadFlags);
|
||||
nsresult rv = clone->Init(mStatusTracker, mLoadGroup, mURI, aObserver);
|
||||
nsresult rv = clone->Init(&mOwner->GetStatusTracker(), mLoadGroup, mURI, aObserver);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
@ -910,7 +907,7 @@ imgRequestProxy::GetStatusTracker() const
|
||||
// That's why this method uses mOwner->GetStatusTracker() instead of just
|
||||
// mOwner->mStatusTracker -- we might have a null mImage and yet have an
|
||||
// mOwner with a non-null mImage (and a null mStatusTracker pointer).
|
||||
return *mStatusTracker;
|
||||
return mOwner->GetStatusTracker();
|
||||
}
|
||||
|
||||
mozilla::image::Image*
|
||||
@ -938,3 +935,9 @@ imgRequestProxyStatic::GetImage() const
|
||||
{
|
||||
return mImage;
|
||||
}
|
||||
|
||||
imgStatusTracker&
|
||||
imgRequestProxyStatic::GetStatusTracker() const
|
||||
{
|
||||
return mImage->GetStatusTracker();
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ protected:
|
||||
// live either on mOwner or mImage, depending on whether
|
||||
// (a) we have an mOwner at all
|
||||
// (b) whether mOwner has instantiated its image yet
|
||||
imgStatusTracker& GetStatusTracker() const;
|
||||
virtual imgStatusTracker& GetStatusTracker() const;
|
||||
|
||||
nsITimedChannel* TimedChannel()
|
||||
{
|
||||
@ -193,9 +193,6 @@ private:
|
||||
// means that imgRequest::mObservers will not have any stale pointers in it.
|
||||
nsRefPtr<imgRequest> mOwner;
|
||||
|
||||
// Weak pointer to the status tracker.
|
||||
imgStatusTracker* mStatusTracker;
|
||||
|
||||
// The URI of our request.
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
|
||||
@ -240,6 +237,7 @@ public:
|
||||
};
|
||||
|
||||
NS_IMETHOD GetImagePrincipal(nsIPrincipal** aPrincipal);
|
||||
virtual imgStatusTracker& GetStatusTracker() const MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
// Our image. We have to hold a strong reference here, because that's normally
|
||||
|
@ -12,12 +12,282 @@
|
||||
#include "Image.h"
|
||||
#include "ImageLogging.h"
|
||||
#include "RasterImage.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
using namespace mozilla::image;
|
||||
|
||||
NS_IMPL_ISUPPORTS3(imgStatusTrackerObserver,
|
||||
imgIDecoderObserver,
|
||||
imgIContainerObserver,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
/** imgIContainerObserver methods **/
|
||||
|
||||
/* [noscript] void frameChanged (in imgIRequest request,
|
||||
in imgIContainer container,
|
||||
in nsIntRect dirtyRect); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::FrameChanged(imgIRequest *request,
|
||||
imgIContainer *container,
|
||||
const nsIntRect *dirtyRect)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::FrameChanged");
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"FrameChanged callback before we've created our image");
|
||||
|
||||
mTracker->RecordFrameChanged(container, dirtyRect);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendFrameChanged(iter.GetNext(), container, dirtyRect);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/** imgIDecoderObserver methods **/
|
||||
|
||||
/* void onStartDecode (in imgIRequest request); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnStartDecode(imgIRequest *request)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStartDecode");
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnStartDecode callback before we've created our image");
|
||||
|
||||
|
||||
mTracker->RecordStartDecode();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendStartDecode(iter.GetNext());
|
||||
}
|
||||
|
||||
if (!mTracker->GetRequest()->GetMultipart()) {
|
||||
MOZ_ASSERT(!mTracker->mBlockingOnload);
|
||||
mTracker->mBlockingOnload = true;
|
||||
|
||||
mTracker->RecordBlockOnload();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendBlockOnload(iter.GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
mTracker->GetRequest()->ResetCacheEntry();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnStartRequest(imgIRequest *aRequest)
|
||||
{
|
||||
NS_NOTREACHED("imgRequest(imgIDecoderObserver)::OnStartRequest");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStartContainer (in imgIRequest request, in imgIContainer image); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnStartContainer(imgIRequest *request, imgIContainer *image)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStartContainer");
|
||||
|
||||
NS_ASSERTION(image, "imgStatusTrackerObserver::OnStartContainer called with a null image!");
|
||||
if (!image) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnStartContainer callback before we've created our image");
|
||||
NS_ABORT_IF_FALSE(image == mTracker->GetImage(),
|
||||
"OnStartContainer callback from an image we don't own");
|
||||
mTracker->RecordStartContainer(image);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendStartContainer(iter.GetNext(), image);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStartFrame (in imgIRequest request, in unsigned long frame); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnStartFrame(imgIRequest *request,
|
||||
uint32_t frame)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStartFrame");
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnStartFrame callback before we've created our image");
|
||||
|
||||
mTracker->RecordStartFrame(frame);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendStartFrame(iter.GetNext(), frame);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* [noscript] void onDataAvailable (in imgIRequest request, in boolean aCurrentFrame, [const] in nsIntRect rect); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnDataAvailable(imgIRequest *request,
|
||||
bool aCurrentFrame,
|
||||
const nsIntRect * rect)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnDataAvailable");
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnDataAvailable callback before we've created our image");
|
||||
|
||||
mTracker->RecordDataAvailable(aCurrentFrame, rect);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendDataAvailable(iter.GetNext(), aCurrentFrame, rect);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStopFrame (in imgIRequest request, in unsigned long frame); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnStopFrame(imgIRequest *request,
|
||||
uint32_t frame)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStopFrame");
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnStopFrame callback before we've created our image");
|
||||
|
||||
mTracker->RecordStopFrame(frame);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendStopFrame(iter.GetNext(), frame);
|
||||
}
|
||||
|
||||
mTracker->MaybeUnblockOnload();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStopContainer (in imgIRequest request, in imgIContainer image); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnStopContainer(imgIRequest *request,
|
||||
imgIContainer *image)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStopContainer");
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnDataContainer callback before we've created our image");
|
||||
|
||||
mTracker->RecordStopContainer(image);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendStopContainer(iter.GetNext(), image);
|
||||
}
|
||||
|
||||
// This is really hacky. We need to handle the case where we start decoding,
|
||||
// block onload, but then hit an error before we get to our first frame. In
|
||||
// theory we would just hook in at OnStopDecode, but OnStopDecode is broken
|
||||
// until we fix bug 505385. OnStopContainer is actually going away at that
|
||||
// point. So for now we take advantage of the fact that OnStopContainer is
|
||||
// always fired in the decoders at the same time as OnStopDecode.
|
||||
mTracker->MaybeUnblockOnload();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onStopDecode (in imgIRequest request, in nsresult status, in wstring statusArg); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnStopDecode(imgIRequest *aRequest,
|
||||
nsresult aStatus,
|
||||
const PRUnichar *aStatusArg)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStopDecode");
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnDataDecode 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.
|
||||
mTracker->GetRequest()->UpdateCacheEntrySize();
|
||||
|
||||
mTracker->RecordStopDecode(aStatus, aStatusArg);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendStopDecode(iter.GetNext(), aStatus, aStatusArg);
|
||||
}
|
||||
|
||||
if (NS_FAILED(aStatus)) {
|
||||
// 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;
|
||||
mTracker->GetRequest()->GetURI(getter_AddRefs(uri));
|
||||
os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// RasterImage and everything below it is completely correct and
|
||||
// bulletproof about its handling of decoder notifications.
|
||||
// Unfortunately, here and above we have to make some gross and
|
||||
// inappropriate use of things to get things to work without
|
||||
// completely overhauling the decoder observer interface (this will,
|
||||
// thankfully, happen in bug 505385). From imgRequest and above (for
|
||||
// the time being), OnStopDecode is just a companion to OnStopRequest
|
||||
// that signals success or failure of the _load_ (not the _decode_).
|
||||
// Within imgStatusTracker, we ignore OnStopDecode notifications from the
|
||||
// decoder and RasterImage and generate our own every time we send
|
||||
// OnStopRequest. From within SendStopDecode, we actually send
|
||||
// OnStopContainer. For more information, see bug 435296.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnStopRequest(imgIRequest *aRequest,
|
||||
bool aLastPart)
|
||||
{
|
||||
NS_NOTREACHED("imgRequest(imgIDecoderObserver)::OnStopRequest");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onDiscard (in imgIRequest request); */
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnDiscard(imgIRequest *aRequest)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnDiscard callback before we've created our image");
|
||||
|
||||
mTracker->RecordDiscard();
|
||||
|
||||
// Update the cache entry size, since we just got rid of frame data
|
||||
mTracker->GetRequest()->UpdateCacheEntrySize();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendDiscard(iter.GetNext());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP imgStatusTrackerObserver::OnImageIsAnimated(imgIRequest *aRequest)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mTracker->GetImage(),
|
||||
"OnImageIsAnimated callback before we've created our image");
|
||||
mTracker->RecordImageIsAnimated();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->GetConsumers());
|
||||
while (iter.HasMore()) {
|
||||
mTracker->SendImageIsAnimated(iter.GetNext());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// imgStatusTracker methods
|
||||
|
||||
static nsresult
|
||||
GetResultFromImageStatus(uint32_t aStatus)
|
||||
{
|
||||
@ -33,7 +303,9 @@ imgStatusTracker::imgStatusTracker(Image* aImage, imgRequest* aRequest)
|
||||
mRequest(aRequest),
|
||||
mState(0),
|
||||
mImageStatus(imgIRequest::STATUS_NONE),
|
||||
mHadLastPart(false)
|
||||
mHadLastPart(false),
|
||||
mBlockingOnload(false),
|
||||
mTrackerObserver(new imgStatusTrackerObserver(this))
|
||||
{}
|
||||
|
||||
imgStatusTracker::imgStatusTracker(const imgStatusTracker& aOther)
|
||||
@ -41,7 +313,8 @@ imgStatusTracker::imgStatusTracker(const imgStatusTracker& aOther)
|
||||
mRequest(aOther.mRequest),
|
||||
mState(aOther.mState),
|
||||
mImageStatus(aOther.mImageStatus),
|
||||
mHadLastPart(aOther.mHadLastPart)
|
||||
mHadLastPart(aOther.mHadLastPart),
|
||||
mBlockingOnload(aOther.mBlockingOnload)
|
||||
// Note: we explicitly don't copy mRequestRunnable, because it won't be
|
||||
// nulled out when the mRequestRunnable's Run function eventually gets
|
||||
// called.
|
||||
@ -240,7 +513,7 @@ imgStatusTracker::SyncNotify(imgRequestProxy* proxy)
|
||||
}
|
||||
}
|
||||
|
||||
// See bug 505385 and imgRequest::OnStopDecode for more information on why we
|
||||
// See bug 505385 and imgStatusTrackerObserver::OnStopDecode for more information on why we
|
||||
// call OnStopContainer based on stateDecodeStopped, and why OnStopDecode is
|
||||
// called with OnStopRequest.
|
||||
if (mState & stateDecodeStopped) {
|
||||
@ -400,13 +673,13 @@ imgStatusTracker::RecordStopContainer(imgIContainer* aContainer)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mImage,
|
||||
"RecordStopContainer called before we have an Image");
|
||||
// No-op: see imgRequest::OnStopDecode for more information
|
||||
// No-op: see imgStatusTrackerObserver::OnStopDecode for more information
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStopContainer(imgRequestProxy* aProxy, imgIContainer* aContainer)
|
||||
{
|
||||
// No-op: see imgRequest::OnStopDecode for more information
|
||||
// No-op: see imgStatusTrackerObserver::OnStopDecode for more information
|
||||
}
|
||||
|
||||
void
|
||||
@ -427,7 +700,7 @@ void
|
||||
imgStatusTracker::SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus,
|
||||
const PRUnichar* statusArg)
|
||||
{
|
||||
// See imgRequest::OnStopDecode for more information on why we call
|
||||
// See imgStatusTrackerObserver::OnStopDecode for more information on why we call
|
||||
// OnStopContainer from here this, and why imgRequestProxy::OnStopDecode() is
|
||||
// called from OnStopRequest() and SyncNotify().
|
||||
if (!aProxy->NotificationsDeferred())
|
||||
@ -532,7 +805,7 @@ imgStatusTracker::RecordStopRequest(bool aLastPart, nsresult aStatus)
|
||||
void
|
||||
imgStatusTracker::SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus)
|
||||
{
|
||||
// See bug 505385 and imgRequest::OnStopDecode for more information on why
|
||||
// See bug 505385 and imgStatusTrackerObserver::OnStopDecode for more information on why
|
||||
// OnStopDecode is called with OnStopRequest.
|
||||
if (!aProxy->NotificationsDeferred()) {
|
||||
aProxy->OnStopDecode(GetResultFromImageStatus(mImageStatus), nullptr);
|
||||
@ -569,3 +842,20 @@ imgStatusTracker::SendUnblockOnload(imgRequestProxy* aProxy)
|
||||
aProxy->UnblockOnload();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::MaybeUnblockOnload()
|
||||
{
|
||||
if (!mBlockingOnload) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBlockingOnload = false;
|
||||
|
||||
RecordUnblockOnload();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
|
||||
while (iter.HasMore()) {
|
||||
SendUnblockOnload(iter.GetNext());
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ class imgRequest;
|
||||
class imgRequestProxy;
|
||||
class imgStatusNotifyRunnable;
|
||||
class imgRequestNotifyRunnable;
|
||||
class imgStatusTracker;
|
||||
struct nsIntRect;
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
@ -21,9 +22,12 @@ class Image;
|
||||
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nscore.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "imgIDecoderObserver.h"
|
||||
|
||||
enum {
|
||||
stateRequestStarted = PR_BIT(0),
|
||||
@ -35,6 +39,27 @@ enum {
|
||||
stateBlockingOnload = PR_BIT(6)
|
||||
};
|
||||
|
||||
class imgStatusTrackerObserver : public imgIDecoderObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGIDECODEROBSERVER
|
||||
NS_DECL_IMGICONTAINEROBSERVER
|
||||
|
||||
imgStatusTrackerObserver(imgStatusTracker* aTracker)
|
||||
: mTracker(aTracker) {}
|
||||
|
||||
virtual ~imgStatusTrackerObserver() {}
|
||||
|
||||
void SetTracker(imgStatusTracker* aTracker) {
|
||||
mTracker = aTracker;
|
||||
}
|
||||
|
||||
private:
|
||||
imgStatusTracker* mTracker;
|
||||
};
|
||||
|
||||
/*
|
||||
* The image status tracker is a class that encapsulates all the loading and
|
||||
* decoding status about an Image, and makes it possible to send notifications
|
||||
@ -167,13 +192,18 @@ public:
|
||||
void RecordUnblockOnload();
|
||||
void SendUnblockOnload(imgRequestProxy* aProxy);
|
||||
|
||||
void MaybeUnblockOnload();
|
||||
|
||||
// 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(); }
|
||||
|
||||
private:
|
||||
friend class imgStatusNotifyRunnable;
|
||||
friend class imgRequestNotifyRunnable;
|
||||
friend class imgStatusTrackerObserver;
|
||||
|
||||
nsCOMPtr<nsIRunnable> mRequestRunnable;
|
||||
|
||||
@ -184,10 +214,13 @@ private:
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user