Merge inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-10-13 04:36:33 -04:00
commit aff5207df8
608 changed files with 13165 additions and 32019 deletions

View File

@ -6,8 +6,17 @@ function test() {
gBrowser.selectedTab = gBrowser.addTab(); gBrowser.selectedTab = gBrowser.addTab();
// Navigate to malware site. Can't use an onload listener here since // Navigate to malware site. Can't use an onload listener here since
// error pages don't fire onload // error pages don't fire onload. Also can't register the DOMContentLoaded
// handler here because registering it too soon would mean that we might
// get it for about:blank, and not about:blocked.
gBrowser.addTabsProgressListener({
onLocationChange: function(aTab, aWebProgress, aRequest, aLocation, aFlags) {
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
gBrowser.removeTabsProgressListener(this);
window.addEventListener("DOMContentLoaded", testMalware, true); window.addEventListener("DOMContentLoaded", testMalware, true);
}
}
});
content.location = "http://www.mozilla.org/firefox/its-an-attack.html"; content.location = "http://www.mozilla.org/firefox/its-an-attack.html";
} }

View File

@ -837,6 +837,10 @@
; Adds a pinned shortcut to Task Bar on update for Windows 7 and above if this ; Adds a pinned shortcut to Task Bar on update for Windows 7 and above if this
; macro has never been called before and the application is default (see ; macro has never been called before and the application is default (see
; PinToTaskBar for more details). ; PinToTaskBar for more details).
; Since defaults handling is handled by Windows in Win8 and later, we always
; attempt to pin a taskbar on that OS. If Windows sets the defaults at
; installation time, then we don't get the opportunity to run this code at
; that time.
!macro MigrateTaskBarShortcut !macro MigrateTaskBarShortcut
${GetShortcutsLogPath} $0 ${GetShortcutsLogPath} $0
${If} ${FileExists} "$0" ${If} ${FileExists} "$0"
@ -846,13 +850,17 @@
ClearErrors ClearErrors
WriteIniStr "$0" "TASKBAR" "Migrated" "true" WriteIniStr "$0" "TASKBAR" "Migrated" "true"
${If} ${AtLeastWin7} ${If} ${AtLeastWin7}
; No need to check the default on Win8 and later
${If} ${AtMostWin2008R2}
; Check if the Firefox is the http handler for this user ; Check if the Firefox is the http handler for this user
SetShellVarContext current ; Set SHCTX to the current user SetShellVarContext current ; Set SHCTX to the current user
${IsHandlerForInstallDir} "http" $R9 ${IsHandlerForInstallDir} "http" $R9
${If} $TmpVal == "HKLM" ${If} $TmpVal == "HKLM"
SetShellVarContext all ; Set SHCTX to all users SetShellVarContext all ; Set SHCTX to all users
${EndIf} ${EndIf}
${EndIf}
${If} "$R9" == "true" ${If} "$R9" == "true"
${OrIf} ${AtLeastWin8}
${PinToTaskBar} ${PinToTaskBar}
${EndIf} ${EndIf}
${EndIf} ${EndIf}

View File

@ -64,7 +64,7 @@ class nsIParserService;
class nsIIOService; class nsIIOService;
class nsIURI; class nsIURI;
class imgIContainer; class imgIContainer;
class imgIDecoderObserver; class imgINotificationObserver;
class imgIRequest; class imgIRequest;
class imgILoader; class imgILoader;
class imgICache; class imgICache;
@ -661,7 +661,7 @@ public:
nsIDocument* aLoadingDocument, nsIDocument* aLoadingDocument,
nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aLoadingPrincipal,
nsIURI* aReferrer, nsIURI* aReferrer,
imgIDecoderObserver* aObserver, imgINotificationObserver* aObserver,
int32_t aLoadFlags, int32_t aLoadFlags,
imgIRequest** aRequest); imgIRequest** aRequest);

View File

@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "imgIDecoderObserver.idl" #include "imgINotificationObserver.idl"
interface imgIRequest; interface imgIRequest;
interface nsIChannel; interface nsIChannel;
@ -34,8 +34,8 @@ interface nsIFrame;
* sufficient, when combined with the imageBlockingStatus information.) * sufficient, when combined with the imageBlockingStatus information.)
*/ */
[scriptable, uuid(4bf1a7c5-6edb-4191-a257-e31a90f6aa85)] [scriptable, builtinclass, uuid(497bfb9b-d996-4d1e-a647-8137b0cfc876)]
interface nsIImageLoadingContent : imgIDecoderObserver interface nsIImageLoadingContent : imgINotificationObserver
{ {
/** /**
* Request types. Image loading content nodes attempt to do atomic * Request types. Image loading content nodes attempt to do atomic
@ -75,14 +75,14 @@ interface nsIImageLoadingContent : imgIDecoderObserver
* *
* @throws NS_ERROR_OUT_OF_MEMORY * @throws NS_ERROR_OUT_OF_MEMORY
*/ */
void addObserver(in imgIDecoderObserver aObserver); void addObserver(in imgINotificationObserver aObserver);
/** /**
* Used to unregister an image decoder observer. * Used to unregister an image decoder observer.
* *
* @param aObserver the observer to unregister * @param aObserver the observer to unregister
*/ */
void removeObserver(in imgIDecoderObserver aObserver); void removeObserver(in imgINotificationObserver aObserver);
/** /**
* Accessor to get the image requests * Accessor to get the image requests

View File

@ -28,7 +28,6 @@ EXPORTS = \
nsRange.h \ nsRange.h \
nsScriptLoader.h \ nsScriptLoader.h \
nsStubDocumentObserver.h \ nsStubDocumentObserver.h \
nsStubImageDecoderObserver.h \
nsStubMutationObserver.h \ nsStubMutationObserver.h \
nsTextFragment.h \ nsTextFragment.h \
mozAutoDocUpdate.h \ mozAutoDocUpdate.h \
@ -109,7 +108,6 @@ CPPSRCS = \
nsScriptElement.cpp \ nsScriptElement.cpp \
nsScriptLoader.cpp \ nsScriptLoader.cpp \
nsStubDocumentObserver.cpp \ nsStubDocumentObserver.cpp \
nsStubImageDecoderObserver.cpp \
nsStubMutationObserver.cpp \ nsStubMutationObserver.cpp \
nsStyledElement.cpp \ nsStyledElement.cpp \
nsStyleLinkElement.cpp \ nsStyleLinkElement.cpp \

View File

@ -1225,15 +1225,9 @@ nsContentSink::Notify(nsITimer *timer)
#ifdef MOZ_DEBUG #ifdef MOZ_DEBUG
{ {
PRTime now = PR_Now(); PRTime now = PR_Now();
int64_t diff, interval;
int32_t delay;
LL_I2L(interval, GetNotificationInterval()); int64_t interval = GetNotificationInterval();
diff = now - mLastNotificationTime; delay = int32_t(now - mLastNotificationTime - interval) / PR_USEC_PER_MSEC;
diff -= interval;
LL_L2I(delay, diff);
delay /= PR_USEC_PER_MSEC;
mBackoffCount--; mBackoffCount--;
SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW, SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_REFLOW,

View File

@ -51,7 +51,7 @@
#include "nsIForm.h" #include "nsIForm.h"
#include "nsIFormControl.h" #include "nsIFormControl.h"
#include "nsGkAtoms.h" #include "nsGkAtoms.h"
#include "imgIDecoderObserver.h" #include "imgINotificationObserver.h"
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIContainer.h" #include "imgIContainer.h"
#include "imgILoader.h" #include "imgILoader.h"
@ -2734,7 +2734,7 @@ nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument)
nsresult nsresult
nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument, nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
nsIPrincipal* aLoadingPrincipal, nsIURI* aReferrer, nsIPrincipal* aLoadingPrincipal, nsIURI* aReferrer,
imgIDecoderObserver* aObserver, int32_t aLoadFlags, imgINotificationObserver* aObserver, int32_t aLoadFlags,
imgIRequest** aRequest) imgIRequest** aRequest)
{ {
NS_PRECONDITION(aURI, "Must have a URI"); NS_PRECONDITION(aURI, "Must have a URI");
@ -2777,7 +2777,7 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
aReferrer, /* referrer */ aReferrer, /* referrer */
aLoadingPrincipal, /* loading principal */ aLoadingPrincipal, /* loading principal */
loadGroup, /* loadgroup */ loadGroup, /* loadgroup */
aObserver, /* imgIDecoderObserver */ aObserver, /* imgINotificationObserver */
aLoadingDocument, /* uniquification key */ aLoadingDocument, /* uniquification key */
aLoadFlags, /* load flags */ aLoadFlags, /* load flags */
nullptr, /* cache key */ nullptr, /* cache key */

View File

@ -6874,9 +6874,7 @@ nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
rv = file->GetLastModifiedTime(&msecs); rv = file->GetLastModifiedTime(&msecs);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
int64_t intermediateValue; modDate = msecs * int64_t(PR_USEC_PER_MSEC);
LL_I2L(intermediateValue, PR_USEC_PER_MSEC);
modDate = msecs * intermediateValue;
} }
} }
} else { } else {

View File

@ -48,11 +48,10 @@ public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
}; };
NS_IMPL_ISUPPORTS_INHERITED4(nsGenConImageContent, NS_IMPL_ISUPPORTS_INHERITED3(nsGenConImageContent,
nsXMLElement, nsXMLElement,
nsIImageLoadingContent, nsIImageLoadingContent,
imgIContainerObserver, imgINotificationObserver,
imgIDecoderObserver,
imgIOnloadBlocker) imgIOnloadBlocker)
nsresult nsresult

View File

@ -122,114 +122,63 @@ nsImageLoadingContent::~nsImageLoadingContent()
} \ } \
PR_END_MACRO PR_END_MACRO
/* /*
* imgIContainerObserver impl * imgINotificationObserver impl
*/ */
NS_IMETHODIMP NS_IMETHODIMP
nsImageLoadingContent::FrameChanged(imgIRequest* aRequest, nsImageLoadingContent::Notify(imgIRequest* aRequest,
imgIContainer* aContainer, int32_t aType,
const nsIntRect* aDirtyRect) const nsIntRect* aData)
{ {
LOOP_OVER_OBSERVERS(FrameChanged(aRequest, aContainer, aDirtyRect)); if (aType == imgINotificationObserver::IS_ANIMATED) {
return NS_OK; return OnImageIsAnimated(aRequest);
} }
/*
* imgIDecoderObserver impl
*/
NS_IMETHODIMP
nsImageLoadingContent::OnStartRequest(imgIRequest* aRequest)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnStartRequest(aRequest));
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::OnStartDecode(imgIRequest* aRequest)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnStartDecode(aRequest));
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::OnStartContainer(imgIRequest* aRequest,
imgIContainer* aContainer)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnStartContainer(aRequest, aContainer));
// Have to check for state changes here, since we might have been in
// the LOADING state before.
UpdateImageState(true);
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::OnStartFrame(imgIRequest* aRequest,
uint32_t aFrame)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnStartFrame(aRequest, aFrame));
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::OnDataAvailable(imgIRequest* aRequest,
bool aCurrentFrame,
const nsIntRect* aRect)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnDataAvailable(aRequest, aCurrentFrame, aRect));
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::OnStopFrame(imgIRequest* aRequest,
uint32_t aFrame)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnStopFrame(aRequest, aFrame));
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::OnStopContainer(imgIRequest* aRequest,
imgIContainer* aContainer)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnStopContainer(aRequest, aContainer));
return NS_OK;
}
// Warning - This isn't actually fired when decode is complete. Rather, it's
// fired when load is complete. See bug 505385, and in the mean time use
// OnStopContainer.
NS_IMETHODIMP
nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
nsresult aStatus,
const PRUnichar* aStatusArg)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
// We should definitely have a request here // We should definitely have a request here
NS_ABORT_IF_FALSE(aRequest, "no request?"); NS_ABORT_IF_FALSE(aRequest, "no request?");
NS_PRECONDITION(aRequest == mCurrentRequest || aRequest == mPendingRequest, NS_PRECONDITION(aRequest == mCurrentRequest || aRequest == mPendingRequest,
"Unknown request"); "Unknown request");
LOOP_OVER_OBSERVERS(OnStopDecode(aRequest, aStatus, aStatusArg)); }
// XXXbholley - When we fix bug 505385, everything here should go in NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
// OnStopRequest.
LOOP_OVER_OBSERVERS(Notify(aRequest, aType, aData));
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
// Have to check for state changes here, since we might have been in
// the LOADING state before.
UpdateImageState(true);
}
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
uint32_t reqStatus;
aRequest->GetImageStatus(&reqStatus);
nsresult status =
reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
return OnStopRequest(aRequest, status);
}
return NS_OK;
}
nsresult
nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest,
nsresult aStatus)
{
uint32_t oldStatus;
aRequest->GetImageStatus(&oldStatus);
//XXXjdm This occurs when we have a pending request created, then another
// pending request replaces it before the first one is finished.
// This begs the question of what the correct behaviour is; we used
// to not have to care because we ran this code in OnStopDecode which
// wasn't called when the first request was cancelled. For now, I choose
// to punt when the given request doesn't appear to have terminated in
// an expected state.
if (!(oldStatus & (imgIRequest::STATUS_ERROR | imgIRequest::STATUS_LOAD_COMPLETE)))
return NS_OK;
// Our state may change. Watch it. // Our state may change. Watch it.
AutoStateChanger changer(this, true); AutoStateChanger changer(this, true);
@ -284,17 +233,7 @@ nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsresult
nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest, bool aLastPart)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnStopRequest(aRequest, aLastPart));
return NS_OK;
}
NS_IMETHODIMP
nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest) nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
{ {
bool* requestFlag = GetRegisteredFlagForRequest(aRequest); bool* requestFlag = GetRegisteredFlagForRequest(aRequest);
@ -306,16 +245,6 @@ nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsImageLoadingContent::OnDiscard(imgIRequest *aRequest)
{
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
LOOP_OVER_OBSERVERS(OnDiscard(aRequest));
return NS_OK;
}
/* /*
* nsIImageLoadingContent impl * nsIImageLoadingContent impl
*/ */
@ -351,7 +280,7 @@ nsImageLoadingContent::GetImageBlockingStatus(int16_t* aStatus)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsImageLoadingContent::AddObserver(imgIDecoderObserver* aObserver) nsImageLoadingContent::AddObserver(imgINotificationObserver* aObserver)
{ {
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE); NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
@ -379,7 +308,7 @@ nsImageLoadingContent::AddObserver(imgIDecoderObserver* aObserver)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsImageLoadingContent::RemoveObserver(imgIDecoderObserver* aObserver) nsImageLoadingContent::RemoveObserver(imgINotificationObserver* aObserver)
{ {
NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE); NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);

View File

@ -13,8 +13,7 @@
#ifndef nsImageLoadingContent_h__ #ifndef nsImageLoadingContent_h__
#define nsImageLoadingContent_h__ #define nsImageLoadingContent_h__
#include "imgIContainerObserver.h" #include "imgINotificationObserver.h"
#include "imgIDecoderObserver.h"
#include "imgIOnloadBlocker.h" #include "imgIOnloadBlocker.h"
#include "mozilla/CORSMode.h" #include "mozilla/CORSMode.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
@ -36,8 +35,7 @@ public:
nsImageLoadingContent(); nsImageLoadingContent();
virtual ~nsImageLoadingContent(); virtual ~nsImageLoadingContent();
NS_DECL_IMGICONTAINEROBSERVER NS_DECL_IMGINOTIFICATIONOBSERVER
NS_DECL_IMGIDECODEROBSERVER
NS_DECL_NSIIMAGELOADINGCONTENT NS_DECL_NSIIMAGELOADINGCONTENT
NS_DECL_IMGIONLOADBLOCKER NS_DECL_IMGIONLOADBLOCKER
@ -161,12 +159,15 @@ protected:
nsIContent* aBindingParent, bool aCompileEventHandlers); nsIContent* aBindingParent, bool aCompileEventHandlers);
void UnbindFromTree(bool aDeep, bool aNullParent); void UnbindFromTree(bool aDeep, bool aNullParent);
nsresult OnStopRequest(imgIRequest* aRequest, nsresult aStatus);
nsresult OnImageIsAnimated(imgIRequest *aRequest);
private: private:
/** /**
* Struct used to manage the image observers. * Struct used to manage the image observers.
*/ */
struct ImageObserver { struct ImageObserver {
ImageObserver(imgIDecoderObserver* aObserver) : ImageObserver(imgINotificationObserver* aObserver) :
mObserver(aObserver), mObserver(aObserver),
mNext(nullptr) mNext(nullptr)
{ {
@ -178,7 +179,7 @@ private:
NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext); NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext);
} }
nsCOMPtr<imgIDecoderObserver> mObserver; nsCOMPtr<imgINotificationObserver> mObserver;
ImageObserver* mNext; ImageObserver* mNext;
}; };

View File

@ -98,13 +98,6 @@ class nsObjectLoadingContent : public nsImageLoadingContent
NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICHANNELEVENTSINK
#ifdef HAVE_CPP_AMBIGUITY_RESOLVING_USING
// Fix gcc compile warnings
using nsImageLoadingContent::OnStartRequest;
using nsImageLoadingContent::OnDataAvailable;
using nsImageLoadingContent::OnStopRequest;
#endif
/** /**
* Object state. This is a bitmask of NS_EVENT_STATEs epresenting the * Object state. This is a bitmask of NS_EVENT_STATEs epresenting the
* current state of the object. * current state of the object.

View File

@ -1,89 +0,0 @@
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsStubImageDecoderObserver.h"
NS_IMETHODIMP
nsStubImageDecoderObserver::OnStartRequest(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnStartDecode(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnStartContainer(imgIRequest *aRequest,
imgIContainer *aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnStartFrame(imgIRequest *aRequest,
uint32_t aFrame)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnDataAvailable(imgIRequest *aRequest,
bool aCurrentFrame,
const nsIntRect * aRect)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnStopFrame(imgIRequest *aRequest,
uint32_t aFrame)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnStopContainer(imgIRequest *aRequest,
imgIContainer *aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnStopDecode(imgIRequest *aRequest,
nsresult status,
const PRUnichar *statusArg)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnStopRequest(imgIRequest *aRequest,
bool aIsLastPart)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnDiscard(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::OnImageIsAnimated(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsStubImageDecoderObserver::FrameChanged(imgIRequest* aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
return NS_OK;
}

View File

@ -1,35 +0,0 @@
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* nsStubImageDecoderObserver is an implementation of the imgIDecoderObserver
* interface (except for the methods on nsISupports) that is intended to be
* used as a base class within the content/layout library. All methods do
* nothing.
*/
#ifndef nsStubImageDecoderObserver_h_
#define nsStubImageDecoderObserver_h_
#include "imgIDecoderObserver.h"
/**
* There are two advantages to inheriting from nsStubImageDecoderObserver
* rather than directly from imgIDecoderObserver:
* 1. smaller compiled code size (since there's no need for the code
* for the empty virtual function implementations for every
* imgIDecoderObserver implementation)
* 2. the performance of document's loop over observers benefits from
* the fact that more of the functions called are the same (which
* can reduce instruction cache misses and perhaps improve branch
* prediction)
*/
class nsStubImageDecoderObserver : public imgIDecoderObserver {
public:
NS_DECL_IMGICONTAINEROBSERVER
NS_DECL_IMGIDECODEROBSERVER
};
#endif /* !defined(nsStubImageDecoderObserver_h_) */

View File

@ -4110,7 +4110,7 @@ NS_IMETHODIMP nsXMLHttpProgressEvent::GetPosition(uint32_t *aPosition)
{ {
WarnAboutLSProgressEvent(nsIDocument::ePosition); WarnAboutLSProgressEvent(nsIDocument::ePosition);
// XXX can we change the iface? // XXX can we change the iface?
LL_L2UI(*aPosition, mCurProgress); *aPosition = uint32_t(mCurProgress);
return NS_OK; return NS_OK;
} }
@ -4118,7 +4118,7 @@ NS_IMETHODIMP nsXMLHttpProgressEvent::GetTotalSize(uint32_t *aTotalSize)
{ {
WarnAboutLSProgressEvent(nsIDocument::eTotalSize); WarnAboutLSProgressEvent(nsIDocument::eTotalSize);
// XXX can we change the iface? // XXX can we change the iface?
LL_L2UI(*aTotalSize, mMaxProgress); *aTotalSize = uint32_t(mMaxProgress);
return NS_OK; return NS_OK;
} }

View File

@ -132,8 +132,6 @@ protected:
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
extern bool AzureCanvasEnabled();
} }
} }

View File

@ -2,8 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file, * License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsCanvasRenderingContext2DAzure_h #ifndef CanvasRenderingContext2D_h
#define nsCanvasRenderingContext2DAzure_h #define CanvasRenderingContext2D_h
#include <vector> #include <vector>
#include "nsIDOMCanvasRenderingContext2D.h" #include "nsIDOMCanvasRenderingContext2D.h"
@ -19,24 +19,26 @@
#include "mozilla/dom/ImageData.h" #include "mozilla/dom/ImageData.h"
#include "mozilla/dom/UnionTypes.h" #include "mozilla/dom/UnionTypes.h"
#define NS_CANVASGRADIENTAZURE_PRIVATE_IID \
{0x28425a6a, 0x90e0, 0x4d42, {0x9c, 0x75, 0xff, 0x60, 0x09, 0xb3, 0x10, 0xa8}}
#define NS_CANVASPATTERNAZURE_PRIVATE_IID \
{0xc9bacc25, 0x28da, 0x421e, {0x9a, 0x4b, 0xbb, 0xd6, 0x93, 0x05, 0x12, 0xbc}}
namespace mozilla { namespace mozilla {
namespace dom {
template<typename T> class Optional;
}
namespace gfx { namespace gfx {
struct Rect; struct Rect;
class SourceSurface; class SourceSurface;
} }
}
namespace dom {
extern const mozilla::gfx::Float SIGMA_MAX; extern const mozilla::gfx::Float SIGMA_MAX;
template<typename T> class Optional;
/** /**
** nsCanvasGradientAzure ** CanvasGradient
**/ **/
#define NS_CANVASGRADIENTAZURE_PRIVATE_IID \ class CanvasGradient : public nsIDOMCanvasGradient
{0x28425a6a, 0x90e0, 0x4d42, {0x9c, 0x75, 0xff, 0x60, 0x09, 0xb3, 0x10, 0xa8}}
class nsCanvasGradientAzure : public nsIDOMCanvasGradient
{ {
public: public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENTAZURE_PRIVATE_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENTAZURE_PRIVATE_IID)
@ -71,21 +73,19 @@ public:
NS_IMETHOD AddColorStop(float offset, const nsAString& colorstr); NS_IMETHOD AddColorStop(float offset, const nsAString& colorstr);
protected: protected:
nsCanvasGradientAzure(Type aType) : mType(aType) CanvasGradient(Type aType) : mType(aType)
{} {}
nsTArray<mozilla::gfx::GradientStop> mRawStops; nsTArray<mozilla::gfx::GradientStop> mRawStops;
mozilla::RefPtr<mozilla::gfx::GradientStops> mStops; mozilla::RefPtr<mozilla::gfx::GradientStops> mStops;
Type mType; Type mType;
virtual ~nsCanvasGradientAzure() {} virtual ~CanvasGradient() {}
}; };
/** /**
** nsCanvasPatternAzure ** CanvasPattern
**/ **/
#define NS_CANVASPATTERNAZURE_PRIVATE_IID \ class CanvasPattern MOZ_FINAL : public nsIDOMCanvasPattern
{0xc9bacc25, 0x28da, 0x421e, {0x9a, 0x4b, 0xbb, 0xd6, 0x93, 0x05, 0x12, 0xbc}}
class nsCanvasPatternAzure MOZ_FINAL : public nsIDOMCanvasPattern
{ {
public: public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERNAZURE_PRIVATE_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERNAZURE_PRIVATE_IID)
@ -98,7 +98,7 @@ public:
NOREPEAT NOREPEAT
}; };
nsCanvasPatternAzure(mozilla::gfx::SourceSurface* aSurface, CanvasPattern(mozilla::gfx::SourceSurface* aSurface,
RepeatMode aRepeat, RepeatMode aRepeat,
nsIPrincipal* principalForSecurityCheck, nsIPrincipal* principalForSecurityCheck,
bool forceWriteOnly, bool forceWriteOnly,
@ -120,13 +120,13 @@ public:
const bool mCORSUsed; const bool mCORSUsed;
}; };
struct nsCanvasBidiProcessorAzure; struct CanvasBidiProcessor;
class CanvasRenderingContext2DUserDataAzure; class CanvasRenderingContext2DUserData;
/** /**
** nsCanvasRenderingContext2DAzure ** CanvasRenderingContext2D
**/ **/
class nsCanvasRenderingContext2DAzure : class CanvasRenderingContext2D :
public nsIDOMCanvasRenderingContext2D, public nsIDOMCanvasRenderingContext2D,
public nsICanvasRenderingContextInternal, public nsICanvasRenderingContextInternal,
public nsWrapperCache public nsWrapperCache
@ -135,8 +135,8 @@ typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
HTMLImageOrCanvasOrVideoElement; HTMLImageOrCanvasOrVideoElement;
public: public:
nsCanvasRenderingContext2DAzure(); CanvasRenderingContext2D();
virtual ~nsCanvasRenderingContext2DAzure(); virtual ~CanvasRenderingContext2D();
virtual JSObject* WrapObject(JSContext *cx, JSObject *scope, virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
bool *triedToWrap); bool *triedToWrap);
@ -495,7 +495,7 @@ public:
// nsISupports interface + CC // nsISupports interface + CC
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsCanvasRenderingContext2DAzure, NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(CanvasRenderingContext2D,
nsIDOMCanvasRenderingContext2D) nsIDOMCanvasRenderingContext2D)
// nsIDOMCanvasRenderingContext2D interface // nsIDOMCanvasRenderingContext2D interface
@ -535,7 +535,7 @@ public:
} }
} }
friend class CanvasRenderingContext2DUserDataAzure; friend class CanvasRenderingContext2DUserData;
protected: protected:
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY, nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
@ -572,12 +572,12 @@ protected:
void SetStyleFromJSValue(JSContext* cx, JS::Value& value, Style whichStyle); void SetStyleFromJSValue(JSContext* cx, JS::Value& value, Style whichStyle);
void SetStyleFromString(const nsAString& str, Style whichStyle); void SetStyleFromString(const nsAString& str, Style whichStyle);
void SetStyleFromGradient(nsCanvasGradientAzure *gradient, Style whichStyle) void SetStyleFromGradient(CanvasGradient *gradient, Style whichStyle)
{ {
CurrentState().SetGradientStyle(whichStyle, gradient); CurrentState().SetGradientStyle(whichStyle, gradient);
} }
void SetStyleFromPattern(nsCanvasPatternAzure *pattern, Style whichStyle) void SetStyleFromPattern(CanvasPattern *pattern, Style whichStyle)
{ {
CurrentState().SetPatternStyle(whichStyle, pattern); CurrentState().SetPatternStyle(whichStyle, pattern);
} }
@ -704,7 +704,7 @@ protected:
// This is needed for drawing in drawAsyncXULElement // This is needed for drawing in drawAsyncXULElement
bool mIPC; bool mIPC;
nsTArray<CanvasRenderingContext2DUserDataAzure*> mUserDatas; nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
// If mCanvasElement is not provided, then a docshell is // If mCanvasElement is not provided, then a docshell is
nsCOMPtr<nsIDocShell> mDocShell; nsCOMPtr<nsIDocShell> mDocShell;
@ -886,18 +886,21 @@ protected:
} }
} }
void SetColorStyle(Style whichStyle, nscolor color) { void SetColorStyle(Style whichStyle, nscolor color)
{
colorStyles[whichStyle] = color; colorStyles[whichStyle] = color;
gradientStyles[whichStyle] = nullptr; gradientStyles[whichStyle] = nullptr;
patternStyles[whichStyle] = nullptr; patternStyles[whichStyle] = nullptr;
} }
void SetPatternStyle(Style whichStyle, nsCanvasPatternAzure* pat) { void SetPatternStyle(Style whichStyle, CanvasPattern* pat)
{
gradientStyles[whichStyle] = nullptr; gradientStyles[whichStyle] = nullptr;
patternStyles[whichStyle] = pat; patternStyles[whichStyle] = pat;
} }
void SetGradientStyle(Style whichStyle, nsCanvasGradientAzure* grad) { void SetGradientStyle(Style whichStyle, CanvasGradient* grad)
{
gradientStyles[whichStyle] = grad; gradientStyles[whichStyle] = grad;
patternStyles[whichStyle] = nullptr; patternStyles[whichStyle] = nullptr;
} }
@ -914,8 +917,8 @@ protected:
std::vector<mozilla::RefPtr<mozilla::gfx::Path> > clipsPushed; std::vector<mozilla::RefPtr<mozilla::gfx::Path> > clipsPushed;
nsRefPtr<gfxFontGroup> fontGroup; nsRefPtr<gfxFontGroup> fontGroup;
nsRefPtr<nsCanvasGradientAzure> gradientStyles[STYLE_MAX]; nsRefPtr<CanvasGradient> gradientStyles[STYLE_MAX];
nsRefPtr<nsCanvasPatternAzure> patternStyles[STYLE_MAX]; nsRefPtr<CanvasPattern> patternStyles[STYLE_MAX];
nsString font; nsString font;
TextAlign textAlign; TextAlign textAlign;
@ -951,7 +954,8 @@ protected:
friend class AdjustedTarget; friend class AdjustedTarget;
// other helpers // other helpers
void GetAppUnitsValues(uint32_t *perDevPixel, uint32_t *perCSSPixel) { void GetAppUnitsValues(uint32_t *perDevPixel, uint32_t *perCSSPixel)
{
// If we don't have a canvas element, we just return something generic. // If we don't have a canvas element, we just return something generic.
uint32_t devPixel = 60; uint32_t devPixel = 60;
uint32_t cssPixel = 60; uint32_t cssPixel = 60;
@ -972,7 +976,10 @@ protected:
*perCSSPixel = cssPixel; *perCSSPixel = cssPixel;
} }
friend struct nsCanvasBidiProcessorAzure; friend struct CanvasBidiProcessor;
}; };
#endif /* nsCanvasRenderingContext2DAzure_h */ }
}
#endif /* CanvasRenderingContext2D_h */

View File

@ -1,38 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef CustomQS_Canvas_h
#define CustomQS_Canvas_h
#include "jsapi.h"
#include "mozilla/dom/ImageData.h"
#include "XPCQuickStubs.h"
static bool
GetImageData(JSContext* cx, JS::Value& imageData,
uint32_t* width, uint32_t* height, JS::Anchor<JSObject*>* array)
{
if (!imageData.isObject()) {
return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR);
}
nsIDOMImageData* domImageData;
xpc_qsSelfRef imageDataRef;
nsresult rv = xpc_qsUnwrapArg<nsIDOMImageData>(cx, imageData, &domImageData,
&imageDataRef.ptr, &imageData);
if (NS_FAILED(rv)) {
return xpc_qsThrow(cx, rv);
}
mozilla::dom::ImageData* concreteImageData =
static_cast<mozilla::dom::ImageData*>(domImageData);
*width = concreteImageData->GetWidth();
*height = concreteImageData->GetHeight();
array->set(concreteImageData->GetDataObject());
return true;
}
#endif // CustomQS_Canvas_h

View File

