mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 572520: step 6, centralize the tracking of load/decode status. Make a single class, imgStatusTracker, which keeps track of the state of an image, and also takes care of calling notifications on imgRequestProxys. r=jrmuizel,bholley
This commit is contained in:
parent
92722f5a0a
commit
dce4fe07b6
@ -58,6 +58,7 @@ CPPSRCS = \
|
||||
imgRequestProxy.cpp \
|
||||
imgTools.cpp \
|
||||
imgDiscardTracker.cpp \
|
||||
imgStatusTracker.cpp \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -144,6 +144,7 @@ imgContainer::imgContainer() :
|
||||
mLoopCount(-1),
|
||||
mObserver(nsnull),
|
||||
mLockCount(0),
|
||||
mStatusTracker(this),
|
||||
mDecoder(nsnull),
|
||||
mWorker(nsnull),
|
||||
mBytesDecoded(0),
|
||||
@ -337,6 +338,9 @@ NS_IMETHODIMP imgContainer::ExtractFrame(PRUint32 aWhichFrame,
|
||||
|
||||
img->mFrames.AppendElement(subframe.forget());
|
||||
|
||||
img->mStatusTracker.RecordLoaded();
|
||||
img->mStatusTracker.RecordDecoded();
|
||||
|
||||
*_retval = img.forget().get();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include "imgFrame.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "imgDiscardTracker.h"
|
||||
#include "imgStatusTracker.h"
|
||||
|
||||
#define NS_IMGCONTAINER_CID \
|
||||
{ /* c76ff2c1-9bf6-418a-b143-3340c00112f7 */ \
|
||||
@ -161,6 +162,9 @@ public:
|
||||
/* Triggers discarding. */
|
||||
void Discard();
|
||||
|
||||
imgStatusTracker& GetStatusTracker() { return mStatusTracker; }
|
||||
PRBool IsInitialized() const { return mInitialized; }
|
||||
|
||||
private:
|
||||
struct Anim
|
||||
{
|
||||
@ -331,6 +335,8 @@ private: // data
|
||||
nsTArray<char> mSourceData;
|
||||
nsCString mSourceDataMimeType;
|
||||
|
||||
imgStatusTracker mStatusTracker;
|
||||
|
||||
friend class imgDecodeWorker;
|
||||
friend class imgDiscardTracker;
|
||||
|
||||
|
@ -671,7 +671,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, aLoadGroup, uri, aObserver);
|
||||
nsresult rv = proxyRequest->Init(aRequest, aLoadGroup, aRequest->mImage, uri, aObserver);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_RELEASE(proxyRequest);
|
||||
return rv;
|
||||
@ -1988,7 +1988,6 @@ imgCacheValidator::imgCacheValidator(imgRequest *request, void *aContext) :
|
||||
|
||||
imgCacheValidator::~imgCacheValidator()
|
||||
{
|
||||
/* destructor code */
|
||||
if (mRequest) {
|
||||
mRequest->mValidator = nsnull;
|
||||
}
|
||||
@ -2008,6 +2007,9 @@ void imgCacheValidator::AddProxy(imgRequestProxy *aProxy)
|
||||
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
|
||||
NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
|
||||
{
|
||||
// If this request is coming from cache, the request all our proxies are
|
||||
// pointing at is valid, and all we have to do is tell them to notify their
|
||||
// listeners.
|
||||
nsCOMPtr<nsICachingChannel> cacheChan(do_QueryInterface(aRequest));
|
||||
if (cacheChan) {
|
||||
PRBool isFromCache;
|
||||
|
@ -166,14 +166,10 @@ NS_IMPL_ISUPPORTS7(imgRequest,
|
||||
nsIInterfaceRequestor)
|
||||
|
||||
imgRequest::imgRequest() :
|
||||
mImageStatus(imgIRequest::STATUS_NONE), mState(0), mCacheId(0),
|
||||
mValidator(nsnull), mImageSniffers("image-sniffing-services"),
|
||||
mDeferredLocks(0), mDecodeRequested(PR_FALSE),
|
||||
mIsMultiPartChannel(PR_FALSE), mLoading(PR_FALSE),
|
||||
mCacheId(0), mValidator(nsnull), mImageSniffers("image-sniffing-services"),
|
||||
mDecodeRequested(PR_FALSE), mIsMultiPartChannel(PR_FALSE),
|
||||
mGotData(PR_FALSE), mIsInCache(PR_FALSE)
|
||||
{
|
||||
/* member initializers and constructor code */
|
||||
}
|
||||
{}
|
||||
|
||||
imgRequest::~imgRequest()
|
||||
{
|
||||
@ -202,8 +198,8 @@ nsresult imgRequest::Init(nsIURI *aURI,
|
||||
NS_ABORT_IF_FALSE(aChannel, "No channel");
|
||||
|
||||
mProperties = do_CreateInstance("@mozilla.org/properties;1");
|
||||
if (!mProperties)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsCOMPtr<imgIContainer> comImg = do_CreateInstance("@mozilla.org/image/container;3");
|
||||
mImage = static_cast<imgContainer*>(comImg.get());
|
||||
|
||||
mURI = aURI;
|
||||
mKeyURI = aKeyURI;
|
||||
@ -216,13 +212,6 @@ nsresult imgRequest::Init(nsIURI *aURI,
|
||||
|
||||
mChannel->SetNotificationCallbacks(this);
|
||||
|
||||
/* set our loading flag to true here.
|
||||
Setting it here lets checks to see if the load is in progress
|
||||
before OnStartRequest gets called, letting 'this' properly get removed
|
||||
from the cache in certain cases.
|
||||
*/
|
||||
mLoading = PR_TRUE;
|
||||
|
||||
mCacheEntry = aCacheEntry;
|
||||
|
||||
mCacheId = aCacheId;
|
||||
@ -272,13 +261,12 @@ nsresult imgRequest::AddProxy(imgRequestProxy *proxy)
|
||||
}
|
||||
|
||||
// If we don't have any current observers, we should restart any animation.
|
||||
if (mImage && !HaveProxyWithObserver(proxy) && proxy->HasObserver()) {
|
||||
if (!HaveProxyWithObserver(proxy) && proxy->HasObserver()) {
|
||||
LOG_MSG(gImgLog, "imgRequest::AddProxy", "resetting animation");
|
||||
|
||||
mImage->ResetAnimation();
|
||||
}
|
||||
|
||||
proxy->SetImage(mImage);
|
||||
proxy->SetPrincipal(mPrincipal);
|
||||
|
||||
return mObservers.AppendElementUnlessExists(proxy) ?
|
||||
@ -291,30 +279,14 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, PRBoo
|
||||
|
||||
mObservers.RemoveElement(proxy);
|
||||
|
||||
/* Check mState below before we potentially call Cancel() below. Since
|
||||
Cancel() may result in OnStopRequest being called back before Cancel()
|
||||
returns, leaving mState in a different state then the one it was in at
|
||||
this point.
|
||||
*/
|
||||
// Let the status tracker do its thing before we potentially call Cancel()
|
||||
// below, because Cancel() may result in OnStopRequest being called back
|
||||
// before Cancel() returns, leaving the image in a different state then the
|
||||
// one it was in at this point.
|
||||
|
||||
if (aNotify) {
|
||||
// The "real" OnStopDecode - fix this with bug 505385.
|
||||
if (!(mState & stateDecodeStopped)) {
|
||||
proxy->OnStopContainer(mImage);
|
||||
}
|
||||
mImage->GetStatusTracker().EmulateRequestFinished(proxy, aStatus, !aNotify);
|
||||
|
||||
// make sure that observer gets an OnStopDecode message sent to it
|
||||
if (!(mState & stateRequestStopped)) {
|
||||
proxy->OnStopDecode(aStatus, nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that observer gets an OnStopRequest message sent to it
|
||||
if (!(mState & stateRequestStopped)) {
|
||||
proxy->OnStopRequest(PR_TRUE);
|
||||
}
|
||||
|
||||
if (mImage && !HaveProxyWithObserver(nsnull)) {
|
||||
if (!HaveProxyWithObserver(nsnull)) {
|
||||
LOG_MSG(gImgLog, "imgRequest::RemoveProxy", "stopping animation");
|
||||
|
||||
mImage->StopAnimation();
|
||||
@ -342,11 +314,9 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, PRBoo
|
||||
This way, if a proxy is destroyed without calling cancel on it, it won't leak
|
||||
and won't leave a bad pointer in mObservers.
|
||||
*/
|
||||
if (mRequest && mLoading && NS_FAILED(aStatus)) {
|
||||
if (mImage->GetStatusTracker().IsLoading() && NS_FAILED(aStatus)) {
|
||||
LOG_MSG(gImgLog, "imgRequest::RemoveProxy", "load in progress. canceling");
|
||||
|
||||
mImageStatus |= imgIRequest::STATUS_LOAD_PARTIAL;
|
||||
|
||||
this->Cancel(NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
@ -362,27 +332,6 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus, PRBoo
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void imgRequest::Cancel(nsresult aStatus)
|
||||
{
|
||||
/* The Cancel() method here should only be called by this class. */
|
||||
|
||||
LOG_SCOPE(gImgLog, "imgRequest::Cancel");
|
||||
|
||||
if (mImage) {
|
||||
LOG_MSG(gImgLog, "imgRequest::Cancel", "stopping animation");
|
||||
|
||||
mImage->StopAnimation();
|
||||
}
|
||||
|
||||
if (!(mImageStatus & imgIRequest::STATUS_LOAD_PARTIAL))
|
||||
mImageStatus |= imgIRequest::STATUS_ERROR;
|
||||
|
||||
RemoveFromCache();
|
||||
|
||||
if (mRequest && mLoading)
|
||||
mRequest->Cancel(aStatus);
|
||||
}
|
||||
|
||||
void imgRequest::CancelAndAbort(nsresult aStatus)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::CancelAndAbort");
|
||||
@ -398,6 +347,23 @@ void imgRequest::CancelAndAbort(nsresult aStatus)
|
||||
}
|
||||
}
|
||||
|
||||
void imgRequest::Cancel(nsresult aStatus)
|
||||
{
|
||||
/* The Cancel() method here should only be called by this class. */
|
||||
|
||||
LOG_SCOPE(gImgLog, "imgRequest::Cancel");
|
||||
|
||||
LOG_MSG(gImgLog, "imgRequest::Cancel", "stopping animation");
|
||||
mImage->StopAnimation();
|
||||
|
||||
mImage->GetStatusTracker().RecordCancel();
|
||||
|
||||
RemoveFromCache();
|
||||
|
||||
if (mRequest && mImage->GetStatusTracker().IsLoading())
|
||||
mRequest->Cancel(aStatus);
|
||||
}
|
||||
|
||||
nsresult imgRequest::GetURI(nsIURI **aURI)
|
||||
{
|
||||
LOG_FUNC(gImgLog, "imgRequest::GetURI");
|
||||
@ -503,8 +469,7 @@ void imgRequest::UpdateCacheEntrySize()
|
||||
{
|
||||
if (mCacheEntry) {
|
||||
PRUint32 imageSize = 0;
|
||||
if (mImage)
|
||||
mImage->GetDataSize(&imageSize);
|
||||
mImage->GetDataSize(&imageSize);
|
||||
mCacheEntry->SetDataSize(imageSize);
|
||||
|
||||
#ifdef DEBUG_joe
|
||||
@ -513,46 +478,25 @@ void imgRequest::UpdateCacheEntrySize()
|
||||
printf("CACHEPUT: %d %s %d\n", time(NULL), url.get(), imageSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nsresult
|
||||
imgRequest::LockImage()
|
||||
{
|
||||
// If we have an image, apply the lock directly
|
||||
if (mImage) {
|
||||
NS_ABORT_IF_FALSE(mDeferredLocks == 0, "Have image, but deferred locks?");
|
||||
return mImage->LockImage();
|
||||
}
|
||||
|
||||
// Otherwise, queue it up for when we have an image
|
||||
mDeferredLocks++;
|
||||
|
||||
return NS_OK;
|
||||
return mImage->LockImage();
|
||||
}
|
||||
|
||||
nsresult
|
||||
imgRequest::UnlockImage()
|
||||
{
|
||||
// If we have an image, apply the unlock directly
|
||||
if (mImage) {
|
||||
NS_ABORT_IF_FALSE(mDeferredLocks == 0, "Have image, but deferred locks?");
|
||||
return mImage->UnlockImage();
|
||||
}
|
||||
|
||||
// If we don't have an image, get rid of one of our deferred locks (we should
|
||||
// have one).
|
||||
NS_ABORT_IF_FALSE(mDeferredLocks > 0, "lock/unlock calls must be matched!");
|
||||
mDeferredLocks--;
|
||||
|
||||
return NS_OK;
|
||||
return mImage->UnlockImage();
|
||||
}
|
||||
|
||||
nsresult
|
||||
imgRequest::RequestDecode()
|
||||
{
|
||||
// If we have an image, apply the request directly
|
||||
if (mImage) {
|
||||
// If we've initialized our image, we can request a decode.
|
||||
if (mImage->IsInitialized()) {
|
||||
return mImage->RequestDecode();
|
||||
}
|
||||
|
||||
@ -570,9 +514,11 @@ NS_IMETHODIMP imgRequest::FrameChanged(imgIContainer *container,
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::FrameChanged");
|
||||
|
||||
mImage->GetStatusTracker().RecordFrameChanged(container, dirtyRect);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->FrameChanged(container, dirtyRect);
|
||||
mImage->GetStatusTracker().SendFrameChanged(iter.GetNext(), container, dirtyRect);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -585,11 +531,11 @@ NS_IMETHODIMP imgRequest::OnStartDecode(imgIRequest *request)
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStartDecode");
|
||||
|
||||
mState |= stateDecodeStarted;
|
||||
mImage->GetStatusTracker().RecordStartDecode();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnStartDecode();
|
||||
mImage->GetStatusTracker().SendStartDecode(iter.GetNext());
|
||||
}
|
||||
|
||||
/* In the case of streaming jpegs, it is possible to get multiple OnStartDecodes which
|
||||
@ -617,20 +563,18 @@ NS_IMETHODIMP imgRequest::OnStartContainer(imgIRequest *request, imgIContainer *
|
||||
NS_ASSERTION(image, "imgRequest::OnStartContainer called with a null image!");
|
||||
if (!image) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// We only want to send onStartContainer once
|
||||
PRBool alreadySent = (mState & stateHasSize) != 0;
|
||||
|
||||
mState |= stateHasSize;
|
||||
|
||||
mImageStatus |= imgIRequest::STATUS_SIZE_AVAILABLE;
|
||||
|
||||
if (!alreadySent) {
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnStartContainer(image);
|
||||
}
|
||||
// We only want to send onStartContainer once, but we might get multiple
|
||||
// OnStartContainer calls (e.g. from multipart/x-mixed-replace). Therefore,
|
||||
// we tell our status tracker about OnStartContainer *after* attempting to
|
||||
// send the notifications. That way, if we have previously called
|
||||
// OnStartContainer, the status tracker can notice.
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendStartContainer(iter.GetNext(), image);
|
||||
}
|
||||
|
||||
mImage->GetStatusTracker().RecordStartContainer(image);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -640,9 +584,11 @@ NS_IMETHODIMP imgRequest::OnStartFrame(imgIRequest *request,
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStartFrame");
|
||||
|
||||
mImage->GetStatusTracker().RecordStartFrame(frame);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnStartFrame(frame);
|
||||
mImage->GetStatusTracker().SendStartFrame(iter.GetNext(), frame);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -655,9 +601,11 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(imgIRequest *request,
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable");
|
||||
|
||||
mImage->GetStatusTracker().RecordDataAvailable(aCurrentFrame, rect);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnDataAvailable(aCurrentFrame, rect);
|
||||
mImage->GetStatusTracker().SendDataAvailable(iter.GetNext(), aCurrentFrame, rect);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -669,11 +617,11 @@ NS_IMETHODIMP imgRequest::OnStopFrame(imgIRequest *request,
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStopFrame");
|
||||
|
||||
mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE;
|
||||
mImage->GetStatusTracker().RecordStopFrame(frame);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnStopFrame(frame);
|
||||
mImage->GetStatusTracker().SendStopFrame(iter.GetNext(), frame);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -685,13 +633,11 @@ NS_IMETHODIMP imgRequest::OnStopContainer(imgIRequest *request,
|
||||
{
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnStopContainer");
|
||||
|
||||
// XXXbholley - This should be moved into OnStopDecode when we fix bug
|
||||
// 505385.
|
||||
mState |= stateDecodeStopped;
|
||||
mImage->GetStatusTracker().RecordStopContainer(image);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnStopContainer(image);
|
||||
mImage->GetStatusTracker().SendStopContainer(iter.GetNext(), image);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -708,12 +654,13 @@ NS_IMETHODIMP imgRequest::OnStopDecode(imgIRequest *aRequest,
|
||||
// entry size to take this into account.
|
||||
UpdateCacheEntrySize();
|
||||
|
||||
// If we were successful, set STATUS_DECODE_COMPLETE
|
||||
if (NS_SUCCEEDED(aStatus))
|
||||
mImageStatus |= imgIRequest::STATUS_DECODE_COMPLETE;
|
||||
// If we weren't, clear all success status bits and set error.
|
||||
else
|
||||
mImageStatus = imgIRequest::STATUS_ERROR;
|
||||
mImage->GetStatusTracker().RecordStopDecode(aStatus, aStatusArg);
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
mImage->GetStatusTracker().SendStopDecode(iter.GetNext(), aStatus,
|
||||
aStatusArg);
|
||||
}
|
||||
|
||||
// ImgContainer and everything below it is completely correct and
|
||||
// bulletproof about its handling of decoder notifications.
|
||||
@ -723,9 +670,10 @@ NS_IMETHODIMP imgRequest::OnStopDecode(imgIRequest *aRequest,
|
||||
// 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_).
|
||||
// As such, we ignore OnStopDecode notifications from the decoder and
|
||||
// container and generate our own every time we send OnStopRequest.
|
||||
// For more information, see bug 435296.
|
||||
// Within imgStatusTracker, we ignore OnStopDecode notifications from the
|
||||
// decoder and container 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;
|
||||
}
|
||||
@ -740,25 +688,17 @@ NS_IMETHODIMP imgRequest::OnStopRequest(imgIRequest *aRequest,
|
||||
/* void onDiscard (in imgIRequest request); */
|
||||
NS_IMETHODIMP imgRequest::OnDiscard(imgIRequest *aRequest)
|
||||
{
|
||||
// Clear the state bits we no longer deserve.
|
||||
PRUint32 stateBitsToClear = stateDecodeStarted | stateDecodeStopped;
|
||||
mState &= ~stateBitsToClear;
|
||||
|
||||
// Clear the status bits we no longer deserve.
|
||||
PRUint32 statusBitsToClear = imgIRequest::STATUS_FRAME_COMPLETE
|
||||
| imgIRequest::STATUS_DECODE_COMPLETE;
|
||||
mImageStatus &= ~statusBitsToClear;
|
||||
mImage->GetStatusTracker().RecordDiscard();
|
||||
|
||||
// Update the cache entry size, since we just got rid of frame data
|
||||
UpdateCacheEntrySize();
|
||||
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnDiscard();
|
||||
mImage->GetStatusTracker().SendDiscard(iter.GetNext());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
/** nsIRequestObserver methods **/
|
||||
@ -776,23 +716,14 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
|
||||
mIsMultiPartChannel = PR_TRUE;
|
||||
|
||||
// If we're not multipart, we shouldn't have an image yet
|
||||
NS_ABORT_IF_FALSE(mIsMultiPartChannel || !mImage,
|
||||
NS_ABORT_IF_FALSE(mIsMultiPartChannel || !mImage->IsInitialized(),
|
||||
"Already have an image for non-multipart request");
|
||||
|
||||
// If we're multipart and have an image, fix things up for another round
|
||||
if (mIsMultiPartChannel && mImage) {
|
||||
// If we're multipart, and our image is initialized, fix things up for another round
|
||||
if (mIsMultiPartChannel && mImage->IsInitialized()) {
|
||||
|
||||
// Inform the container that we have new source data
|
||||
mImage->NewSourceData();
|
||||
|
||||
// Clear any status and state bits indicating load/decode
|
||||
mImageStatus &= ~imgIRequest::STATUS_LOAD_PARTIAL;
|
||||
mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE;
|
||||
mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE;
|
||||
mState &= ~stateRequestStarted;
|
||||
mState &= ~stateDecodeStarted;
|
||||
mState &= ~stateDecodeStopped;
|
||||
mState &= ~stateRequestStopped;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -810,20 +741,15 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
|
||||
mRequest = chan;
|
||||
}
|
||||
|
||||
// The request has started
|
||||
mState |= stateRequestStarted;
|
||||
mImage->GetStatusTracker().RecordStartRequest();
|
||||
|
||||
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
|
||||
if (channel)
|
||||
channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
|
||||
|
||||
/* set our loading flag to true */
|
||||
mLoading = PR_TRUE;
|
||||
|
||||
/* notify our kids */
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->OnStartRequest();
|
||||
mImage->GetStatusTracker().SendStartRequest(iter.GetNext());
|
||||
}
|
||||
|
||||
/* Get our principal */
|
||||
@ -909,11 +835,6 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt,
|
||||
{
|
||||
LOG_FUNC(gImgLog, "imgRequest::OnStopRequest");
|
||||
|
||||
mState |= stateRequestStopped;
|
||||
|
||||
/* set our loading flag to false */
|
||||
mLoading = PR_FALSE;
|
||||
|
||||
PRBool lastPart = PR_TRUE;
|
||||
nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
|
||||
if (mpchan)
|
||||
@ -937,7 +858,7 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt,
|
||||
// Tell the image that it has all of the source data. Note that this can
|
||||
// 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) {
|
||||
if (mImage->IsInitialized()) {
|
||||
|
||||
// Notify the image
|
||||
nsresult rv = mImage->SourceDataComplete();
|
||||
@ -950,30 +871,24 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt,
|
||||
status = rv;
|
||||
}
|
||||
|
||||
// If the request went through, say we loaded the image, and update the
|
||||
// cache entry size. Otherwise, cancel the request, which adds an error
|
||||
// flag to mImageStatus.
|
||||
if (mImage && NS_SUCCEEDED(status)) {
|
||||
|
||||
// Flag that we loaded the image
|
||||
mImageStatus |= imgIRequest::STATUS_LOAD_COMPLETE;
|
||||
mImage->GetStatusTracker().RecordStopRequest(lastPart, status);
|
||||
|
||||
// If the request went through, update the cache entry size. Otherwise,
|
||||
// cancel the request, which removes us from the cache.
|
||||
if (mImage->IsInitialized() && NS_SUCCEEDED(status)) {
|
||||
// We update the cache entry size here because this is where we finish
|
||||
// loading compressed source data, which is part of our size calculus.
|
||||
UpdateCacheEntrySize();
|
||||
}
|
||||
else
|
||||
this->Cancel(status); // sets status, stops animations, removes from cache
|
||||
|
||||
/* notify the kids */
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator sdIter(mObservers);
|
||||
while (sdIter.HasMore()) {
|
||||
sdIter.GetNext()->OnStopDecode(GetResultFromImageStatus(mImageStatus), nsnull);
|
||||
else {
|
||||
// stops animations, removes from cache
|
||||
this->Cancel(status);
|
||||
}
|
||||
|
||||
/* notify the kids */
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator srIter(mObservers);
|
||||
while (srIter.HasMore()) {
|
||||
srIter.GetNext()->OnStopRequest(lastPart);
|
||||
mImage->GetStatusTracker().SendStopRequest(srIter.GetNext(), lastPart, status);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -992,12 +907,13 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
|
||||
|
||||
NS_ASSERTION(aRequest, "imgRequest::OnDataAvailable -- no request!");
|
||||
|
||||
mGotData = PR_TRUE;
|
||||
nsresult rv;
|
||||
|
||||
if (!mImage) {
|
||||
if (!mGotData) {
|
||||
LOG_SCOPE(gImgLog, "imgRequest::OnDataAvailable |First time through... finding mimetype|");
|
||||
|
||||
mGotData = PR_TRUE;
|
||||
|
||||
/* look at the first few bytes and see if we can tell what the data is from that
|
||||
* since servers tend to lie. :(
|
||||
*/
|
||||
@ -1095,25 +1011,12 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
|
||||
if (mIsMultiPartChannel)
|
||||
containerFlags |= imgIContainer::INIT_FLAG_MULTIPART;
|
||||
|
||||
// Create and initialize the imgContainer. 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 = do_CreateInstance("@mozilla.org/image/container;3");
|
||||
if (!mImage) {
|
||||
this->Cancel(NS_ERROR_OUT_OF_MEMORY);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
// Initialize the image that we created in OnStartRequest(). 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(), containerFlags);
|
||||
if (NS_FAILED(rv)) { // Probably bad mimetype
|
||||
|
||||
// There's no reason to keep the image around. Save memory.
|
||||
//
|
||||
// XXXbholley - This is also here because I'm not sure we've found
|
||||
// all the consumers who (incorrectly) check whether the container
|
||||
// is null to determine things like size availability (they should
|
||||
// be checking the image status instead).
|
||||
mImage = nsnull;
|
||||
|
||||
this->Cancel(rv);
|
||||
return NS_BINDING_ABORTED;
|
||||
}
|
||||
@ -1136,21 +1039,10 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If we were waiting on the image to do something, now's our chance.
|
||||
if (mDecodeRequested) {
|
||||
mImage->RequestDecode();
|
||||
}
|
||||
while (mDeferredLocks) {
|
||||
mImage->LockImage();
|
||||
mDeferredLocks--;
|
||||
}
|
||||
|
||||
// Tell all of our proxies that we have an image.
|
||||
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
|
||||
while (iter.HasMore()) {
|
||||
iter.GetNext()->SetImage(mImage);
|
||||
}
|
||||
}
|
||||
|
||||
// WriteToContainer always consumes everything it gets
|
||||
|
@ -61,6 +61,7 @@
|
||||
#include "nsWeakReference.h"
|
||||
#include "ImageErrors.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "imgContainer.h"
|
||||
|
||||
class imgCacheValidator;
|
||||
|
||||
@ -68,14 +69,6 @@ class imgRequestProxy;
|
||||
class imgCacheEntry;
|
||||
class imgMemoryReporter;
|
||||
|
||||
enum {
|
||||
stateRequestStarted = PR_BIT(0),
|
||||
stateHasSize = PR_BIT(1),
|
||||
stateDecodeStarted = PR_BIT(2),
|
||||
stateDecodeStopped = PR_BIT(3),
|
||||
stateRequestStopped = PR_BIT(4)
|
||||
};
|
||||
|
||||
class imgRequest : public imgIDecoderObserver,
|
||||
public nsIStreamListener,
|
||||
public nsSupportsWeakReference,
|
||||
@ -107,7 +100,10 @@ public:
|
||||
// a request is "reusable" if it has already been loaded, or it is
|
||||
// currently being loaded on the same event queue as the new request
|
||||
// being made...
|
||||
PRBool IsReusable(void *aCacheId) { return !mLoading || (aCacheId == mCacheId); }
|
||||
PRBool IsReusable(void *aCacheId) {
|
||||
return (mImage && mImage->GetStatusTracker().IsLoading()) ||
|
||||
(aCacheId == mCacheId);
|
||||
}
|
||||
|
||||
// Cancel, but also ensure that all work done in Init() is undone. Call this
|
||||
// only when the channel has failed to open, and so calling Cancel() on it
|
||||
@ -119,14 +115,7 @@ public:
|
||||
nsresult LockImage();
|
||||
nsresult UnlockImage();
|
||||
nsresult RequestDecode();
|
||||
static nsresult GetResultFromImageStatus(PRUint32 aStatus)
|
||||
{
|
||||
if (aStatus & imgIRequest::STATUS_ERROR)
|
||||
return NS_IMAGELIB_ERROR_FAILURE;
|
||||
if (aStatus & imgIRequest::STATUS_LOAD_COMPLETE)
|
||||
return NS_IMAGELIB_SUCCESS_LOAD_FINISHED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class imgCacheEntry;
|
||||
friend class imgRequestProxy;
|
||||
@ -138,13 +127,13 @@ private:
|
||||
mLoadId = aLoadId;
|
||||
mLoadTime = PR_Now();
|
||||
}
|
||||
inline PRUint32 GetImageStatus() const { return mImageStatus; }
|
||||
inline PRUint32 GetState() const { return mState; }
|
||||
void Cancel(nsresult aStatus);
|
||||
void RemoveFromCache();
|
||||
|
||||
nsresult GetURI(nsIURI **aURI);
|
||||
nsresult GetKeyURI(nsIURI **aURI);
|
||||
nsresult GetSecurityInfo(nsISupports **aSecurityInfo);
|
||||
void RemoveFromCache();
|
||||
|
||||
inline const char *GetMimeType() const {
|
||||
return mContentType.get();
|
||||
}
|
||||
@ -200,7 +189,7 @@ private:
|
||||
// The URI we are keyed on in the cache.
|
||||
nsCOMPtr<nsIURI> mKeyURI;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<imgIContainer> mImage;
|
||||
nsRefPtr<imgContainer> mImage;
|
||||
nsCOMPtr<nsIProperties> mProperties;
|
||||
nsCOMPtr<nsISupports> mSecurityInfo;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
@ -208,8 +197,6 @@ private:
|
||||
|
||||
nsTObserverArray<imgRequestProxy*> mObservers;
|
||||
|
||||
PRUint32 mImageStatus;
|
||||
PRUint32 mState;
|
||||
nsCString mContentType;
|
||||
|
||||
nsRefPtr<imgCacheEntry> mCacheEntry; /* we hold on to this to this so long as we have observers */
|
||||
@ -224,11 +211,9 @@ private:
|
||||
|
||||
// Sometimes consumers want to do things before the image is ready. Let them,
|
||||
// and apply the action when the image becomes available.
|
||||
PRUint32 mDeferredLocks;
|
||||
PRPackedBool mDecodeRequested : 1;
|
||||
|
||||
PRPackedBool mIsMultiPartChannel : 1;
|
||||
PRPackedBool mLoading : 1;
|
||||
PRPackedBool mGotData : 1;
|
||||
PRPackedBool mIsInCache : 1;
|
||||
};
|
||||
|
@ -62,16 +62,13 @@ imgRequestProxy::imgRequestProxy() :
|
||||
mURI(nsnull),
|
||||
mImage(nsnull),
|
||||
mPrincipal(nsnull),
|
||||
mImageStatus(0),
|
||||
mState(0),
|
||||
mListener(nsnull),
|
||||
mLoadFlags(nsIRequest::LOAD_NORMAL),
|
||||
mLocksHeld(0),
|
||||
mCanceled(PR_FALSE),
|
||||
mIsInLoadGroup(PR_FALSE),
|
||||
mListenerIsStrongRef(PR_FALSE),
|
||||
mDecodeRequested(PR_FALSE),
|
||||
mHadLastPart(PR_FALSE)
|
||||
mDecodeRequested(PR_FALSE)
|
||||
{
|
||||
/* member initializers and constructor code */
|
||||
|
||||
@ -84,10 +81,8 @@ imgRequestProxy::~imgRequestProxy()
|
||||
|
||||
// Unlock the image the proper number of times if we're holding locks on it.
|
||||
// Note that UnlockImage() decrements mLocksHeld each time it's called.
|
||||
if (mOwner) {
|
||||
while (mLocksHeld)
|
||||
UnlockImage();
|
||||
}
|
||||
while (mLocksHeld)
|
||||
UnlockImage();
|
||||
|
||||
// Explicitly set mListener to null to ensure that the RemoveProxy
|
||||
// call below can't send |this| to an arbitrary listener while |this|
|
||||
@ -112,13 +107,10 @@ imgRequestProxy::~imgRequestProxy()
|
||||
}
|
||||
}
|
||||
|
||||
nsresult imgRequestProxy::Init(imgRequest* request, nsILoadGroup* aLoadGroup, nsIURI* aURI,
|
||||
imgIDecoderObserver* aObserver)
|
||||
nsresult imgRequestProxy::Init(imgRequest* request, nsILoadGroup* aLoadGroup, imgContainer* aImage,
|
||||
nsIURI* aURI, imgIDecoderObserver* aObserver)
|
||||
{
|
||||
NS_PRECONDITION(!mOwner && !mListener, "imgRequestProxy is already initialized");
|
||||
NS_PRECONDITION(request, "no request");
|
||||
if (!request)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequestProxy::Init", "request", request);
|
||||
|
||||
@ -132,10 +124,12 @@ nsresult imgRequestProxy::Init(imgRequest* request, nsILoadGroup* aLoadGroup, ns
|
||||
NS_ADDREF(mListener);
|
||||
}
|
||||
mLoadGroup = aLoadGroup;
|
||||
mImage = aImage;
|
||||
mURI = aURI;
|
||||
|
||||
// Note: AddProxy won't send all the On* notifications immediately
|
||||
request->AddProxy(this);
|
||||
if (mOwner)
|
||||
mOwner->AddProxy(this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -144,20 +138,28 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
|
||||
{
|
||||
NS_PRECONDITION(mOwner, "Cannot ChangeOwner on a proxy without an owner!");
|
||||
|
||||
if (mCanceled)
|
||||
return NS_OK;
|
||||
|
||||
// Were we decoded before?
|
||||
PRBool wasDecoded = PR_FALSE;
|
||||
if (mOwner->GetImageStatus() & imgIRequest::STATUS_FRAME_COMPLETE)
|
||||
wasDecoded = PR_TRUE;
|
||||
|
||||
// If we're holding locks, unlock the old image.
|
||||
// Note that UnlockImage decrements mLocksHeld each time it's called.
|
||||
PRUint32 oldLockCount = mLocksHeld;
|
||||
while (mLocksHeld)
|
||||
UnlockImage();
|
||||
|
||||
// Even if we are cancelled, we MUST change our image, because the image
|
||||
// holds our status, and the status must always be correct.
|
||||
mImage = aNewOwner->mImage;
|
||||
|
||||
// If we were locked, apply the locks here
|
||||
for (PRUint32 i = 0; i < oldLockCount; i++)
|
||||
LockImage();
|
||||
|
||||
if (mCanceled)
|
||||
return NS_OK;
|
||||
|
||||
// Were we decoded before?
|
||||
PRBool wasDecoded = PR_FALSE;
|
||||
if (mImage->GetStatusTracker().GetImageStatus() & imgIRequest::STATUS_FRAME_COMPLETE)
|
||||
wasDecoded = PR_TRUE;
|
||||
|
||||
// Passing false to aNotify means that mListener will still get
|
||||
// OnStopRequest, if needed.
|
||||
mOwner->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER, PR_FALSE);
|
||||
@ -171,10 +173,6 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
|
||||
if (wasDecoded || mDecodeRequested)
|
||||
mOwner->RequestDecode();
|
||||
|
||||
// If we were locked, apply the locks here
|
||||
for (PRUint32 i = 0; i < oldLockCount; i++)
|
||||
LockImage();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -238,7 +236,7 @@ NS_IMETHODIMP imgRequestProxy::GetStatus(nsresult *aStatus)
|
||||
/* void cancel (in nsresult status); */
|
||||
NS_IMETHODIMP imgRequestProxy::Cancel(nsresult status)
|
||||
{
|
||||
if (mCanceled || !mOwner)
|
||||
if (mCanceled)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
LOG_SCOPE(gImgLog, "imgRequestProxy::Cancel");
|
||||
@ -254,7 +252,8 @@ imgRequestProxy::DoCancel(nsresult status)
|
||||
{
|
||||
// Passing false to aNotify means that mListener will still get
|
||||
// OnStopRequest, if needed.
|
||||
mOwner->RemoveProxy(this, status, PR_FALSE);
|
||||
if (mOwner)
|
||||
mOwner->RemoveProxy(this, status, PR_FALSE);
|
||||
|
||||
NullOutListener();
|
||||
}
|
||||
@ -262,7 +261,7 @@ imgRequestProxy::DoCancel(nsresult status)
|
||||
/* void cancelAndForgetObserver (in nsresult aStatus); */
|
||||
NS_IMETHODIMP imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
|
||||
{
|
||||
if (mCanceled || !mOwner)
|
||||
if (mCanceled)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
LOG_SCOPE(gImgLog, "imgRequestProxy::CancelAndForgetObserver");
|
||||
@ -272,10 +271,11 @@ NS_IMETHODIMP imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
|
||||
// Now cheat and make sure our removal from loadgroup happens async
|
||||
PRBool oldIsInLoadGroup = mIsInLoadGroup;
|
||||
mIsInLoadGroup = PR_FALSE;
|
||||
|
||||
|
||||
// Passing false to aNotify means that mListener will still get
|
||||
// OnStopRequest, if needed.
|
||||
mOwner->RemoveProxy(this, aStatus, PR_FALSE);
|
||||
if (mOwner)
|
||||
mOwner->RemoveProxy(this, aStatus, PR_FALSE);
|
||||
|
||||
mIsInLoadGroup = oldIsInLoadGroup;
|
||||
|
||||
@ -308,9 +308,6 @@ imgRequestProxy::RequestDecode()
|
||||
NS_IMETHODIMP
|
||||
imgRequestProxy::LockImage()
|
||||
{
|
||||
if (!mImage)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mLocksHeld++;
|
||||
|
||||
return mImage->LockImage();
|
||||
@ -320,10 +317,8 @@ imgRequestProxy::LockImage()
|
||||
NS_IMETHODIMP
|
||||
imgRequestProxy::UnlockImage()
|
||||
{
|
||||
if (!mImage)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_ABORT_IF_FALSE(mLocksHeld > 0, "calling unlock but no locks!");
|
||||
|
||||
mLocksHeld--;
|
||||
|
||||
return mImage->UnlockImage();
|
||||
@ -370,7 +365,7 @@ NS_IMETHODIMP imgRequestProxy::SetLoadFlags(nsLoadFlags flags)
|
||||
/* attribute imgIContainer image; */
|
||||
NS_IMETHODIMP imgRequestProxy::GetImage(imgIContainer * *aImage)
|
||||
{
|
||||
if (!mImage)
|
||||
if (!mImage->IsInitialized())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_ADDREF(*aImage = mImage);
|
||||
@ -381,19 +376,8 @@ NS_IMETHODIMP imgRequestProxy::GetImage(imgIContainer * *aImage)
|
||||
/* readonly attribute unsigned long imageStatus; */
|
||||
NS_IMETHODIMP imgRequestProxy::GetImageStatus(PRUint32 *aStatus)
|
||||
{
|
||||
if (!mOwner && !mImage) {
|
||||
*aStatus = imgIRequest::STATUS_ERROR;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aStatus = mImage->GetStatusTracker().GetImageStatus();
|
||||
|
||||
if (mOwner) {
|
||||
*aStatus = mOwner->GetImageStatus();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we don't have an owner, we have an image, and have cached the image's
|
||||
// status.
|
||||
*aStatus = mImageStatus;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -435,6 +419,9 @@ NS_IMETHODIMP imgRequestProxy::Clone(imgIDecoderObserver* aObserver,
|
||||
imgIRequest** aClone)
|
||||
{
|
||||
NS_PRECONDITION(aClone, "Null out param");
|
||||
|
||||
LOG_SCOPE(gImgLog, "imgRequestProxy::Clone");
|
||||
|
||||
*aClone = nsnull;
|
||||
nsRefPtr<imgRequestProxy> clone = new imgRequestProxy();
|
||||
|
||||
@ -445,32 +432,18 @@ 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(mOwner, mLoadGroup, mURI, aObserver);
|
||||
nsresult rv = clone->Init(mOwner, mLoadGroup, mImage, mURI, aObserver);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
clone->mHadLastPart = mHadLastPart;
|
||||
clone->SetImage(mImage);
|
||||
clone->SetPrincipal(mPrincipal);
|
||||
|
||||
// Temporary hack - must be removed in patch to centralize image state tracking.
|
||||
PRUint32 imageStatus = 0;
|
||||
GetImageStatus(&imageStatus);
|
||||
PRUint32 state = 0;
|
||||
GetState(&state);
|
||||
clone->mImageStatus = imageStatus;
|
||||
clone->mState = state;
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Assign to *aClone before calling Notify so that if the caller expects to
|
||||
// only be notified for requests it's already holding pointers to it won't be
|
||||
// surprised.
|
||||
*aClone = clone.forget().get();
|
||||
NS_ADDREF(*aClone = clone);
|
||||
|
||||
// Send the notifications to the clone's observer
|
||||
static_cast<imgRequestProxy*>(*aClone)->NotifyListener();
|
||||
clone->NotifyListener();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -663,8 +636,6 @@ void imgRequestProxy::OnStopRequest(PRBool lastPart)
|
||||
// listener, etc). Don't let them do it.
|
||||
nsCOMPtr<imgIRequest> kungFuDeathGrip(this);
|
||||
|
||||
mHadLastPart = lastPart;
|
||||
|
||||
if (mListener) {
|
||||
// Hold a ref to the listener while we call it, just in case.
|
||||
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
|
||||
@ -708,66 +679,38 @@ void imgRequestProxy::NullOutListener()
|
||||
}
|
||||
}
|
||||
|
||||
nsresult imgRequestProxy::GetState(PRUint32 *aState)
|
||||
{
|
||||
if (!mOwner && !mImage) {
|
||||
*aState = 0;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mOwner) {
|
||||
*aState = mOwner->GetState();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we don't have an owner, we have an image, and have cached the image's
|
||||
// state.
|
||||
*aState = mState;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
imgRequestProxy::GetStaticRequest(imgIRequest** aReturn)
|
||||
{
|
||||
*aReturn = nsnull;
|
||||
|
||||
nsCOMPtr<imgIContainer> img;
|
||||
nsCOMPtr<imgIContainer> currentFrame;
|
||||
GetImage(getter_AddRefs(img));
|
||||
PRBool animated;
|
||||
|
||||
if (img && NS_SUCCEEDED(img->GetAnimated(&animated)) && !animated) {
|
||||
if (NS_SUCCEEDED(mImage->GetAnimated(&animated)) && !animated) {
|
||||
// Early exit - we're not animated, so we don't have to do anything.
|
||||
NS_ADDREF(*aReturn = this);
|
||||
return NS_OK;
|
||||
} else if (img) {
|
||||
// We are animated. We need to extract the current frame from this image.
|
||||
PRInt32 w = 0;
|
||||
PRInt32 h = 0;
|
||||
img->GetWidth(&w);
|
||||
img->GetHeight(&h);
|
||||
nsIntRect rect(0, 0, w, h);
|
||||
img->ExtractFrame(imgIContainer::FRAME_CURRENT, rect,
|
||||
imgIContainer::FLAG_SYNC_DECODE,
|
||||
getter_AddRefs(currentFrame));
|
||||
}
|
||||
|
||||
// Now, we're creating a static imgRequestProxy, so we have to extract this
|
||||
// image's status and other ancillary information.
|
||||
PRUint32 imageStatus = 0;
|
||||
GetImageStatus(&imageStatus);
|
||||
PRUint32 state = 0;
|
||||
GetState(&state);
|
||||
// We are animated. We need to extract the current frame from this image.
|
||||
PRInt32 w = 0;
|
||||
PRInt32 h = 0;
|
||||
mImage->GetWidth(&w);
|
||||
mImage->GetHeight(&h);
|
||||
nsIntRect rect(0, 0, w, h);
|
||||
nsCOMPtr<imgIContainer> currentFrame;
|
||||
nsresult rv = mImage->ExtractFrame(imgIContainer::FRAME_CURRENT, rect,
|
||||
imgIContainer::FLAG_SYNC_DECODE,
|
||||
getter_AddRefs(currentFrame));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
imgRequestProxy* req = new imgRequestProxy();
|
||||
req->Init(nsnull, nsnull, mURI, nsnull);
|
||||
req->SetImage(currentFrame);
|
||||
nsRefPtr<imgContainer> frame = static_cast<imgContainer*>(currentFrame.get());
|
||||
|
||||
// Create a static imgRequestProxy with our new extracted frame.
|
||||
nsRefPtr<imgRequestProxy> req = new imgRequestProxy();
|
||||
req->Init(nsnull, nsnull, frame, mURI, nsnull);
|
||||
req->SetPrincipal(mPrincipal);
|
||||
|
||||
// Temporary hack - must be removed in patch to centralize image state tracking.
|
||||
req->mImageStatus = imageStatus;
|
||||
req->mState = state;
|
||||
|
||||
NS_ADDREF(*aReturn = req);
|
||||
|
||||
return NS_OK;
|
||||
@ -778,64 +721,13 @@ void imgRequestProxy::SetPrincipal(nsIPrincipal *aPrincipal)
|
||||
mPrincipal = aPrincipal;
|
||||
}
|
||||
|
||||
void imgRequestProxy::SetImage(imgIContainer *aImage)
|
||||
void imgRequestProxy::NotifyListener()
|
||||
{
|
||||
mImage = aImage;
|
||||
}
|
||||
|
||||
nsresult imgRequestProxy::NotifyListener()
|
||||
{
|
||||
nsCOMPtr<imgIRequest> kungFuDeathGrip(this);
|
||||
|
||||
PRUint32 imageStatus = 0;
|
||||
GetImageStatus(&imageStatus);
|
||||
PRUint32 state = 0;
|
||||
GetState(&state);
|
||||
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
GetImage(getter_AddRefs(image));
|
||||
|
||||
// OnStartRequest
|
||||
if (state & stateRequestStarted)
|
||||
OnStartRequest();
|
||||
|
||||
// OnStartContainer
|
||||
if (state & stateHasSize)
|
||||
OnStartContainer(image);
|
||||
|
||||
// OnStartDecode
|
||||
if (state & stateDecodeStarted)
|
||||
OnStartDecode();
|
||||
|
||||
// Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame)
|
||||
PRUint32 nframes = 0;
|
||||
if (image)
|
||||
image->GetNumFrames(&nframes);
|
||||
|
||||
if (nframes > 0) {
|
||||
PRUint32 frame;
|
||||
image->GetCurrentFrameIndex(&frame);
|
||||
OnStartFrame(frame);
|
||||
|
||||
// OnDataAvailable
|
||||
// XXX - Should only send partial rects here, but that needs to
|
||||
// wait until we fix up the observer interface
|
||||
nsIntRect r;
|
||||
image->GetCurrentFrameRect(r);
|
||||
OnDataAvailable(frame, &r);
|
||||
|
||||
if (state & stateRequestStopped)
|
||||
OnStopFrame(frame);
|
||||
}
|
||||
|
||||
// The "real" OnStopDecode - Fix this with bug 505385.
|
||||
if (state & stateDecodeStopped)
|
||||
OnStopContainer(image);
|
||||
|
||||
if (state & stateRequestStopped) {
|
||||
OnStopDecode(imgRequest::GetResultFromImageStatus(imageStatus), nsnull);
|
||||
OnStopRequest(mHadLastPart);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
// It would be nice to notify the observer directly instead of through the
|
||||
// proxy, but there are several places we do extra processing when we receive
|
||||
// notifications (like OnStopRequest()), and we need to check mCanceled
|
||||
// everywhere too.
|
||||
|
||||
if (mListener)
|
||||
mImage->GetStatusTracker().Notify(this);
|
||||
}
|
||||
|
@ -37,6 +37,9 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef imgRequestProxy_h__
|
||||
#define imgRequestProxy_h__
|
||||
|
||||
#include "imgIRequest.h"
|
||||
#include "imgIDecoderObserver.h"
|
||||
#include "nsISecurityInfoProvider.h"
|
||||
@ -75,7 +78,8 @@ public:
|
||||
|
||||
// Callers to Init or ChangeOwner are required to call NotifyListener after
|
||||
// (although not immediately after) doing so.
|
||||
nsresult Init(imgRequest *request, nsILoadGroup *aLoadGroup, nsIURI* aURI, imgIDecoderObserver *aObserver);
|
||||
nsresult Init(imgRequest *request, nsILoadGroup *aLoadGroup, imgContainer* aImage,
|
||||
nsIURI* aURI, imgIDecoderObserver *aObserver);
|
||||
|
||||
nsresult ChangeOwner(imgRequest *aNewOwner); // this will change mOwner. Do not call this if the previous
|
||||
// owner has already sent notifications out!
|
||||
@ -83,14 +87,17 @@ public:
|
||||
void AddToLoadGroup();
|
||||
void RemoveFromLoadGroup(PRBool releaseLoadGroup);
|
||||
|
||||
// Notify this proxy's listener of the current state of the request.
|
||||
nsresult NotifyListener();
|
||||
|
||||
protected:
|
||||
friend class imgRequest;
|
||||
inline PRBool HasObserver() const {
|
||||
return mListener != nsnull;
|
||||
}
|
||||
|
||||
void SetPrincipal(nsIPrincipal *aPrincipal);
|
||||
void SetImage(imgIContainer *aImage);
|
||||
|
||||
// Notify this proxy's listener of the current state of the request.
|
||||
void NotifyListener();
|
||||
|
||||
protected:
|
||||
friend class imgStatusTracker;
|
||||
|
||||
class imgCancelRunnable;
|
||||
friend class imgCancelRunnable;
|
||||
@ -129,10 +136,6 @@ protected:
|
||||
void OnStartRequest();
|
||||
void OnStopRequest(PRBool aLastPart);
|
||||
|
||||
inline PRBool HasObserver() const {
|
||||
return mListener != nsnull;
|
||||
}
|
||||
|
||||
/* Finish up canceling ourselves */
|
||||
void DoCancel(nsresult status);
|
||||
|
||||
@ -143,8 +146,6 @@ protected:
|
||||
RemoveFromLoadGroup(PR_TRUE);
|
||||
}
|
||||
|
||||
nsresult GetState(PRUint32 *aState);
|
||||
|
||||
private:
|
||||
friend class imgCacheValidator;
|
||||
|
||||
@ -161,15 +162,12 @@ private:
|
||||
|
||||
// The image we represent. Is null until data has been received, and is then
|
||||
// set by imgRequest.
|
||||
nsCOMPtr<imgIContainer> mImage;
|
||||
nsRefPtr<imgContainer> mImage;
|
||||
|
||||
// Our principal. Is null until data has been received from the channel, and
|
||||
// is then set by imgRequest.
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
PRUint32 mImageStatus;
|
||||
PRUint32 mState;
|
||||
|
||||
// mListener is only promised to be a weak ref (see imgILoader.idl),
|
||||
// but we actually keep a strong ref to it until we've seen our
|
||||
// first OnStopRequest.
|
||||
@ -182,8 +180,6 @@ private:
|
||||
PRPackedBool mIsInLoadGroup;
|
||||
PRPackedBool mListenerIsStrongRef;
|
||||
PRPackedBool mDecodeRequested;
|
||||
// Whether we've seen the last part of the load. For normal,
|
||||
// non-multipart/x-mixed-replace loads, this is true once OnStopRequest has
|
||||
// been received.
|
||||
PRPackedBool mHadLastPart;
|
||||
};
|
||||
|
||||
#endif // imgRequestProxy_h__
|
||||
|
351
modules/libpr0n/src/imgStatusTracker.cpp
Normal file
351
modules/libpr0n/src/imgStatusTracker.cpp
Normal file
@ -0,0 +1,351 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
*
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Drew <joe@drew.ca> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "imgStatusTracker.h"
|
||||
|
||||
#include "imgRequest.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "imgRequestProxy.h"
|
||||
|
||||
static nsresult
|
||||
GetResultFromImageStatus(PRUint32 aStatus)
|
||||
{
|
||||
if (aStatus & imgIRequest::STATUS_ERROR)
|
||||
return NS_IMAGELIB_ERROR_FAILURE;
|
||||
if (aStatus & imgIRequest::STATUS_LOAD_COMPLETE)
|
||||
return NS_IMAGELIB_SUCCESS_LOAD_FINISHED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
imgStatusTracker::imgStatusTracker(imgIContainer* aImage)
|
||||
: mImage(aImage),
|
||||
mState(0),
|
||||
mImageStatus(imgIRequest::STATUS_NONE),
|
||||
mHadLastPart(PR_FALSE)
|
||||
{}
|
||||
|
||||
PRBool
|
||||
imgStatusTracker::IsLoading() const
|
||||
{
|
||||
// Checking for whether OnStopRequest has fired allows us to say we're
|
||||
// loading before OnStartRequest gets called, letting the request properly
|
||||
// get removed from the cache in certain cases.
|
||||
return !(mState & stateRequestStopped);
|
||||
}
|
||||
|
||||
PRUint32
|
||||
imgStatusTracker::GetImageStatus() const
|
||||
{
|
||||
return mImageStatus;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::Notify(imgRequestProxy* proxy)
|
||||
{
|
||||
nsCOMPtr<imgIRequest> kungFuDeathGrip(proxy);
|
||||
|
||||
// OnStartRequest
|
||||
if (mState & stateRequestStarted)
|
||||
proxy->OnStartRequest();
|
||||
|
||||
// OnStartContainer
|
||||
if (mState & stateHasSize)
|
||||
proxy->OnStartContainer(mImage);
|
||||
|
||||
// OnStartDecode
|
||||
if (mState & stateDecodeStarted)
|
||||
proxy->OnStartDecode();
|
||||
|
||||
// Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame)
|
||||
PRUint32 nframes = 0;
|
||||
mImage->GetNumFrames(&nframes);
|
||||
|
||||
if (nframes > 0) {
|
||||
PRUint32 frame;
|
||||
mImage->GetCurrentFrameIndex(&frame);
|
||||
proxy->OnStartFrame(frame);
|
||||
|
||||
// OnDataAvailable
|
||||
// XXX - Should only send partial rects here, but that needs to
|
||||
// wait until we fix up the observer interface
|
||||
nsIntRect r;
|
||||
mImage->GetCurrentFrameRect(r);
|
||||
proxy->OnDataAvailable(frame, &r);
|
||||
|
||||
if (mState & stateFrameStopped)
|
||||
proxy->OnStopFrame(frame);
|
||||
}
|
||||
|
||||
// See bug 505385 and imgRequest::OnStopDecode for more information on why we
|
||||
// call OnStopContainer based on stateDecodeStopped, and why OnStopDecode is
|
||||
// called with OnStopRequest.
|
||||
if (mState & stateDecodeStopped)
|
||||
proxy->OnStopContainer(mImage);
|
||||
|
||||
if (mState & stateRequestStopped) {
|
||||
proxy->OnStopDecode(GetResultFromImageStatus(mImageStatus), nsnull);
|
||||
proxy->OnStopRequest(mHadLastPart);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::EmulateRequestFinished(imgRequestProxy* aProxy, nsresult aStatus,
|
||||
PRBool aOnlySendStopRequest)
|
||||
{
|
||||
nsCOMPtr<imgIRequest> kungFuDeathGrip(aProxy);
|
||||
|
||||
if (!aOnlySendStopRequest) {
|
||||
// The "real" OnStopDecode - fix this with bug 505385.
|
||||
if (!(mState & stateDecodeStopped)) {
|
||||
aProxy->OnStopContainer(mImage);
|
||||
}
|
||||
|
||||
if (!(mState & stateRequestStopped)) {
|
||||
aProxy->OnStopDecode(aStatus, nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(mState & stateRequestStopped)) {
|
||||
aProxy->OnStopRequest(PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordCancel()
|
||||
{
|
||||
if (!(mImageStatus & imgIRequest::STATUS_LOAD_PARTIAL))
|
||||
mImageStatus |= imgIRequest::STATUS_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordLoaded()
|
||||
{
|
||||
mState |= stateRequestStarted | stateHasSize | stateRequestStopped;
|
||||
mImageStatus |= imgIRequest::STATUS_SIZE_AVAILABLE | imgIRequest::STATUS_LOAD_COMPLETE;
|
||||
mHadLastPart = PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordDecoded()
|
||||
{
|
||||
mState |= stateDecodeStarted | stateDecodeStopped | stateFrameStopped;
|
||||
mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE | imgIRequest::STATUS_DECODE_COMPLETE;
|
||||
}
|
||||
|
||||
/* non-virtual imgIDecoderObserver methods */
|
||||
void
|
||||
imgStatusTracker::RecordStartDecode()
|
||||
{
|
||||
mState |= stateDecodeStarted;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStartDecode(imgRequestProxy* aProxy)
|
||||
{
|
||||
aProxy->OnStartDecode();
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordStartContainer(imgIContainer* aContainer)
|
||||
{
|
||||
mState |= stateHasSize;
|
||||
mImageStatus |= imgIRequest::STATUS_SIZE_AVAILABLE;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStartContainer(imgRequestProxy* aProxy, imgIContainer* aContainer)
|
||||
{
|
||||
// We only want to send onStartContainer once, but we might get multiple
|
||||
// OnStartContainer calls (e.g. from multipart/x-mixed-replace).
|
||||
PRBool alreadySent = (mState & stateHasSize) != 0;
|
||||
if (!alreadySent)
|
||||
aProxy->OnStartContainer(aContainer);
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordStartFrame(PRUint32 aFrame)
|
||||
{
|
||||
// no bookkeeping necessary here - this is implied by imgIContainer's number
|
||||
// of frames
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStartFrame(imgRequestProxy* aProxy, PRUint32 aFrame)
|
||||
{
|
||||
aProxy->OnStartFrame(aFrame);
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordDataAvailable(PRBool aCurrentFrame, const nsIntRect* aRect)
|
||||
{
|
||||
// no bookkeeping necessary here - this is implied by imgIContainer's
|
||||
// number of frames and frame rect
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendDataAvailable(imgRequestProxy* aProxy, PRBool aCurrentFrame,
|
||||
const nsIntRect* aRect)
|
||||
{
|
||||
aProxy->OnDataAvailable(aCurrentFrame, aRect);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordStopFrame(PRUint32 aFrame)
|
||||
{
|
||||
mState |= stateFrameStopped;
|
||||
mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStopFrame(imgRequestProxy* aProxy, PRUint32 aFrame)
|
||||
{
|
||||
aProxy->OnStopFrame(aFrame);
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordStopContainer(imgIContainer* aContainer)
|
||||
{
|
||||
// No-op: see imgRequest::OnStopDecode for more information
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStopContainer(imgRequestProxy* aProxy, imgIContainer* aContainer)
|
||||
{
|
||||
// No-op: see imgRequest::OnStopDecode for more information
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordStopDecode(nsresult aStatus, const PRUnichar* statusArg)
|
||||
{
|
||||
mState |= stateDecodeStopped;
|
||||
|
||||
if (NS_SUCCEEDED(aStatus))
|
||||
mImageStatus |= imgIRequest::STATUS_DECODE_COMPLETE;
|
||||
// If we weren't successful, clear all success status bits and set error.
|
||||
else
|
||||
mImageStatus = imgIRequest::STATUS_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus,
|
||||
const PRUnichar* statusArg)
|
||||
{
|
||||
// See imgRequest::OnStopDecode for more information on why we call
|
||||
// OnStopContainer from here this, and why imgRequestProxy::OnStopDecode() is
|
||||
// called from OnStopRequest().
|
||||
aProxy->OnStopContainer(mImage);
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordDiscard()
|
||||
{
|
||||
// Clear the state bits we no longer deserve.
|
||||
PRUint32 stateBitsToClear = stateDecodeStarted | stateDecodeStopped;
|
||||
mState &= ~stateBitsToClear;
|
||||
|
||||
// Clear the status bits we no longer deserve.
|
||||
PRUint32 statusBitsToClear = imgIRequest::STATUS_FRAME_COMPLETE
|
||||
| imgIRequest::STATUS_DECODE_COMPLETE;
|
||||
mImageStatus &= ~statusBitsToClear;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendDiscard(imgRequestProxy* aProxy)
|
||||
{
|
||||
aProxy->OnDiscard();
|
||||
}
|
||||
|
||||
/* non-virtual imgIContainerObserver methods */
|
||||
void
|
||||
imgStatusTracker::RecordFrameChanged(imgIContainer* aContainer, nsIntRect* aDirtyRect)
|
||||
{
|
||||
// no bookkeeping necessary here - this is only for in-frame updates, which we
|
||||
// don't fire while we're recording
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendFrameChanged(imgRequestProxy* aProxy, imgIContainer* aContainer,
|
||||
nsIntRect* aDirtyRect)
|
||||
{
|
||||
aProxy->FrameChanged(aContainer, aDirtyRect);
|
||||
}
|
||||
|
||||
/* non-virtual sort-of-nsIRequestObserver methods */
|
||||
void
|
||||
imgStatusTracker::RecordStartRequest()
|
||||
{
|
||||
// We're starting a new load, so clear any status and state bits indicating
|
||||
// load/decode
|
||||
mImageStatus &= ~imgIRequest::STATUS_LOAD_PARTIAL;
|
||||
mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE;
|
||||
mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE;
|
||||
mState &= ~stateRequestStarted;
|
||||
mState &= ~stateDecodeStarted;
|
||||
mState &= ~stateDecodeStopped;
|
||||
mState &= ~stateRequestStopped;
|
||||
|
||||
mState |= stateRequestStarted;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStartRequest(imgRequestProxy* aProxy)
|
||||
{
|
||||
aProxy->OnStartRequest();
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::RecordStopRequest(PRBool aLastPart, nsresult aStatus)
|
||||
{
|
||||
mHadLastPart = aLastPart;
|
||||
mState |= stateRequestStopped;
|
||||
|
||||
// If we were successful in loading, note that the image is complete.
|
||||
if (NS_SUCCEEDED(aStatus))
|
||||
mImageStatus |= imgIRequest::STATUS_LOAD_COMPLETE;
|
||||
}
|
||||
|
||||
void
|
||||
imgStatusTracker::SendStopRequest(imgRequestProxy* aProxy, PRBool aLastPart, nsresult aStatus)
|
||||
{
|
||||
// See bug 505385 and imgRequest::OnStopDecode for more information on why
|
||||
// OnStopDecode is called with OnStopRequest.
|
||||
aProxy->OnStopDecode(GetResultFromImageStatus(mImageStatus), nsnull);
|
||||
aProxy->OnStopRequest(aLastPart);
|
||||
}
|
146
modules/libpr0n/src/imgStatusTracker.h
Normal file
146
modules/libpr0n/src/imgStatusTracker.h
Normal file
@ -0,0 +1,146 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
*
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Drew <joe@drew.ca> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef imgStatusTracker_h__
|
||||
#define imgStatusTracker_h__
|
||||
|
||||
class nsIntRect;
|
||||
class imgIContainer;
|
||||
class imgRequest;
|
||||
class imgRequestProxy;
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nscore.h"
|
||||
|
||||
enum {
|
||||
stateRequestStarted = PR_BIT(0),
|
||||
stateHasSize = PR_BIT(1),
|
||||
stateDecodeStarted = PR_BIT(2),
|
||||
stateDecodeStopped = PR_BIT(3),
|
||||
stateFrameStopped = PR_BIT(4),
|
||||
stateRequestStopped = PR_BIT(5)
|
||||
};
|
||||
|
||||
/*
|
||||
* The image status tracker is a class that encapsulates all the loading and
|
||||
* decoding status about an image (imgContainer), and makes it possible to send
|
||||
* notifications to imgRequestProxys. When a new proxy needs to be notified of
|
||||
* the current state of an image, simply call the Notify() method on this class
|
||||
* with the relevant proxy as its argument.
|
||||
*/
|
||||
|
||||
class imgStatusTracker
|
||||
{
|
||||
public:
|
||||
// aImage is the image that this status tracker will pass to the
|
||||
// imgRequestProxys in Notify() and EmulateRequestFinished(), and must be
|
||||
// alive as long as this instance is, because we hold a weak reference to it.
|
||||
imgStatusTracker(imgIContainer* aImage);
|
||||
|
||||
// "Replay" all of the notifications that would have to happen to put us in
|
||||
// the state we're currently in.
|
||||
void Notify(imgRequestProxy* proxy);
|
||||
|
||||
// Send all notifications that would be necessary to make |proxy| believe the
|
||||
// request is finished downloading and decoding.
|
||||
// If aOnlySendStopRequest is true, we will only send OnStopRequest, and then
|
||||
// only if that is necessary.
|
||||
void EmulateRequestFinished(imgRequestProxy* proxy, nsresult aStatus,
|
||||
PRBool aOnlySendStopRequest);
|
||||
|
||||
// Returns whether we are in the process of loading; that is, whether we have
|
||||
// not received OnStopRequest.
|
||||
PRBool IsLoading() const;
|
||||
|
||||
// Get the current image status (as in imgIRequest).
|
||||
PRUint32 GetImageStatus() const;
|
||||
|
||||
// Following are all the notification methods. You must call the Record
|
||||
// variant on this status tracker, then call the Send variant for each proxy
|
||||
// you want to notify.
|
||||
|
||||
// Call when the request is being cancelled.
|
||||
void RecordCancel();
|
||||
|
||||
// Shorthand for recording all the load notifications: StartRequest,
|
||||
// StartContainer, StopRequest.
|
||||
void RecordLoaded();
|
||||
|
||||
// Shorthand for recording all the decode notifications: StartDecode,
|
||||
// StartFrame, DataAvailable, StopFrame, StopContainer, StopDecode.
|
||||
void RecordDecoded();
|
||||
|
||||
/* non-virtual imgIDecoderObserver methods */
|
||||
void RecordStartDecode();
|
||||
void SendStartDecode(imgRequestProxy* aProxy);
|
||||
void RecordStartContainer(imgIContainer* aContainer);
|
||||
void SendStartContainer(imgRequestProxy* aProxy, imgIContainer* aContainer);
|
||||
void RecordStartFrame(PRUint32 aFrame);
|
||||
void SendStartFrame(imgRequestProxy* aProxy, PRUint32 aFrame);
|
||||
void RecordDataAvailable(PRBool aCurrentFrame, const nsIntRect* aRect);
|
||||
void SendDataAvailable(imgRequestProxy* aProxy, PRBool aCurrentFrame, const nsIntRect* aRect);
|
||||
void RecordStopFrame(PRUint32 aFrame);
|
||||
void SendStopFrame(imgRequestProxy* aProxy, PRUint32 aFrame);
|
||||
void RecordStopContainer(imgIContainer* aContainer);
|
||||
void SendStopContainer(imgRequestProxy* aProxy, imgIContainer* aContainer);
|
||||
void RecordStopDecode(nsresult status, const PRUnichar* statusArg);
|
||||
void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus, const PRUnichar* statusArg);
|
||||
void RecordDiscard();
|
||||
void SendDiscard(imgRequestProxy* aProxy);
|
||||
|
||||
/* non-virtual imgIContainerObserver methods */
|
||||
void RecordFrameChanged(imgIContainer* aContainer, nsIntRect* aDirtyRect);
|
||||
void SendFrameChanged(imgRequestProxy* aProxy, imgIContainer* aContainer, nsIntRect* aDirtyRect);
|
||||
|
||||
/* non-virtual sort-of-nsIRequestObserver methods */
|
||||
void RecordStartRequest();
|
||||
void SendStartRequest(imgRequestProxy* aProxy);
|
||||
void RecordStopRequest(PRBool aLastPart, nsresult aStatus);
|
||||
void SendStopRequest(imgRequestProxy* aProxy, PRBool aLastPart, nsresult aStatus);
|
||||
|
||||
private:
|
||||
// A weak pointer to the imgIContainer, because the container owns us, and we
|
||||
// can't create a cycle.
|
||||
imgIContainer* mImage;
|
||||
PRUint32 mState;
|
||||
nsresult mImageStatus;
|
||||
PRPackedBool mHadLastPart;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user