@ -1,302 +0,0 @@
/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsError.h"
#include "nsIDOMCanvasRenderingContext2D.h"
#include "mozilla/CheckedInt.h"
#include "nsMathUtils.h"
#include "CustomQS_Canvas.h"
#include "jsapi.h"
#include "jsfriendapi.h"
typedef NS_STDCALL_FUNCPROTO(nsresult, CanvasStyleSetterType, nsIDOMCanvasRenderingContext2D,
SetStrokeStyle_multi, (const nsAString &, nsISupports *));
typedef NS_STDCALL_FUNCPROTO(nsresult, CanvasStyleGetterType, nsIDOMCanvasRenderingContext2D,
GetStrokeStyle_multi, (nsAString &, nsISupports **, int32_t *));
static JSBool
Canvas2D_SetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleValue vp,
CanvasStyleSetterType setfunc)
{
XPC_QS_ASSERT_CONTEXT_OK(cx);
nsIDOMCanvasRenderingContext2D *self;
xpc_qsSelfRef selfref;
JS::AutoValueRooter tvr(cx);
if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, tvr.jsval_addr(), nullptr))
return JS_FALSE;
nsresult rv = NS_OK;
if (JSVAL_IS_STRING(vp)) {
xpc_qsDOMString arg0(cx, vp, vp.address(),
xpc_qsDOMString::eDefaultNullBehavior,
xpc_qsDOMString::eDefaultUndefinedBehavior);
if (!arg0.IsValid())
return JS_FALSE;
rv = (self->*setfunc)(arg0, nullptr);
} else {
nsISupports *arg0;
xpc_qsSelfRef arg0ref;
rv = xpc_qsUnwrapArg<nsISupports>(cx, vp, &arg0, &arg0ref.ptr, vp.address());
if (NS_FAILED(rv)) {
xpc_qsThrowBadSetterValue(cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id);
return JS_FALSE;
}
rv = (self->*setfunc)(NullString(), arg0);
}
if (NS_FAILED(rv))
return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id);
return JS_TRUE;
}
static JSBool
Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsid id, JSMutableHandleValue vp,
CanvasStyleGetterType getfunc)
{
XPC_QS_ASSERT_CONTEXT_OK(cx);
nsIDOMCanvasRenderingContext2D *self;
xpc_qsSelfRef selfref;
XPCLazyCallContext lccx(JS_CALLER, cx, obj);
if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, vp.address(), &lccx))
return JS_FALSE;
nsresult rv;
nsString resultString;
nsCOMPtr<nsISupports> resultInterface;
int32_t resultType;
rv = (self->*getfunc)(resultString, getter_AddRefs(resultInterface), &resultType);
if (NS_FAILED(rv))
return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(vp), id);
switch (resultType) {
case nsIDOMCanvasRenderingContext2D::CMG_STYLE_STRING:
return xpc::StringToJsval(cx, resultString, vp.address());
case nsIDOMCanvasRenderingContext2D::CMG_STYLE_PATTERN:
{
qsObjectHelper helper(resultInterface,
xpc_qsGetWrapperCache(resultInterface));
return xpc_qsXPCOMObjectToJsval(lccx, helper,
&NS_GET_IID(nsIDOMCanvasPattern),
&interfaces[k_nsIDOMCanvasPattern], vp.address());
}
case nsIDOMCanvasRenderingContext2D::CMG_STYLE_GRADIENT:
{
qsObjectHelper helper(resultInterface,
xpc_qsGetWrapperCache(resultInterface));
return xpc_qsXPCOMObjectToJsval(lccx, helper,
&NS_GET_IID(nsIDOMCanvasGradient),
&interfaces[k_nsIDOMCanvasGradient], vp.address());
}
default:
return xpc_qsThrowGetterSetterFailed(cx, NS_ERROR_FAILURE, JSVAL_TO_OBJECT(vp), id);
}
}
static JSBool
nsIDOMCanvasRenderingContext2D_SetStrokeStyle(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp)
{
return Canvas2D_SetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::SetStrokeStyle_multi);
}
static JSBool
nsIDOMCanvasRenderingContext2D_GetStrokeStyle(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
{
return Canvas2D_GetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::GetStrokeStyle_multi);
}
static JSBool
nsIDOMCanvasRenderingContext2D_SetFillStyle(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp)
{
return Canvas2D_SetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::SetFillStyle_multi);
}
static JSBool
nsIDOMCanvasRenderingContext2D_GetFillStyle(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
{
return Canvas2D_GetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::GetFillStyle_multi);
}
static bool
CreateImageData(JSContext* cx, JSObject* obj, uint32_t w, uint32_t h, jsval* vp)
{
using mozilla::CheckedInt;
if (w == 0)
w = 1;
if (h == 0)
h = 1;
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(w) * h * 4;
if (!len.isValid()) {
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
}
// Create the fast typed array; it's initialized to 0 by default.
JSObject* darray = JS_NewUint8ClampedArray(cx, len.value());
JS::AutoObjectRooter rd(cx, darray);
if (!darray) {
return false;
}
XPCLazyCallContext lccx(JS_CALLER, cx, obj);
const nsIID *iid = &NS_GET_IID(nsIDOMImageData);
nsRefPtr<mozilla::dom::ImageData> imageData =
new mozilla::dom::ImageData(w, h, *darray);
qsObjectHelper helper(imageData, NULL);
return xpc_qsXPCOMObjectToJsval(lccx, helper, iid,
&interfaces[k_nsIDOMImageData], vp);
}
static JSBool
nsIDOMCanvasRenderingContext2D_CreateImageData(JSContext *cx, unsigned argc, jsval *vp)
{
XPC_QS_ASSERT_CONTEXT_OK(cx);
JSObject* obj = JS_THIS_OBJECT(cx, vp);
if (!obj) {
return false;
}
if (argc < 1)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
if (argc == 1) {
uint32_t data_width, data_height;
JS::Anchor<JSObject*> darray;
if (!GetImageData(cx, argv[0], &data_width, &data_height, &darray)) {
return false;
}
return CreateImageData(cx, obj, data_width, data_height, vp);
}
double width, height;
if (!JS_ValueToNumber(cx, argv[0], &width) ||
!JS_ValueToNumber(cx, argv[1], &height))
return false;
if (!NS_finite(width) || !NS_finite(height))
return xpc_qsThrow(cx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
if (!width || !height)
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
int32_t wi = JS_DoubleToInt32(width);
int32_t hi = JS_DoubleToInt32(height);
uint32_t w = NS_ABS(wi);
uint32_t h = NS_ABS(hi);
return CreateImageData(cx, obj, w, h, vp);
}
static JSBool
nsIDOMCanvasRenderingContext2D_PutImageData(JSContext *cx, unsigned argc, jsval *vp)
{
XPC_QS_ASSERT_CONTEXT_OK(cx);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsresult rv;
nsIDOMCanvasRenderingContext2D *self;
xpc_qsSelfRef selfref;
JS::AutoValueRooter tvr(cx);
if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, tvr.jsval_addr(), nullptr))
return JS_FALSE;
if (argc < 3)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
uint32_t w, h;
JS::Anchor<JSObject*> darray;
if (!GetImageData(cx, argv[0], &w, &h, &darray)) {
return false;
}
double xd, yd;
if (!JS_ValueToNumber(cx, argv[1], &xd) ||
!JS_ValueToNumber(cx, argv[2], &yd)) {
return false;
}
if (!NS_finite(xd) || !NS_finite(yd)) {
return xpc_qsThrow(cx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
int32_t x = JS_DoubleToInt32(xd);
int32_t y = JS_DoubleToInt32(yd);
// the optional dirty rect
bool hasDirtyRect = false;
int32_t dirtyX = 0,
dirtyY = 0,
dirtyWidth = w,
dirtyHeight = h;
if (argc >= 7) {
double dx, dy, dw, dh;
if (!JS_ValueToNumber(cx, argv[3], &dx) ||
!JS_ValueToNumber(cx, argv[4], &dy) ||
!JS_ValueToNumber(cx, argv[5], &dw) ||
!JS_ValueToNumber(cx, argv[6], &dh)) {
return false;
}
if (!NS_finite(dx) || !NS_finite(dy) ||
!NS_finite(dw) || !NS_finite(dh)) {
return xpc_qsThrow(cx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
}
dirtyX = JS_DoubleToInt32(dx);
dirtyY = JS_DoubleToInt32(dy);
dirtyWidth = JS_DoubleToInt32(dw);
dirtyHeight = JS_DoubleToInt32(dh);
hasDirtyRect = true;
}
JS::AutoValueRooter tsrc_tvr(cx);
JSObject * tsrc = NULL;
if (JS_IsInt8Array(darray.get(), cx) ||
JS_IsUint8Array(darray.get(), cx) ||
JS_IsUint8ClampedArray(darray.get(), cx))
{
tsrc = darray.get();
} else if (JS_IsTypedArrayObject(darray.get(), cx) || JS_IsArrayObject(cx, darray.get())) {
// ugh, this isn't a uint8 typed array, someone made their own object; convert it to a typed array
JSObject *nobj = JS_NewUint8ClampedArrayFromArray(cx, darray.get());
if (!nobj)
return JS_FALSE;
*tsrc_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
tsrc = nobj;
} else {
// yeah, no.
return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR);
}
// make the call
MOZ_ASSERT(JS_IsTypedArrayObject(tsrc, cx));
uint8_t* data = reinterpret_cast<uint8_t*>(JS_GetArrayBufferViewData(tsrc, cx));
uint32_t byteLength = JS_GetTypedArrayByteLength(tsrc, cx);
rv = self->PutImageData_explicit(x, y, w, h, data, byteLength, hasDirtyRect, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
if (NS_FAILED(rv))
return xpc_qsThrowMethodFailed(cx, rv, vp);
*vp = JSVAL_VOID;
return JS_TRUE;
}

View File

@ -17,8 +17,6 @@ LIBRARY_NAME = gkconcvs_s
LIBXUL_LIBRARY = 1 LIBXUL_LIBRARY = 1
EXPORTS = \ EXPORTS = \
CustomQS_Canvas.h \
CustomQS_Canvas2D.h \
WebGLContext.h \ WebGLContext.h \
WebGLElementArrayCache.h \ WebGLElementArrayCache.h \
WebGLExtensions.h \ WebGLExtensions.h \
@ -27,14 +25,14 @@ EXPORTS = \
EXPORTS_NAMESPACES = mozilla/dom EXPORTS_NAMESPACES = mozilla/dom
EXPORTS_mozilla/dom = \ EXPORTS_mozilla/dom = \
CanvasRenderingContext2D.h \
ImageData.h \ ImageData.h \
$(NULL) $(NULL)
CPPSRCS = \ CPPSRCS = \
CanvasImageCache.cpp \ CanvasImageCache.cpp \
CanvasRenderingContext2D.cpp \
CanvasUtils.cpp \ CanvasUtils.cpp \
nsCanvasRenderingContext2D.cpp \
nsCanvasRenderingContext2DAzure.cpp \
DocumentRendererParent.cpp \ DocumentRendererParent.cpp \
DocumentRendererChild.cpp \ DocumentRendererChild.cpp \
ImageData.cpp \ ImageData.cpp \

File diff suppressed because it is too large Load Diff

View File

@ -168,7 +168,6 @@ protected:
const nsAString& aType, const nsAString& aType,
nsIDOMFile** aResult); nsIDOMFile** aResult);
nsresult GetContextHelper(const nsAString& aContextId, nsresult GetContextHelper(const nsAString& aContextId,
bool aForceThebes,
nsICanvasRenderingContextInternal **aContext); nsICanvasRenderingContextInternal **aContext);
void CallPrintCallback(); void CallPrintCallback();

View File

@ -601,7 +601,6 @@ nsHTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
nsresult nsresult
nsHTMLCanvasElement::GetContextHelper(const nsAString& aContextId, nsHTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
bool aForceThebes,
nsICanvasRenderingContextInternal **aContext) nsICanvasRenderingContextInternal **aContext)
{ {
NS_ENSURE_ARG(aContext); NS_ENSURE_ARG(aContext);
@ -624,10 +623,6 @@ nsHTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
nsCString ctxString("@mozilla.org/content/canvas-rendering-context;1?id="); nsCString ctxString("@mozilla.org/content/canvas-rendering-context;1?id=");
ctxString.Append(ctxId); ctxString.Append(ctxId);
if (aForceThebes && ctxId.EqualsASCII("2d")) {
ctxString.AssignASCII("@mozilla.org/content/2dthebes-canvas-rendering-context;1");
}
nsresult rv; nsresult rv;
nsCOMPtr<nsICanvasRenderingContextInternal> ctx = nsCOMPtr<nsICanvasRenderingContextInternal> ctx =
do_CreateInstance(ctxString.get(), &rv); do_CreateInstance(ctxString.get(), &rv);
@ -653,10 +648,8 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
{ {
nsresult rv; nsresult rv;
bool forceThebes = false; if (mCurrentContextId.IsEmpty()) {
rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext));
while (mCurrentContextId.IsEmpty()) {
rv = GetContextHelper(aContextId, forceThebes, getter_AddRefs(mCurrentContext));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!mCurrentContext) { if (!mCurrentContext) {
return NS_OK; return NS_OK;
@ -720,17 +713,12 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
rv = UpdateContext(contextProps); rv = UpdateContext(contextProps);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
if (!forceThebes) {
// Try again with a Thebes context
forceThebes = true;
continue;
}
return rv; return rv;
} }
mCurrentContextId.Assign(aContextId); mCurrentContextId.Assign(aContextId);
break;
} }
if (!mCurrentContextId.Equals(aContextId)) { if (!mCurrentContextId.Equals(aContextId)) {
//XXX eventually allow for more than one active context on a given canvas //XXX eventually allow for more than one active context on a given canvas
return NS_OK; return NS_OK;
@ -754,7 +742,7 @@ nsHTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
if (mCurrentContextId.IsEmpty()) { if (mCurrentContextId.IsEmpty()) {
nsresult rv = GetContextHelper(aContextId, false, getter_AddRefs(mCurrentContext)); nsresult rv = GetContextHelper(aContextId, getter_AddRefs(mCurrentContext));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!mCurrentContext) { if (!mCurrentContext) {
return NS_OK; return NS_OK;
@ -948,16 +936,3 @@ nsHTMLCanvasElement::RenderContextsExternal(gfxContext *aContext, gfxPattern::Gr
return mCurrentContext->Render(aContext, aFilter, aFlags); return mCurrentContext->Render(aContext, aFilter, aFlags);
} }
nsresult NS_NewCanvasRenderingContext2DThebes(nsIDOMCanvasRenderingContext2D** aResult);
nsresult NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult);
nsresult
NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult)
{
Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
if (AzureCanvasEnabled()) {
return NS_NewCanvasRenderingContext2DAzure(aResult);
}
return NS_NewCanvasRenderingContext2DThebes(aResult);
}

View File

@ -29,7 +29,7 @@
#include "imgIContainer.h" #include "imgIContainer.h"
#include "imgILoader.h" #include "imgILoader.h"
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIDecoderObserver.h" #include "imgINotificationObserver.h"
#include "nsILoadGroup.h" #include "nsILoadGroup.h"
@ -89,13 +89,12 @@ DOMCI_NODE_DATA(HTMLImageElement, nsHTMLImageElement)
// QueryInterface implementation for nsHTMLImageElement // QueryInterface implementation for nsHTMLImageElement
NS_INTERFACE_TABLE_HEAD(nsHTMLImageElement) NS_INTERFACE_TABLE_HEAD(nsHTMLImageElement)
NS_HTML_CONTENT_INTERFACE_TABLE6(nsHTMLImageElement, NS_HTML_CONTENT_INTERFACE_TABLE5(nsHTMLImageElement,
nsIDOMHTMLImageElement, nsIDOMHTMLImageElement,
nsIJSNativeInitializer, nsIJSNativeInitializer,
imgIDecoderObserver,
nsIImageLoadingContent, nsIImageLoadingContent,
imgIContainerObserver, imgIOnloadBlocker,
imgIOnloadBlocker) imgINotificationObserver)
NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLImageElement, NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLImageElement,
nsGenericHTMLElement) nsGenericHTMLElement)
NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLImageElement) NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLImageElement)

View File

@ -642,13 +642,12 @@ DOMCI_NODE_DATA(HTMLInputElement, nsHTMLInputElement)
// QueryInterface implementation for nsHTMLInputElement // QueryInterface implementation for nsHTMLInputElement
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLInputElement) NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLInputElement)
NS_HTML_CONTENT_INTERFACE_TABLE9(nsHTMLInputElement, NS_HTML_CONTENT_INTERFACE_TABLE8(nsHTMLInputElement,
nsIDOMHTMLInputElement, nsIDOMHTMLInputElement,
nsITextControlElement, nsITextControlElement,
nsIPhonetic, nsIPhonetic,
imgIDecoderObserver, imgINotificationObserver,
nsIImageLoadingContent, nsIImageLoadingContent,
imgIContainerObserver,
imgIOnloadBlocker, imgIOnloadBlocker,
nsIDOMNSEditableElement, nsIDOMNSEditableElement,
nsIConstraintValidation) nsIConstraintValidation)

View File

@ -185,14 +185,13 @@ DOMCI_NODE_DATA(HTMLObjectElement, nsHTMLObjectElement)
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLObjectElement) NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLObjectElement)
NS_HTML_CONTENT_INTERFACE_TABLE_BEGIN(nsHTMLObjectElement) NS_HTML_CONTENT_INTERFACE_TABLE_BEGIN(nsHTMLObjectElement)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIDOMHTMLObjectElement) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIDOMHTMLObjectElement)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, imgIDecoderObserver) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, imgINotificationObserver)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIRequestObserver) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIRequestObserver)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIStreamListener) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIStreamListener)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIFrameLoaderOwner) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIFrameLoaderOwner)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIObjectLoadingContent) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIObjectLoadingContent)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIImageLoadingContent) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIImageLoadingContent)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, imgIOnloadBlocker) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, imgIOnloadBlocker)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, imgIContainerObserver)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIInterfaceRequestor) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIInterfaceRequestor)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIChannelEventSink) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIChannelEventSink)
NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIConstraintValidation) NS_INTERFACE_TABLE_ENTRY(nsHTMLObjectElement, nsIConstraintValidation)

View File

@ -234,9 +234,8 @@ NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLSharedObjectElement)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIRequestObserver) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIRequestObserver)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIStreamListener) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIStreamListener)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIFrameLoaderOwner) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIFrameLoaderOwner)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, imgIContainerObserver)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIObjectLoadingContent) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIObjectLoadingContent)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, imgIDecoderObserver) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, imgINotificationObserver)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIImageLoadingContent) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIImageLoadingContent)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, imgIOnloadBlocker) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, imgIOnloadBlocker)
NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIInterfaceRequestor) NS_INTERFACE_TABLE_ENTRY(nsHTMLSharedObjectElement, nsIInterfaceRequestor)

View File

@ -72,7 +72,7 @@ function HTML_TAG(aTagName, aImplClass) {
} }
const objectIfaces = [ const objectIfaces = [
"imgIDecoderObserver", "nsIRequestObserver", "nsIStreamListener", "imgINotificationObserver", "nsIRequestObserver", "nsIStreamListener",
"nsIFrameLoaderOwner", "nsIObjectLoadingContent", "nsIInterfaceRequestor", "nsIFrameLoaderOwner", "nsIObjectLoadingContent", "nsIInterfaceRequestor",
"nsIChannelEventSink" "nsIChannelEventSink"
]; ];
@ -160,9 +160,9 @@ HTML_TAG("i", "");
HTML_TAG("iframe", "IFrame", [ "nsIDOMGetSVGDocument", "nsIDOMMozBrowserFrame" ], HTML_TAG("iframe", "IFrame", [ "nsIDOMGetSVGDocument", "nsIDOMMozBrowserFrame" ],
[ "nsIFrameLoaderOwner" ]); [ "nsIFrameLoaderOwner" ]);
HTML_TAG("image", "Span"); HTML_TAG("image", "Span");
HTML_TAG("img", "Image", [], [ "imgIDecoderObserver", HTML_TAG("img", "Image", [], [ "imgINotificationObserver",
"nsIImageLoadingContent" ]); "nsIImageLoadingContent" ]);
HTML_TAG("input", "Input", [], [ "imgIDecoderObserver", HTML_TAG("input", "Input", [], [ "imgINotificationObserver",
"nsIImageLoadingContent", "nsIImageLoadingContent",
"nsIDOMNSEditableElement" ]); "nsIDOMNSEditableElement" ]);
HTML_TAG("ins", "Mod"); HTML_TAG("ins", "Mod");

View File

@ -18,7 +18,7 @@
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgILoader.h" #include "imgILoader.h"
#include "imgIContainer.h" #include "imgIContainer.h"
#include "nsStubImageDecoderObserver.h" #include "imgINotificationObserver.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "nsPresContext.h" #include "nsPresContext.h"
#include "nsStyleContext.h" #include "nsStyleContext.h"
@ -64,7 +64,7 @@ public:
class ImageDocument : public MediaDocument class ImageDocument : public MediaDocument
, public nsIImageDocument , public nsIImageDocument
, public nsStubImageDecoderObserver , public imgINotificationObserver
, public nsIDOMEventListener , public nsIDOMEventListener
{ {
public: public:
@ -89,12 +89,7 @@ public:
nsIDOMEventTarget* aDispatchStartTarget); nsIDOMEventTarget* aDispatchStartTarget);
NS_DECL_NSIIMAGEDOCUMENT NS_DECL_NSIIMAGEDOCUMENT
NS_DECL_IMGINOTIFICATIONOBSERVER
// imgIDecoderObserver (override nsStubImageDecoderObserver)
NS_IMETHOD OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage);
NS_IMETHOD OnStopContainer(imgIRequest* aRequest, imgIContainer* aImage);
NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult aStatus, const PRUnichar *aStatusArg);
NS_IMETHOD OnDiscard(imgIRequest *aRequest);
// nsIDOMEventListener // nsIDOMEventListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent); NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
@ -123,6 +118,9 @@ protected:
void ResetZoomLevel(); void ResetZoomLevel();
float GetZoomLevel(); float GetZoomLevel();
nsresult OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage);
nsresult OnStopRequest(imgIRequest *aRequest, nsresult aStatus);
nsCOMPtr<nsIContent> mImageContent; nsCOMPtr<nsIContent> mImageContent;
int32_t mVisibleWidth; int32_t mVisibleWidth;
@ -238,8 +236,7 @@ DOMCI_NODE_DATA(ImageDocument, ImageDocument)
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(ImageDocument) NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(ImageDocument)
NS_HTML_DOCUMENT_INTERFACE_TABLE_BEGIN(ImageDocument) NS_HTML_DOCUMENT_INTERFACE_TABLE_BEGIN(ImageDocument)
NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIImageDocument) NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIImageDocument)
NS_INTERFACE_TABLE_ENTRY(ImageDocument, imgIDecoderObserver) NS_INTERFACE_TABLE_ENTRY(ImageDocument, imgINotificationObserver)
NS_INTERFACE_TABLE_ENTRY(ImageDocument, imgIContainerObserver)
NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIDOMEventListener) NS_INTERFACE_TABLE_ENTRY(ImageDocument, nsIDOMEventListener)
NS_OFFSET_AND_INTERFACE_TABLE_END NS_OFFSET_AND_INTERFACE_TABLE_END
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
@ -509,6 +506,45 @@ ImageDocument::ToggleImageSize()
} }
NS_IMETHODIMP NS_IMETHODIMP
ImageDocument::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
{
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
nsCOMPtr<imgIContainer> image;
aRequest->GetImage(getter_AddRefs(image));
return OnStartContainer(aRequest, image);
}
if (aType == imgINotificationObserver::DECODE_COMPLETE) {
if (mImageContent) {
// Update the background-color of the image only after the
// image has been decoded to prevent flashes of just the
// background-color.
mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
NS_LITERAL_STRING("decoded"), true);
}
}
if (aType == imgINotificationObserver::DISCARD) {
// mImageContent can be null if the document is already destroyed
if (mImageContent) {
// Remove any decoded-related styling when the image is unloaded.
mImageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class,
true);
}
}
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
uint32_t reqStatus;
aRequest->GetImageStatus(&reqStatus);
nsresult status =
reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
return OnStopRequest(aRequest, status);
}
return NS_OK;
}
nsresult
ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage) ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
{ {
aImage->GetWidth(&mImageWidth); aImage->GetWidth(&mImageWidth);
@ -521,24 +557,9 @@ ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsresult
ImageDocument::OnStopContainer(imgIRequest* aRequest, imgIContainer* aImage) ImageDocument::OnStopRequest(imgIRequest *aRequest,
{ nsresult aStatus)
if (mImageContent) {
// Update the background-color of the image only after the
// image has been decoded to prevent flashes of just the
// background-color.
mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
NS_LITERAL_STRING("decoded"), true);
}
return NS_OK;
}
NS_IMETHODIMP
ImageDocument::OnStopDecode(imgIRequest *aRequest,
nsresult aStatus,
const PRUnichar *aStatusArg)
{ {
UpdateTitleAndCharset(); UpdateTitleAndCharset();
@ -559,18 +580,6 @@ ImageDocument::OnStopDecode(imgIRequest *aRequest,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
ImageDocument::OnDiscard(imgIRequest *aRequest)
{
// mImageContent can be null if the document is already destroyed
if (mImageContent) {
// Remove any decoded-related styling when the image is unloaded.
mImageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class,
true);
}
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
ImageDocument::HandleEvent(nsIDOMEvent* aEvent) ImageDocument::HandleEvent(nsIDOMEvent* aEvent)
{ {

View File

@ -5505,7 +5505,7 @@ NS_INTERFACE_TABLE_HEAD(nsSVGFEImageElement)
nsIDOMSVGElement, nsIDOMSVGElement,
nsIDOMSVGFilterPrimitiveStandardAttributes, nsIDOMSVGFilterPrimitiveStandardAttributes,
nsIDOMSVGFEImageElement, nsIDOMSVGURIReference, nsIDOMSVGFEImageElement, nsIDOMSVGURIReference,
imgIDecoderObserver, nsIImageLoadingContent, imgINotificationObserver, nsIImageLoadingContent,
imgIOnloadBlocker) imgIOnloadBlocker)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGFEImageElement) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGFEImageElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGFEImageElementBase) NS_INTERFACE_MAP_END_INHERITING(nsSVGFEImageElementBase)
@ -5756,43 +5756,27 @@ nsSVGFEImageElement::GetStringInfo()
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// imgIDecoderObserver methods // imgINotificationObserver methods
NS_IMETHODIMP NS_IMETHODIMP
nsSVGFEImageElement::OnStopDecode(imgIRequest *aRequest, nsSVGFEImageElement::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
nsresult status,
const PRUnichar *statusArg)
{ {
nsresult rv = nsresult rv = nsImageLoadingContent::Notify(aRequest, aType, aData);
nsImageLoadingContent::OnStopDecode(aRequest, status, statusArg);
Invalidate();
return rv;
}
NS_IMETHODIMP
nsSVGFEImageElement::FrameChanged(imgIRequest* aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
nsresult rv =
nsImageLoadingContent::FrameChanged(aRequest, aContainer, aDirtyRect);
Invalidate();
return rv;
}
NS_IMETHODIMP
nsSVGFEImageElement::OnStartContainer(imgIRequest *aRequest,
imgIContainer *aContainer)
{
nsresult rv =
nsImageLoadingContent::OnStartContainer(aRequest, aContainer);
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
// Request a decode // Request a decode
NS_ABORT_IF_FALSE(aContainer, "who sent the notification then?"); nsCOMPtr<imgIContainer> container;
aContainer->StartDecoding(); aRequest->GetImage(getter_AddRefs(container));
NS_ABORT_IF_FALSE(container, "who sent the notification then?");
container->StartDecoding();
}
// We have a size - invalidate if (aType == imgINotificationObserver::LOAD_COMPLETE ||
aType == imgINotificationObserver::FRAME_UPDATE ||
aType == imgINotificationObserver::SIZE_AVAILABLE) {
Invalidate(); Invalidate();
}
return rv; return rv;
} }

View File

@ -267,16 +267,7 @@ public:
virtual void UnbindFromTree(bool aDeep, bool aNullParent); virtual void UnbindFromTree(bool aDeep, bool aNullParent);
virtual nsEventStates IntrinsicState() const; virtual nsEventStates IntrinsicState() const;
// imgIDecoderObserver NS_IMETHODIMP Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData);
NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
const PRUnichar *statusArg);
// imgIContainerObserver
NS_IMETHOD FrameChanged(imgIRequest* aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect);
// imgIContainerObserver
NS_IMETHOD OnStartContainer(imgIRequest *aRequest,
imgIContainer *aContainer);
void MaybeLoadSVGImage(); void MaybeLoadSVGImage();

View File

@ -10,7 +10,7 @@
#include "nsIURI.h" #include "nsIURI.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "imgIContainer.h" #include "imgIContainer.h"
#include "imgIDecoderObserver.h" #include "imgINotificationObserver.h"
#include "gfxContext.h" #include "gfxContext.h"
using namespace mozilla; using namespace mozilla;
@ -42,7 +42,7 @@ NS_INTERFACE_TABLE_HEAD(nsSVGImageElement)
NS_NODE_INTERFACE_TABLE9(nsSVGImageElement, nsIDOMNode, nsIDOMElement, NS_NODE_INTERFACE_TABLE9(nsSVGImageElement, nsIDOMNode, nsIDOMElement,
nsIDOMSVGElement, nsIDOMSVGTests, nsIDOMSVGElement, nsIDOMSVGTests,
nsIDOMSVGImageElement, nsIDOMSVGImageElement,
nsIDOMSVGURIReference, imgIDecoderObserver, nsIDOMSVGURIReference, imgINotificationObserver,
nsIImageLoadingContent, imgIOnloadBlocker) nsIImageLoadingContent, imgIOnloadBlocker)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGImageElement) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGImageElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGImageElementBase) NS_INTERFACE_MAP_END_INHERITING(nsSVGImageElementBase)

View File

@ -532,12 +532,8 @@ protected:
static inline uint32_t static inline uint32_t
PRTimeToSeconds(PRTime t_usec) PRTimeToSeconds(PRTime t_usec)
{ {
PRTime usec_per_sec; PRTime usec_per_sec = PR_USEC_PER_SEC;
uint32_t t_sec; return uint32_t(t_usec /= usec_per_sec);
LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
t_usec /= usec_per_sec;
LL_L2I(t_sec, t_usec);
return t_sec;
} }
bool IsFrame(); bool IsFrame();

View File

@ -4546,11 +4546,6 @@ nsDOMClassInfo::Init()
// overwrite some values. // overwrite some values.
mozilla::dom::oldproxybindings::Register(nameSpaceManager); mozilla::dom::oldproxybindings::Register(nameSpaceManager);
if (!AzureCanvasEnabled()) {
nameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING("CanvasRenderingContext2D"),
nullptr, nullptr);
}
sIsInitialized = true; sIsInitialized = true;
return NS_OK; return NS_OK;

View File

@ -109,10 +109,6 @@ DOMInterfaces = {
'CanvasRenderingContext2D': [ 'CanvasRenderingContext2D': [
{ {
'nativeType': 'nsCanvasRenderingContext2DAzure',
# Making this non-prefable requires that we ensure that nothing takes this
# type as an argument or that the non-Azure variant is removed.
'prefable': True,
'implicitJSContext': [ 'implicitJSContext': [
'createImageData', 'getImageData', 'putImageData', 'strokeStyle', 'createImageData', 'getImageData', 'putImageData', 'strokeStyle',
'fillStyle', 'mozDash' 'fillStyle', 'mozDash'

View File

@ -20,13 +20,15 @@
USING_BLUETOOTH_NAMESPACE USING_BLUETOOTH_NAMESPACE
using namespace mozilla::ipc; using namespace mozilla::ipc;
static const uint32_t kUpdateProgressBase = 500000; // Sending system message "bluetooth-opp-update-progress" every 50kb
static const uint32_t kUpdateProgressBase = 50 * 1024;
static mozilla::RefPtr<BluetoothOppManager> sInstance; static mozilla::RefPtr<BluetoothOppManager> sInstance;
static nsCOMPtr<nsIInputStream> stream = nullptr; static nsCOMPtr<nsIInputStream> stream = nullptr;
static uint32_t sSentFileLength = 0; static uint32_t sSentFileLength = 0;
static nsString sFileName; static nsString sFileName;
static uint64_t sFileLength = 0; static uint64_t sFileLength = 0;
static nsString sContentType;
static int sUpdateProgressCounter = 0; static int sUpdateProgressCounter = 0;
class ReadFileTask : public nsRunnable class ReadFileTask : public nsRunnable
@ -97,6 +99,11 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
, mReadFileThread(nullptr) , mReadFileThread(nullptr)
, mPacketLeftLength(0) , mPacketLeftLength(0)
{ {
// FIXME / Bug 800249:
// mConnectedDeviceAddress is Bluetooth address of connected device,
// we will be able to get this value after bug 800249 lands. For now,
// just assign a fake value to it.
mConnectedDeviceAddress.AssignASCII("00:00:00:00:00:00");
} }
BluetoothOppManager::~BluetoothOppManager() BluetoothOppManager::~BluetoothOppManager()
@ -232,6 +239,12 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
return; return;
} }
rv = mBlob->GetType(sContentType);
if (NS_FAILED(rv)) {
NS_WARNING("Can't get content type");
return;
}
if (NS_FAILED(NS_NewThread(getter_AddRefs(mReadFileThread)))) { if (NS_FAILED(NS_NewThread(getter_AddRefs(mReadFileThread)))) {
NS_WARNING("Can't create thread"); NS_WARNING("Can't create thread");
SendDisconnectRequest(); SendDisconnectRequest();
@ -242,6 +255,8 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
sSentFileLength = 0; sSentFileLength = 0;
mAbortFlag = false; mAbortFlag = false;
sInstance->SendPutHeaderRequest(sFileName, sFileLength); sInstance->SendPutHeaderRequest(sFileName, sFileLength);
StartFileTransfer(mConnectedDeviceAddress, false,
sFileName, sFileLength, sContentType);
} }
} }
} else if (mLastCommand == ObexRequestCode::Disconnect) { } else if (mLastCommand == ObexRequestCode::Disconnect) {
@ -262,9 +277,9 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
if (mAbortFlag || mReadFileThread == nullptr) { if (mAbortFlag || mReadFileThread == nullptr) {
SendAbortRequest(); SendAbortRequest();
} else { } else {
// Sending system message "bluetooth-opp-update-progress" every 50kb,
if (kUpdateProgressBase * sUpdateProgressCounter < sSentFileLength) { if (kUpdateProgressBase * sUpdateProgressCounter < sSentFileLength) {
UpdateProgress(sSentFileLength, sFileLength); UpdateProgress(mConnectedDeviceAddress, false,
sSentFileLength, sFileLength);
++sUpdateProgressCounter; ++sUpdateProgressCounter;
} }
@ -280,7 +295,8 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
// FIXME: Needs error handling here // FIXME: Needs error handling here
NS_WARNING("[OPP] PutFinal failed"); NS_WARNING("[OPP] PutFinal failed");
} else { } else {
FileTransferComplete(true, false, sFileName, sSentFileLength); FileTransferComplete(mConnectedDeviceAddress, true, false, sFileName,
sSentFileLength, sContentType);
SendDisconnectRequest(); SendDisconnectRequest();
} }
} else if (mLastCommand == ObexRequestCode::Abort) { } else if (mLastCommand == ObexRequestCode::Abort) {
@ -288,7 +304,8 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
NS_WARNING("[OPP] Abort failed"); NS_WARNING("[OPP] Abort failed");
} }
FileTransferComplete(false, false, sFileName, sSentFileLength); FileTransferComplete(mConnectedDeviceAddress, false, false, sFileName,
sSentFileLength, sContentType);
SendDisconnectRequest(); SendDisconnectRequest();
} else { } else {
// Remote request or unknown mLastCommand // Remote request or unknown mLastCommand
@ -517,16 +534,22 @@ BluetoothOppManager::ReplyToPut(bool aFinal)
} }
void void
BluetoothOppManager::FileTransferComplete(bool aSuccess, BluetoothOppManager::FileTransferComplete(const nsString& aDeviceAddress,
bool aSuccess,
bool aReceived, bool aReceived,
const nsString& aFileName, const nsString& aFileName,
uint32_t aFileLength) uint32_t aFileLength,
const nsString& aContentType)
{ {
nsString type, name; nsString type, name;
BluetoothValue v; BluetoothValue v;
InfallibleTArray<BluetoothNamedValue> parameters; InfallibleTArray<BluetoothNamedValue> parameters;
type.AssignLiteral("bluetooth-opp-transfer-complete"); type.AssignLiteral("bluetooth-opp-transfer-complete");
name.AssignLiteral("address");
v = aDeviceAddress;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("success"); name.AssignLiteral("success");
v = aSuccess; v = aSuccess;
parameters.AppendElement(BluetoothNamedValue(name, v)); parameters.AppendElement(BluetoothNamedValue(name, v));
@ -535,14 +558,18 @@ BluetoothOppManager::FileTransferComplete(bool aSuccess,
v = aReceived; v = aReceived;
parameters.AppendElement(BluetoothNamedValue(name, v)); parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("filename"); name.AssignLiteral("fileName");
v = aFileName; v = aFileName;
parameters.AppendElement(BluetoothNamedValue(name, v)); parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("filelength"); name.AssignLiteral("fileLength");
v = aFileLength; v = aFileLength;
parameters.AppendElement(BluetoothNamedValue(name, v)); parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("contentType");
v = aContentType;
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) { if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]"); NS_WARNING("Failed to broadcast [bluetooth-opp-transfer-complete]");
return; return;
@ -550,18 +577,67 @@ BluetoothOppManager::FileTransferComplete(bool aSuccess,
} }
void void
BluetoothOppManager::UpdateProgress(uint32_t aProcessed, uint32_t aFileLength) BluetoothOppManager::StartFileTransfer(const nsString& aDeviceAddress,
bool aReceived,
const nsString& aFileName,
uint32_t aFileLength,
const nsString& aContentType)
{
nsString type, name;
BluetoothValue v;
InfallibleTArray<BluetoothNamedValue> parameters;
type.AssignLiteral("bluetooth-opp-transfer-start");
name.AssignLiteral("address");
v = aDeviceAddress;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("received");
v = aReceived;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("fileName");
v = aFileName;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("fileLength");
v = aFileLength;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("contentType");
v = aContentType;
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast [bluetooth-opp-transfer-start]");
return;
}
}
void
BluetoothOppManager::UpdateProgress(const nsString& aDeviceAddress,
bool aReceived,
uint32_t aProcessedLength,
uint32_t aFileLength)
{ {
nsString type, name; nsString type, name;
BluetoothValue v; BluetoothValue v;
InfallibleTArray<BluetoothNamedValue> parameters; InfallibleTArray<BluetoothNamedValue> parameters;
type.AssignLiteral("bluetooth-opp-update-progress"); type.AssignLiteral("bluetooth-opp-update-progress");
name.AssignLiteral("processed"); name.AssignLiteral("address");
v = aProcessed; v = aDeviceAddress;
parameters.AppendElement(BluetoothNamedValue(name, v)); parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("filelength"); name.AssignLiteral("received");
v = aReceived;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("processedLength");
v = aProcessedLength;
parameters.AppendElement(BluetoothNamedValue(name, v));
name.AssignLiteral("fileLength");
v = aFileLength; v = aFileLength;
parameters.AppendElement(BluetoothNamedValue(name, v)); parameters.AppendElement(BluetoothNamedValue(name, v));

View File

@ -60,9 +60,21 @@ public:
private: private:
BluetoothOppManager(); BluetoothOppManager();
void FileTransferComplete(bool aSuccess, bool aReceived, void StartFileTransfer(const nsString& aDeviceAddress,
const nsString& aFileName, uint32_t aFileLength); bool aReceived,
void UpdateProgress(uint32_t aProcessed, uint32_t aFileLength); const nsString& aFileName,
uint32_t aFileLength,
const nsString& aContentType);
void FileTransferComplete(const nsString& aDeviceAddress,
bool aSuccess,
bool aReceived,
const nsString& aFileName,
uint32_t aFileLength,
const nsString& aContentType);
void UpdateProgress(const nsString& aDeviceAddress,
bool aReceived,
uint32_t aProcessedLength,
uint32_t aFileLength);
void ReplyToConnect(); void ReplyToConnect();
void ReplyToDisconnect(); void ReplyToDisconnect();
void ReplyToPut(bool aFinal); void ReplyToPut(bool aFinal);
@ -77,6 +89,7 @@ private:
int mRemoteMaxPacketLength; int mRemoteMaxPacketLength;
bool mAbortFlag; bool mAbortFlag;
int mPacketLeftLength; int mPacketLeftLength;
nsString mConnectedDeviceAddress;
nsCOMPtr<nsIDOMBlob> mBlob; nsCOMPtr<nsIDOMBlob> mBlob;
nsCOMPtr<nsIThread> mReadFileThread; nsCOMPtr<nsIThread> mReadFileThread;

View File

@ -1183,8 +1183,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
PR_ParseTimeString(lastModified.get(), true, &time64); //convert string time to integer time PR_ParseTimeString(lastModified.get(), true, &time64); //convert string time to integer time
// Convert PRTime to unix-style time_t, i.e. seconds since the epoch // Convert PRTime to unix-style time_t, i.e. seconds since the epoch
double fpTime; double fpTime = double(time64);
LL_L2D(fpTime, time64);
mModified = (uint32_t)(fpTime * 1e-6 + 0.5); mModified = (uint32_t)(fpTime * 1e-6 + 0.5);
} }
} }

View File

@ -418,13 +418,13 @@ nsresult nsAutoConfig::evaluateLocalFile(nsIFile *file)
return rv; return rv;
int64_t fileSize; int64_t fileSize;
uint32_t fs, amt=0;
file->GetFileSize(&fileSize); file->GetFileSize(&fileSize);
LL_L2UI(fs, fileSize); // Converting 64 bit structure to unsigned int uint32_t fs = fileSize; // Converting 64 bit structure to unsigned int
char *buf = (char *)PR_Malloc(fs * sizeof(char)); char *buf = (char *)PR_Malloc(fs * sizeof(char));
if (!buf) if (!buf)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
uint32_t amt = 0;
rv = inStr->Read(buf, fs, &amt); rv = inStr->Read(buf, fs, &amt);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
EvaluateAdminConfigScript(buf, fs, nullptr, false, EvaluateAdminConfigScript(buf, fs, nullptr, false,

View File

@ -499,7 +499,6 @@ LayerManagerD3D10::CreateDrawTarget(const IntSize &aSize,
{ {
if ((aFormat != FORMAT_B8G8R8A8 && if ((aFormat != FORMAT_B8G8R8A8 &&
aFormat != FORMAT_B8G8R8X8) || aFormat != FORMAT_B8G8R8X8) ||
!gfxPlatform::GetPlatform()->SupportsAzureCanvas() ||
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend() != BACKEND_DIRECT2D) { gfxPlatform::GetPlatform()->GetPreferredCanvasBackend() != BACKEND_DIRECT2D) {
return LayerManager::CreateDrawTarget(aSize, aFormat); return LayerManager::CreateDrawTarget(aSize, aFormat);
} }

View File

@ -706,10 +706,6 @@ gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
RefPtr<DrawTarget> RefPtr<DrawTarget>
gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
{ {
if (!SupportsAzureCanvas()) {
return NULL;
}
// There is a bunch of knowledge in the gfxPlatform heirarchy about how to // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
// create the best offscreen surface for the current system and situation. We // create the best offscreen surface for the current system and situation. We
// can easily take advantage of this for the Cairo backend, so that's what we // can easily take advantage of this for the Cairo backend, so that's what we
@ -734,10 +730,7 @@ gfxPlatform::CreateDrawTargetForBackend(BackendType aBackend, const IntSize& aSi
RefPtr<DrawTarget> RefPtr<DrawTarget>
gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat) gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
{ {
if (!SupportsAzureCanvas()) { NS_ASSERTION(mPreferredCanvasBackend, "No backend.");
return NULL;
}
RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat); RefPtr<DrawTarget> target = CreateDrawTargetForBackend(mPreferredCanvasBackend, aSize, aFormat);
if (target || if (target ||
mFallbackCanvasBackend == BACKEND_NONE) { mFallbackCanvasBackend == BACKEND_NONE) {
@ -751,20 +744,10 @@ gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aForm
RefPtr<DrawTarget> RefPtr<DrawTarget>
gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat) gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
{ {
if (!SupportsAzureCanvas()) { NS_ASSERTION(mPreferredCanvasBackend, "No backend.");
return NULL;
}
return Factory::CreateDrawTargetForData(mPreferredCanvasBackend, aData, aSize, aStride, aFormat); return Factory::CreateDrawTargetForData(mPreferredCanvasBackend, aData, aSize, aStride, aFormat);
} }
bool
gfxPlatform::SupportsAzureCanvas()
{
NS_ASSERTION(mFallbackCanvasBackend == BACKEND_NONE || mPreferredCanvasBackend != BACKEND_NONE,
"fallback backend with no preferred backend");
return mPreferredCanvasBackend != BACKEND_NONE;
}
/* static */ BackendType /* static */ BackendType
gfxPlatform::BackendTypeForName(const nsCString& aName) gfxPlatform::BackendTypeForName(const nsCString& aName)
{ {
@ -1203,6 +1186,9 @@ void
gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, uint32_t aContentBitmask) gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, uint32_t aContentBitmask)
{ {
mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask); mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask);
if (!mPreferredCanvasBackend) {
mPreferredCanvasBackend = BACKEND_CAIRO;
}
mFallbackCanvasBackend = GetCanvasBackendPref(aCanvasBitmask & ~(1 << mPreferredCanvasBackend)); mFallbackCanvasBackend = GetCanvasBackendPref(aCanvasBitmask & ~(1 << mPreferredCanvasBackend));
mContentBackend = GetContentBackendPref(aContentBitmask); mContentBackend = GetContentBackendPref(aContentBitmask);
} }
@ -1210,7 +1196,7 @@ gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, uint32_t aContentBitmask)
/* static */ BackendType /* static */ BackendType
gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask) gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
{ {
return GetBackendPref("gfx.canvas.azure.enabled", "gfx.canvas.azure.backends", aBackendBitmask); return GetBackendPref(nullptr, "gfx.canvas.azure.backends", aBackendBitmask);
} }
/* static */ BackendType /* static */ BackendType
@ -1222,7 +1208,8 @@ gfxPlatform::GetContentBackendPref(uint32_t aBackendBitmask)
/* static */ BackendType /* static */ BackendType
gfxPlatform::GetBackendPref(const char* aEnabledPrefName, const char* aBackendPrefName, uint32_t aBackendBitmask) gfxPlatform::GetBackendPref(const char* aEnabledPrefName, const char* aBackendPrefName, uint32_t aBackendBitmask)
{ {
if (!Preferences::GetBool(aEnabledPrefName, false)) { if (aEnabledPrefName &&
!Preferences::GetBool(aEnabledPrefName, false)) {
return BACKEND_NONE; return BACKEND_NONE;
} }

View File

@ -198,7 +198,6 @@ public:
CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize, CreateDrawTargetForData(unsigned char* aData, const mozilla::gfx::IntSize& aSize,
int32_t aStride, mozilla::gfx::SurfaceFormat aFormat); int32_t aStride, mozilla::gfx::SurfaceFormat aFormat);
bool SupportsAzureCanvas();
bool SupportsAzureContent() { bool SupportsAzureContent() {
return GetContentBackend() != mozilla::gfx::BACKEND_NONE; return GetContentBackend() != mozilla::gfx::BACKEND_NONE;
} }
@ -494,9 +493,10 @@ protected:
static mozilla::gfx::BackendType GetContentBackendPref(uint32_t aBackendBitmask); static mozilla::gfx::BackendType GetContentBackendPref(uint32_t aBackendBitmask);
/** /**
* Checks the aEnabledPrefName pref and returns BACKEND_NONE if the pref is * If aEnabledPrefName is non-null, checks the aEnabledPrefName pref and
* not enabled. Otherwise it will return the first backend named in * returns BACKEND_NONE if the pref is not enabled.
* aBackendPrefName allowed by aBackendBitmask, a bitmask of backend types. * Otherwise it will return the first backend named in aBackendPrefName
* allowed by aBackendBitmask, a bitmask of backend types.
*/ */
static mozilla::gfx::BackendType GetBackendPref(const char* aEnabledPrefName, static mozilla::gfx::BackendType GetBackendPref(const char* aEnabledPrefName,
const char* aBackendPrefName, const char* aBackendPrefName,

View File

@ -458,8 +458,8 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
return; return;
} }
// Feed the actual image data (not including headers) into the BMP decoder // Feed the actual image data (not including headers) into the BMP decoder
int32_t bmpDataOffset = mDirEntry.mImageOffset + BITMAPINFOSIZE; uint32_t bmpDataOffset = mDirEntry.mImageOffset + BITMAPINFOSIZE;
int32_t bmpDataEnd = mDirEntry.mImageOffset + BITMAPINFOSIZE + uint32_t bmpDataEnd = mDirEntry.mImageOffset + BITMAPINFOSIZE +
static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetCompressedImageSize() + static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetCompressedImageSize() +
4 * numColors; 4 * numColors;

View File

@ -278,7 +278,7 @@ nsICOEncoder::ParseOptions(const nsAString& aOptions, uint32_t* bpp,
} }
// For each name/value pair in the set // For each name/value pair in the set
for (int i = 0; i < nameValuePairs.Length(); ++i) { for (unsigned i = 0; i < nameValuePairs.Length(); ++i) {
// Split the name value pair [0] = name, [1] = value // Split the name value pair [0] = name, [1] = value
nsTArray<nsCString> nameValuePair; nsTArray<nsCString> nameValuePair;

View File

@ -23,8 +23,10 @@ XPIDLSRCS = \
imgIDecoderObserver.idl \ imgIDecoderObserver.idl \
imgIEncoder.idl \ imgIEncoder.idl \
imgILoader.idl \ imgILoader.idl \
imgINotificationObserver.idl \
imgIOnloadBlocker.idl \ imgIOnloadBlocker.idl \
imgIRequest.idl \ imgIRequest.idl \
imgIScriptedNotificationObserver.idl \
imgITools.idl \ imgITools.idl \
$(NULL) $(NULL)

View File

@ -10,7 +10,6 @@
#include "nsRect.h" #include "nsRect.h"
%} %}
interface imgIContainer;
interface imgIRequest; interface imgIRequest;
[ptr] native nsIntRect(nsIntRect); [ptr] native nsIntRect(nsIntRect);
@ -20,10 +19,8 @@ interface imgIRequest;
* @author Stuart Parmenter <pavlov@netscape.com> * @author Stuart Parmenter <pavlov@netscape.com>
* @version 0.1 * @version 0.1
*/ */
[scriptable, uuid(f01efdb3-4b20-4313-a636-a2aa01a4ef5d)] [scriptable, uuid(f4aaf410-e88f-4036-b91c-610c9c11d825)]
interface imgIContainerObserver : nsISupports interface imgIContainerObserver : nsISupports
{ {
[noscript] void frameChanged(in imgIRequest aRequest, [noscript] void frameChanged([const] in nsIntRect aDirtyRect);
in imgIContainer aContainer,
[const] in nsIntRect aDirtyRect);
}; };

View File

@ -43,7 +43,7 @@ interface imgIContainer;
* @version 0.1 * @version 0.1
* @see imagelib2 * @see imagelib2
*/ */
[scriptable, uuid(5ca71b89-1a2f-475f-881d-d76c1531c4c8)] [scriptable, uuid(0089cf0c-210c-4b44-9ab0-8099b32bcf64)]
interface imgIDecoderObserver : imgIContainerObserver interface imgIDecoderObserver : imgIContainerObserver
{ {
/** /**
@ -53,7 +53,7 @@ interface imgIDecoderObserver : imgIContainerObserver
* (used only for observers of imgIRequest objects, which are nsIRequests, * (used only for observers of imgIRequest objects, which are nsIRequests,
* not imgIDecoder objects) * not imgIDecoder objects)
*/ */
void onStartRequest(in imgIRequest aRequest); void onStartRequest();
/** /**
* Decode notification. * Decode notification.
@ -62,7 +62,7 @@ interface imgIDecoderObserver : imgIContainerObserver
* "header-only" decodes used by decode-on-draw to parse the width/height * "header-only" decodes used by decode-on-draw to parse the width/height
* out of the image. Thus, it is a decode notification only. * out of the image. Thus, it is a decode notification only.
*/ */
void onStartDecode(in imgIRequest aRequest); void onStartDecode();
/** /**
* Load notification. * Load notification.
@ -72,54 +72,34 @@ interface imgIDecoderObserver : imgIContainerObserver
* called, the size has been set on the container and STATUS_SIZE_AVAILABLE * called, the size has been set on the container and STATUS_SIZE_AVAILABLE
* has been set on the associated imgRequest. * has been set on the associated imgRequest.
*/ */
void onStartContainer(in imgIRequest aRequest, in imgIContainer aContainer); void onStartContainer();
/**
* Decode notification.
*
* called when each frame is created.
*/
void onStartFrame(in imgIRequest aRequest, in unsigned long aFrame);
/** /**
* Decode notification. * Decode notification.
* *
* called when there is more to paint. * called when there is more to paint.
*/ */
[noscript] void onDataAvailable(in imgIRequest aRequest, in boolean aCurrentFrame, [const] in nsIntRect aRect); [noscript] void onDataAvailable([const] in nsIntRect aRect);
/** /**
* Decode notification. * Decode notification.
* *
* called when a frame is finished decoding. * called when a frame is finished decoding.
*/ */
void onStopFrame(in imgIRequest aRequest, in unsigned long aFrame); void onStopFrame();
/**
* Do not implement this. It is useless and going away.
*/
void onStopContainer(in imgIRequest aRequest, in imgIContainer aContainer);
/** /**
* Notification for when an image is known to be animated. This should be * Notification for when an image is known to be animated. This should be
* fired at the earliest possible time. * fired at the earliest possible time.
*/ */
void onImageIsAnimated(in imgIRequest aRequest); void onImageIsAnimated();
/** /**
* In theory a decode notification, but currently a load notification. * Decode notification.
* *
* Ideally this would be called when the decode is complete. Unfortunately, * Called when all decoding has terminated.
* this is currently the only way to signal decoding errors to consumers,
* and the only decoding errors that consumers care about (indeed, the only
* ones that they're prepared to hear about) are failures to instantiate the
* decoder (<img src="foo.html"> for example). Thus, currently this is just
* a companion to onStopDecode to signal success or failure. This will be
* revisited in bug 505385. If you're thinking of doing something new with
* this, please talk to bholley first.
*/ */
void onStopDecode(in imgIRequest aRequest, in nsresult status, void onStopDecode(in nsresult status);
in wstring statusArg);
/** /**
* Load notification. * Load notification.
@ -128,13 +108,13 @@ interface imgIDecoderObserver : imgIContainerObserver
* (used only for observers of imgIRequest objects, which are nsIRequests, * (used only for observers of imgIRequest objects, which are nsIRequests,
* not imgIDecoder objects) * not imgIDecoder objects)
*/ */
void onStopRequest(in imgIRequest aRequest, in boolean aIsLastPart); void onStopRequest(in boolean aIsLastPart);
/** /**
* Called when the decoded image data is discarded. This means that the frames * Called when the decoded image data is discarded. This means that the frames
* no longer exist in decoded form, and any attempt to access or draw the * no longer exist in decoded form, and any attempt to access or draw the
* image will initiate a new series of progressive decode notifications. * image will initiate a new series of progressive decode notifications.
*/ */
void onDiscard(in imgIRequest aRequest); void onDiscard();
}; };

View File

@ -6,7 +6,7 @@
#include "nsISupports.idl" #include "nsISupports.idl"
interface imgIDecoderObserver; interface imgINotificationObserver;
interface imgIRequest; interface imgIRequest;
interface nsIChannel; interface nsIChannel;
@ -61,7 +61,7 @@ interface imgILoader : nsISupports
in nsIURI aReferrerURI, in nsIURI aReferrerURI,
in nsIPrincipal aLoadingPrincipal, in nsIPrincipal aLoadingPrincipal,
in nsILoadGroup aLoadGroup, in nsILoadGroup aLoadGroup,
in imgIDecoderObserver aObserver, in imgINotificationObserver aObserver,
in nsISupports aCX, in nsISupports aCX,
in nsLoadFlags aLoadFlags, in nsLoadFlags aLoadFlags,
in nsISupports cacheKey, in nsISupports cacheKey,
@ -86,7 +86,7 @@ interface imgILoader : nsISupports
* make sure to Cancel() the resulting request before the observer goes away. * make sure to Cancel() the resulting request before the observer goes away.
*/ */
imgIRequest loadImageWithChannel(in nsIChannel aChannel, imgIRequest loadImageWithChannel(in nsIChannel aChannel,
in imgIDecoderObserver aObserver, in imgINotificationObserver aObserver,
in nsISupports cx, in nsISupports cx,
out nsIStreamListener aListener); out nsIStreamListener aListener);
}; };

View File

@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface imgIRequest;
%{C++
#include "nsRect.h"
%}
[ptr] native nsIntRect(nsIntRect);
[scriptable, builtinclass, uuid(90b3d21c-317d-4d96-93c0-12add64a26bf)]
interface imgINotificationObserver : nsISupports
{
const long SIZE_AVAILABLE = 1;
const long FRAME_UPDATE = 2;
const long FRAME_COMPLETE = 3;
const long LOAD_COMPLETE = 4;
const long DECODE_COMPLETE = 5;
const long DISCARD = 6;
const long IS_ANIMATED = 7;
[noscript] void notify(in imgIRequest aProxy, in long aType, [const] in nsIntRect aRect);
};

View File

@ -8,7 +8,7 @@
#include "nsIRequest.idl" #include "nsIRequest.idl"
interface imgIContainer; interface imgIContainer;
interface imgIDecoderObserver; interface imgINotificationObserver;
interface nsIURI; interface nsIURI;
interface nsIPrincipal; interface nsIPrincipal;
@ -19,7 +19,7 @@ interface nsIPrincipal;
* @version 0.1 * @version 0.1
* @see imagelib2 * @see imagelib2
*/ */
[scriptable, uuid(a5a785a8-9881-11e1-aaff-001fbc092072)] [scriptable, uuid(3ea9fc87-2e97-45bf-b373-d1dd253a0b5e)]
interface imgIRequest : nsIRequest interface imgIRequest : nsIRequest
{ {
/** /**
@ -82,7 +82,7 @@ interface imgIRequest : nsIRequest
*/ */
readonly attribute nsIURI URI; readonly attribute nsIURI URI;
readonly attribute imgIDecoderObserver decoderObserver; readonly attribute imgINotificationObserver notificationObserver;
readonly attribute string mimeType; readonly attribute string mimeType;
@ -92,7 +92,7 @@ interface imgIRequest : nsIRequest
* call returns) with all the notifications that have already been dispatched * call returns) with all the notifications that have already been dispatched
* for this image load. * for this image load.
*/ */
imgIRequest clone(in imgIDecoderObserver aObserver); imgIRequest clone(in imgINotificationObserver aObserver);
/** /**
* The principal gotten from the channel the image was loaded from. * The principal gotten from the channel the image was loaded from.

View File

@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface imgIRequest;
[scriptable, uuid(10be55b3-2029-41a7-a975-538efed250ed)]
interface imgIScriptedNotificationObserver : nsISupports
{
void sizeAvailable(in imgIRequest aRequest);
void frameUpdate(in imgIRequest aRequest);
void frameComplete(in imgIRequest aRequest);
void loadComplete(in imgIRequest aRequest);
void decodeComplete(in imgIRequest aRequest);
void discard(in imgIRequest aRequest);
void isAnimated(in imgIRequest aRequest);
};

View File

@ -11,8 +11,10 @@ interface imgIContainer;
interface imgILoader; interface imgILoader;
interface imgICache; interface imgICache;
interface nsIDOMDocument; interface nsIDOMDocument;
interface imgIScriptedNotificationObserver;
interface imgINotificationObserver;
[scriptable, uuid(53dd1cbe-cb9f-4d9e-8104-1ab72851c88e)] [scriptable, uuid(98bd5bf9-87eb-4d92-81b1-4cd10c64f7b2)]
interface imgITools : nsISupports interface imgITools : nsISupports
{ {
/** /**
@ -123,4 +125,12 @@ interface imgITools : nsISupports
in long aWidth, in long aWidth,
in long aHeight, in long aHeight,
[optional] in AString outputOptions); [optional] in AString outputOptions);
/**
* Create a wrapper around a scripted notification observer (ordinarily
* imgINotificationObserver cannot be implemented from scripts).
*
* @param aObserver The scripted observer to wrap
*/
imgINotificationObserver createScriptedObserver(in imgIScriptedNotificationObserver aObserver);
}; };

View File

@ -45,7 +45,7 @@ Decoder::Init()
// Fire OnStartDecode at init time to support bug 512435 // Fire OnStartDecode at init time to support bug 512435
if (!IsSizeDecode() && mObserver) if (!IsSizeDecode() && mObserver)
mObserver->OnStartDecode(nullptr); mObserver->OnStartDecode();
// Implementation-specific initialization // Implementation-specific initialization
InitInternal(); InitInternal();
@ -124,8 +124,7 @@ Decoder::Finish()
// Fire teardown notifications // Fire teardown notifications
if (mObserver) { if (mObserver) {
mObserver->OnStopContainer(nullptr, &mImage); mObserver->OnStopDecode(salvage ? NS_OK : NS_ERROR_FAILURE);
mObserver->OnStopDecode(nullptr, salvage ? NS_OK : NS_ERROR_FAILURE, nullptr);
} }
} }
} }
@ -167,8 +166,7 @@ Decoder::FlushInvalidations()
mInvalidRect.Inflate(1); mInvalidRect.Inflate(1);
mInvalidRect = mInvalidRect.Intersect(mImageBound); mInvalidRect = mInvalidRect.Intersect(mImageBound);
#endif #endif
bool isCurrentFrame = mImage.GetCurrentFrameIndex() == (mFrameCount - 1); mObserver->OnDataAvailable(&mInvalidRect);
mObserver->OnDataAvailable(nullptr, isCurrentFrame, &mInvalidRect);
} }
// Clear the invalidation rectangle // Clear the invalidation rectangle
@ -199,7 +197,7 @@ Decoder::PostSize(int32_t aWidth, int32_t aHeight)
// Notify the observer // Notify the observer
if (mObserver) if (mObserver)
mObserver->OnStartContainer(nullptr, &mImage); mObserver->OnStartContainer();
} }
void void
@ -222,10 +220,6 @@ Decoder::PostFrameStart()
// reported by the Image. // reported by the Image.
NS_ABORT_IF_FALSE(mFrameCount == mImage.GetNumFrames(), NS_ABORT_IF_FALSE(mFrameCount == mImage.GetNumFrames(),
"Decoder frame count doesn't match image's!"); "Decoder frame count doesn't match image's!");
// Fire notification
if (mObserver)
mObserver->OnStartFrame(nullptr, mFrameCount - 1); // frame # is zero-indexed
} }
void void
@ -242,10 +236,10 @@ Decoder::PostFrameStop()
// Fire notifications // Fire notifications
if (mObserver) { if (mObserver) {
mObserver->OnStopFrame(nullptr, mFrameCount - 1); // frame # is zero-indexed mObserver->OnStopFrame();
if (mFrameCount > 1 && !mIsAnimated) { if (mFrameCount > 1 && !mIsAnimated) {
mIsAnimated = true; mIsAnimated = true;
mObserver->OnImageIsAnimated(nullptr); mObserver->OnImageIsAnimated();
} }
} }
} }
@ -278,8 +272,7 @@ Decoder::PostDecodeDone()
// Notify // Notify
mImage.DecodingComplete(); mImage.DecodingComplete();
if (mObserver) { if (mObserver) {
mObserver->OnStopContainer(nullptr, &mImage); mObserver->OnStopDecode(NS_OK);
mObserver->OnStopDecode(nullptr, NS_OK, nullptr);
} }
} }

View File

@ -21,7 +21,7 @@ Image::Image(imgStatusTracker* aStatusTracker) :
mStatusTracker = aStatusTracker; mStatusTracker = aStatusTracker;
mStatusTracker->SetImage(this); mStatusTracker->SetImage(this);
} else { } else {
mStatusTracker = new imgStatusTracker(this); mStatusTracker = new imgStatusTracker(this, nullptr);
} }
} }

View File

@ -27,6 +27,7 @@ CPPSRCS = \
Decoder.cpp \ Decoder.cpp \
DiscardTracker.cpp \ DiscardTracker.cpp \
RasterImage.cpp \ RasterImage.cpp \
ScriptedNotificationObserver.cpp \
SVGDocumentWrapper.cpp \ SVGDocumentWrapper.cpp \
VectorImage.cpp \ VectorImage.cpp \
imgFrame.cpp \ imgFrame.cpp \

View File

@ -514,7 +514,7 @@ RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
#endif #endif
UpdateImageContainer(); UpdateImageContainer();
observer->FrameChanged(nullptr, this, &dirtyRect); observer->FrameChanged(&dirtyRect);
} }
} }
@ -1500,7 +1500,7 @@ RasterImage::ResetAnimation()
// Update display if we were animating before // Update display if we were animating before
nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver)); nsCOMPtr<imgIContainerObserver> observer(do_QueryReferent(mObserver));
if (mAnimating && observer) if (mAnimating && observer)
observer->FrameChanged(nullptr, this, &(mAnim->firstFrameRefreshArea)); observer->FrameChanged(&(mAnim->firstFrameRefreshArea));
if (ShouldAnimate()) { if (ShouldAnimate()) {
StartAnimation(); StartAnimation();
@ -2284,7 +2284,7 @@ RasterImage::Discard(bool force)
// Notify that we discarded // Notify that we discarded
nsCOMPtr<imgIDecoderObserver> observer(do_QueryReferent(mObserver)); nsCOMPtr<imgIDecoderObserver> observer(do_QueryReferent(mObserver));
if (observer) if (observer)
observer->OnDiscard(nullptr); observer->OnDiscard();
if (force) if (force)
DiscardTracker::Remove(&mDiscardTrackerNode); DiscardTracker::Remove(&mDiscardTrackerNode);
@ -2774,7 +2774,7 @@ RasterImage::DrawWorker::Run()
imgFrame *scaledFrame = request->dstFrame.get(); imgFrame *scaledFrame = request->dstFrame.get();
scaledFrame->ImageUpdated(scaledFrame->GetRect()); scaledFrame->ImageUpdated(scaledFrame->GetRect());
nsIntRect frameRect = request->srcFrame->GetRect(); nsIntRect frameRect = request->srcFrame->GetRect();
observer->FrameChanged(nullptr, request->image, &frameRect); observer->FrameChanged(&frameRect);
} }
} }

View File

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ScriptedNotificationObserver.h"
#include "imgIScriptedNotificationObserver.h"
#include "nsCycleCollectionParticipant.h"
using namespace mozilla::image;
NS_IMPL_CYCLE_COLLECTION_1(ScriptedNotificationObserver, mInner)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptedNotificationObserver)
NS_INTERFACE_MAP_ENTRY(imgINotificationObserver)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptedNotificationObserver)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptedNotificationObserver)
ScriptedNotificationObserver::ScriptedNotificationObserver(
imgIScriptedNotificationObserver* aInner)
: mInner(aInner)
{
}
NS_IMETHODIMP
ScriptedNotificationObserver::Notify(imgIRequest* aRequest,
int32_t aType,
const nsIntRect* /*aUnused*/)
{
if (aType == imgINotificationObserver::SIZE_AVAILABLE)
return mInner->SizeAvailable(aRequest);
if (aType == imgINotificationObserver::FRAME_UPDATE)
return mInner->FrameUpdate(aRequest);
if (aType == imgINotificationObserver::FRAME_COMPLETE)
return mInner->FrameComplete(aRequest);
if (aType == imgINotificationObserver::DECODE_COMPLETE)
return mInner->DecodeComplete(aRequest);
if (aType == imgINotificationObserver::LOAD_COMPLETE)
return mInner->LoadComplete(aRequest);
if (aType == imgINotificationObserver::DISCARD)
return mInner->Discard(aRequest);
if (aType == imgINotificationObserver::IS_ANIMATED)
return mInner->IsAnimated(aRequest);
return NS_OK;
}

View File

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "imgINotificationObserver.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
class imgIScriptedNotificationObserver;
namespace mozilla {
namespace image {
class ScriptedNotificationObserver : public imgINotificationObserver
{
public:
ScriptedNotificationObserver(imgIScriptedNotificationObserver* aInner);
virtual ~ScriptedNotificationObserver() {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_IMGINOTIFICATIONOBSERVER
NS_DECL_CYCLE_COLLECTION_CLASS(ScriptedNotificationObserver)
private:
nsCOMPtr<imgIScriptedNotificationObserver> mInner;
};
}}

View File

@ -681,11 +681,11 @@ VectorImage::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt,
nsCOMPtr<imgIDecoderObserver> observer = do_QueryReferent(mObserver); nsCOMPtr<imgIDecoderObserver> observer = do_QueryReferent(mObserver);
if (observer) { if (observer) {
// NOTE: This signals that width/height are available. // NOTE: This signals that width/height are available.
observer->OnStartContainer(nullptr, this); observer->OnStartContainer();
observer->FrameChanged(nullptr, this, &nsIntRect::GetMaxSizedIntRect()); observer->FrameChanged(&nsIntRect::GetMaxSizedIntRect());
observer->OnStopFrame(nullptr, 0); observer->OnStopFrame();
observer->OnStopDecode(nullptr, NS_OK, nullptr); observer->OnStopDecode(NS_OK);
} }
EvaluateAnimation(); EvaluateAnimation();
@ -722,12 +722,12 @@ VectorImage::InvalidateObserver()
nsCOMPtr<imgIContainerObserver> containerObs(do_QueryReferent(mObserver)); nsCOMPtr<imgIContainerObserver> containerObs(do_QueryReferent(mObserver));
if (containerObs) { if (containerObs) {
containerObs->FrameChanged(nullptr, this, &nsIntRect::GetMaxSizedIntRect()); containerObs->FrameChanged(&nsIntRect::GetMaxSizedIntRect());
} }
nsCOMPtr<imgIDecoderObserver> decoderObs(do_QueryReferent(mObserver)); nsCOMPtr<imgIDecoderObserver> decoderObs(do_QueryReferent(mObserver));
if (decoderObs) { if (decoderObs) {
decoderObs->OnStopFrame(nullptr, imgIContainer::FRAME_CURRENT); decoderObs->OnStopFrame();
} }
} }

View File

@ -680,7 +680,7 @@ imgCacheQueue::const_iterator imgCacheQueue::end() const
} }
nsresult imgLoader::CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup, nsresult imgLoader::CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup,
imgIDecoderObserver *aObserver, imgINotificationObserver *aObserver,
nsLoadFlags aLoadFlags, imgIRequest *aProxyRequest, nsLoadFlags aLoadFlags, imgIRequest *aProxyRequest,
imgIRequest **_retval) imgIRequest **_retval)
{ {
@ -708,7 +708,7 @@ nsresult imgLoader::CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup
aRequest->GetURI(getter_AddRefs(uri)); aRequest->GetURI(getter_AddRefs(uri));
// init adds itself to imgRequest's list of observers // init adds itself to imgRequest's list of observers
nsresult rv = proxyRequest->Init(aRequest, aLoadGroup, aRequest->mImage, uri, aObserver); nsresult rv = proxyRequest->Init(&aRequest->GetStatusTracker(), aLoadGroup, uri, aObserver);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
NS_RELEASE(proxyRequest); NS_RELEASE(proxyRequest);
return rv; return rv;
@ -1162,7 +1162,7 @@ bool imgLoader::ValidateRequestWithNewChannel(imgRequest *request,
nsIURI *aInitialDocumentURI, nsIURI *aInitialDocumentURI,
nsIURI *aReferrerURI, nsIURI *aReferrerURI,
nsILoadGroup *aLoadGroup, nsILoadGroup *aLoadGroup,
imgIDecoderObserver *aObserver, imgINotificationObserver *aObserver,
nsISupports *aCX, nsISupports *aCX,
nsLoadFlags aLoadFlags, nsLoadFlags aLoadFlags,
imgIRequest *aExistingRequest, imgIRequest *aExistingRequest,
@ -1284,7 +1284,7 @@ bool imgLoader::ValidateEntry(imgCacheEntry *aEntry,
nsIURI *aInitialDocumentURI, nsIURI *aInitialDocumentURI,
nsIURI *aReferrerURI, nsIURI *aReferrerURI,
nsILoadGroup *aLoadGroup, nsILoadGroup *aLoadGroup,
imgIDecoderObserver *aObserver, imgINotificationObserver *aObserver,
nsISupports *aCX, nsISupports *aCX,
nsLoadFlags aLoadFlags, nsLoadFlags aLoadFlags,
bool aCanMakeNewChannel, bool aCanMakeNewChannel,
@ -1521,14 +1521,14 @@ nsresult imgLoader::EvictEntries(imgCacheQueue &aQueueToClear)
nsIRequest::VALIDATE_ONCE_PER_SESSION) nsIRequest::VALIDATE_ONCE_PER_SESSION)
/* imgIRequest loadImage (in nsIURI aURI, in nsIURI initialDocumentURI, in nsIPrincipal loadingPrincipal, in nsILoadGroup aLoadGroup, in imgIDecoderObserver aObserver, in nsISupports aCX, in nsLoadFlags aLoadFlags, in nsISupports cacheKey, in imgIRequest aRequest); */ /* imgIRequest loadImage (in nsIURI aURI, in nsIURI initialDocumentURI, in nsIPrincipal loadingPrincipal, in nsILoadGroup aLoadGroup, in imgINotificationObserver aObserver, in nsISupports aCX, in nsLoadFlags aLoadFlags, in nsISupports cacheKey, in imgIRequest aRequest); */
NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI, NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
nsIURI *aInitialDocumentURI, nsIURI *aInitialDocumentURI,
nsIURI *aReferrerURI, nsIURI *aReferrerURI,
nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aLoadingPrincipal,
nsILoadGroup *aLoadGroup, nsILoadGroup *aLoadGroup,
imgIDecoderObserver *aObserver, imgINotificationObserver *aObserver,
nsISupports *aCX, nsISupports *aCX,
nsLoadFlags aLoadFlags, nsLoadFlags aLoadFlags,
nsISupports *aCacheKey, nsISupports *aCacheKey,
@ -1784,8 +1784,8 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
return NS_OK; return NS_OK;
} }
/* imgIRequest loadImageWithChannel(in nsIChannel channel, in imgIDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener); */ /* imgIRequest loadImageWithChannel(in nsIChannel channel, in imgINotificationObserver aObserver, in nsISupports cx, out nsIStreamListener); */
NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgIDecoderObserver *aObserver, nsISupports *aCX, nsIStreamListener **listener, imgIRequest **_retval) NS_IMETHODIMP imgLoader::LoadImageWithChannel(nsIChannel *channel, imgINotificationObserver *aObserver, nsISupports *aCX, nsIStreamListener **listener, imgIRequest **_retval)
{ {
NS_ASSERTION(channel, "imgLoader::LoadImageWithChannel -- NULL channel pointer"); NS_ASSERTION(channel, "imgLoader::LoadImageWithChannel -- NULL channel pointer");

View File

@ -30,7 +30,7 @@ class imgLoader;
class imgRequest; class imgRequest;
class imgRequestProxy; class imgRequestProxy;
class imgIRequest; class imgIRequest;
class imgIDecoderObserver; class imgINotificationObserver;
class nsILoadGroup; class nsILoadGroup;
class imgCacheExpirationTracker; class imgCacheExpirationTracker;
class imgMemoryReporter; class imgMemoryReporter;
@ -289,7 +289,7 @@ private: // methods
bool ValidateEntry(imgCacheEntry *aEntry, nsIURI *aKey, bool ValidateEntry(imgCacheEntry *aEntry, nsIURI *aKey,
nsIURI *aInitialDocumentURI, nsIURI *aReferrerURI, nsIURI *aInitialDocumentURI, nsIURI *aReferrerURI,
nsILoadGroup *aLoadGroup, nsILoadGroup *aLoadGroup,
imgIDecoderObserver *aObserver, nsISupports *aCX, imgINotificationObserver *aObserver, nsISupports *aCX,
nsLoadFlags aLoadFlags, bool aCanMakeNewChannel, nsLoadFlags aLoadFlags, bool aCanMakeNewChannel,
imgIRequest *aExistingRequest, imgIRequest *aExistingRequest,
imgIRequest **aProxyRequest, imgIRequest **aProxyRequest,
@ -300,7 +300,7 @@ private: // methods
nsIURI *aInitialDocumentURI, nsIURI *aInitialDocumentURI,
nsIURI *aReferrerURI, nsIURI *aReferrerURI,
nsILoadGroup *aLoadGroup, nsILoadGroup *aLoadGroup,
imgIDecoderObserver *aObserver, imgINotificationObserver *aObserver,
nsISupports *aCX, nsLoadFlags aLoadFlags, nsISupports *aCX, nsLoadFlags aLoadFlags,
imgIRequest *aExistingRequest, imgIRequest *aExistingRequest,
imgIRequest **aProxyRequest, imgIRequest **aProxyRequest,
@ -309,7 +309,7 @@ private: // methods
int32_t aCORSMode); int32_t aCORSMode);
nsresult CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup, nsresult CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup,
imgIDecoderObserver *aObserver, imgINotificationObserver *aObserver,
nsLoadFlags aLoadFlags, imgIRequest *aRequestProxy, nsLoadFlags aLoadFlags, imgIRequest *aRequestProxy,
imgIRequest **_retval); imgIRequest **_retval);

View File

@ -71,16 +71,15 @@ InitPrefCaches()
PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest"); PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest");
#endif #endif
NS_IMPL_ISUPPORTS8(imgRequest, NS_IMPL_ISUPPORTS5(imgRequest,
imgIDecoderObserver, imgIContainerObserver,
nsIStreamListener, nsIRequestObserver, nsIStreamListener, nsIRequestObserver,
nsISupportsWeakReference,
nsIChannelEventSink, nsIChannelEventSink,
nsIInterfaceRequestor, nsIInterfaceRequestor,
nsIAsyncVerifyRedirectCallback) nsIAsyncVerifyRedirectCallback)
imgRequest::imgRequest(imgLoader* aLoader) imgRequest::imgRequest(imgLoader* aLoader)
: mLoader(aLoader) : mLoader(aLoader)
, mStatusTracker(new imgStatusTracker(nullptr, this))
, mValidator(nullptr) , mValidator(nullptr)
, mImageSniffers("image-sniffing-services") , mImageSniffers("image-sniffing-services")
, mInnerWindowId(0) , mInnerWindowId(0)
@ -89,7 +88,6 @@ imgRequest::imgRequest(imgLoader* aLoader)
, mIsMultiPartChannel(false) , mIsMultiPartChannel(false)
, mGotData(false) , mGotData(false)
, mIsInCache(false) , mIsInCache(false)
, mBlockingOnload(false)
, mResniffMimeType(false) , mResniffMimeType(false)
{ {
// Register our pref observers if we haven't yet. // Register our pref observers if we haven't yet.
@ -127,8 +125,6 @@ nsresult imgRequest::Init(nsIURI *aURI,
mProperties = do_CreateInstance("@mozilla.org/properties;1"); mProperties = do_CreateInstance("@mozilla.org/properties;1");
mStatusTracker = new imgStatusTracker(nullptr);
mURI = aURI; mURI = aURI;
mCurrentURI = aCurrentURI; mCurrentURI = aCurrentURI;
mRequest = aRequest; mRequest = aRequest;
@ -176,6 +172,13 @@ bool imgRequest::HasCacheEntry() const
return mCacheEntry != nullptr; return mCacheEntry != nullptr;
} }
void imgRequest::ResetCacheEntry()
{
if (HasCacheEntry()) {
mCacheEntry->SetDataSize(0);
}
}
void imgRequest::AddProxy(imgRequestProxy *proxy) void imgRequest::AddProxy(imgRequestProxy *proxy)
{ {
NS_PRECONDITION(proxy, "null imgRequestProxy passed in"); NS_PRECONDITION(proxy, "null imgRequestProxy passed in");
@ -183,21 +186,12 @@ void imgRequest::AddProxy(imgRequestProxy *proxy)
// If we're empty before adding, we have to tell the loader we now have // If we're empty before adding, we have to tell the loader we now have
// proxies. // proxies.
if (mObservers.IsEmpty()) { if (GetStatusTracker().ConsumerCount() == 0) {
NS_ABORT_IF_FALSE(mURI, "Trying to SetHasProxies without key uri."); NS_ABORT_IF_FALSE(mURI, "Trying to SetHasProxies without key uri.");
mLoader->SetHasProxies(mURI); mLoader->SetHasProxies(mURI);
} }
// If we don't have any current observers, we should restart any animation. GetStatusTracker().AddConsumer(proxy);
if (mImage && !HaveProxyWithObserver(proxy) && proxy->HasObserver()) {
LOG_MSG(gImgLog, "imgRequest::AddProxy", "resetting animation");
mImage->ResetAnimation();
}
proxy->SetPrincipal(mPrincipal);
mObservers.AppendElementUnlessExists(proxy);
} }
nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus) nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus)
@ -209,20 +203,15 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus)
// have animation consumers. // have animation consumers.
proxy->ClearAnimationConsumers(); proxy->ClearAnimationConsumers();
if (!mObservers.RemoveElement(proxy)) {
// Not one of our proxies; we're done
return NS_OK;
}
// Let the status tracker do its thing before we potentially call Cancel() // Let the status tracker do its thing before we potentially call Cancel()
// below, because Cancel() may result in OnStopRequest being called back // below, because Cancel() may result in OnStopRequest being called back
// before Cancel() returns, leaving the image in a different state then the // before Cancel() returns, leaving the image in a different state then the
// one it was in at this point. // one it was in at this point.
imgStatusTracker& statusTracker = GetStatusTracker(); imgStatusTracker& statusTracker = GetStatusTracker();
statusTracker.EmulateRequestFinished(proxy, aStatus); if (!statusTracker.RemoveConsumer(proxy, aStatus))
return NS_OK;
if (mObservers.IsEmpty()) { if (statusTracker.ConsumerCount() == 0) {
// If we have no observers, there's nothing holding us alive. If we haven't // If we have no observers, there's nothing holding us alive. If we haven't
// been cancelled and thus removed from the cache, tell the image loader so // been cancelled and thus removed from the cache, tell the image loader so
// we can be evicted from the cache. // we can be evicted from the cache.
@ -242,7 +231,7 @@ nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus)
/* If |aStatus| is a failure code, then cancel the load if it is still in progress. /* If |aStatus| is a failure code, then cancel the load if it is still in progress.
Otherwise, let the load continue, keeping 'this' in the cache with no observers. Otherwise, let the load continue, keeping 'this' in the cache with no observers.
This way, if a proxy is destroyed without calling cancel on it, it won't leak 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. and won't leave a bad pointer in the observer list.
*/ */
if (statusTracker.IsLoading() && NS_FAILED(aStatus)) { if (statusTracker.IsLoading() && NS_FAILED(aStatus)) {
LOG_MSG(gImgLog, "imgRequest::RemoveProxy", "load in progress. canceling"); LOG_MSG(gImgLog, "imgRequest::RemoveProxy", "load in progress. canceling");
@ -285,16 +274,7 @@ void imgRequest::Cancel(nsresult aStatus)
imgStatusTracker& statusTracker = GetStatusTracker(); imgStatusTracker& statusTracker = GetStatusTracker();
if (mBlockingOnload) { statusTracker.MaybeUnblockOnload();
mBlockingOnload = false;
statusTracker.RecordUnblockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
statusTracker.SendUnblockOnload(iter.GetNext());
}
}
statusTracker.RecordCancel(); statusTracker.RecordCancel();
@ -342,24 +322,6 @@ void imgRequest::RemoveFromCache()
mCacheEntry = nullptr; mCacheEntry = nullptr;
} }
bool imgRequest::HaveProxyWithObserver(imgRequestProxy* aProxyToIgnore) const
{
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
imgRequestProxy* proxy;
while (iter.HasMore()) {
proxy = iter.GetNext();
if (proxy == aProxyToIgnore) {
continue;
}
if (proxy->HasObserver()) {
return true;
}
}
return false;
}
int32_t imgRequest::Priority() const int32_t imgRequest::Priority() const
{ {
int32_t priority = nsISupportsPriority::PRIORITY_NORMAL; int32_t priority = nsISupportsPriority::PRIORITY_NORMAL;
@ -378,7 +340,7 @@ void imgRequest::AdjustPriority(imgRequestProxy *proxy, int32_t delta)
// concern though is that image loads remain lower priority than other pieces // concern though is that image loads remain lower priority than other pieces
// of content such as link clicks, CSS, and JS. // of content such as link clicks, CSS, and JS.
// //
if (mObservers.SafeElementAt(0, nullptr) != proxy) if (!GetStatusTracker().FirstConsumerIs(proxy))
return; return;
nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mRequest); nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mRequest);
@ -510,289 +472,6 @@ imgRequest::StartDecoding()
return NS_OK; 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(mObservers);
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(mObservers);
while (iter.HasMore()) {
tracker.SendStartDecode(iter.GetNext());
}
if (!mIsMultiPartChannel) {
MOZ_ASSERT(!mBlockingOnload);
mBlockingOnload = true;
tracker.RecordBlockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
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(mObservers);
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(mObservers);
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(mObservers);
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(mObservers);
while (iter.HasMore()) {
tracker.SendStopFrame(iter.GetNext(), frame);
}
if (mBlockingOnload) {
mBlockingOnload = false;
tracker.RecordUnblockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
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(mObservers);
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(mObservers);
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(mObservers);
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(mObservers);
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(mObservers);
while (iter.HasMore()) {
mImage->GetStatusTracker().SendImageIsAnimated(iter.GetNext());
}
return NS_OK;
}
/** nsIRequestObserver methods **/ /** nsIRequestObserver methods **/
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */ /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
@ -838,18 +517,12 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
mRequest = chan; mRequest = chan;
} }
imgStatusTracker& statusTracker = GetStatusTracker(); GetStatusTracker().OnStartRequest();
statusTracker.RecordStartRequest();
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
if (channel) if (channel)
channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo)); channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
statusTracker.SendStartRequest(iter.GetNext());
}
/* Get our principal */ /* Get our principal */
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest)); nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
if (chan) { if (chan) {
@ -861,19 +534,13 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }
// Tell all of our proxies that we have a principal.
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
iter.GetNext()->SetPrincipal(mPrincipal);
}
} }
} }
SetCacheValidation(mCacheEntry, aRequest); SetCacheValidation(mCacheEntry, aRequest);
// Shouldn't we be dead already if this gets hit? Probably multipart/x-mixed-replace... // Shouldn't we be dead already if this gets hit? Probably multipart/x-mixed-replace...
if (mObservers.IsEmpty()) { if (GetStatusTracker().ConsumerCount() == 0) {
this->Cancel(NS_IMAGELIB_ERROR_FAILURE); this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
} }
@ -943,11 +610,7 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt,
this->Cancel(status); this->Cancel(status);
} }
/* notify the kids */ GetStatusTracker().OnStopRequest(lastPart, status);
nsTObserverArray<imgRequestProxy*>::ForwardIterator srIter(mObservers);
while (srIter.HasMore()) {
statusTracker.SendStopRequest(srIter.GetNext(), lastPart, status);
}
mTimedChannel = nullptr; mTimedChannel = nullptr;
return NS_OK; return NS_OK;
@ -1033,7 +696,9 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
// our own any more. // our own any more.
if (mResniffMimeType) { if (mResniffMimeType) {
NS_ABORT_IF_FALSE(mIsMultiPartChannel, "Resniffing a non-multipart image"); NS_ABORT_IF_FALSE(mIsMultiPartChannel, "Resniffing a non-multipart image");
mStatusTracker = new imgStatusTracker(nullptr); imgStatusTracker* freshTracker = new imgStatusTracker(nullptr, this);
freshTracker->AdoptConsumers(&GetStatusTracker());
mStatusTracker = freshTracker;
} }
mResniffMimeType = false; mResniffMimeType = false;
@ -1046,11 +711,7 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
} }
mImage->SetInnerWindowID(mInnerWindowId); mImage->SetInnerWindowID(mInnerWindowId);
// Notify any imgRequestProxys that are observing us that we have an Image. GetStatusTracker().OnDataAvailable();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
while (iter.HasMore()) {
iter.GetNext()->SetImage(mImage);
}
/* set our mimetype as a property */ /* set our mimetype as a property */
nsCOMPtr<nsISupportsCString> contentType(do_CreateInstance("@mozilla.org/supports-cstring;1")); nsCOMPtr<nsISupportsCString> contentType(do_CreateInstance("@mozilla.org/supports-cstring;1"));
@ -1119,7 +780,8 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt,
// Initialize the image that we created above. For RasterImages, this // Initialize the image that we created above. For RasterImages, this
// instantiates a decoder behind the scenes, so if we don't have a decoder // instantiates a decoder behind the scenes, so if we don't have a decoder
// for this mimetype we'll find out about it here. // 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 // We allow multipart images to fail to initialize without cancelling the
// load because subsequent images might be fine. // load because subsequent images might be fine.

View File

@ -7,8 +7,6 @@
#ifndef imgRequest_h__ #ifndef imgRequest_h__
#define imgRequest_h__ #define imgRequest_h__
#include "imgIDecoderObserver.h"
#include "nsIChannelEventSink.h" #include "nsIChannelEventSink.h"
#include "nsIContentSniffer.h" #include "nsIContentSniffer.h"
#include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestor.h"
@ -22,8 +20,6 @@
#include "nsCategoryCache.h" #include "nsCategoryCache.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsStringGlue.h" #include "nsStringGlue.h"
#include "nsTObserverArray.h"
#include "nsWeakReference.h"
#include "nsError.h" #include "nsError.h"
#include "imgIRequest.h" #include "imgIRequest.h"
#include "nsIAsyncVerifyRedirectCallback.h" #include "nsIAsyncVerifyRedirectCallback.h"
@ -42,9 +38,7 @@ class Image;
} // namespace image } // namespace image
} // namespace mozilla } // namespace mozilla
class imgRequest : public imgIDecoderObserver, class imgRequest : public nsIStreamListener,
public nsIStreamListener,
public nsSupportsWeakReference,
public nsIChannelEventSink, public nsIChannelEventSink,
public nsIInterfaceRequestor, public nsIInterfaceRequestor,
public nsIAsyncVerifyRedirectCallback public nsIAsyncVerifyRedirectCallback
@ -110,6 +104,22 @@ public:
return principal.forget(); return principal.forget();
} }
// Return the imgStatusTracker associated with this imgRequest. It may live
// in |mStatusTracker| or in |mImage.mStatusTracker|, depending on whether
// mImage has been instantiated yet.
imgStatusTracker& GetStatusTracker();
// 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: private:
friend class imgCacheEntry; friend class imgCacheEntry;
friend class imgRequestProxy; friend class imgRequestProxy;
@ -125,7 +135,6 @@ private:
void Cancel(nsresult aStatus); void Cancel(nsresult aStatus);
void RemoveFromCache(); void RemoveFromCache();
nsresult GetURI(nsIURI **aURI);
nsresult GetSecurityInfo(nsISupports **aSecurityInfo); nsresult GetSecurityInfo(nsISupports **aSecurityInfo);
inline const char *GetMimeType() const { inline const char *GetMimeType() const {
@ -135,11 +144,6 @@ private:
return mProperties; return mProperties;
} }
// Return the imgStatusTracker associated with this imgRequest. It may live
// in |mStatusTracker| or in |mImage.mStatusTracker|, depending on whether
// mImage has been instantiated yet..
imgStatusTracker& GetStatusTracker();
// Reset the cache entry after we've dropped our reference to it. Used by the // Reset the cache entry after we've dropped our reference to it. Used by the
// imgLoader when our cache entry is re-requested after we've dropped our // imgLoader when our cache entry is re-requested after we've dropped our
// reference to it. // reference to it.
@ -148,10 +152,6 @@ private:
// Returns whether we've got a reference to the cache entry. // Returns whether we've got a reference to the cache entry.
bool HasCacheEntry() const; bool HasCacheEntry() const;
// Return true if at least one of our proxies, excluding
// aProxyToIgnore, has an observer. aProxyToIgnore may be null.
bool HaveProxyWithObserver(imgRequestProxy* aProxyToIgnore) const;
// Return the priority of the underlying network request, or return // Return the priority of the underlying network request, or return
// PRIORITY_NORMAL if it doesn't support nsISupportsPriority. // PRIORITY_NORMAL if it doesn't support nsISupportsPriority.
int32_t Priority() const; int32_t Priority() const;
@ -168,12 +168,10 @@ private:
// try to update or modify the image cache. // try to update or modify the image cache.
void SetIsInCache(bool cacheable); void SetIsInCache(bool cacheable);
// Update the cache entry size based on the image container bool IsBlockingOnload() const;
void UpdateCacheEntrySize(); void SetBlockingOnload(bool block) const;
public: public:
NS_DECL_IMGIDECODEROBSERVER
NS_DECL_IMGICONTAINEROBSERVER
NS_DECL_NSISTREAMLISTENER NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICHANNELEVENTSINK
@ -203,8 +201,6 @@ private:
nsCOMPtr<nsIChannel> mChannel; nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIInterfaceRequestor> mPrevChannelSink; nsCOMPtr<nsIInterfaceRequestor> mPrevChannelSink;
nsTObserverArray<imgRequestProxy*> mObservers;
nsCOMPtr<nsITimedChannel> mTimedChannel; nsCOMPtr<nsITimedChannel> mTimedChannel;
nsCString mContentType; nsCString mContentType;

View File

@ -40,8 +40,6 @@ NS_INTERFACE_MAP_END
imgRequestProxy::imgRequestProxy() : imgRequestProxy::imgRequestProxy() :
mOwner(nullptr), mOwner(nullptr),
mURI(nullptr), mURI(nullptr),
mImage(nullptr),
mPrincipal(nullptr),
mListener(nullptr), mListener(nullptr),
mLoadFlags(nsIRequest::LOAD_NORMAL), mLoadFlags(nsIRequest::LOAD_NORMAL),
mLockCount(0), mLockCount(0),
@ -51,7 +49,8 @@ imgRequestProxy::imgRequestProxy() :
mListenerIsStrongRef(false), mListenerIsStrongRef(false),
mDecodeRequested(false), mDecodeRequested(false),
mDeferNotifications(false), mDeferNotifications(false),
mSentStartContainer(false) mSentStartContainer(false),
mOwnerHasImage(false)
{ {
/* member initializers and constructor code */ /* member initializers and constructor code */
@ -89,16 +88,18 @@ imgRequestProxy::~imgRequestProxy()
} }
} }
nsresult imgRequestProxy::Init(imgRequest* request, nsILoadGroup* aLoadGroup, Image* aImage, nsresult imgRequestProxy::Init(imgStatusTracker* aStatusTracker,
nsIURI* aURI, imgIDecoderObserver* aObserver) nsILoadGroup* aLoadGroup,
nsIURI* aURI, imgINotificationObserver* aObserver)
{ {
NS_PRECONDITION(!mOwner && !mListener, "imgRequestProxy is already initialized"); NS_PRECONDITION(!mOwner && !mListener, "imgRequestProxy is already initialized");
LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequestProxy::Init", "request", request); LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequestProxy::Init", "request", aStatusTracker->GetRequest());
NS_ABORT_IF_FALSE(mAnimationConsumers == 0, "Cannot have animation before Init"); NS_ABORT_IF_FALSE(mAnimationConsumers == 0, "Cannot have animation before Init");
mOwner = request; mOwner = aStatusTracker->GetRequest();
mOwnerHasImage = !!aStatusTracker->GetImage();
mListener = aObserver; mListener = aObserver;
// Make sure to addref mListener before the AddProxy call below, since // Make sure to addref mListener before the AddProxy call below, since
// that call might well want to release it if the imgRequest has // that call might well want to release it if the imgRequest has
@ -108,7 +109,6 @@ nsresult imgRequestProxy::Init(imgRequest* request, nsILoadGroup* aLoadGroup, Im
NS_ADDREF(mListener); NS_ADDREF(mListener);
} }
mLoadGroup = aLoadGroup; mLoadGroup = aLoadGroup;
mImage = aImage;
mURI = aURI; mURI = aURI;
// Note: AddProxy won't send all the On* notifications immediately // Note: AddProxy won't send all the On* notifications immediately
@ -132,9 +132,9 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
uint32_t oldAnimationConsumers = mAnimationConsumers; uint32_t oldAnimationConsumers = mAnimationConsumers;
ClearAnimationConsumers(); ClearAnimationConsumers();
// Even if we are cancelled, we MUST change our image, because the image nsRefPtr<imgRequest> oldOwner = mOwner;
// holds our status, and the status must always be correct. mOwner = aNewOwner;
mImage = aNewOwner->mImage; mOwnerHasImage = !!GetStatusTracker().GetImage();
// If we were locked, apply the locks here // If we were locked, apply the locks here
for (uint32_t i = 0; i < oldLockCount; i++) for (uint32_t i = 0; i < oldLockCount; i++)
@ -151,13 +151,12 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
// Were we decoded before? // Were we decoded before?
bool wasDecoded = false; bool wasDecoded = false;
if (mImage && if (GetImage() &&
(mImage->GetStatusTracker().GetImageStatus() & (GetStatusTracker().GetImageStatus() & imgIRequest::STATUS_FRAME_COMPLETE)) {
imgIRequest::STATUS_FRAME_COMPLETE)) {
wasDecoded = true; wasDecoded = true;
} }
mOwner->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER); oldOwner->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER);
// If we had animation requests, restore them here. Note that we // If we had animation requests, restore them here. Note that we
// do this *after* RemoveProxy, which clears out animation consumers // do this *after* RemoveProxy, which clears out animation consumers
@ -165,8 +164,6 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
for (uint32_t i = 0; i < oldAnimationConsumers; i++) for (uint32_t i = 0; i < oldAnimationConsumers; i++)
IncrementAnimationConsumers(); IncrementAnimationConsumers();
mOwner = aNewOwner;
mOwner->AddProxy(this); mOwner->AddProxy(this);
// If we were decoded, or if we'd previously requested a decode, request a // If we were decoded, or if we'd previously requested a decode, request a
@ -329,8 +326,8 @@ NS_IMETHODIMP
imgRequestProxy::LockImage() imgRequestProxy::LockImage()
{ {
mLockCount++; mLockCount++;
if (mImage) if (GetImage())
return mImage->LockImage(); return GetImage()->LockImage();
return NS_OK; return NS_OK;
} }
@ -341,8 +338,8 @@ imgRequestProxy::UnlockImage()
NS_ABORT_IF_FALSE(mLockCount > 0, "calling unlock but no locks!"); NS_ABORT_IF_FALSE(mLockCount > 0, "calling unlock but no locks!");
mLockCount--; mLockCount--;
if (mImage) if (GetImage())
return mImage->UnlockImage(); return GetImage()->UnlockImage();
return NS_OK; return NS_OK;
} }
@ -350,9 +347,8 @@ imgRequestProxy::UnlockImage()
NS_IMETHODIMP NS_IMETHODIMP
imgRequestProxy::RequestDiscard() imgRequestProxy::RequestDiscard()
{ {
if (mImage) { if (GetImage())
return mImage->RequestDiscard(); return GetImage()->RequestDiscard();
}
return NS_OK; return NS_OK;
} }
@ -360,8 +356,8 @@ NS_IMETHODIMP
imgRequestProxy::IncrementAnimationConsumers() imgRequestProxy::IncrementAnimationConsumers()
{ {
mAnimationConsumers++; mAnimationConsumers++;
if (mImage) if (GetImage())
mImage->IncrementAnimationConsumers(); GetImage()->IncrementAnimationConsumers();
return NS_OK; return NS_OK;
} }
@ -376,8 +372,8 @@ imgRequestProxy::DecrementAnimationConsumers()
// early, but not the observer.) // early, but not the observer.)
if (mAnimationConsumers > 0) { if (mAnimationConsumers > 0) {
mAnimationConsumers--; mAnimationConsumers--;
if (mImage) if (GetImage())
mImage->DecrementAnimationConsumers(); GetImage()->DecrementAnimationConsumers();
} }
return NS_OK; return NS_OK;
} }
@ -434,7 +430,7 @@ NS_IMETHODIMP imgRequestProxy::GetImage(imgIContainer * *aImage)
// that'll happen if we get Canceled before the owner instantiates its image // that'll happen if we get Canceled before the owner instantiates its image
// (because Canceling unregisters us as a listener on mOwner). If we're // (because Canceling unregisters us as a listener on mOwner). If we're
// in that situation, just grab the image off of mOwner. // in that situation, just grab the image off of mOwner.
imgIContainer* imageToReturn = mImage ? mImage : mOwner->mImage; imgIContainer* imageToReturn = GetImage() ? GetImage() : mOwner->mImage.get();
if (!imageToReturn) if (!imageToReturn)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -463,11 +459,11 @@ NS_IMETHODIMP imgRequestProxy::GetURI(nsIURI **aURI)
return NS_OK; return NS_OK;
} }
/* readonly attribute imgIDecoderObserver decoderObserver; */ /* readonly attribute imgINotificationObserver notificationObserver; */
NS_IMETHODIMP imgRequestProxy::GetDecoderObserver(imgIDecoderObserver **aDecoderObserver) NS_IMETHODIMP imgRequestProxy::GetNotificationObserver(imgINotificationObserver **aObserver)
{ {
*aDecoderObserver = mListener; *aObserver = mListener;
NS_IF_ADDREF(*aDecoderObserver); NS_IF_ADDREF(*aObserver);
return NS_OK; return NS_OK;
} }
@ -486,7 +482,27 @@ NS_IMETHODIMP imgRequestProxy::GetMimeType(char **aMimeType)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP imgRequestProxy::Clone(imgIDecoderObserver* aObserver, static imgRequestProxy* NewProxy(imgRequestProxy* /*aThis*/)
{
return new imgRequestProxy();
}
imgRequestProxy* NewStaticProxy(imgRequestProxy* aThis)
{
nsCOMPtr<nsIPrincipal> currentPrincipal;
aThis->GetImagePrincipal(getter_AddRefs(currentPrincipal));
return new imgRequestProxyStatic(
static_cast<imgRequestProxyStatic*>(aThis)->mImage, currentPrincipal);
}
NS_IMETHODIMP imgRequestProxy::Clone(imgINotificationObserver* aObserver,
imgIRequest** aClone)
{
return PerformClone(aObserver, NewProxy, aClone);
}
nsresult imgRequestProxy::PerformClone(imgINotificationObserver* aObserver,
imgRequestProxy* (aAllocFn)(imgRequestProxy*),
imgIRequest** aClone) imgIRequest** aClone)
{ {
NS_PRECONDITION(aClone, "Null out param"); NS_PRECONDITION(aClone, "Null out param");
@ -494,7 +510,7 @@ NS_IMETHODIMP imgRequestProxy::Clone(imgIDecoderObserver* aObserver,
LOG_SCOPE(gImgLog, "imgRequestProxy::Clone"); LOG_SCOPE(gImgLog, "imgRequestProxy::Clone");
*aClone = nullptr; *aClone = nullptr;
nsRefPtr<imgRequestProxy> clone = new imgRequestProxy(); nsRefPtr<imgRequestProxy> clone = aAllocFn(this);
// It is important to call |SetLoadFlags()| before calling |Init()| because // It is important to call |SetLoadFlags()| before calling |Init()| because
// |Init()| adds the request to the loadgroup. // |Init()| adds the request to the loadgroup.
@ -503,14 +519,10 @@ NS_IMETHODIMP imgRequestProxy::Clone(imgIDecoderObserver* aObserver,
// XXXldb That's not true anymore. Stuff from imgLoader adds the // XXXldb That's not true anymore. Stuff from imgLoader adds the
// request to the loadgroup. // request to the loadgroup.
clone->SetLoadFlags(mLoadFlags); clone->SetLoadFlags(mLoadFlags);
nsresult rv = clone->Init(mOwner, mLoadGroup, nsresult rv = clone->Init(&GetStatusTracker(), mLoadGroup, mURI, aObserver);
mImage ? mImage : mOwner->mImage,
mURI, aObserver);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
clone->SetPrincipal(mPrincipal);
// Assign to *aClone before calling Notify so that if the caller expects to // 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 // only be notified for requests it's already holding pointers to it won't be
// surprised. // surprised.
@ -526,11 +538,10 @@ NS_IMETHODIMP imgRequestProxy::Clone(imgIDecoderObserver* aObserver,
/* readonly attribute nsIPrincipal imagePrincipal; */ /* readonly attribute nsIPrincipal imagePrincipal; */
NS_IMETHODIMP imgRequestProxy::GetImagePrincipal(nsIPrincipal **aPrincipal) NS_IMETHODIMP imgRequestProxy::GetImagePrincipal(nsIPrincipal **aPrincipal)
{ {
if (!mPrincipal) if (!mOwner)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
NS_ADDREF(*aPrincipal = mPrincipal); NS_ADDREF(*aPrincipal = mOwner->GetPrincipal());
return NS_OK; return NS_OK;
} }
@ -601,102 +612,55 @@ NS_IMETHODIMP imgRequestProxy::GetHasTransferredData(bool* hasData)
return NS_OK; return NS_OK;
} }
/** imgIContainerObserver methods **/
void imgRequestProxy::FrameChanged(imgIContainer *container,
const nsIntRect *dirtyRect)
{
LOG_FUNC(gImgLog, "imgRequestProxy::FrameChanged");
if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->FrameChanged(this, container, dirtyRect);
}
}
/** imgIDecoderObserver methods **/ /** imgIDecoderObserver methods **/
void imgRequestProxy::OnStartDecode() void imgRequestProxy::OnStartContainer()
{
LOG_FUNC(gImgLog, "imgRequestProxy::OnStartDecode");
if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStartDecode(this);
}
}
void imgRequestProxy::OnStartContainer(imgIContainer *image)
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStartContainer"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStartContainer");
if (mListener && !mCanceled && !mSentStartContainer) { if (mListener && !mCanceled && !mSentStartContainer) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->OnStartContainer(this, image); mListener->Notify(this, imgINotificationObserver::SIZE_AVAILABLE, nullptr);
mSentStartContainer = true; mSentStartContainer = true;
} }
} }
void imgRequestProxy::OnStartFrame(uint32_t frame) void imgRequestProxy::OnFrameUpdate(const nsIntRect * rect)
{
LOG_FUNC(gImgLog, "imgRequestProxy::OnStartFrame");
if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStartFrame(this, frame);
}
}
void imgRequestProxy::OnDataAvailable(bool aCurrentFrame, const nsIntRect * rect)
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnDataAvailable"); LOG_FUNC(gImgLog, "imgRequestProxy::OnDataAvailable");
if (mListener && !mCanceled) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->OnDataAvailable(this, aCurrentFrame, rect); mListener->Notify(this, imgINotificationObserver::FRAME_UPDATE, rect);
} }
} }
void imgRequestProxy::OnStopFrame(uint32_t frame) void imgRequestProxy::OnStopFrame()
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStopFrame"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStopFrame");
if (mListener && !mCanceled) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->OnStopFrame(this, frame); mListener->Notify(this, imgINotificationObserver::FRAME_COMPLETE, nullptr);
} }
} }
void imgRequestProxy::OnStopContainer(imgIContainer *image) void imgRequestProxy::OnStopDecode()
{
LOG_FUNC(gImgLog, "imgRequestProxy::OnStopContainer");
if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStopContainer(this, image);
}
// Multipart needs reset for next OnStartContainer
if (mOwner && mOwner->GetMultipart())
mSentStartContainer = false;
}
void imgRequestProxy::OnStopDecode(nsresult status, const PRUnichar *statusArg)
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStopDecode"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStopDecode");
if (mListener && !mCanceled) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->OnStopDecode(this, status, statusArg); mListener->Notify(this, imgINotificationObserver::DECODE_COMPLETE, nullptr);
} }
// Multipart needs reset for next OnStartContainer
if (mOwner && mOwner->GetMultipart())
mSentStartContainer = false;
} }
void imgRequestProxy::OnDiscard() void imgRequestProxy::OnDiscard()
@ -705,8 +669,8 @@ void imgRequestProxy::OnDiscard()
if (mListener && !mCanceled) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->OnDiscard(this); mListener->Notify(this, imgINotificationObserver::DISCARD, nullptr);
} }
} }
@ -715,8 +679,8 @@ void imgRequestProxy::OnImageIsAnimated()
LOG_FUNC(gImgLog, "imgRequestProxy::OnImageIsAnimated"); LOG_FUNC(gImgLog, "imgRequestProxy::OnImageIsAnimated");
if (mListener && !mCanceled) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->OnImageIsAnimated(this); mListener->Notify(this, imgINotificationObserver::IS_ANIMATED, nullptr);
} }
} }
@ -727,14 +691,6 @@ void imgRequestProxy::OnStartRequest()
GetName(name); GetName(name);
LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStartRequest", "name", name.get()); LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStartRequest", "name", name.get());
#endif #endif
// Notify even if mCanceled, since OnStartRequest is guaranteed by the
// nsIStreamListener contract so it makes sense to do the same here.
if (mListener) {
// Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStartRequest(this);
}
} }
void imgRequestProxy::OnStopRequest(bool lastPart) void imgRequestProxy::OnStopRequest(bool lastPart)
@ -751,8 +707,8 @@ void imgRequestProxy::OnStopRequest(bool lastPart)
if (mListener) { if (mListener) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->OnStopRequest(this, lastPart); mListener->Notify(this, imgINotificationObserver::LOAD_COMPLETE, nullptr);
} }
// If we're expecting more data from a multipart channel, re-add ourself // If we're expecting more data from a multipart channel, re-add ourself
@ -774,7 +730,7 @@ void imgRequestProxy::OnStopRequest(bool lastPart)
// Drop our strong ref to the listener now that we're done with // Drop our strong ref to the listener now that we're done with
// everything. Note that this can cancel us and other fun things // everything. Note that this can cancel us and other fun things
// like that. Don't add anything in this method after this point. // like that. Don't add anything in this method after this point.
imgIDecoderObserver* obs = mListener; imgINotificationObserver* obs = mListener;
mListenerIsStrongRef = false; mListenerIsStrongRef = false;
NS_RELEASE(obs); NS_RELEASE(obs);
} }
@ -816,7 +772,7 @@ void imgRequestProxy::NullOutListener()
if (mListenerIsStrongRef) { if (mListenerIsStrongRef) {
// Releasing could do weird reentery stuff, so just play it super-safe // Releasing could do weird reentery stuff, so just play it super-safe
nsCOMPtr<imgIDecoderObserver> obs; nsCOMPtr<imgINotificationObserver> obs;
obs.swap(mListener); obs.swap(mListener);
mListenerIsStrongRef = false; mListenerIsStrongRef = false;
} else { } else {
@ -828,9 +784,10 @@ NS_IMETHODIMP
imgRequestProxy::GetStaticRequest(imgIRequest** aReturn) imgRequestProxy::GetStaticRequest(imgIRequest** aReturn)
{ {
*aReturn = nullptr; *aReturn = nullptr;
mozilla::image::Image* image = GetImage();
bool animated; bool animated;
if (!mImage || (NS_SUCCEEDED(mImage->GetAnimated(&animated)) && !animated)) { if (!image || (NS_SUCCEEDED(image->GetAnimated(&animated)) && !animated)) {
// Early exit - we're not animated, so we don't have to do anything. // Early exit - we're not animated, so we don't have to do anything.
NS_ADDREF(*aReturn = this); NS_ADDREF(*aReturn = this);
return NS_OK; return NS_OK;
@ -839,11 +796,11 @@ imgRequestProxy::GetStaticRequest(imgIRequest** aReturn)
// We are animated. We need to extract the current frame from this image. // We are animated. We need to extract the current frame from this image.
int32_t w = 0; int32_t w = 0;
int32_t h = 0; int32_t h = 0;
mImage->GetWidth(&w); image->GetWidth(&w);
mImage->GetHeight(&h); image->GetHeight(&h);
nsIntRect rect(0, 0, w, h); nsIntRect rect(0, 0, w, h);
nsCOMPtr<imgIContainer> currentFrame; nsCOMPtr<imgIContainer> currentFrame;
nsresult rv = mImage->ExtractFrame(imgIContainer::FRAME_CURRENT, rect, nsresult rv = image->ExtractFrame(imgIContainer::FRAME_CURRENT, rect,
imgIContainer::FLAG_SYNC_DECODE, imgIContainer::FLAG_SYNC_DECODE,
getter_AddRefs(currentFrame)); getter_AddRefs(currentFrame));
if (NS_FAILED(rv)) if (NS_FAILED(rv))
@ -852,20 +809,16 @@ imgRequestProxy::GetStaticRequest(imgIRequest** aReturn)
nsRefPtr<Image> frame = static_cast<Image*>(currentFrame.get()); nsRefPtr<Image> frame = static_cast<Image*>(currentFrame.get());
// Create a static imgRequestProxy with our new extracted frame. // Create a static imgRequestProxy with our new extracted frame.
nsRefPtr<imgRequestProxy> req = new imgRequestProxy(); nsCOMPtr<nsIPrincipal> currentPrincipal;
req->Init(nullptr, nullptr, frame, mURI, nullptr); GetImagePrincipal(getter_AddRefs(currentPrincipal));
req->SetPrincipal(mPrincipal); nsRefPtr<imgRequestProxy> req = new imgRequestProxyStatic(frame, currentPrincipal);
req->Init(&frame->GetStatusTracker(), nullptr, mURI, nullptr);
NS_ADDREF(*aReturn = req); NS_ADDREF(*aReturn = req);
return NS_OK; return NS_OK;
} }
void imgRequestProxy::SetPrincipal(nsIPrincipal *aPrincipal)
{
mPrincipal = aPrincipal;
}
void imgRequestProxy::NotifyListener() void imgRequestProxy::NotifyListener()
{ {
// It would be nice to notify the observer directly in the status tracker // It would be nice to notify the observer directly in the status tracker
@ -879,9 +832,9 @@ void imgRequestProxy::NotifyListener()
} else { } else {
// We don't have an imgRequest, so we can only notify the clone of our // We don't have an imgRequest, so we can only notify the clone of our
// current state, but we still have to do that asynchronously. // current state, but we still have to do that asynchronously.
NS_ABORT_IF_FALSE(mImage, NS_ABORT_IF_FALSE(GetImage(),
"if we have no imgRequest, we should have an Image"); "if we have no imgRequest, we should have an Image");
mImage->GetStatusTracker().NotifyCurrentState(this); GetStatusTracker().NotifyCurrentState(this);
} }
} }
@ -896,25 +849,23 @@ void imgRequestProxy::SyncNotifyListener()
} }
void void
imgRequestProxy::SetImage(Image* aImage) imgRequestProxy::SetHasImage()
{ {
NS_ABORT_IF_FALSE(aImage, "Setting null image"); Image* image = GetStatusTracker().GetImage();
NS_ABORT_IF_FALSE(!mImage || mOwner->GetMultipart(),
"Setting image when we already have one");
mImage = aImage; mOwnerHasImage = true;
// Apply any locks we have // Apply any locks we have
for (uint32_t i = 0; i < mLockCount; ++i) for (uint32_t i = 0; i < mLockCount; ++i)
mImage->LockImage(); image->LockImage();
// Apply any animation consumers we have // Apply any animation consumers we have
for (uint32_t i = 0; i < mAnimationConsumers; i++) for (uint32_t i = 0; i < mAnimationConsumers; i++)
mImage->IncrementAnimationConsumers(); image->IncrementAnimationConsumers();
} }
imgStatusTracker& imgStatusTracker&
imgRequestProxy::GetStatusTracker() imgRequestProxy::GetStatusTracker() const
{ {
// NOTE: It's possible that our mOwner has an Image that it didn't notify // NOTE: It's possible that our mOwner has an Image that it didn't notify
// us about, if we were Canceled before its Image was constructed. // us about, if we were Canceled before its Image was constructed.
@ -922,5 +873,44 @@ imgRequestProxy::GetStatusTracker()
// That's why this method uses mOwner->GetStatusTracker() instead of just // That's why this method uses mOwner->GetStatusTracker() instead of just
// mOwner->mStatusTracker -- we might have a null mImage and yet have an // mOwner->mStatusTracker -- we might have a null mImage and yet have an
// mOwner with a non-null mImage (and a null mStatusTracker pointer). // mOwner with a non-null mImage (and a null mStatusTracker pointer).
return mImage ? mImage->GetStatusTracker() : mOwner->GetStatusTracker(); return mOwner->GetStatusTracker();
}
mozilla::image::Image*
imgRequestProxy::GetImage() const
{
if (!mOwnerHasImage)
return nullptr;
return GetStatusTracker().GetImage();
}
////////////////// imgRequestProxyStatic methods
NS_IMETHODIMP imgRequestProxyStatic::GetImagePrincipal(nsIPrincipal **aPrincipal)
{
if (!mPrincipal)
return NS_ERROR_FAILURE;
NS_ADDREF(*aPrincipal = mPrincipal);
return NS_OK;
}
mozilla::image::Image*
imgRequestProxyStatic::GetImage() const
{
return mImage;
}
imgStatusTracker&
imgRequestProxyStatic::GetStatusTracker() const
{
return mImage->GetStatusTracker();
}
NS_IMETHODIMP
imgRequestProxyStatic::Clone(imgINotificationObserver* aObserver,
imgIRequest** aClone)
{
return PerformClone(aObserver, NewStaticProxy, aClone);
} }

View File

@ -8,7 +8,7 @@
#define imgRequestProxy_h__ #define imgRequestProxy_h__
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIDecoderObserver.h" #include "imgINotificationObserver.h"
#include "nsISecurityInfoProvider.h" #include "nsISecurityInfoProvider.h"
#include "nsIRequestObserver.h" #include "nsIRequestObserver.h"
@ -57,9 +57,9 @@ public:
// Callers to Init or ChangeOwner are required to call NotifyListener after // Callers to Init or ChangeOwner are required to call NotifyListener after
// (although not immediately after) doing so. // (although not immediately after) doing so.
nsresult Init(imgRequest *request, nsILoadGroup *aLoadGroup, nsresult Init(imgStatusTracker* aStatusTracker,
mozilla::image::Image* aImage, nsILoadGroup *aLoadGroup,
nsIURI* aURI, imgIDecoderObserver *aObserver); nsIURI* aURI, imgINotificationObserver *aObserver);
nsresult ChangeOwner(imgRequest *aNewOwner); // this will change mOwner. Do not call this if the previous nsresult ChangeOwner(imgRequest *aNewOwner); // this will change mOwner. Do not call this if the previous
// owner has already sent notifications out! // owner has already sent notifications out!
@ -71,8 +71,6 @@ public:
return mListener != nullptr; return mListener != nullptr;
} }
void SetPrincipal(nsIPrincipal *aPrincipal);
// Asynchronously notify this proxy's listener of the current state of the // Asynchronously notify this proxy's listener of the current state of the
// image, and, if we have an imgRequest mOwner, any status changes that // image, and, if we have an imgRequest mOwner, any status changes that
// happen between the time this function is called and the time the // happen between the time this function is called and the time the
@ -95,9 +93,8 @@ public:
mDeferNotifications = aDeferNotifications; mDeferNotifications = aDeferNotifications;
} }
// Setter for our |mImage| pointer, for imgRequest to use, once it // XXXbholley - This eventually gets folded into the new notification API.
// instantiates an Image. void SetHasImage();
void SetImage(mozilla::image::Image* aImage);
// Removes all animation consumers that were created with // Removes all animation consumers that were created with
// IncrementAnimationConsumers. This is necessary since we need // IncrementAnimationConsumers. This is necessary since we need
@ -135,20 +132,13 @@ protected:
// notifications. // notifications.
/* non-virtual imgIDecoderObserver methods */ /* non-virtual imgIDecoderObserver methods */
void OnStartDecode (); void OnStartContainer ();
void OnStartContainer (imgIContainer *aContainer); void OnFrameUpdate (const nsIntRect * aRect);
void OnStartFrame (uint32_t aFrame); void OnStopFrame ();
void OnDataAvailable (bool aCurrentFrame, const nsIntRect * aRect); void OnStopDecode ();
void OnStopFrame (uint32_t aFrame);
void OnStopContainer (imgIContainer *aContainer);
void OnStopDecode (nsresult status, const PRUnichar *statusArg);
void OnDiscard (); void OnDiscard ();
void OnImageIsAnimated (); void OnImageIsAnimated ();
/* non-virtual imgIContainerObserver methods */
void FrameChanged(imgIContainer *aContainer,
const nsIntRect *aDirtyRect);
/* non-virtual sort-of-nsIRequestObserver methods */ /* non-virtual sort-of-nsIRequestObserver methods */
void OnStartRequest(); void OnStartRequest();
void OnStopRequest(bool aLastPart); void OnStopRequest(bool aLastPart);
@ -171,7 +161,7 @@ protected:
// live either on mOwner or mImage, depending on whether // live either on mOwner or mImage, depending on whether
// (a) we have an mOwner at all // (a) we have an mOwner at all
// (b) whether mOwner has instantiated its image yet // (b) whether mOwner has instantiated its image yet
imgStatusTracker& GetStatusTracker(); virtual imgStatusTracker& GetStatusTracker() const;
nsITimedChannel* TimedChannel() nsITimedChannel* TimedChannel()
{ {
@ -180,6 +170,12 @@ protected:
return mOwner->mTimedChannel; return mOwner->mTimedChannel;
} }
virtual mozilla::image::Image* GetImage() const;
nsresult PerformClone(imgINotificationObserver* aObserver,
imgRequestProxy* (aAllocFn)(imgRequestProxy*),
imgIRequest** aClone);
public: public:
NS_FORWARD_SAFE_NSITIMEDCHANNEL(TimedChannel()) NS_FORWARD_SAFE_NSITIMEDCHANNEL(TimedChannel())
@ -197,18 +193,10 @@ private:
// The URI of our request. // The URI of our request.
nsCOMPtr<nsIURI> mURI; nsCOMPtr<nsIURI> mURI;
// The image we represent. Is null until data has been received, and is then
// set by imgRequest.
nsRefPtr<mozilla::image::Image> mImage;
// Our principal. Is null until data has been received from the channel, and
// is then set by imgRequest.
nsCOMPtr<nsIPrincipal> mPrincipal;
// mListener is only promised to be a weak ref (see imgILoader.idl), // 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 // but we actually keep a strong ref to it until we've seen our
// first OnStopRequest. // first OnStopRequest.
imgIDecoderObserver* mListener; imgINotificationObserver* mListener;
nsCOMPtr<nsILoadGroup> mLoadGroup; nsCOMPtr<nsILoadGroup> mLoadGroup;
nsLoadFlags mLoadFlags; nsLoadFlags mLoadFlags;
@ -226,6 +214,44 @@ private:
// We only want to send OnStartContainer once for each proxy, but we might // We only want to send OnStartContainer once for each proxy, but we might
// get multiple OnStartContainer calls. // get multiple OnStartContainer calls.
bool mSentStartContainer; bool mSentStartContainer;
protected:
bool mOwnerHasImage;
};
// Used for static image proxies for which no requests are available, so
// certain behaviours must be overridden to compensate.
class imgRequestProxyStatic : public imgRequestProxy
{
public:
imgRequestProxyStatic(mozilla::image::Image* aImage,
nsIPrincipal* aPrincipal)
: mImage(aImage)
, mPrincipal(aPrincipal)
{
mOwnerHasImage = true;
};
NS_IMETHOD GetImagePrincipal(nsIPrincipal** aPrincipal) MOZ_OVERRIDE;
virtual imgStatusTracker& GetStatusTracker() const MOZ_OVERRIDE;
NS_IMETHOD Clone(imgINotificationObserver* aObserver,
imgIRequest** aClone) MOZ_OVERRIDE;
protected:
friend imgRequestProxy* NewStaticProxy(imgRequestProxy*);
// Our image. We have to hold a strong reference here, because that's normally
// the job of the underlying request.
nsRefPtr<mozilla::image::Image> mImage;
// Our principal. We have to cache it, rather than accessing the underlying
// request on-demand, because static proxies don't have an underlying request.
nsCOMPtr<nsIPrincipal> mPrincipal;
mozilla::image::Image* GetImage() const MOZ_OVERRIDE;
using imgRequestProxy::GetImage;
}; };
#endif // imgRequestProxy_h__ #endif // imgRequestProxy_h__

View File

@ -12,31 +12,230 @@
#include "Image.h" #include "Image.h"
#include "ImageLogging.h" #include "ImageLogging.h"
#include "RasterImage.h" #include "RasterImage.h"
#include "nsIObserverService.h"
#include "mozilla/Util.h"
#include "mozilla/Assertions.h"
#include "mozilla/Services.h"
using namespace mozilla::image; using namespace mozilla::image;
static nsresult NS_IMPL_ISUPPORTS3(imgStatusTrackerObserver,
GetResultFromImageStatus(uint32_t aStatus) imgIDecoderObserver,
imgIContainerObserver,
nsISupportsWeakReference)
/** imgIContainerObserver methods **/
/* [noscript] void frameChanged (in nsIntRect dirtyRect); */
NS_IMETHODIMP imgStatusTrackerObserver::FrameChanged(const nsIntRect *dirtyRect)
{ {
if (aStatus & imgIRequest::STATUS_ERROR) LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::FrameChanged");
return NS_IMAGELIB_ERROR_FAILURE; NS_ABORT_IF_FALSE(mTracker->GetImage(),
if (aStatus & imgIRequest::STATUS_LOAD_COMPLETE) "FrameChanged callback before we've created our image");
return NS_IMAGELIB_SUCCESS_LOAD_FINISHED;
mTracker->RecordFrameChanged(dirtyRect);
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendFrameChanged(iter.GetNext(), dirtyRect);
}
return NS_OK; return NS_OK;
} }
imgStatusTracker::imgStatusTracker(Image* aImage) /** imgIDecoderObserver methods **/
NS_IMETHODIMP imgStatusTrackerObserver::OnStartDecode()
{
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStartDecode");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStartDecode callback before we've created our image");
if (!mTracker->GetRequest()->GetMultipart()) {
MOZ_ASSERT(!mTracker->mBlockingOnload);
mTracker->mBlockingOnload = true;
mTracker->RecordBlockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
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()
{
NS_NOTREACHED("imgRequest(imgIDecoderObserver)::OnStartRequest");
return NS_OK;
}
/* void onStartContainer (); */
NS_IMETHODIMP imgStatusTrackerObserver::OnStartContainer()
{
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStartContainer");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStartContainer callback before we've created our image");
mTracker->RecordStartContainer(mTracker->GetImage());
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendStartContainer(iter.GetNext());
}
return NS_OK;
}
/* [noscript] void onDataAvailable ([const] in nsIntRect rect); */
NS_IMETHODIMP imgStatusTrackerObserver::OnDataAvailable(const nsIntRect * rect)
{
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnDataAvailable");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnDataAvailable callback before we've created our image");
mTracker->RecordDataAvailable();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendDataAvailable(iter.GetNext(), rect);
}
return NS_OK;
}
/* void onStopFrame (); */
NS_IMETHODIMP imgStatusTrackerObserver::OnStopFrame()
{
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStopFrame");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStopFrame callback before we've created our image");
mTracker->RecordStopFrame();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendStopFrame(iter.GetNext());
}
mTracker->MaybeUnblockOnload();
return NS_OK;
}
static void
FireFailureNotification(imgRequest* aRequest)
{
// Some kind of problem has happened with image decoding.
// Report the URI to net:failed-to-process-uri-conent observers.
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (os) {
nsCOMPtr<nsIURI> uri;
aRequest->GetURI(getter_AddRefs(uri));
os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
}
}
/* void onStopDecode (in nsresult status); */
NS_IMETHODIMP imgStatusTrackerObserver::OnStopDecode(nsresult aStatus)
{
LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStopDecode");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStopDecode callback before we've created our image");
// We finished the decode, and thus have the decoded frames. Update the cache
// entry size to take this into account.
mTracker->GetRequest()->UpdateCacheEntrySize();
bool preexistingError = mTracker->GetImageStatus() == imgIRequest::STATUS_ERROR;
mTracker->RecordStopDecode(aStatus);
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendStopDecode(iter.GetNext(), aStatus);
}
// 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.
mTracker->MaybeUnblockOnload();
if (NS_FAILED(aStatus) && !preexistingError) {
FireFailureNotification(mTracker->GetRequest());
}
return NS_OK;
}
NS_IMETHODIMP imgStatusTrackerObserver::OnStopRequest(bool aLastPart)
{
NS_NOTREACHED("imgRequest(imgIDecoderObserver)::OnStopRequest");
return NS_OK;
}
/* void onDiscard (); */
NS_IMETHODIMP imgStatusTrackerObserver::OnDiscard()
{
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->mConsumers);
while (iter.HasMore()) {
mTracker->SendDiscard(iter.GetNext());
}
return NS_OK;
}
NS_IMETHODIMP imgStatusTrackerObserver::OnImageIsAnimated()
{
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnImageIsAnimated callback before we've created our image");
mTracker->RecordImageIsAnimated();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendImageIsAnimated(iter.GetNext());
}
return NS_OK;
}
// imgStatusTracker methods
imgStatusTracker::imgStatusTracker(Image* aImage, imgRequest* aRequest)
: mImage(aImage), : mImage(aImage),
mRequest(aRequest),
mState(0), mState(0),
mImageStatus(imgIRequest::STATUS_NONE), mImageStatus(imgIRequest::STATUS_NONE),
mHadLastPart(false) mHadLastPart(false),
mBlockingOnload(false),
mTrackerObserver(new imgStatusTrackerObserver(this))
{} {}
imgStatusTracker::imgStatusTracker(const imgStatusTracker& aOther) imgStatusTracker::imgStatusTracker(const imgStatusTracker& aOther)
: mImage(aOther.mImage), : mImage(aOther.mImage),
mRequest(aOther.mRequest),
mState(aOther.mState), mState(aOther.mState),
mImageStatus(aOther.mImageStatus), mImageStatus(aOther.mImageStatus),
mHadLastPart(aOther.mHadLastPart) mHadLastPart(aOther.mHadLastPart),
mBlockingOnload(aOther.mBlockingOnload)
// Note: we explicitly don't copy mRequestRunnable, because it won't be // Note: we explicitly don't copy mRequestRunnable, because it won't be
// nulled out when the mRequestRunnable's Run function eventually gets // nulled out when the mRequestRunnable's Run function eventually gets
// called. // called.
@ -194,11 +393,7 @@ imgStatusTracker::SyncNotify(imgRequestProxy* proxy)
// OnStartContainer // OnStartContainer
if (mState & stateHasSize) if (mState & stateHasSize)
proxy->OnStartContainer(mImage); proxy->OnStartContainer();
// OnStartDecode
if (mState & stateDecodeStarted)
proxy->OnStartDecode();
// BlockOnload // BlockOnload
if (mState & stateBlockingOnload) if (mState & stateBlockingOnload)
@ -206,24 +401,19 @@ imgStatusTracker::SyncNotify(imgRequestProxy* proxy)
if (mImage) { if (mImage) {
int16_t imageType = mImage->GetType(); int16_t imageType = mImage->GetType();
// Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame) // Send frame messages (OnDataAvailable, OnStopFrame)
if (imageType == imgIContainer::TYPE_VECTOR || if (imageType == imgIContainer::TYPE_VECTOR ||
static_cast<RasterImage*>(mImage)->GetNumFrames() > 0) { static_cast<RasterImage*>(mImage)->GetNumFrames() > 0) {
uint32_t frame = (imageType == imgIContainer::TYPE_VECTOR) ?
0 : static_cast<RasterImage*>(mImage)->GetCurrentFrameIndex();
proxy->OnStartFrame(frame);
// OnDataAvailable // OnDataAvailable
// XXX - Should only send partial rects here, but that needs to // XXX - Should only send partial rects here, but that needs to
// wait until we fix up the observer interface // wait until we fix up the observer interface
nsIntRect r; nsIntRect r;
mImage->GetCurrentFrameRect(r); mImage->GetCurrentFrameRect(r);
proxy->OnDataAvailable(frame, &r); proxy->OnFrameUpdate(&r);
if (mState & stateFrameStopped) if (mState & stateFrameStopped)
proxy->OnStopFrame(frame); proxy->OnStopFrame();
} }
// OnImageIsAnimated // OnImageIsAnimated
@ -235,16 +425,12 @@ imgStatusTracker::SyncNotify(imgRequestProxy* proxy)
} }
} }
// 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) { if (mState & stateDecodeStopped) {
NS_ABORT_IF_FALSE(mImage, "stopped decoding without ever having an image?"); NS_ABORT_IF_FALSE(mImage, "stopped decoding without ever having an image?");
proxy->OnStopContainer(mImage); proxy->OnStopDecode();
} }
if (mState & stateRequestStopped) { if (mState & stateRequestStopped) {
proxy->OnStopDecode(GetResultFromImageStatus(mImageStatus), nullptr);
proxy->OnStopRequest(mHadLastPart); proxy->OnStopRequest(mHadLastPart);
} }
} }
@ -255,6 +441,12 @@ imgStatusTracker::EmulateRequestFinished(imgRequestProxy* aProxy,
{ {
nsCOMPtr<imgIRequest> kungFuDeathGrip(aProxy); nsCOMPtr<imgIRequest> kungFuDeathGrip(aProxy);
// In certain cases the request might not have started yet.
// We still need to fulfill the contract.
if (!(mState & stateRequestStarted)) {
aProxy->OnStartRequest();
}
if (mState & stateBlockingOnload) { if (mState & stateBlockingOnload) {
aProxy->UnblockOnload(); aProxy->UnblockOnload();
} }
@ -264,6 +456,26 @@ imgStatusTracker::EmulateRequestFinished(imgRequestProxy* aProxy,
} }
} }
void
imgStatusTracker::AddConsumer(imgRequestProxy* aConsumer)
{
mConsumers.AppendElementUnlessExists(aConsumer);
}
// XXX - The last argument should go away.
bool
imgStatusTracker::RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus)
{
// Remove the proxy from the list.
bool removed = mConsumers.RemoveElement(aConsumer);
// Consumers can get confused if they don't get all the proper teardown
// notifications. Part ways on good terms.
if (removed)
EmulateRequestFinished(aConsumer, aStatus);
return removed;
}
void void
imgStatusTracker::RecordCancel() imgStatusTracker::RecordCancel()
{ {
@ -284,25 +496,10 @@ void
imgStatusTracker::RecordDecoded() imgStatusTracker::RecordDecoded()
{ {
NS_ABORT_IF_FALSE(mImage, "RecordDecoded called before we have an Image"); NS_ABORT_IF_FALSE(mImage, "RecordDecoded called before we have an Image");
mState |= stateDecodeStarted | stateDecodeStopped | stateFrameStopped; mState |= stateDecodeStopped | stateFrameStopped;
mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE | imgIRequest::STATUS_DECODE_COMPLETE; mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE | imgIRequest::STATUS_DECODE_COMPLETE;
} }
/* non-virtual imgIDecoderObserver methods */
void
imgStatusTracker::RecordStartDecode()
{
NS_ABORT_IF_FALSE(mImage, "RecordStartDecode without an Image");
mState |= stateDecodeStarted;
}
void
imgStatusTracker::SendStartDecode(imgRequestProxy* aProxy)
{
if (!aProxy->NotificationsDeferred())
aProxy->OnStartDecode();
}
void void
imgStatusTracker::RecordStartContainer(imgIContainer* aContainer) imgStatusTracker::RecordStartContainer(imgIContainer* aContainer)
{ {
@ -315,29 +512,14 @@ imgStatusTracker::RecordStartContainer(imgIContainer* aContainer)
} }
void void
imgStatusTracker::SendStartContainer(imgRequestProxy* aProxy, imgIContainer* aContainer) imgStatusTracker::SendStartContainer(imgRequestProxy* aProxy)
{ {
if (!aProxy->NotificationsDeferred()) if (!aProxy->NotificationsDeferred())
aProxy->OnStartContainer(aContainer); aProxy->OnStartContainer();
} }
void void
imgStatusTracker::RecordStartFrame(uint32_t aFrame) imgStatusTracker::RecordDataAvailable()
{
NS_ABORT_IF_FALSE(mImage, "RecordStartFrame called before we have an Image");
// no bookkeeping necessary here - this is implied by imgIContainer's number
// of frames
}
void
imgStatusTracker::SendStartFrame(imgRequestProxy* aProxy, uint32_t aFrame)
{
if (!aProxy->NotificationsDeferred())
aProxy->OnStartFrame(aFrame);
}
void
imgStatusTracker::RecordDataAvailable(bool aCurrentFrame, const nsIntRect* aRect)
{ {
NS_ABORT_IF_FALSE(mImage, NS_ABORT_IF_FALSE(mImage,
"RecordDataAvailable called before we have an Image"); "RecordDataAvailable called before we have an Image");
@ -346,16 +528,16 @@ imgStatusTracker::RecordDataAvailable(bool aCurrentFrame, const nsIntRect* aRect
} }
void void
imgStatusTracker::SendDataAvailable(imgRequestProxy* aProxy, bool aCurrentFrame, imgStatusTracker::SendDataAvailable(imgRequestProxy* aProxy,
const nsIntRect* aRect) const nsIntRect* aRect)
{ {
if (!aProxy->NotificationsDeferred()) if (!aProxy->NotificationsDeferred())
aProxy->OnDataAvailable(aCurrentFrame, aRect); aProxy->OnFrameUpdate(aRect);
} }
void void
imgStatusTracker::RecordStopFrame(uint32_t aFrame) imgStatusTracker::RecordStopFrame()
{ {
NS_ABORT_IF_FALSE(mImage, "RecordStopFrame called before we have an Image"); NS_ABORT_IF_FALSE(mImage, "RecordStopFrame called before we have an Image");
mState |= stateFrameStopped; mState |= stateFrameStopped;
@ -363,34 +545,20 @@ imgStatusTracker::RecordStopFrame(uint32_t aFrame)
} }
void void
imgStatusTracker::SendStopFrame(imgRequestProxy* aProxy, uint32_t aFrame) imgStatusTracker::SendStopFrame(imgRequestProxy* aProxy)
{ {
if (!aProxy->NotificationsDeferred()) if (!aProxy->NotificationsDeferred())
aProxy->OnStopFrame(aFrame); aProxy->OnStopFrame();
} }
void void
imgStatusTracker::RecordStopContainer(imgIContainer* aContainer) imgStatusTracker::RecordStopDecode(nsresult aStatus)
{
NS_ABORT_IF_FALSE(mImage,
"RecordStopContainer called before we have an Image");
// 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)
{ {
NS_ABORT_IF_FALSE(mImage, NS_ABORT_IF_FALSE(mImage,
"RecordStopDecode called before we have an Image"); "RecordStopDecode called before we have an Image");
mState |= stateDecodeStopped; mState |= stateDecodeStopped;
if (NS_SUCCEEDED(aStatus)) if (NS_SUCCEEDED(aStatus) && mImageStatus != imgIRequest::STATUS_ERROR)
mImageStatus |= imgIRequest::STATUS_DECODE_COMPLETE; mImageStatus |= imgIRequest::STATUS_DECODE_COMPLETE;
// If we weren't successful, clear all success status bits and set error. // If we weren't successful, clear all success status bits and set error.
else else
@ -398,14 +566,11 @@ imgStatusTracker::RecordStopDecode(nsresult aStatus, const PRUnichar* statusArg)
} }
void void
imgStatusTracker::SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus, imgStatusTracker::SendStopDecode(imgRequestProxy* aProxy,
const PRUnichar* statusArg) nsresult aStatus)
{ {
// See imgRequest::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()) if (!aProxy->NotificationsDeferred())
aProxy->OnStopContainer(mImage); aProxy->OnStopDecode();
} }
void void
@ -414,7 +579,7 @@ imgStatusTracker::RecordDiscard()
NS_ABORT_IF_FALSE(mImage, NS_ABORT_IF_FALSE(mImage,
"RecordDiscard called before we have an Image"); "RecordDiscard called before we have an Image");
// Clear the state bits we no longer deserve. // Clear the state bits we no longer deserve.
uint32_t stateBitsToClear = stateDecodeStarted | stateDecodeStopped; uint32_t stateBitsToClear = stateDecodeStopped;
mState &= ~stateBitsToClear; mState &= ~stateBitsToClear;
// Clear the status bits we no longer deserve. // Clear the status bits we no longer deserve.
@ -450,8 +615,7 @@ imgStatusTracker::SendDiscard(imgRequestProxy* aProxy)
/* non-virtual imgIContainerObserver methods */ /* non-virtual imgIContainerObserver methods */
void void
imgStatusTracker::RecordFrameChanged(imgIContainer* aContainer, imgStatusTracker::RecordFrameChanged(const nsIntRect* aDirtyRect)
const nsIntRect* aDirtyRect)
{ {
NS_ABORT_IF_FALSE(mImage, NS_ABORT_IF_FALSE(mImage,
"RecordFrameChanged called before we have an Image"); "RecordFrameChanged called before we have an Image");
@ -460,11 +624,11 @@ imgStatusTracker::RecordFrameChanged(imgIContainer* aContainer,
} }
void void
imgStatusTracker::SendFrameChanged(imgRequestProxy* aProxy, imgIContainer* aContainer, imgStatusTracker::SendFrameChanged(imgRequestProxy* aProxy,
const nsIntRect* aDirtyRect) const nsIntRect* aDirtyRect)
{ {
if (!aProxy->NotificationsDeferred()) if (!aProxy->NotificationsDeferred())
aProxy->FrameChanged(aContainer, aDirtyRect); aProxy->OnFrameUpdate(aDirtyRect);
} }
/* non-virtual sort-of-nsIRequestObserver methods */ /* non-virtual sort-of-nsIRequestObserver methods */
@ -477,7 +641,6 @@ imgStatusTracker::RecordStartRequest()
mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE; mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE;
mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE; mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE;
mState &= ~stateRequestStarted; mState &= ~stateRequestStarted;
mState &= ~stateDecodeStarted;
mState &= ~stateDecodeStopped; mState &= ~stateDecodeStopped;
mState &= ~stateRequestStopped; mState &= ~stateRequestStopped;
mState &= ~stateBlockingOnload; mState &= ~stateBlockingOnload;
@ -493,27 +656,67 @@ imgStatusTracker::SendStartRequest(imgRequestProxy* aProxy)
} }
void void
imgStatusTracker::RecordStopRequest(bool aLastPart, nsresult aStatus) imgStatusTracker::OnStartRequest()
{
RecordStartRequest();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
while (iter.HasMore()) {
SendStartRequest(iter.GetNext());
}
}
void
imgStatusTracker::RecordStopRequest(bool aLastPart,
nsresult aStatus)
{ {
mHadLastPart = aLastPart; mHadLastPart = aLastPart;
mState |= stateRequestStopped; mState |= stateRequestStopped;
// If we were successful in loading, note that the image is complete. // If we were successful in loading, note that the image is complete.
if (NS_SUCCEEDED(aStatus)) if (NS_SUCCEEDED(aStatus) && mImageStatus != imgIRequest::STATUS_ERROR)
mImageStatus |= imgIRequest::STATUS_LOAD_COMPLETE; mImageStatus |= imgIRequest::STATUS_LOAD_COMPLETE;
else
mImageStatus = imgIRequest::STATUS_ERROR;
} }
void void
imgStatusTracker::SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus) imgStatusTracker::SendStopRequest(imgRequestProxy* aProxy,
bool aLastPart,
nsresult aStatus)
{ {
// See bug 505385 and imgRequest::OnStopDecode for more information on why
// OnStopDecode is called with OnStopRequest.
if (!aProxy->NotificationsDeferred()) { if (!aProxy->NotificationsDeferred()) {
aProxy->OnStopDecode(GetResultFromImageStatus(mImageStatus), nullptr);
aProxy->OnStopRequest(aLastPart); aProxy->OnStopRequest(aLastPart);
} }
} }
void
imgStatusTracker::OnStopRequest(bool aLastPart,
nsresult aStatus)
{
bool preexistingError = mImageStatus == imgIRequest::STATUS_ERROR;
RecordStopRequest(aLastPart, aStatus);
/* notify the kids */
nsTObserverArray<imgRequestProxy*>::ForwardIterator srIter(mConsumers);
while (srIter.HasMore()) {
SendStopRequest(srIter.GetNext(), aLastPart, aStatus);
}
if (NS_FAILED(aStatus) && !preexistingError) {
FireFailureNotification(GetRequest());
}
}
void
imgStatusTracker::OnDataAvailable()
{
// Notify any imgRequestProxys that are observing us that we have an Image.
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
while (iter.HasMore()) {
iter.GetNext()->SetHasImage();
}
}
void void
imgStatusTracker::RecordBlockOnload() imgStatusTracker::RecordBlockOnload()
{ {
@ -543,3 +746,20 @@ imgStatusTracker::SendUnblockOnload(imgRequestProxy* aProxy)
aProxy->UnblockOnload(); aProxy->UnblockOnload();
} }
} }
void
imgStatusTracker::MaybeUnblockOnload()
{
if (!mBlockingOnload) {
return;
}
mBlockingOnload = false;
RecordUnblockOnload();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
while (iter.HasMore()) {
SendUnblockOnload(iter.GetNext());
}
}

View File

@ -12,6 +12,7 @@ class imgRequest;
class imgRequestProxy; class imgRequestProxy;
class imgStatusNotifyRunnable; class imgStatusNotifyRunnable;
class imgRequestNotifyRunnable; class imgRequestNotifyRunnable;
class imgStatusTracker;
struct nsIntRect; struct nsIntRect;
namespace mozilla { namespace mozilla {
namespace image { namespace image {
@ -21,19 +22,43 @@ class Image;
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsTObserverArray.h"
#include "nsIRunnable.h" #include "nsIRunnable.h"
#include "nscore.h" #include "nscore.h"
#include "nsWeakReference.h"
#include "imgIDecoderObserver.h"
enum { enum {
stateRequestStarted = PR_BIT(0), stateRequestStarted = PR_BIT(0),
stateHasSize = PR_BIT(1), stateHasSize = PR_BIT(1),
stateDecodeStarted = PR_BIT(2),
stateDecodeStopped = PR_BIT(3), stateDecodeStopped = PR_BIT(3),
stateFrameStopped = PR_BIT(4), stateFrameStopped = PR_BIT(4),
stateRequestStopped = PR_BIT(5), stateRequestStopped = PR_BIT(5),
stateBlockingOnload = PR_BIT(6) 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 * 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 * decoding status about an Image, and makes it possible to send notifications
@ -51,7 +76,7 @@ public:
// aImage is the image that this status tracker will pass to the // aImage is the image that this status tracker will pass to the
// imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be // imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be
// alive as long as this instance is, because we hold a weak reference to it. // alive as long as this instance is, because we hold a weak reference to it.
imgStatusTracker(mozilla::image::Image* aImage); imgStatusTracker(mozilla::image::Image* aImage, imgRequest* aRequest);
imgStatusTracker(const imgStatusTracker& aOther); imgStatusTracker(const imgStatusTracker& aOther);
// Image-setter, for imgStatusTrackers created by imgRequest::Init, which // Image-setter, for imgStatusTrackers created by imgRequest::Init, which
@ -85,6 +110,21 @@ public:
// OnStopRequest and UnblockOnload, and only if necessary. // OnStopRequest and UnblockOnload, and only if necessary.
void EmulateRequestFinished(imgRequestProxy* proxy, nsresult aStatus); void EmulateRequestFinished(imgRequestProxy* proxy, nsresult aStatus);
// We manage a set of consumers that are using an image and thus concerned
// with its status. Weak pointers.
void AddConsumer(imgRequestProxy* aConsumer);
bool RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus);
size_t ConsumerCount() const { return mConsumers.Length(); };
// This is intentionally non-general because its sole purpose is to support an
// some obscure network priority logic in imgRequest. That stuff could probably
// be improved, but it's too scary to mess with at the moment.
bool FirstConsumerIs(imgRequestProxy* aConsumer) {
return mConsumers.SafeElementAt(0, nullptr) == aConsumer;
}
void AdoptConsumers(imgStatusTracker* aTracker) { mConsumers = aTracker->mConsumers; }
// Returns whether we are in the process of loading; that is, whether we have // Returns whether we are in the process of loading; that is, whether we have
// not received OnStopRequest. // not received OnStopRequest.
bool IsLoading() const; bool IsLoading() const;
@ -104,34 +144,26 @@ public:
void RecordLoaded(); void RecordLoaded();
// Shorthand for recording all the decode notifications: StartDecode, // Shorthand for recording all the decode notifications: StartDecode,
// StartFrame, DataAvailable, StopFrame, StopContainer, StopDecode. // StartFrame, DataAvailable, StopFrame, StopDecode.
void RecordDecoded(); void RecordDecoded();
/* non-virtual imgIDecoderObserver methods */ /* non-virtual imgIDecoderObserver methods */
void RecordStartDecode();
void SendStartDecode(imgRequestProxy* aProxy);
void RecordStartContainer(imgIContainer* aContainer); void RecordStartContainer(imgIContainer* aContainer);
void SendStartContainer(imgRequestProxy* aProxy, imgIContainer* aContainer); void SendStartContainer(imgRequestProxy* aProxy);
void RecordStartFrame(uint32_t aFrame); void RecordDataAvailable();
void SendStartFrame(imgRequestProxy* aProxy, uint32_t aFrame); void SendDataAvailable(imgRequestProxy* aProxy, const nsIntRect* aRect);
void RecordDataAvailable(bool aCurrentFrame, const nsIntRect* aRect); void RecordStopFrame();
void SendDataAvailable(imgRequestProxy* aProxy, bool aCurrentFrame, const nsIntRect* aRect); void SendStopFrame(imgRequestProxy* aProxy);
void RecordStopFrame(uint32_t aFrame); void RecordStopDecode(nsresult statusg);
void SendStopFrame(imgRequestProxy* aProxy, uint32_t aFrame); void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus);
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 RecordDiscard();
void SendDiscard(imgRequestProxy* aProxy); void SendDiscard(imgRequestProxy* aProxy);
void RecordImageIsAnimated(); void RecordImageIsAnimated();
void SendImageIsAnimated(imgRequestProxy *aProxy); void SendImageIsAnimated(imgRequestProxy *aProxy);
/* non-virtual imgIContainerObserver methods */ /* non-virtual imgIContainerObserver methods */
void RecordFrameChanged(imgIContainer* aContainer, void RecordFrameChanged(const nsIntRect* aDirtyRect);
const nsIntRect* aDirtyRect); void SendFrameChanged(imgRequestProxy* aProxy, const nsIntRect* aDirtyRect);
void SendFrameChanged(imgRequestProxy* aProxy, imgIContainer* aContainer,
const nsIntRect* aDirtyRect);
/* non-virtual sort-of-nsIRequestObserver methods */ /* non-virtual sort-of-nsIRequestObserver methods */
void RecordStartRequest(); void RecordStartRequest();
@ -139,6 +171,10 @@ public:
void RecordStopRequest(bool aLastPart, nsresult aStatus); void RecordStopRequest(bool aLastPart, nsresult aStatus);
void SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus); void SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus);
void OnStartRequest();
void OnDataAvailable();
void OnStopRequest(bool aLastPart, nsresult aStatus);
/* non-virtual imgIOnloadBlocker methods */ /* non-virtual imgIOnloadBlocker methods */
// NB: If UnblockOnload is sent, and then we are asked to replay the // NB: If UnblockOnload is sent, and then we are asked to replay the
// notifications, we will not send a BlockOnload/UnblockOnload pair. This // notifications, we will not send a BlockOnload/UnblockOnload pair. This
@ -148,18 +184,35 @@ public:
void RecordUnblockOnload(); void RecordUnblockOnload();
void SendUnblockOnload(imgRequestProxy* aProxy); 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: private:
friend class imgStatusNotifyRunnable; friend class imgStatusNotifyRunnable;
friend class imgRequestNotifyRunnable; friend class imgRequestNotifyRunnable;
friend class imgStatusTrackerObserver;
nsCOMPtr<nsIRunnable> mRequestRunnable; nsCOMPtr<nsIRunnable> mRequestRunnable;
// A weak pointer to the Image, because it owns us, and we // Weak pointers to the image and request. The request owns the image, and
// can't create a cycle. // the image (or the request, if there's no image) owns the status tracker.
mozilla::image::Image* mImage; mozilla::image::Image* mImage;
imgRequest* mRequest;
uint32_t mState; uint32_t mState;
uint32_t mImageStatus; uint32_t mImageStatus;
bool mHadLastPart; 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 #endif

View File

@ -23,6 +23,8 @@
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "RasterImage.h" #include "RasterImage.h"
#include "ScriptedNotificationObserver.h"
#include "imgIScriptedNotificationObserver.h"
using namespace mozilla::image; using namespace mozilla::image;
@ -276,6 +278,13 @@ NS_IMETHODIMP imgTools::GetFirstImageFrame(imgIContainer *aContainer,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP imgTools::CreateScriptedObserver(imgIScriptedNotificationObserver* aInner,
imgINotificationObserver** aObserver)
{
NS_ADDREF(*aObserver = new ScriptedNotificationObserver(aInner));
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader) imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader)
{ {

View File

@ -121,15 +121,14 @@ function getImagePref(pref)
return null; return null;
} }
// JS implementation of imgIDecoderObserver with stubs for all of its methods. // JS implementation of imgIScriptedNotificationObserver with stubs for all of its methods.
function ImageDecoderObserverStub() function ImageDecoderObserverStub()
{ {
this.onStartRequest = function onStartRequest(aRequest) {} this.sizeAvailable = function sizeAvailable(aRequest) {}
this.onStartDecode = function onStartDecode(aRequest) {} this.frameComplete = function frameComplete(aRequest) {}
this.onStartContainer = function onStartContainer(aRequest, aContainer) {} this.decodeComplete = function decodeComplete(aRequest) {}
this.onStartFrame = function onStartFrame(aRequest, aFrame) {} this.loadComplete = function loadComplete(aRequest) {}
this.onStopFrame = function onStopFrame(aRequest, aFrame) {} this.frameUpdate = function frameUpdate(aRequest) {}
this.onStopContainer = function onStopContainer(aRequest, aContainer) {} this.discard = function discard(aRequest) {}
this.onStopDecode = function onStopDecode(aRequest, status, statusArg) {} this.isAnimated = function isAnimated(aRequest) {}
this.onStopRequest = function onStopRequest(aRequest, aIsLastPart) {}
} }

View File

@ -26,6 +26,7 @@ SimpleTest.waitForExplicitFinish();
const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes) const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
const Cc = Components.classes;
const Ci = Components.interfaces; const Ci = Components.interfaces;
const gImg = document.getElementsByTagName("img")[0]; const gImg = document.getElementsByTagName("img")[0];
@ -53,7 +54,7 @@ function takeReferenceSnapshot() {
"reference div should disappear when it becomes display:none"); "reference div should disappear when it becomes display:none");
} }
function myOnStopFrame(aRequest, aFrame) { function myOnStopFrame(aRequest) {
gOnStopFrameCounter++; gOnStopFrameCounter++;
ok(true, "myOnStopFrame called"); ok(true, "myOnStopFrame called");
let currentSnapshot = snapshotWindow(window, false); let currentSnapshot = snapshotWindow(window, false);
@ -89,8 +90,11 @@ function main() {
takeReferenceSnapshot(); takeReferenceSnapshot();
// Create, customize & attach decoder observer // Create, customize & attach decoder observer
gMyDecoderObserver = new ImageDecoderObserverStub(); observer = new ImageDecoderObserverStub();
gMyDecoderObserver.onStopFrame = myOnStopFrame; observer.frameComplete = myOnStopFrame;
gMyDecoderObserver =
Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(observer);
let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent); let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent);
imgLoadingContent.addObserver(gMyDecoderObserver); imgLoadingContent.addObserver(gMyDecoderObserver);

View File

@ -45,12 +45,18 @@ function checkClone(other_listener, aRequest)
// For as long as clone notification is synchronous, we can't test the clone state reliably. // For as long as clone notification is synchronous, we can't test the clone state reliably.
var listener = new ImageListener(null, function(foo, bar) { do_test_finished(); } /*getCloneStopCallback(other_listener)*/); var listener = new ImageListener(null, function(foo, bar) { do_test_finished(); } /*getCloneStopCallback(other_listener)*/);
listener.synchronous = false; listener.synchronous = false;
var clone = aRequest.clone(listener); var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener);
var clone = aRequest.clone(outer);
} }
// Ensure that all the callbacks were called on aRequest. // Ensure that all the callbacks were called on aRequest.
function checkAllCallbacks(listener, aRequest) function checkAllCallbacks(listener, aRequest)
{ {
do_check_neq(listener.state & SIZE_AVAILABLE, 0);
do_check_neq(listener.state & FRAME_COMPLETE, 0);
do_check_neq(listener.state & DECODE_COMPLETE, 0);
do_check_neq(listener.state & LOAD_COMPLETE, 0);
do_check_eq(listener.state, ALL_BITS); do_check_eq(listener.state, ALL_BITS);
do_test_finished(); do_test_finished();
@ -67,7 +73,9 @@ function secondLoadDone(oldlistener, aRequest)
// clone state reliably. // clone state reliably.
var listener = new ImageListener(null, checkAllCallbacks); var listener = new ImageListener(null, checkAllCallbacks);
listener.synchronous = false; listener.synchronous = false;
var staticrequestclone = staticrequest.clone(listener); var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener);
var staticrequestclone = staticrequest.clone(outer);
} catch(e) { } catch(e) {
// We can't create a static request. Most likely the request we started // We can't create a static request. Most likely the request we started
// with didn't load successfully. // with didn't load successfully.
@ -86,7 +94,9 @@ function checkSecondLoad()
do_test_pending(); do_test_pending();
var listener = new ImageListener(checkClone, secondLoadDone); var listener = new ImageListener(checkClone, secondLoadDone);
requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null)); var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener);
requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, outer, null, 0, null, null, null));
listener.synchronous = false; listener.synchronous = false;
} }
@ -102,10 +112,10 @@ function firstLoadDone(oldlistener, aRequest)
function getChannelLoadImageStartCallback(streamlistener) function getChannelLoadImageStartCallback(streamlistener)
{ {
return function channelLoadStart(imglistener, aRequest) { return function channelLoadStart(imglistener, aRequest) {
// We must not have received any status before we get this start callback. // We must not have received all status before we get this start callback.
// If we have, we've broken people's expectations by delaying events from a // If we have, we've broken people's expectations by delaying events from a
// channel we were given. // channel we were given.
do_check_eq(streamlistener.requestStatus, 0); do_check_eq(streamlistener.requestStatus & STOP_REQUEST, 0);
checkClone(imglistener, aRequest); checkClone(imglistener, aRequest);
} }
@ -141,8 +151,10 @@ function checkSecondChannelLoad()
var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener), var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener),
getChannelLoadImageStopCallback(channellistener, getChannelLoadImageStopCallback(channellistener,
all_done_callback)); all_done_callback));
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener);
var outlistener = {}; var outlistener = {};
requests.push(gCurrentLoader.loadImageWithChannel(channel, listener, null, outlistener)); requests.push(gCurrentLoader.loadImageWithChannel(channel, outer, null, outlistener));
channellistener.outputListener = outlistener.value; channellistener.outputListener = outlistener.value;
listener.synchronous = false; listener.synchronous = false;
@ -163,8 +175,10 @@ function run_loadImageWithChannel_tests()
var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener), var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener),
getChannelLoadImageStopCallback(channellistener, getChannelLoadImageStopCallback(channellistener,
checkSecondChannelLoad)); checkSecondChannelLoad));
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener);
var outlistener = {}; var outlistener = {};
requests.push(gCurrentLoader.loadImageWithChannel(channel, listener, null, outlistener)); requests.push(gCurrentLoader.loadImageWithChannel(channel, outer, null, outlistener));
channellistener.outputListener = outlistener.value; channellistener.outputListener = outlistener.value;
listener.synchronous = false; listener.synchronous = false;
@ -182,7 +196,9 @@ function startImageCallback(otherCb)
// Make sure we can load the same image immediately out of the cache. // Make sure we can load the same image immediately out of the cache.
do_test_pending(); do_test_pending();
var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); }); var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); });
requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, listener2, null, 0, null, null, null)); var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener2);
requests.push(gCurrentLoader.loadImage(uri, null, null, null, null, outer, null, 0, null, null, null));
listener2.synchronous = false; listener2.synchronous = false;
// Now that we've started another load, chain to the callback. // Now that we've started another load, chain to the callback.
@ -198,7 +214,9 @@ function run_test()
do_test_pending(); do_test_pending();
var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone); var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone);
var req = gCurrentLoader.loadImage(uri, null, null, null, null, listener, null, 0, null, null, null); var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener);
var req = gCurrentLoader.loadImage(uri, null, null, null, null, outer, null, 0, null, null, null);
requests.push(req); requests.push(req);
// Ensure that we don't cause any mayhem when we lock an image. // Ensure that we don't cause any mayhem when we lock an image.

View File

@ -2,86 +2,65 @@
* Helper structures to track callbacks from image and channel loads. * Helper structures to track callbacks from image and channel loads.
*/ */
// One bit per callback that imageListener below implements. Stored in // START_REQUEST and STOP_REQUEST are used by ChannelListener, and
// ImageListener.state.
// START_REQUEST and STOP_REQUEST are also reused by ChannelListener, and
// stored in ChannelListener.requestStatus. // stored in ChannelListener.requestStatus.
const START_REQUEST = 0x01; const START_REQUEST = 0x01;
const START_DECODE = 0x02; const STOP_REQUEST = 0x02;
const START_CONTAINER = 0x04; const DATA_AVAILABLE = 0x04;
const START_FRAME = 0x08;
const STOP_FRAME = 0x10; // One bit per callback that imageListener below implements. Stored in
const STOP_CONTAINER = 0x20; // ImageListener.state.
const STOP_DECODE = 0x40; const SIZE_AVAILABLE = 0x01;
const STOP_REQUEST = 0x80; const FRAME_UPDATE = 0x02;
const ALL_BITS = 0xFF; const FRAME_COMPLETE = 0x04;
const LOAD_COMPLETE = 0x08;
const DECODE_COMPLETE = 0x10;
const ALL_BITS = SIZE_AVAILABLE | FRAME_COMPLETE | DECODE_COMPLETE | LOAD_COMPLETE;
// An implementation of imgIDecoderObserver with the ability to call specified // An implementation of imgIDecoderObserver with the ability to call specified
// functions on onStartRequest and onStopRequest. // functions on onStartRequest and onStopRequest.
function ImageListener(start_callback, stop_callback) function ImageListener(start_callback, stop_callback)
{ {
this.onStartRequest = function onStartRequest(aRequest) this.sizeAvailable = function onSizeAvailable(aRequest)
{ {
do_check_false(this.synchronous); do_check_false(this.synchronous);
this.state |= START_REQUEST; this.state |= SIZE_AVAILABLE;
if (this.start_callback) if (this.start_callback)
this.start_callback(this, aRequest); this.start_callback(this, aRequest);
} }
this.onStartDecode = function onStartDecode(aRequest) this.frameComplete = function onFrameComplete(aRequest)
{ {
do_check_false(this.synchronous); do_check_false(this.synchronous);
this.state |= START_DECODE; this.state |= FRAME_COMPLETE;
} }
this.onStartContainer = function onStartContainer(aRequest, aContainer) this.decodeComplete = function onDecodeComplete(aRequest)
{ {
do_check_false(this.synchronous); do_check_false(this.synchronous);
this.state |= START_CONTAINER; this.state |= DECODE_COMPLETE;
} }
this.onStartFrame = function onStartFrame(aRequest, aFrame) this.loadComplete = function onLoadcomplete(aRequest)
{ {
do_check_false(this.synchronous); do_check_false(this.synchronous);
this.state |= START_FRAME;
}
this.onStopFrame = function onStopFrame(aRequest, aFrame)
{
do_check_false(this.synchronous);
this.state |= STOP_FRAME;
}
this.onStopContainer = function onStopContainer(aRequest, aContainer)
{
do_check_false(this.synchronous);
this.state |= STOP_CONTAINER;
}
this.onStopDecode = function onStopDecode(aRequest, status, statusArg)
{
do_check_false(this.synchronous);
this.state |= STOP_DECODE;
}
this.onStopRequest = function onStopRequest(aRequest, aIsLastPart)
{
do_check_false(this.synchronous);
// onStopDecode must always be called before, and with, onStopRequest. See
// imgRequest::OnStopDecode for more information.
do_check_true(!!(this.state & STOP_DECODE));
// We have to cancel the request when we're done with it to break any // We have to cancel the request when we're done with it to break any
// reference loops! // reference loops!
aRequest.cancelAndForgetObserver(0); aRequest.cancelAndForgetObserver(0);
this.state |= STOP_REQUEST; this.state |= LOAD_COMPLETE;
if (this.stop_callback) if (this.stop_callback)
this.stop_callback(this, aRequest); this.stop_callback(this, aRequest);
} }
this.frameUpdate = function onFrameUpdate(aRequest)
{
}
this.isAnimated = function onIsAnimated()
{
}
// Initialize the synchronous flag to true to start. This must be set to // Initialize the synchronous flag to true to start. This must be set to
// false before exiting to the event loop! // false before exiting to the event loop!
@ -118,6 +97,8 @@ function ChannelListener()
{ {
if (this.outputListener) if (this.outputListener)
this.outputListener.onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount); this.outputListener.onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
this.requestStatus |= DATA_AVAILABLE;
} }
this.onStopRequest = function onStopRequest(aRequest, aContext, aStatusCode) this.onStopRequest = function onStopRequest(aRequest, aContext, aStatusCode)

View File

@ -55,21 +55,25 @@ function setup_chan(path, isPrivate, callback) {
chan.asyncOpen(channelListener, null); chan.asyncOpen(channelListener, null);
var listener = new ImageListener(null, callback); var listener = new ImageListener(null, callback);
listeners.push(listener);
var outlistener = {}; var outlistener = {};
var loader = isPrivate ? gPrivateLoader : gPublicLoader; var loader = isPrivate ? gPrivateLoader : gPublicLoader;
requests.push(loader.loadImageWithChannel(chan, listener, null, outlistener)); var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener);
listeners.push(outer);
requests.push(loader.loadImageWithChannel(chan, outer, null, outlistener));
channelListener.outputListener = outlistener.value; channelListener.outputListener = outlistener.value;
listener.synchronous = false; listener.synchronous = false;
} }
function loadImage(isPrivate, callback) { function loadImage(isPrivate, callback) {
var listener = new ImageListener(null, callback); var listener = new ImageListener(null, callback);
var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
.createScriptedObserver(listener);
var uri = gIoService.newURI(gImgPath, null, null); var uri = gIoService.newURI(gImgPath, null, null);
var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup); var loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup);
loadGroup.notificationCallbacks = new NotificationCallbacks(isPrivate); loadGroup.notificationCallbacks = new NotificationCallbacks(isPrivate);
var loader = isPrivate ? gPrivateLoader : gPublicLoader; var loader = isPrivate ? gPrivateLoader : gPublicLoader;
requests.push(loader.loadImage(uri, null, null, null, loadGroup, listener, null, 0, null, null, null)); requests.push(loader.loadImage(uri, null, null, null, loadGroup, outer, null, 0, null, null, null));
listener.synchronous = false; listener.synchronous = false;
} }

View File

@ -53,7 +53,7 @@ struct RuntimeSizes
, ionCode(0) , ionCode(0)
, regexpCode(0) , regexpCode(0)
, unusedCode(0) , unusedCode(0)
, stackCommitted(0) , stack(0)
, gcMarker(0) , gcMarker(0)
, mathCache(0) , mathCache(0)
, scriptFilenames(0) , scriptFilenames(0)
@ -69,7 +69,7 @@ struct RuntimeSizes
size_t ionCode; size_t ionCode;
size_t regexpCode; size_t regexpCode;
size_t unusedCode; size_t unusedCode;
size_t stackCommitted; size_t stack;
size_t gcMarker; size_t gcMarker;
size_t mathCache; size_t mathCache;
size_t scriptFilenames; size_t scriptFilenames;

View File

@ -125,7 +125,7 @@ JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, RuntimeSizes *rtS
rtSizes->unusedCode = 0; rtSizes->unusedCode = 0;
} }
rtSizes->stackCommitted = stackSpace.sizeOfCommitted(); rtSizes->stack = stackSpace.sizeOf();
rtSizes->gcMarker = gcMarker.sizeOfExcludingThis(mallocSizeOf); rtSizes->gcMarker = gcMarker.sizeOfExcludingThis(mallocSizeOf);
@ -139,12 +139,15 @@ JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, RuntimeSizes *rtS
size_t size_t
JSRuntime::sizeOfExplicitNonHeap() JSRuntime::sizeOfExplicitNonHeap()
{ {
if (!execAlloc_) size_t size = stackSpace.sizeOf();
return 0;
if (execAlloc_) {
size_t jaegerCode, ionCode, regexpCode, unusedCode; size_t jaegerCode, ionCode, regexpCode, unusedCode;
execAlloc_->sizeOfCode(&jaegerCode, &ionCode, &regexpCode, &unusedCode); execAlloc_->sizeOfCode(&jaegerCode, &ionCode, &regexpCode, &unusedCode);
return jaegerCode + ionCode + regexpCode + unusedCode + stackSpace.sizeOfCommitted(); size += jaegerCode + ionCode + regexpCode + unusedCode;
}
return size;
} }
void void

View File

@ -810,11 +810,58 @@ StackSpace::tryBumpLimit(JSContext *cx, Value *from, unsigned nvals, Value **lim
} }
size_t size_t
StackSpace::sizeOfCommitted() StackSpace::sizeOf()
{ {
#ifdef XP_WIN #if defined(XP_UNIX)
/*
* Measure how many of our pages are resident in RAM using mincore, and
* return that as our size. This is slow, but hopefully nobody expects
* this method to be fast.
*
* Note that using mincore means that we don't count pages of the stack
* which are swapped out to disk. We really should, but what we have here
* is better than counting the whole stack!
*/
const int pageSize = getpagesize();
size_t numBytes = (trustedEnd_ - base_) * sizeof(Value);
size_t numPages = (numBytes + pageSize - 1) / pageSize;
// On Linux, mincore's third argument has type unsigned char*. On Mac, it
// has type char*.
#if defined(XP_MACOSX)
typedef char MincoreArgType;
#else
typedef unsigned char MincoreArgType;
#endif
MincoreArgType *vec = (MincoreArgType *) js_malloc(numPages);
int result = mincore(base_, numBytes, vec);
if (result) {
js_free(vec);
/*
* If mincore fails us, return the vsize (like we do below if we're not
* on Windows or Unix).
*/
return (trustedEnd_ - base_) * sizeof(Value);
}
size_t residentBytes = 0;
for (size_t i = 0; i < numPages; i++) {
/* vec[i] has its least-significant bit set iff page i is in RAM. */
if (vec[i] & 0x1)
residentBytes += pageSize;
}
js_free(vec);
return residentBytes;
#elif defined(XP_WIN)
return (commitEnd_ - base_) * sizeof(Value); return (commitEnd_ - base_) * sizeof(Value);
#else #else
/*
* Return the stack's virtual size, which is at least an upper bound on its
* resident size.
*/
return (trustedEnd_ - base_) * sizeof(Value); return (trustedEnd_ - base_) * sizeof(Value);
#endif #endif
} }

View File

@ -1439,8 +1439,12 @@ class StackSpace
/* Called during GC: sets active flag on compartments with active frames. */ /* Called during GC: sets active flag on compartments with active frames. */
void markActiveCompartments(); void markActiveCompartments();
/* We only report the committed size; uncommitted size is uninteresting. */ /*
JS_FRIEND_API(size_t) sizeOfCommitted(); * On Windows, report the committed size; on *nix, we report the resident
* size (which means that if part of the stack is swapped to disk, we say
* it's shrunk).
*/
JS_FRIEND_API(size_t) sizeOf();
#ifdef DEBUG #ifdef DEBUG
/* Only used in assertion of debuggers API. */ /* Only used in assertion of debuggers API. */

View File

@ -770,8 +770,7 @@ mozJSComponentLoader::GlobalForLocation(nsIFile *aComponentFile,
// Make sure the file map is closed, no matter how we return. // Make sure the file map is closed, no matter how we return.
FileMapAutoCloser mapCloser(map); FileMapAutoCloser mapCloser(map);
uint32_t fileSize32; uint32_t fileSize32 = fileSize;
LL_L2UI(fileSize32, fileSize);
char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32)); char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
if (!buf) { if (!buf) {

View File

@ -1743,11 +1743,15 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
"Memory allocated by one of the JITs to hold the " "Memory allocated by one of the JITs to hold the "
"runtime's code, but which is currently unused."); "runtime's code, but which is currently unused.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/stack-committed"), RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/stack"),
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.stackCommitted, nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.stack,
"Memory used for the JS call stack. This is the committed " "Memory used for the JS call stack. This is the committed "
"portion of the stack; the uncommitted portion is not " "portion of the stack on Windows; on *nix, it is the resident "
"measured because it hardly costs anything."); "portion of the stack. Therefore, on *nix, if part of the "
"stack is swapped out to disk, we do not count it here.\n\n"
"Note that debug builds usually have stack poisoning enabled, "
"which causes the whole stack to be committed (and likely "
"resident).");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc-marker"), RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc-marker"),
nsIMemoryReporter::KIND_HEAP, rtStats.runtime.gcMarker, nsIMemoryReporter::KIND_HEAP, rtStats.runtime.gcMarker,

View File

@ -57,8 +57,7 @@ members = [
# dom/interfaces/canvas # dom/interfaces/canvas
# #
# nsIDOMCanvasRenderingContext2D and friends # canvas friends
'nsIDOMCanvasRenderingContext2D.*',
'nsIDOMTextMetrics.*', 'nsIDOMTextMetrics.*',
'nsIDOMCanvasGradient.*', 'nsIDOMCanvasGradient.*',
'nsIDOMCanvasPattern.*', 'nsIDOMCanvasPattern.*',
@ -489,10 +488,6 @@ customIncludes = [
'mozilla/dom/ImageData.h' 'mozilla/dom/ImageData.h'
] ]
customQuickStubs = [
'CustomQS_Canvas2D.h'
]
customReturnInterfaces = [ customReturnInterfaces = [
'nsIDOMCanvasPattern', 'nsIDOMCanvasPattern',
'nsIDOMCanvasGradient', 'nsIDOMCanvasGradient',
@ -649,10 +644,6 @@ customMethodCalls = {
'nsIDOMStorage_Clear': { 'nsIDOMStorage_Clear': {
'code': nsIDOMStorage_Clear_customMethodCallCode 'code': nsIDOMStorage_Clear_customMethodCallCode
}, },
'nsIDOMCanvasRenderingContext2D_StrokeStyle': { 'skipgen': True },
'nsIDOMCanvasRenderingContext2D_StrokeStyle': { 'skipgen': True },
'nsIDOMCanvasRenderingContext2D_FillStyle': { 'skipgen': True },
'nsIDOMCanvasRenderingContext2D_FillStyle': { 'skipgen': True },
'nsIDOMCSS2Properties_': { 'nsIDOMCSS2Properties_': {
'thisType': 'nsICSSDeclaration', 'thisType': 'nsICSSDeclaration',
'additionalArguments': 'const nsCSSProperty prop', 'additionalArguments': 'const nsCSSProperty prop',
@ -971,13 +962,6 @@ customMethodCalls = {
'thisType' : 'nsIDOMWindow', 'thisType' : 'nsIDOMWindow',
'unwrapThisFailureFatal' : False 'unwrapThisFailureFatal' : False
}, },
# Canvas 2D
'nsIDOMCanvasRenderingContext2D_CreateImageData': CUSTOM_QS,
'nsIDOMCanvasRenderingContext2D_PutImageData': CUSTOM_QS,
# Nasty hack to make the ordering of |arc| and |arcTo| correct.
# |arc| is not traceable because it has an optional argument.
'nsIDOMCanvasRenderingContext2D_ArcTo' : { 'traceable' : False },
'nsIDOMImageData_GetWidth': { 'nsIDOMImageData_GetWidth': {
'thisType': 'nsIDOMImageData', 'thisType': 'nsIDOMImageData',
'code': 'uint32_t result = static_cast<mozilla::dom::ImageData*>(self)->GetWidth();', 'code': 'uint32_t result = static_cast<mozilla::dom::ImageData*>(self)->GetWidth();',
@ -992,4 +976,3 @@ customMethodCalls = {
'canFail': False 'canFail': False
} }
} }

View File

@ -433,7 +433,6 @@ nsresult NS_NewTreeBoxObject(nsIBoxObject** aResult);
#endif #endif
nsresult NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult); nsresult NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult);
nsresult NS_NewCanvasRenderingContext2DThebes(nsIDOMCanvasRenderingContext2D** aResult);
nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult); nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult);
nsresult NS_NewDomSelection(nsISelection** aResult); nsresult NS_NewDomSelection(nsISelection** aResult);
@ -555,7 +554,6 @@ MAKE_CTOR(CreateVideoDocument, nsIDocument, NS_NewVid
MAKE_CTOR(CreateFocusManager, nsIFocusManager, NS_NewFocusManager) MAKE_CTOR(CreateFocusManager, nsIFocusManager, NS_NewFocusManager)
MAKE_CTOR(CreateCanvasRenderingContext2D, nsIDOMCanvasRenderingContext2D, NS_NewCanvasRenderingContext2D) MAKE_CTOR(CreateCanvasRenderingContext2D, nsIDOMCanvasRenderingContext2D, NS_NewCanvasRenderingContext2D)
MAKE_CTOR(CreateCanvasRenderingContext2DThebes, nsIDOMCanvasRenderingContext2D, NS_NewCanvasRenderingContext2DThebes)
MAKE_CTOR(CreateCanvasRenderingContextWebGL, nsIDOMWebGLRenderingContext, NS_NewCanvasRenderingContextWebGL) MAKE_CTOR(CreateCanvasRenderingContextWebGL, nsIDOMWebGLRenderingContext, NS_NewCanvasRenderingContextWebGL)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStyleSheetService, Init) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStyleSheetService, Init)
@ -718,7 +716,6 @@ NS_DEFINE_NAMED_CID(NS_HTMLOPTIONELEMENT_CID);
NS_DEFINE_NAMED_CID(NS_HTMLAUDIOELEMENT_CID); NS_DEFINE_NAMED_CID(NS_HTMLAUDIOELEMENT_CID);
#endif #endif
NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2D_CID); NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2D_CID);
NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2DTHEBES_CID);
NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXTWEBGL_CID); NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXTWEBGL_CID);
NS_DEFINE_NAMED_CID(NS_TEXT_ENCODER_CID); NS_DEFINE_NAMED_CID(NS_TEXT_ENCODER_CID);
NS_DEFINE_NAMED_CID(NS_HTMLCOPY_TEXT_ENCODER_CID); NS_DEFINE_NAMED_CID(NS_HTMLCOPY_TEXT_ENCODER_CID);
@ -1000,7 +997,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
#ifdef MOZ_MEDIA #ifdef MOZ_MEDIA
{ &kNS_HTMLAUDIOELEMENT_CID, false, NULL, CreateHTMLAudioElement }, { &kNS_HTMLAUDIOELEMENT_CID, false, NULL, CreateHTMLAudioElement },
#endif #endif
{ &kNS_CANVASRENDERINGCONTEXT2DTHEBES_CID, false, NULL, CreateCanvasRenderingContext2DThebes },
{ &kNS_CANVASRENDERINGCONTEXT2D_CID, false, NULL, CreateCanvasRenderingContext2D }, { &kNS_CANVASRENDERINGCONTEXT2D_CID, false, NULL, CreateCanvasRenderingContext2D },
{ &kNS_CANVASRENDERINGCONTEXTWEBGL_CID, false, NULL, CreateCanvasRenderingContextWebGL }, { &kNS_CANVASRENDERINGCONTEXTWEBGL_CID, false, NULL, CreateCanvasRenderingContextWebGL },
{ &kNS_TEXT_ENCODER_CID, false, NULL, CreateTextEncoder }, { &kNS_TEXT_ENCODER_CID, false, NULL, CreateTextEncoder },
@ -1146,7 +1142,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
{ NS_HTMLAUDIOELEMENT_CONTRACTID, &kNS_HTMLAUDIOELEMENT_CID }, { NS_HTMLAUDIOELEMENT_CONTRACTID, &kNS_HTMLAUDIOELEMENT_CID },
#endif #endif
{ "@mozilla.org/content/canvas-rendering-context;1?id=2d", &kNS_CANVASRENDERINGCONTEXT2D_CID }, { "@mozilla.org/content/canvas-rendering-context;1?id=2d", &kNS_CANVASRENDERINGCONTEXT2D_CID },
{ "@mozilla.org/content/2dthebes-canvas-rendering-context;1", &kNS_CANVASRENDERINGCONTEXT2DTHEBES_CID },
{ "@mozilla.org/content/canvas-rendering-context;1?id=moz-webgl", &kNS_CANVASRENDERINGCONTEXTWEBGL_CID }, { "@mozilla.org/content/canvas-rendering-context;1?id=moz-webgl", &kNS_CANVASRENDERINGCONTEXTWEBGL_CID },
{ "@mozilla.org/content/canvas-rendering-context;1?id=experimental-webgl", &kNS_CANVASRENDERINGCONTEXTWEBGL_CID }, { "@mozilla.org/content/canvas-rendering-context;1?id=experimental-webgl", &kNS_CANVASRENDERINGCONTEXTWEBGL_CID },
{ NS_DOC_ENCODER_CONTRACTID_BASE "text/xml", &kNS_TEXT_ENCODER_CID }, { NS_DOC_ENCODER_CONTRACTID_BASE "text/xml", &kNS_TEXT_ENCODER_CID },

View File

@ -1236,7 +1236,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
int32_t numLines = mLines.size(); int32_t numLines = mLines.size();
if (!numLines) numLines = 1; if (!numLines) numLines = 1;
PRTime delta, perLineDelta, lines; PRTime delta, perLineDelta, lines;
LL_I2L(lines, numLines); lines = int64_t(numLines);
delta = end - start; delta = end - start;
perLineDelta = delta / lines; perLineDelta = delta / lines;
@ -6207,7 +6207,7 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
int32_t numLines = mLines.size(); int32_t numLines = mLines.size();
if (!numLines) numLines = 1; if (!numLines) numLines = 1;
PRTime lines, deltaPerLine, delta; PRTime lines, deltaPerLine, delta;
LL_I2L(lines, numLines); lines = int64_t(numLines);
delta = end - start; delta = end - start;
deltaPerLine = delta / lines; deltaPerLine = delta / lines;

View File

@ -1431,8 +1431,35 @@ nsBulletFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
return metrics.width; return metrics.width;
} }
NS_IMETHODIMP
nsBulletFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
{
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
nsCOMPtr<imgIContainer> image;
aRequest->GetImage(getter_AddRefs(image));
return OnStartContainer(aRequest, image);
}
NS_IMETHODIMP nsBulletFrame::OnStartContainer(imgIRequest *aRequest, if (aType == imgINotificationObserver::FRAME_UPDATE) {
// The image has changed.
// Invalidate the entire content area. Maybe it's not optimal but it's simple and
// always correct, and I'll be a stunned mullet if it ever matters for performance
InvalidateFrame();
}
if (aType == imgINotificationObserver::IS_ANIMATED) {
// Register the image request with the refresh driver now that we know it's
// animated.
if (aRequest == mImageRequest) {
nsLayoutUtils::RegisterImageRequest(PresContext(), mImageRequest,
&mRequestRegistered);
}
}
return NS_OK;
}
nsresult nsBulletFrame::OnStartContainer(imgIRequest *aRequest,
imgIContainer *aImage) imgIContainer *aImage)
{ {
if (!aImage) return NS_ERROR_INVALID_ARG; if (!aImage) return NS_ERROR_INVALID_ARG;
@ -1475,60 +1502,6 @@ NS_IMETHODIMP nsBulletFrame::OnStartContainer(imgIRequest *aRequest,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
bool aCurrentFrame,
const nsIntRect *aRect)
{
// The image has changed.
// Invalidate the entire content area. Maybe it's not optimal but it's simple and
// always correct, and I'll be a stunned mullet if it ever matters for performance
InvalidateFrame();
return NS_OK;
}
NS_IMETHODIMP nsBulletFrame::OnStopDecode(imgIRequest *aRequest,
nsresult aStatus,
const PRUnichar *aStatusArg)
{
// XXX should the bulletframe do anything if the image failed to load?
// it didn't in the old code...
#if 0
if (NS_FAILED(aStatus)) {
// We failed to load the image. Notify the pres shell
if (NS_FAILED(aStatus) && (mImageRequest == aRequest || !mImageRequest)) {
imageFailed = true;
}
}
#endif
return NS_OK;
}
NS_IMETHODIMP nsBulletFrame::OnImageIsAnimated(imgIRequest* aRequest)
{
// Register the image request with the refresh driver now that we know it's
// animated.
if (aRequest == mImageRequest) {
nsLayoutUtils::RegisterImageRequest(PresContext(), mImageRequest,
&mRequestRegistered);
}
return NS_OK;
}
NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
// Invalidate the entire content area. Maybe it's not optimal but it's simple and
// always correct.
InvalidateFrame();
return NS_OK;
}
void void
nsBulletFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup) nsBulletFrame::GetLoadGroup(nsPresContext *aPresContext, nsILoadGroup **aLoadGroup)
{ {
@ -1624,7 +1597,7 @@ nsBulletFrame::GetBaseline() const
NS_IMPL_ISUPPORTS2(nsBulletListener, imgIDecoderObserver, imgIContainerObserver) NS_IMPL_ISUPPORTS1(nsBulletListener, imgINotificationObserver)
nsBulletListener::nsBulletListener() : nsBulletListener::nsBulletListener() :
mFrame(nullptr) mFrame(nullptr)
@ -1635,49 +1608,10 @@ nsBulletListener::~nsBulletListener()
{ {
} }
NS_IMETHODIMP nsBulletListener::OnStartContainer(imgIRequest *aRequest, NS_IMETHODIMP
imgIContainer *aImage) nsBulletListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
{ {
if (!mFrame) if (!mFrame)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
return mFrame->Notify(aRequest, aType, aData);
return mFrame->OnStartContainer(aRequest, aImage);
}
NS_IMETHODIMP nsBulletListener::OnDataAvailable(imgIRequest *aRequest,
bool aCurrentFrame,
const nsIntRect *aRect)
{
if (!mFrame)
return NS_OK;
return mFrame->OnDataAvailable(aRequest, aCurrentFrame, aRect);
}
NS_IMETHODIMP nsBulletListener::OnStopDecode(imgIRequest *aRequest,
nsresult status,
const PRUnichar *statusArg)
{
if (!mFrame)
return NS_OK;
return mFrame->OnStopDecode(aRequest, status, statusArg);
}
NS_IMETHODIMP nsBulletListener::OnImageIsAnimated(imgIRequest *aRequest)
{
if (!mFrame)
return NS_OK;
return mFrame->OnImageIsAnimated(aRequest);
}
NS_IMETHODIMP nsBulletListener::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
if (!mFrame)
return NS_OK;
return mFrame->FrameChanged(aRequest, aContainer, aDirtyRect);
} }

View File

@ -14,32 +14,21 @@
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIDecoderObserver.h" #include "imgIDecoderObserver.h"
#include "nsStubImageDecoderObserver.h" #include "imgINotificationObserver.h"
#define BULLET_FRAME_IMAGE_LOADING NS_FRAME_STATE_BIT(63) #define BULLET_FRAME_IMAGE_LOADING NS_FRAME_STATE_BIT(63)
#define BULLET_FRAME_HAS_FONT_INFLATION NS_FRAME_STATE_BIT(62) #define BULLET_FRAME_HAS_FONT_INFLATION NS_FRAME_STATE_BIT(62)
class nsBulletFrame; class nsBulletFrame;
class nsBulletListener : public nsStubImageDecoderObserver class nsBulletListener : public imgINotificationObserver
{ {
public: public:
nsBulletListener(); nsBulletListener();
virtual ~nsBulletListener(); virtual ~nsBulletListener();
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
// imgIDecoderObserver (override nsStubImageDecoderObserver) NS_DECL_IMGINOTIFICATIONOBSERVER
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, bool aCurrentFrame,
const nsIntRect *aRect);
NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
const PRUnichar *statusArg);
NS_IMETHOD OnImageIsAnimated(imgIRequest *aRequest);
// imgIContainerObserver (override nsStubImageDecoderObserver)
NS_IMETHOD FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *dirtyRect);
void SetFrame(nsBulletFrame *frame) { mFrame = frame; } void SetFrame(nsBulletFrame *frame) { mFrame = frame; }
@ -61,6 +50,8 @@ public:
} }
virtual ~nsBulletFrame(); virtual ~nsBulletFrame();
NS_IMETHOD Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData);
// nsIFrame // nsIFrame
virtual void DestroyFrom(nsIFrame* aDestructRoot); virtual void DestroyFrom(nsIFrame* aDestructRoot);
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder, NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
@ -85,18 +76,6 @@ public:
int32_t aIncrement); int32_t aIncrement);
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
NS_IMETHOD OnDataAvailable(imgIRequest *aRequest,
bool aCurrentFrame,
const nsIntRect *aRect);
NS_IMETHOD OnStopDecode(imgIRequest *aRequest,
nsresult aStatus,
const PRUnichar *aStatusArg);
NS_IMETHOD OnImageIsAnimated(imgIRequest *aRequest);
NS_IMETHOD FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect);
/* get list item text, without '.' */ /* get list item text, without '.' */
static bool AppendCounterText(int32_t aListStyleType, static bool AppendCounterText(int32_t aListStyleType,
int32_t aOrdinal, int32_t aOrdinal,
@ -120,6 +99,8 @@ public:
void SetFontSizeInflation(float aInflation); void SetFontSizeInflation(float aInflation);
protected: protected:
nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
void GetDesiredSize(nsPresContext* aPresContext, void GetDesiredSize(nsPresContext* aPresContext,
nsRenderingContext *aRenderingContext, nsRenderingContext *aRenderingContext,
nsHTMLReflowMetrics& aMetrics, nsHTMLReflowMetrics& aMetrics,

View File

@ -140,7 +140,8 @@ nsImageFrame::nsImageFrame(nsStyleContext* aContext) :
ImageFrameSuper(aContext), ImageFrameSuper(aContext),
mComputedSize(0, 0), mComputedSize(0, 0),
mIntrinsicRatio(0, 0), mIntrinsicRatio(0, 0),
mDisplayingIcon(false) mDisplayingIcon(false),
mFirstFrameComplete(false)
{ {
// We assume our size is not constrained and we haven't gotten an // We assume our size is not constrained and we haven't gotten an
// initial reflow yet, so don't touch those flags. // initial reflow yet, so don't touch those flags.
@ -525,6 +526,34 @@ nsImageFrame::ShouldCreateImageFrameFor(Element* aElement,
return useSizedBox; return useSizedBox;
} }
nsresult
nsImageFrame::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
{
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
nsCOMPtr<imgIContainer> image;
aRequest->GetImage(getter_AddRefs(image));
return OnStartContainer(aRequest, image);
}
if (aType == imgINotificationObserver::FRAME_UPDATE) {
return OnDataAvailable(aRequest, aData);
}
if (aType == imgINotificationObserver::FRAME_COMPLETE) {
mFirstFrameComplete = true;
}
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
uint32_t imgStatus;
aRequest->GetImageStatus(&imgStatus);
nsresult status =
imgStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
return OnStopRequest(aRequest, status);
}
return NS_OK;
}
nsresult nsresult
nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage) nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage)
{ {
@ -564,9 +593,14 @@ nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage)
nsresult nsresult
nsImageFrame::OnDataAvailable(imgIRequest *aRequest, nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
bool aCurrentFrame,
const nsIntRect *aRect) const nsIntRect *aRect)
{ {
if (mFirstFrameComplete) {
nsCOMPtr<imgIContainer> container;
aRequest->GetImage(getter_AddRefs(container));
return FrameChanged(aRequest, container);
}
// XXX do we need to make sure that the reflow from the // XXX do we need to make sure that the reflow from the
// OnStartContainer has been processed before we start calling // OnStartContainer has been processed before we start calling
// invalidate? // invalidate?
@ -583,11 +617,6 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
return NS_OK; return NS_OK;
} }
// Don't invalidate if the current visible frame isn't the one the data is
// from
if (!aCurrentFrame)
return NS_OK;
#ifdef DEBUG_decode #ifdef DEBUG_decode
printf("Source rect (%d,%d,%d,%d)\n", printf("Source rect (%d,%d,%d,%d)\n",
aRect->x, aRect->y, aRect->width, aRect->height); aRect->x, aRect->y, aRect->width, aRect->height);
@ -606,9 +635,8 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
} }
nsresult nsresult
nsImageFrame::OnStopDecode(imgIRequest *aRequest, nsImageFrame::OnStopRequest(imgIRequest *aRequest,
nsresult aStatus, nsresult aStatus)
const PRUnichar *aStatusArg)
{ {
// Check what request type we're dealing with // Check what request type we're dealing with
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent); nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
@ -667,8 +695,7 @@ nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest,
nsresult nsresult
nsImageFrame::FrameChanged(imgIRequest *aRequest, nsImageFrame::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer, imgIContainer *aContainer)
const nsIntRect *aDirtyRect)
{ {
if (!GetStyleVisibility()->IsVisible()) { if (!GetStyleVisibility()->IsVisible()) {
return NS_OK; return NS_OK;
@ -1894,7 +1921,7 @@ nsresult nsImageFrame::LoadIcons(nsPresContext *aPresContext)
} }
NS_IMPL_ISUPPORTS2(nsImageFrame::IconLoad, nsIObserver, NS_IMPL_ISUPPORTS2(nsImageFrame::IconLoad, nsIObserver,
imgIDecoderObserver) imgINotificationObserver)
static const char* kIconLoadPrefs[] = { static const char* kIconLoadPrefs[] = {
"browser.display.force_inline_alttext", "browser.display.force_inline_alttext",
@ -1951,74 +1978,14 @@ void nsImageFrame::IconLoad::GetPrefs()
Preferences::GetBool("browser.display.show_image_placeholders", true); Preferences::GetBool("browser.display.show_image_placeholders", true);
} }
NS_IMETHODIMP NS_IMETHODIMP
nsImageFrame::IconLoad::OnStartRequest(imgIRequest *aRequest) nsImageFrame::IconLoad::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
{ {
if (aType != imgINotificationObserver::LOAD_COMPLETE &&
aType != imgINotificationObserver::FRAME_UPDATE) {
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStartDecode(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStartContainer(imgIRequest *aRequest,
imgIContainer *aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStartFrame(imgIRequest *aRequest,
uint32_t aFrame)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnDataAvailable(imgIRequest *aRequest,
bool aCurrentFrame,
const nsIntRect * aRect)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStopFrame(imgIRequest *aRequest,
uint32_t aFrame)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStopContainer(imgIRequest *aRequest,
imgIContainer *aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStopDecode(imgIRequest *aRequest,
nsresult status,
const PRUnichar *statusArg)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnImageIsAnimated(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::OnStopRequest(imgIRequest *aRequest,
bool aIsLastPart)
{
nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers); nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
nsImageFrame *frame; nsImageFrame *frame;
while (iter.HasMore()) { while (iter.HasMore()) {
@ -2029,30 +1996,7 @@ nsImageFrame::IconLoad::OnStopRequest(imgIRequest *aRequest,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMPL_ISUPPORTS1(nsImageListener, imgINotificationObserver)
nsImageFrame::IconLoad::OnDiscard(imgIRequest *aRequest)
{
return NS_OK;
}
NS_IMETHODIMP
nsImageFrame::IconLoad::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
nsImageFrame *frame;
while (iter.HasMore()) {
frame = iter.GetNext();
frame->InvalidateFrame();
}
return NS_OK;
}
NS_IMPL_ISUPPORTS2(nsImageListener, imgIDecoderObserver, imgIContainerObserver)
nsImageListener::nsImageListener(nsImageFrame *aFrame) : nsImageListener::nsImageListener(nsImageFrame *aFrame) :
mFrame(aFrame) mFrame(aFrame)
@ -2063,43 +2007,13 @@ nsImageListener::~nsImageListener()
{ {
} }
NS_IMETHODIMP nsImageListener::OnStartContainer(imgIRequest *aRequest, NS_IMETHODIMP
imgIContainer *aImage) nsImageListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
{ {
if (!mFrame) if (!mFrame)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
return mFrame->OnStartContainer(aRequest, aImage); return mFrame->Notify(aRequest, aType, aData);
}
NS_IMETHODIMP nsImageListener::OnDataAvailable(imgIRequest *aRequest,
bool aCurrentFrame,
const nsIntRect *aRect)
{
if (!mFrame)
return NS_ERROR_FAILURE;
return mFrame->OnDataAvailable(aRequest, aCurrentFrame, aRect);
}
NS_IMETHODIMP nsImageListener::OnStopDecode(imgIRequest *aRequest,
nsresult status,
const PRUnichar *statusArg)
{
if (!mFrame)
return NS_ERROR_FAILURE;
return mFrame->OnStopDecode(aRequest, status, statusArg);
}
NS_IMETHODIMP nsImageListener::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
if (!mFrame)
return NS_ERROR_FAILURE;
return mFrame->FrameChanged(aRequest, aContainer, aDirtyRect);
} }
static bool static bool

View File

@ -12,8 +12,7 @@
#include "nsIIOService.h" #include "nsIIOService.h"
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsStubImageDecoderObserver.h" #include "imgINotificationObserver.h"
#include "imgIDecoderObserver.h"
#include "nsDisplayList.h" #include "nsDisplayList.h"
#include "imgIContainer.h" #include "imgIContainer.h"
@ -40,23 +39,14 @@ namespace layers {
} }
} }
class nsImageListener : public nsStubImageDecoderObserver class nsImageListener : public imgINotificationObserver
{ {
public: public:
nsImageListener(nsImageFrame *aFrame); nsImageListener(nsImageFrame *aFrame);
virtual ~nsImageListener(); virtual ~nsImageListener();
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
// imgIDecoderObserver (override nsStubImageDecoderObserver) NS_DECL_IMGINOTIFICATIONOBSERVER
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, bool aCurrentFrame,
const nsIntRect *aRect);
NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
const PRUnichar *statusArg);
// imgIContainerObserver (override nsStubImageDecoderObserver)
NS_IMETHOD FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *dirtyRect);
void SetFrame(nsImageFrame *frame) { mFrame = frame; } void SetFrame(nsImageFrame *frame) { mFrame = frame; }
@ -137,6 +127,8 @@ public:
NS_IF_RELEASE(sIOService); NS_IF_RELEASE(sIOService);
} }
nsresult Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData);
/** /**
* Function to test whether aContent, which has aStyleContext as its style, * Function to test whether aContent, which has aStyleContext as its style,
* should get an image frame. Note that this method is only used by the * should get an image frame. Note that this method is only used by the
@ -221,14 +213,11 @@ protected:
friend class nsImageListener; friend class nsImageListener;
friend class nsImageLoadingContent; friend class nsImageLoadingContent;
nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage); nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
nsresult OnDataAvailable(imgIRequest *aRequest, bool aCurrentFrame, nsresult OnDataAvailable(imgIRequest *aRequest, const nsIntRect *rect);
const nsIntRect *rect); nsresult OnStopRequest(imgIRequest *aRequest,
nsresult OnStopDecode(imgIRequest *aRequest, nsresult aStatus);
nsresult aStatus,
const PRUnichar *aStatusArg);
nsresult FrameChanged(imgIRequest *aRequest, nsresult FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer, imgIContainer *aContainer);
const nsIntRect *aDirtyRect);
/** /**
* Notification that aRequest will now be the current request. * Notification that aRequest will now be the current request.
*/ */
@ -288,13 +277,14 @@ private:
nsImageMap* mImageMap; nsImageMap* mImageMap;
nsCOMPtr<imgIDecoderObserver> mListener; nsCOMPtr<imgINotificationObserver> mListener;
nsSize mComputedSize; nsSize mComputedSize;
nsIFrame::IntrinsicSize mIntrinsicSize; nsIFrame::IntrinsicSize mIntrinsicSize;
nsSize mIntrinsicRatio; nsSize mIntrinsicRatio;
bool mDisplayingIcon; bool mDisplayingIcon;
bool mFirstFrameComplete;
static nsIIOService* sIOService; static nsIIOService* sIOService;
@ -311,7 +301,7 @@ private:
imgIRequest **aRequest); imgIRequest **aRequest);
class IconLoad MOZ_FINAL : public nsIObserver, class IconLoad MOZ_FINAL : public nsIObserver,
public imgIDecoderObserver { public imgINotificationObserver {
// private class that wraps the data and logic needed for // private class that wraps the data and logic needed for
// broken image and loading image icons // broken image and loading image icons
public: public:
@ -321,8 +311,7 @@ private:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
NS_DECL_IMGICONTAINEROBSERVER NS_DECL_IMGINOTIFICATIONOBSERVER
NS_DECL_IMGIDECODEROBSERVER
void AddIconObserver(nsImageFrame *frame) { void AddIconObserver(nsImageFrame *frame) {
NS_ABORT_IF_FALSE(!mIconObservers.Contains(frame), NS_ABORT_IF_FALSE(!mIconObservers.Contains(frame),

View File

@ -56,8 +56,8 @@ ImageLoader::AssociateRequestToFrame(imgIRequest* aRequest,
mFrameToRequestMap.IsInitialized() && mFrameToRequestMap.IsInitialized() &&
mImages.IsInitialized()); mImages.IsInitialized());
nsCOMPtr<imgIDecoderObserver> observer; nsCOMPtr<imgINotificationObserver> observer;
aRequest->GetDecoderObserver(getter_AddRefs(observer)); aRequest->GetNotificationObserver(getter_AddRefs(observer));
if (!observer) { if (!observer) {
// The request has already been canceled, so ignore it. This is ok because // The request has already been canceled, so ignore it. This is ok because
// we're not going to get any more notifications from a canceled request. // we're not going to get any more notifications from a canceled request.
@ -157,8 +157,8 @@ ImageLoader::DisassociateRequestFromFrame(imgIRequest* aRequest,
#ifdef DEBUG #ifdef DEBUG
{ {
nsCOMPtr<imgIDecoderObserver> observer; nsCOMPtr<imgINotificationObserver> observer;
aRequest->GetDecoderObserver(getter_AddRefs(observer)); aRequest->GetNotificationObserver(getter_AddRefs(observer));
MOZ_ASSERT(!observer || observer == this); MOZ_ASSERT(!observer || observer == this);
} }
#endif #endif
@ -334,12 +334,35 @@ NS_IMPL_ADDREF(ImageLoader)
NS_IMPL_RELEASE(ImageLoader) NS_IMPL_RELEASE(ImageLoader)
NS_INTERFACE_MAP_BEGIN(ImageLoader) NS_INTERFACE_MAP_BEGIN(ImageLoader)
NS_INTERFACE_MAP_ENTRY(imgIDecoderObserver) NS_INTERFACE_MAP_ENTRY(imgINotificationObserver)
NS_INTERFACE_MAP_ENTRY(imgIContainerObserver)
NS_INTERFACE_MAP_ENTRY(imgIOnloadBlocker) NS_INTERFACE_MAP_ENTRY(imgIOnloadBlocker)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
NS_IMETHODIMP NS_IMETHODIMP
ImageLoader::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
{
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
nsCOMPtr<imgIContainer> image;
aRequest->GetImage(getter_AddRefs(image));
return OnStartContainer(aRequest, image);
}
if (aType == imgINotificationObserver::IS_ANIMATED) {
return OnImageIsAnimated(aRequest);
}
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
return OnStopFrame(aRequest);
}
if (aType == imgINotificationObserver::FRAME_UPDATE) {
return FrameChanged(aRequest);
}
return NS_OK;
}
nsresult
ImageLoader::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage) ImageLoader::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
{ {
nsPresContext* presContext = GetPresContext(); nsPresContext* presContext = GetPresContext();
@ -352,7 +375,7 @@ ImageLoader::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsresult
ImageLoader::OnImageIsAnimated(imgIRequest* aRequest) ImageLoader::OnImageIsAnimated(imgIRequest* aRequest)
{ {
if (!mDocument) { if (!mDocument) {
@ -376,8 +399,8 @@ ImageLoader::OnImageIsAnimated(imgIRequest* aRequest)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsresult
ImageLoader::OnStopFrame(imgIRequest *aRequest, uint32_t aFrame) ImageLoader::OnStopFrame(imgIRequest *aRequest)
{ {
if (!mDocument || mInClone) { if (!mDocument || mInClone) {
return NS_OK; return NS_OK;
@ -395,10 +418,8 @@ ImageLoader::OnStopFrame(imgIRequest *aRequest, uint32_t aFrame)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsresult
ImageLoader::FrameChanged(imgIRequest *aRequest, ImageLoader::FrameChanged(imgIRequest *aRequest)
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{ {
if (!mDocument || mInClone) { if (!mDocument || mInClone) {
return NS_OK; return NS_OK;

View File

@ -12,7 +12,7 @@
#include "nsCSSValue.h" #include "nsCSSValue.h"
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIOnloadBlocker.h" #include "imgIOnloadBlocker.h"
#include "nsStubImageDecoderObserver.h" #include "imgINotificationObserver.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
class nsIFrame; class nsIFrame;
@ -24,7 +24,7 @@ class nsIPrincipal;
namespace mozilla { namespace mozilla {
namespace css { namespace css {
class ImageLoader MOZ_FINAL : public nsStubImageDecoderObserver, class ImageLoader MOZ_FINAL : public imgINotificationObserver,
public imgIOnloadBlocker { public imgIOnloadBlocker {
public: public:
typedef mozilla::css::ImageValue Image; typedef mozilla::css::ImageValue Image;
@ -42,19 +42,7 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_IMGIONLOADBLOCKER NS_DECL_IMGIONLOADBLOCKER
NS_DECL_IMGINOTIFICATIONOBSERVER
// imgIDecoderObserver (override nsStubImageDecoderObserver)
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
NS_IMETHOD OnStopFrame(imgIRequest *aRequest, uint32_t aFrame);
NS_IMETHOD OnImageIsAnimated(imgIRequest *aRequest);
// Do not override OnDataAvailable since background images are not
// displayed incrementally; they are displayed after the entire image
// has been loaded.
// imgIContainerObserver (override nsStubImageDecoderObserver)
NS_IMETHOD FrameChanged(imgIRequest* aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect);
void DropDocumentReference(); void DropDocumentReference();
@ -103,6 +91,14 @@ private:
SetAnimationModeEnumerator(nsISupports* aKey, FrameSet* aValue, SetAnimationModeEnumerator(nsISupports* aKey, FrameSet* aValue,
void* aClosure); void* aClosure);
nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer* aImage);
nsresult OnStopFrame(imgIRequest *aRequest);
nsresult OnImageIsAnimated(imgIRequest *aRequest);
nsresult FrameChanged(imgIRequest* aRequest);
// Do not override OnDataAvailable since background images are not
// displayed incrementally; they are displayed after the entire image
// has been loaded.
// A map of imgIRequests to the nsIFrames that are using them. // A map of imgIRequests to the nsIFrames that are using them.
RequestToFrameMap mRequestToFrameMap; RequestToFrameMap mRequestToFrameMap;

View File

@ -11,7 +11,7 @@
#include "nsIDOMSVGImageElement.h" #include "nsIDOMSVGImageElement.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsRenderingContext.h" #include "nsRenderingContext.h"
#include "nsStubImageDecoderObserver.h" #include "imgINotificationObserver.h"
#include "nsSVGEffects.h" #include "nsSVGEffects.h"
#include "nsSVGImageElement.h" #include "nsSVGImageElement.h"
#include "nsSVGPathGeometryFrame.h" #include "nsSVGPathGeometryFrame.h"
@ -23,22 +23,13 @@ using namespace mozilla;
class nsSVGImageFrame; class nsSVGImageFrame;
class nsSVGImageListener MOZ_FINAL : public nsStubImageDecoderObserver class nsSVGImageListener MOZ_FINAL : public imgINotificationObserver
{ {
public: public:
nsSVGImageListener(nsSVGImageFrame *aFrame); nsSVGImageListener(nsSVGImageFrame *aFrame);
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
// imgIDecoderObserver (override nsStubImageDecoderObserver) NS_DECL_IMGINOTIFICATIONOBSERVER
NS_IMETHOD OnStopDecode(imgIRequest *aRequest, nsresult status,
const PRUnichar *statusArg);
// imgIContainerObserver (override nsStubImageDecoderObserver)
NS_IMETHOD FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect);
// imgIContainerObserver (override nsStubImageDecoderObserver)
NS_IMETHOD OnStartContainer(imgIRequest *aRequest,
imgIContainer *aContainer);
void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; } void SetFrame(nsSVGImageFrame *frame) { mFrame = frame; }
@ -98,7 +89,7 @@ private:
gfxMatrix GetVectorImageTransform(uint32_t aFor); gfxMatrix GetVectorImageTransform(uint32_t aFor);
bool TransformContextForPainting(gfxContext* aGfxContext); bool TransformContextForPainting(gfxContext* aGfxContext);
nsCOMPtr<imgIDecoderObserver> mListener; nsCOMPtr<imgINotificationObserver> mListener;
nsCOMPtr<imgIContainer> mImageContainer; nsCOMPtr<imgIContainer> mImageContainer;
@ -560,49 +551,34 @@ nsSVGImageFrame::GetHitTestFlags()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// nsSVGImageListener implementation // nsSVGImageListener implementation
NS_IMPL_ISUPPORTS2(nsSVGImageListener, NS_IMPL_ISUPPORTS1(nsSVGImageListener, imgINotificationObserver)
imgIDecoderObserver,
imgIContainerObserver)
nsSVGImageListener::nsSVGImageListener(nsSVGImageFrame *aFrame) : mFrame(aFrame) nsSVGImageListener::nsSVGImageListener(nsSVGImageFrame *aFrame) : mFrame(aFrame)
{ {
} }
NS_IMETHODIMP nsSVGImageListener::OnStopDecode(imgIRequest *aRequest, NS_IMETHODIMP
nsresult status, nsSVGImageListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
const PRUnichar *statusArg)
{ {
if (!mFrame) if (!mFrame)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
nsSVGUtils::InvalidateAndScheduleReflowSVG(mFrame); nsSVGUtils::InvalidateAndScheduleReflowSVG(mFrame);
return NS_OK; }
}
NS_IMETHODIMP nsSVGImageListener::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
if (!mFrame)
return NS_ERROR_FAILURE;
if (aType == imgINotificationObserver::FRAME_UPDATE) {
// No new dimensions, so we don't need to call // No new dimensions, so we don't need to call
// nsSVGUtils::InvalidateAndScheduleBoundsUpdate. // nsSVGUtils::InvalidateAndScheduleBoundsUpdate.
nsSVGEffects::InvalidateRenderingObservers(mFrame); nsSVGEffects::InvalidateRenderingObservers(mFrame);
nsSVGUtils::InvalidateBounds(mFrame); nsSVGUtils::InvalidateBounds(mFrame);
return NS_OK; }
}
NS_IMETHODIMP nsSVGImageListener::OnStartContainer(imgIRequest *aRequest, if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
imgIContainer *aContainer)
{
// Called once the resource's dimensions have been obtained. // Called once the resource's dimensions have been obtained.
aRequest->GetImage(getter_AddRefs(mFrame->mImageContainer));
if (!mFrame)
return NS_ERROR_FAILURE;
mFrame->mImageContainer = aContainer;
nsSVGUtils::InvalidateAndScheduleReflowSVG(mFrame); nsSVGUtils::InvalidateAndScheduleReflowSVG(mFrame);
}
return NS_OK; return NS_OK;
} }

View File

@ -63,6 +63,7 @@ _HARNESS_FILES = \
$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \ $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \
$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \ $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \
$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py \ $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py \
$(topsrcdir)/testing/mozbase/mozdevice/mozdevice/Zeroconf.py \
$(topsrcdir)/build/mobile/b2gautomation.py \ $(topsrcdir)/build/mobile/b2gautomation.py \
$(topsrcdir)/build/automationutils.py \ $(topsrcdir)/build/automationutils.py \
$(topsrcdir)/build/mobile/remoteautomation.py \ $(topsrcdir)/build/mobile/remoteautomation.py \

View File

@ -188,7 +188,7 @@ nsImageBoxFrame::Init(nsIContent* aContent,
nsImageBoxListener *listener = new nsImageBoxListener(); nsImageBoxListener *listener = new nsImageBoxListener();
NS_ADDREF(listener); NS_ADDREF(listener);
listener->SetFrame(this); listener->SetFrame(this);
listener->QueryInterface(NS_GET_IID(imgIDecoderObserver), getter_AddRefs(mListener)); listener->QueryInterface(NS_GET_IID(imgINotificationObserver), getter_AddRefs(mListener));
NS_RELEASE(listener); NS_RELEASE(listener);
} }
@ -577,8 +577,39 @@ nsImageBoxFrame::GetFrameName(nsAString& aResult) const
} }
#endif #endif
nsresult
nsImageBoxFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
{
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
nsCOMPtr<imgIContainer> image;
aRequest->GetImage(getter_AddRefs(image));
return OnStartContainer(aRequest, image);
}
NS_IMETHODIMP nsImageBoxFrame::OnStartContainer(imgIRequest *request, if (aType == imgINotificationObserver::DECODE_COMPLETE) {
return OnStopDecode(aRequest);
}
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
uint32_t imgStatus;
aRequest->GetImageStatus(&imgStatus);
nsresult status =
imgStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
return OnStopRequest(aRequest, status);
}
if (aType == imgINotificationObserver::IS_ANIMATED) {
return OnImageIsAnimated(aRequest);
}
if (aType == imgINotificationObserver::FRAME_UPDATE) {
return FrameChanged(aRequest);
}
return NS_OK;
}
nsresult nsImageBoxFrame::OnStartContainer(imgIRequest *request,
imgIContainer *image) imgIContainer *image)
{ {
NS_ENSURE_ARG_POINTER(image); NS_ENSURE_ARG_POINTER(image);
@ -603,8 +634,7 @@ NS_IMETHODIMP nsImageBoxFrame::OnStartContainer(imgIRequest *request,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsImageBoxFrame::OnStopContainer(imgIRequest *request, nsresult nsImageBoxFrame::OnStopDecode(imgIRequest *request)
imgIContainer *image)
{ {
nsBoxLayoutState state(PresContext()); nsBoxLayoutState state(PresContext());
this->Redraw(state); this->Redraw(state);
@ -612,9 +642,8 @@ NS_IMETHODIMP nsImageBoxFrame::OnStopContainer(imgIRequest *request,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsImageBoxFrame::OnStopDecode(imgIRequest *request, nsresult nsImageBoxFrame::OnStopRequest(imgIRequest *request,
nsresult aStatus, nsresult aStatus)
const PRUnichar *statusArg)
{ {
if (NS_SUCCEEDED(aStatus)) if (NS_SUCCEEDED(aStatus))
// Fire an onload DOM event. // Fire an onload DOM event.
@ -630,7 +659,7 @@ NS_IMETHODIMP nsImageBoxFrame::OnStopDecode(imgIRequest *request,
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsImageBoxFrame::OnImageIsAnimated(imgIRequest *aRequest) nsresult nsImageBoxFrame::OnImageIsAnimated(imgIRequest *aRequest)
{ {
// Register with our refresh driver, if we're animated. // Register with our refresh driver, if we're animated.
nsLayoutUtils::RegisterImageRequest(PresContext(), aRequest, nsLayoutUtils::RegisterImageRequest(PresContext(), aRequest,
@ -639,9 +668,7 @@ NS_IMETHODIMP nsImageBoxFrame::OnImageIsAnimated(imgIRequest *aRequest)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIRequest *aRequest, nsresult nsImageBoxFrame::FrameChanged(imgIRequest *aRequest)
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{ {
if ((0 == mRect.width) || (0 == mRect.height)) { if ((0 == mRect.width) || (0 == mRect.height)) {
return NS_OK; return NS_OK;
@ -652,7 +679,7 @@ NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIRequest *aRequest,
return NS_OK; return NS_OK;
} }
NS_IMPL_ISUPPORTS2(nsImageBoxListener, imgIDecoderObserver, imgIContainerObserver) NS_IMPL_ISUPPORTS1(nsImageBoxListener, imgINotificationObserver)
nsImageBoxListener::nsImageBoxListener() nsImageBoxListener::nsImageBoxListener()
{ {
@ -662,49 +689,11 @@ nsImageBoxListener::~nsImageBoxListener()
{ {
} }
NS_IMETHODIMP nsImageBoxListener::OnStartContainer(imgIRequest *request, NS_IMETHODIMP
imgIContainer *image) nsImageBoxListener::Notify(imgIRequest *request, int32_t aType, const nsIntRect* aData)
{ {
if (!mFrame) if (!mFrame)
return NS_OK; return NS_OK;
return mFrame->OnStartContainer(request, image); return mFrame->Notify(request, aType, aData);
} }
NS_IMETHODIMP nsImageBoxListener::OnStopContainer(imgIRequest *request,
imgIContainer *image)
{
if (!mFrame)
return NS_OK;
return mFrame->OnStopContainer(request, image);
}
NS_IMETHODIMP nsImageBoxListener::OnStopDecode(imgIRequest *request,
nsresult status,
const PRUnichar *statusArg)
{
if (!mFrame)
return NS_OK;
return mFrame->OnStopDecode(request, status, statusArg);
}
NS_IMETHODIMP nsImageBoxListener::OnImageIsAnimated(imgIRequest* aRequest)
{
if (!mFrame)
return NS_OK;
return mFrame->OnImageIsAnimated(aRequest);
}
NS_IMETHODIMP nsImageBoxListener::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
if (!mFrame)
return NS_ERROR_FAILURE;
return mFrame->FrameChanged(aRequest, aContainer, aDirtyRect);
}

View File

@ -11,30 +11,20 @@
#include "imgILoader.h" #include "imgILoader.h"
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIContainer.h" #include "imgIContainer.h"
#include "nsStubImageDecoderObserver.h" #include "imgINotificationObserver.h"
class nsImageBoxFrame; class nsImageBoxFrame;
class nsDisplayXULImage; class nsDisplayXULImage;
class nsImageBoxListener : public nsStubImageDecoderObserver class nsImageBoxListener : public imgINotificationObserver
{ {
public: public:
nsImageBoxListener(); nsImageBoxListener();
virtual ~nsImageBoxListener(); virtual ~nsImageBoxListener();
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
// imgIDecoderObserver (override nsStubImageDecoderObserver) NS_DECL_IMGINOTIFICATIONOBSERVER
NS_IMETHOD OnStartContainer(imgIRequest *request, imgIContainer *image);
NS_IMETHOD OnStopContainer(imgIRequest *request, imgIContainer *image);
NS_IMETHOD OnStopDecode(imgIRequest *request, nsresult status,
const PRUnichar *statusArg);
NS_IMETHOD OnImageIsAnimated(imgIRequest* aRequest);
// imgIContainerObserver (override nsStubImageDecoderObserver)
NS_IMETHOD FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect);
void SetFrame(nsImageBoxFrame *frame) { mFrame = frame; } void SetFrame(nsImageBoxFrame *frame) { mFrame = frame; }
@ -53,6 +43,8 @@ public:
virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE; virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE; virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE;
nsresult Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData);
friend nsIFrame* NS_NewImageBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); friend nsIFrame* NS_NewImageBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
NS_IMETHOD Init(nsIContent* aContent, NS_IMETHOD Init(nsIContent* aContent,
@ -89,17 +81,6 @@ public:
const nsRect& aDirtyRect, const nsRect& aDirtyRect,
const nsDisplayListSet& aLists) MOZ_OVERRIDE; const nsDisplayListSet& aLists) MOZ_OVERRIDE;
NS_IMETHOD OnStartContainer(imgIRequest *request, imgIContainer *image);
NS_IMETHOD OnStopContainer(imgIRequest *request, imgIContainer *image);
NS_IMETHOD OnStopDecode(imgIRequest *request,
nsresult status,
const PRUnichar *statusArg);
NS_IMETHOD OnImageIsAnimated(imgIRequest* aRequest);
NS_IMETHOD FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect);
virtual ~nsImageBoxFrame(); virtual ~nsImageBoxFrame();
void PaintImage(nsRenderingContext& aRenderingContext, void PaintImage(nsRenderingContext& aRenderingContext,
@ -113,6 +94,11 @@ protected:
virtual void GetImageSize(); virtual void GetImageSize();
private: private:
nsresult OnStartContainer(imgIRequest *request, imgIContainer *image);
nsresult OnStopDecode(imgIRequest *request);
nsresult OnStopRequest(imgIRequest *request, nsresult status);
nsresult OnImageIsAnimated(imgIRequest* aRequest);
nsresult FrameChanged(imgIRequest *aRequest);
nsRect mSubRect; ///< If set, indicates that only the portion of the image specified by the rect should be used. nsRect mSubRect; ///< If set, indicates that only the portion of the image specified by the rect should be used.
nsSize mIntrinsicSize; nsSize mIntrinsicSize;
@ -123,7 +109,7 @@ private:
bool mRequestRegistered; bool mRequestRegistered;
nsCOMPtr<imgIRequest> mImageRequest; nsCOMPtr<imgIRequest> mImageRequest;
nsCOMPtr<imgIDecoderObserver> mListener; nsCOMPtr<imgINotificationObserver> mListener;
int32_t mLoadFlags; int32_t mLoadFlags;

View File

@ -907,11 +907,7 @@ nsListBoxBodyFrame::DoInternalPositionChanged(bool aUp, int32_t aDelta)
PRTime end = PR_Now(); PRTime end = PR_Now();
PRTime difTime = end - start; int32_t newTime = int32_t(end - start) / aDelta;
int32_t newTime;
LL_L2I(newTime, difTime);
newTime /= aDelta;
// average old and new // average old and new
mTimePerRow = (newTime + mTimePerRow)/2; mTimePerRow = (newTime + mTimePerRow)/2;

View File

@ -2117,8 +2117,8 @@ nsTreeBodyFrame::GetImage(int32_t aRowIndex, nsTreeColumn* aCol, bool aUseContex
if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || animated) { if ((!(status & imgIRequest::STATUS_LOAD_COMPLETE)) || animated) {
// We either aren't done loading, or we're animating. Add our row as a listener for invalidations. // We either aren't done loading, or we're animating. Add our row as a listener for invalidations.
nsCOMPtr<imgIDecoderObserver> obs; nsCOMPtr<imgINotificationObserver> obs;
imgReq->GetDecoderObserver(getter_AddRefs(obs)); imgReq->GetNotificationObserver(getter_AddRefs(obs));
if (obs) { if (obs) {
static_cast<nsTreeImageListener*> (obs.get())->AddCell(aRowIndex, aCol); static_cast<nsTreeImageListener*> (obs.get())->AddCell(aRowIndex, aCol);
@ -2140,11 +2140,11 @@ nsTreeBodyFrame::GetImage(int32_t aRowIndex, nsTreeColumn* aCol, bool aUseContex
} }
listener->AddCell(aRowIndex, aCol); listener->AddCell(aRowIndex, aCol);
nsCOMPtr<imgIDecoderObserver> imgDecoderObserver = listener; nsCOMPtr<imgINotificationObserver> imgNotificationObserver = listener;
nsCOMPtr<imgIRequest> imageRequest; nsCOMPtr<imgIRequest> imageRequest;
if (styleRequest) { if (styleRequest) {
styleRequest->Clone(imgDecoderObserver, getter_AddRefs(imageRequest)); styleRequest->Clone(imgNotificationObserver, getter_AddRefs(imageRequest));
} else { } else {
nsIDocument* doc = mContent->GetDocument(); nsIDocument* doc = mContent->GetDocument();
if (!doc) if (!doc)
@ -2169,7 +2169,7 @@ nsTreeBodyFrame::GetImage(int32_t aRowIndex, nsTreeColumn* aCol, bool aUseContex
doc, doc,
mContent->NodePrincipal(), mContent->NodePrincipal(),
doc->GetDocumentURI(), doc->GetDocumentURI(),
imgDecoderObserver, imgNotificationObserver,
nsIRequest::LOAD_NORMAL, nsIRequest::LOAD_NORMAL,
getter_AddRefs(imageRequest)); getter_AddRefs(imageRequest));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -2187,7 +2187,7 @@ nsTreeBodyFrame::GetImage(int32_t aRowIndex, nsTreeColumn* aCol, bool aUseContex
// In a case it was already cached. // In a case it was already cached.
imageRequest->GetImage(aResult); imageRequest->GetImage(aResult);
nsTreeImageCacheEntry cacheEntry(imageRequest, imgDecoderObserver); nsTreeImageCacheEntry cacheEntry(imageRequest, imgNotificationObserver);
mImageCache.Put(imageSrc, cacheEntry); mImageCache.Put(imageSrc, cacheEntry);
} }
return NS_OK; return NS_OK;

View File

@ -20,7 +20,7 @@
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIDecoderObserver.h" #include "imgINotificationObserver.h"
#include "nsScrollbarFrame.h" #include "nsScrollbarFrame.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "mozilla/LookAndFeel.h" #include "mozilla/LookAndFeel.h"
@ -32,11 +32,11 @@ class nsTreeImageListener;
struct nsTreeImageCacheEntry struct nsTreeImageCacheEntry
{ {
nsTreeImageCacheEntry() {} nsTreeImageCacheEntry() {}
nsTreeImageCacheEntry(imgIRequest *aRequest, imgIDecoderObserver *aListener) nsTreeImageCacheEntry(imgIRequest *aRequest, imgINotificationObserver *aListener)
: request(aRequest), listener(aListener) {} : request(aRequest), listener(aListener) {}
nsCOMPtr<imgIRequest> request; nsCOMPtr<imgIRequest> request;
nsCOMPtr<imgIDecoderObserver> listener; nsCOMPtr<imgINotificationObserver> listener;
}; };
// The actual frame that paints the cells and rows. // The actual frame that paints the cells and rows.

View File

@ -8,7 +8,7 @@
#include "imgIRequest.h" #include "imgIRequest.h"
#include "imgIContainer.h" #include "imgIContainer.h"
NS_IMPL_ISUPPORTS2(nsTreeImageListener, imgIDecoderObserver, imgIContainerObserver) NS_IMPL_ISUPPORTS1(nsTreeImageListener, imgINotificationObserver)
nsTreeImageListener::nsTreeImageListener(nsTreeBodyFrame* aTreeFrame) nsTreeImageListener::nsTreeImageListener(nsTreeBodyFrame* aTreeFrame)
: mTreeFrame(aTreeFrame), : mTreeFrame(aTreeFrame),
@ -23,42 +23,26 @@ nsTreeImageListener::~nsTreeImageListener()
} }
NS_IMETHODIMP NS_IMETHODIMP
nsTreeImageListener::OnImageIsAnimated(imgIRequest *aRequest) nsTreeImageListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
{ {
if (!mTreeFrame) { if (aType == imgINotificationObserver::IS_ANIMATED) {
return NS_OK; return mTreeFrame ? mTreeFrame->OnImageIsAnimated(aRequest) : NS_OK;
} }
return mTreeFrame->OnImageIsAnimated(aRequest); if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
}
NS_IMETHODIMP nsTreeImageListener::OnStartContainer(imgIRequest *aRequest,
imgIContainer *aImage)
{
// Ensure the animation (if any) is started. Note: There is no // Ensure the animation (if any) is started. Note: There is no
// corresponding call to Decrement for this. This Increment will be // corresponding call to Decrement for this. This Increment will be
// 'cleaned up' by the Request when it is destroyed, but only then. // 'cleaned up' by the Request when it is destroyed, but only then.
aRequest->IncrementAnimationConsumers(); aRequest->IncrementAnimationConsumers();
return NS_OK; }
}
NS_IMETHODIMP nsTreeImageListener::OnDataAvailable(imgIRequest *aRequest, if (aType == imgINotificationObserver::FRAME_UPDATE) {
bool aCurrentFrame,
const nsIntRect *aRect)
{
Invalidate(); Invalidate();
}
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsTreeImageListener::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect)
{
Invalidate();
return NS_OK;
}
void void
nsTreeImageListener::AddCell(int32_t aIndex, nsITreeColumn* aCol) nsTreeImageListener::AddCell(int32_t aIndex, nsITreeColumn* aCol)
{ {

View File

@ -9,27 +9,18 @@
#include "nsString.h" #include "nsString.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsITreeColumns.h" #include "nsITreeColumns.h"
#include "nsStubImageDecoderObserver.h"
#include "nsTreeBodyFrame.h" #include "nsTreeBodyFrame.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
// This class handles image load observation. // This class handles image load observation.
class nsTreeImageListener MOZ_FINAL : public nsStubImageDecoderObserver class nsTreeImageListener MOZ_FINAL : public imgINotificationObserver
{ {
public: public:
nsTreeImageListener(nsTreeBodyFrame *aTreeFrame); nsTreeImageListener(nsTreeBodyFrame *aTreeFrame);
~nsTreeImageListener(); ~nsTreeImageListener();
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
// imgIDecoderObserver (override nsStubImageDecoderObserver) NS_DECL_IMGINOTIFICATIONOBSERVER
NS_IMETHOD OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage);
NS_IMETHOD OnImageIsAnimated(imgIRequest* aRequest);
NS_IMETHOD OnDataAvailable(imgIRequest *aRequest, bool aCurrentFrame,
const nsIntRect *aRect);
// imgIContainerObserver (override nsStubImageDecoderObserver)
NS_IMETHOD FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer,
const nsIntRect *aDirtyRect);
NS_IMETHOD ClearFrame(); NS_IMETHOD ClearFrame();

View File

@ -1,41 +1,6 @@
/* ***** BEGIN LICENSE BLOCK ***** /* This Source Code Form is subject to the terms of the Mozilla Public
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 * License, v. 2.0. If a copy of the MPL was not distributed with this
* * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
* 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 the Cisco Systems SIP Stack.
*
* The Initial Developer of the Original Code is
* Cisco Systems (CSCO).
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Enda Mannion <emannion@cisco.com>
* Suhas Nandakumar <snandaku@cisco.com>
* Ethan Hugg <ehugg@cisco.com>
*
* 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 ***** */
#pragma once #pragma once

View File

@ -1,41 +1,6 @@
/* ***** BEGIN LICENSE BLOCK ***** /* This Source Code Form is subject to the terms of the Mozilla Public
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 * License, v. 2.0. If a copy of the MPL was not distributed with this
* * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
* 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 the Cisco Systems SIP Stack.
*
* The Initial Developer of the Original Code is
* Cisco Systems (CSCO).
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Enda Mannion <emannion@cisco.com>
* Suhas Nandakumar <snandaku@cisco.com>
* Ethan Hugg <ehugg@cisco.com>
*
* 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 ***** */
#pragma once #pragma once

Some files were not shown because too many files have changed in this diff Show More