2007-03-22 10:30:00 -07:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
2012-05-21 04:12:37 -07:00
* 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/. */
2007-03-22 10:30:00 -07:00
# include "imgRequest.h"
2011-07-08 10:55:03 -07:00
# include "ImageLogging.h"
2007-03-22 10:30:00 -07:00
2010-07-28 14:51:37 -07:00
/* We end up pulling in windows.h because we eventually hit gfxWindowsSurface;
* windows . h defines LoadImage , so we have to # undef it or imgLoader : : LoadImage
* gets changed .
* This # undef needs to be in multiple places because we don ' t always pull
* headers in in the same order .
*/
# undef LoadImage
2007-03-22 10:30:00 -07:00
# include "imgLoader.h"
# include "imgRequestProxy.h"
2010-08-13 21:09:49 -07:00
# include "RasterImage.h"
2010-09-08 13:40:39 -07:00
# include "VectorImage.h"
2007-03-22 10:30:00 -07:00
# include "imgILoader.h"
# include "netCore.h"
# include "nsIChannel.h"
# include "nsICachingChannel.h"
# include "nsILoadGroup.h"
# include "nsIInputStream.h"
# include "nsIMultiPartChannel.h"
# include "nsIHttpChannel.h"
# include "nsIComponentManager.h"
2008-12-22 14:20:46 -08:00
# include "nsIInterfaceRequestorUtils.h"
2007-03-22 10:30:00 -07:00
# include "nsIServiceManager.h"
# include "nsISupportsPrimitives.h"
2007-11-08 18:55:41 -08:00
# include "nsIScriptSecurityManager.h"
2007-03-22 10:30:00 -07:00
2008-09-04 16:00:42 -07:00
# include "nsICacheVisitor.h"
2007-03-22 10:30:00 -07:00
# include "nsString.h"
# include "nsXPIDLString.h"
# include "plstr.h" // PL_strcasestr(...)
2010-02-11 13:59:00 -08:00
# include "nsNetUtil.h"
# include "nsIProtocolHandler.h"
2007-03-22 10:30:00 -07:00
2011-06-11 19:30:15 -07:00
# include "mozilla/Preferences.h"
2010-06-24 11:33:34 -07:00
2010-08-13 21:09:49 -07:00
# include "DiscardTracker.h"
2010-08-04 19:15:55 -07:00
# include "nsAsyncRedirectVerifyHelper.h"
2010-07-11 18:51:52 -07:00
2010-08-13 21:09:49 -07:00
# define SVG_MIMETYPE "image / svg+xml"
2010-06-24 11:33:34 -07:00
2011-06-11 19:30:15 -07:00
using namespace mozilla ;
2012-01-06 08:02:27 -08:00
using namespace mozilla : : image ;
2010-08-13 21:09:48 -07:00
2011-12-22 06:21:00 -08:00
static bool gInitializedPrefCaches = false ;
2011-09-28 23:19:26 -07:00
static bool gDecodeOnDraw = false ;
static bool gDiscardable = false ;
2009-09-12 15:44:18 -07:00
2010-06-24 11:33:34 -07:00
static void
2011-12-22 06:21:00 -08:00
InitPrefCaches ( )
2010-06-24 11:33:34 -07:00
{
2011-12-22 06:21:00 -08:00
Preferences : : AddBoolVarCache ( & gDiscardable , " image.mem.discardable " ) ;
Preferences : : AddBoolVarCache ( & gDecodeOnDraw , " image.mem.decodeondraw " ) ;
gInitializedPrefCaches = true ;
2010-06-24 11:33:34 -07:00
}
2007-03-22 10:30:00 -07:00
# if defined(PR_LOGGING)
PRLogModuleInfo * gImgLog = PR_NewLogModule ( " imgRequest " ) ;
# endif
2010-08-04 19:15:55 -07:00
NS_IMPL_ISUPPORTS8 ( imgRequest ,
2007-03-22 10:30:00 -07:00
imgIDecoderObserver , imgIContainerObserver ,
nsIStreamListener , nsIRequestObserver ,
2008-12-22 14:20:46 -08:00
nsISupportsWeakReference ,
nsIChannelEventSink ,
2010-08-04 19:15:55 -07:00
nsIInterfaceRequestor ,
nsIAsyncVerifyRedirectCallback )
2007-03-22 10:30:00 -07:00
imgRequest : : imgRequest ( ) :
2011-09-19 12:57:21 -07:00
mValidator ( nsnull ) , mImageSniffers ( " image-sniffing-services " ) ,
2011-08-24 13:44:35 -07:00
mInnerWindowId ( 0 ) , mCORSMode ( imgIRequest : : CORS_NONE ) ,
2011-10-17 07:59:28 -07:00
mDecodeRequested ( false ) , mIsMultiPartChannel ( false ) , mGotData ( false ) ,
2012-04-07 10:36:49 -07:00
mIsInCache ( false )
2011-12-22 06:21:00 -08:00
{
// Register our pref observers if we haven't yet.
if ( NS_UNLIKELY ( ! gInitializedPrefCaches ) ) {
InitPrefCaches ( ) ;
}
}
2007-03-22 10:30:00 -07:00
imgRequest : : ~ imgRequest ( )
{
2011-07-01 10:03:40 -07:00
if ( mURI ) {
2009-01-30 18:17:47 -08:00
nsCAutoString spec ;
2011-07-01 10:03:40 -07:00
mURI - > GetSpec ( spec ) ;
2009-01-30 18:17:47 -08:00
LOG_FUNC_WITH_PARAM ( gImgLog , " imgRequest::~imgRequest() " , " keyuri " , spec . get ( ) ) ;
} else
LOG_FUNC ( gImgLog , " imgRequest::~imgRequest() " ) ;
2007-03-22 10:30:00 -07:00
}
nsresult imgRequest : : Init ( nsIURI * aURI ,
2011-07-01 10:03:40 -07:00
nsIURI * aCurrentURI ,
2007-03-22 10:30:00 -07:00
nsIRequest * aRequest ,
2008-12-22 14:20:46 -08:00
nsIChannel * aChannel ,
2008-09-04 16:00:42 -07:00
imgCacheEntry * aCacheEntry ,
2011-07-14 11:47:32 -07:00
void * aLoadId ,
2011-07-14 11:47:34 -07:00
nsIPrincipal * aLoadingPrincipal ,
PRInt32 aCORSMode )
2007-03-22 10:30:00 -07:00
{
LOG_FUNC ( gImgLog , " imgRequest::Init " ) ;
2009-01-30 18:17:47 -08:00
NS_ABORT_IF_FALSE ( ! mImage , " Multiple calls to init " ) ;
NS_ABORT_IF_FALSE ( aURI , " No uri " ) ;
2011-07-01 10:03:40 -07:00
NS_ABORT_IF_FALSE ( aCurrentURI , " No current uri " ) ;
2009-01-30 18:17:47 -08:00
NS_ABORT_IF_FALSE ( aRequest , " No request " ) ;
NS_ABORT_IF_FALSE ( aChannel , " No channel " ) ;
2007-03-22 10:30:00 -07:00
mProperties = do_CreateInstance ( " @mozilla.org/properties;1 " ) ;
2010-08-13 21:09:49 -07:00
2010-08-23 15:44:07 -07:00
mStatusTracker = new imgStatusTracker ( nsnull ) ;
2007-03-22 10:30:00 -07:00
mURI = aURI ;
2011-07-01 10:03:40 -07:00
mCurrentURI = aCurrentURI ;
2007-03-22 10:30:00 -07:00
mRequest = aRequest ;
2008-12-22 14:20:46 -08:00
mChannel = aChannel ;
2011-06-09 14:11:57 -07:00
mTimedChannel = do_QueryInterface ( mChannel ) ;
2011-07-14 11:47:32 -07:00
mLoadingPrincipal = aLoadingPrincipal ;
2011-07-14 11:47:34 -07:00
mCORSMode = aCORSMode ;
2011-07-14 11:47:32 -07:00
2008-12-22 14:20:46 -08:00
mChannel - > GetNotificationCallbacks ( getter_AddRefs ( mPrevChannelSink ) ) ;
NS_ASSERTION ( mPrevChannelSink ! = this ,
" Initializing with a channel that already calls back to us! " ) ;
mChannel - > SetNotificationCallbacks ( this ) ;
2007-03-22 10:30:00 -07:00
mCacheEntry = aCacheEntry ;
SetLoadId ( aLoadId ) ;
return NS_OK ;
}
2010-08-23 15:44:07 -07:00
imgStatusTracker &
imgRequest : : GetStatusTracker ( )
{
2012-05-19 12:32:37 -07:00
if ( mImage & & mGotData ) {
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( ! mStatusTracker ,
" Should have given mStatusTracker to mImage " ) ;
return mImage - > GetStatusTracker ( ) ;
} else {
NS_ABORT_IF_FALSE ( mStatusTracker ,
" Should have mStatusTracker until we create mImage " ) ;
return * mStatusTracker ;
}
}
2009-01-30 18:17:47 -08:00
void imgRequest : : SetCacheEntry ( imgCacheEntry * entry )
{
mCacheEntry = entry ;
}
2011-09-28 23:19:26 -07:00
bool imgRequest : : HasCacheEntry ( ) const
2009-01-30 18:17:47 -08:00
{
return mCacheEntry ! = nsnull ;
}
2007-09-22 12:40:57 -07:00
nsresult imgRequest : : AddProxy ( imgRequestProxy * proxy )
2007-03-22 10:30:00 -07:00
{
2007-09-22 12:40:57 -07:00
NS_PRECONDITION ( proxy , " null imgRequestProxy passed in " ) ;
2007-03-22 10:30:00 -07:00
LOG_SCOPE_WITH_PARAM ( gImgLog , " imgRequest::AddProxy " , " proxy " , proxy ) ;
2009-01-30 18:17:47 -08:00
// If we're empty before adding, we have to tell the loader we now have
// proxies.
if ( mObservers . IsEmpty ( ) ) {
2011-07-01 10:03:40 -07:00
NS_ABORT_IF_FALSE ( mURI , " Trying to SetHasProxies without key uri. " ) ;
imgLoader : : SetHasProxies ( mURI ) ;
2009-01-30 18:17:47 -08:00
}
2010-05-10 20:25:11 -07:00
// If we don't have any current observers, we should restart any animation.
2010-08-23 15:44:07 -07:00
if ( mImage & & ! HaveProxyWithObserver ( proxy ) & & proxy - > HasObserver ( ) ) {
2010-05-10 20:25:11 -07:00
LOG_MSG ( gImgLog , " imgRequest::AddProxy " , " resetting animation " ) ;
mImage - > ResetAnimation ( ) ;
}
2010-05-10 20:27:41 -07:00
proxy - > SetPrincipal ( mPrincipal ) ;
2007-12-19 23:30:04 -08:00
return mObservers . AppendElementUnlessExists ( proxy ) ?
2007-12-13 17:41:48 -08:00
NS_OK : NS_ERROR_OUT_OF_MEMORY ;
2007-03-22 10:30:00 -07:00
}
2011-09-28 23:19:26 -07:00
nsresult imgRequest : : RemoveProxy ( imgRequestProxy * proxy , nsresult aStatus , bool aNotify )
2007-03-22 10:30:00 -07:00
{
LOG_SCOPE_WITH_PARAM ( gImgLog , " imgRequest::RemoveProxy " , " proxy " , proxy ) ;
2010-09-07 17:33:02 -07:00
// This will remove our animation consumers, so after removing
// this proxy, we don't end up without proxies with observers, but still
// have animation consumers.
proxy - > ClearAnimationConsumers ( ) ;
2011-10-14 13:15:56 -07:00
if ( ! mObservers . RemoveElement ( proxy ) ) {
// Not one of our proxies; we're done
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
2010-05-14 13:47:59 -07:00
// Let the status tracker do its thing before we potentially call Cancel()
// below, because Cancel() may result in OnStopRequest being called back
// before Cancel() returns, leaving the image in a different state then the
// one it was in at this point.
2009-12-14 02:35:47 -08:00
2010-08-23 15:44:07 -07:00
imgStatusTracker & statusTracker = GetStatusTracker ( ) ;
statusTracker . EmulateRequestFinished ( proxy , aStatus , ! aNotify ) ;
2007-03-22 10:30:00 -07:00
2007-09-22 12:40:57 -07:00
if ( mObservers . IsEmpty ( ) ) {
2009-01-30 18:17:47 -08:00
// 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
// we can be evicted from the cache.
if ( mCacheEntry ) {
2011-07-01 10:03:40 -07:00
NS_ABORT_IF_FALSE ( mURI , " Removing last observer without key uri. " ) ;
2009-01-30 18:17:47 -08:00
2011-07-01 10:03:40 -07:00
imgLoader : : SetHasNoProxies ( mURI , mCacheEntry ) ;
2009-01-30 18:17:47 -08:00
}
# if defined(PR_LOGGING)
else {
nsCAutoString spec ;
2011-07-01 10:03:40 -07:00
mURI - > GetSpec ( spec ) ;
2009-01-30 18:17:47 -08:00
LOG_MSG_WITH_PARAM ( gImgLog , " imgRequest::RemoveProxy no cache entry " , " uri " , spec . get ( ) ) ;
}
# endif
2007-03-22 10:30:00 -07:00
/* 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 .
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 .
*/
2010-08-23 15:44:07 -07:00
if ( statusTracker . IsLoading ( ) & & NS_FAILED ( aStatus ) ) {
2007-03-22 10:30:00 -07:00
LOG_MSG ( gImgLog , " imgRequest::RemoveProxy " , " load in progress. canceling " ) ;
this - > Cancel ( NS_BINDING_ABORTED ) ;
}
/* break the cycle from the cache entry. */
mCacheEntry = nsnull ;
}
// If a proxy is removed for a reason other than its owner being
// changed, remove the proxy from the loadgroup.
if ( aStatus ! = NS_IMAGELIB_CHANGING_OWNER )
2011-10-17 07:59:28 -07:00
proxy - > RemoveFromLoadGroup ( true ) ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
2008-12-22 14:20:46 -08:00
void imgRequest : : CancelAndAbort ( nsresult aStatus )
{
2009-01-30 18:17:47 -08:00
LOG_SCOPE ( gImgLog , " imgRequest::CancelAndAbort " ) ;
2008-12-22 14:20:46 -08:00
Cancel ( aStatus ) ;
// It's possible for the channel to fail to open after we've set our
// notification callbacks. In that case, make sure to break the cycle between
// the channel and us, because it won't.
if ( mChannel ) {
mChannel - > SetNotificationCallbacks ( mPrevChannelSink ) ;
mPrevChannelSink = nsnull ;
}
2007-03-22 10:30:00 -07:00
}
2010-05-14 13:47:59 -07:00
void imgRequest : : Cancel ( nsresult aStatus )
{
/* The Cancel() method here should only be called by this class. */
LOG_SCOPE ( gImgLog , " imgRequest::Cancel " ) ;
2010-08-23 15:44:07 -07:00
imgStatusTracker & statusTracker = GetStatusTracker ( ) ;
statusTracker . RecordCancel ( ) ;
2010-05-14 13:47:59 -07:00
RemoveFromCache ( ) ;
2010-08-23 15:44:07 -07:00
if ( mRequest & & statusTracker . IsLoading ( ) )
2010-05-14 13:47:59 -07:00
mRequest - > Cancel ( aStatus ) ;
}
2007-03-22 10:30:00 -07:00
nsresult imgRequest : : GetURI ( nsIURI * * aURI )
{
LOG_FUNC ( gImgLog , " imgRequest::GetURI " ) ;
if ( mURI ) {
* aURI = mURI ;
NS_ADDREF ( * aURI ) ;
return NS_OK ;
}
return NS_ERROR_FAILURE ;
}
2008-09-01 13:53:59 -07:00
nsresult imgRequest : : GetSecurityInfo ( nsISupports * * aSecurityInfo )
{
LOG_FUNC ( gImgLog , " imgRequest::GetSecurityInfo " ) ;
// Missing security info means this is not a security load
// i.e. it is not an error when security info is missing
NS_IF_ADDREF ( * aSecurityInfo = mSecurityInfo ) ;
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
void imgRequest : : RemoveFromCache ( )
{
LOG_SCOPE ( gImgLog , " imgRequest::RemoveFromCache " ) ;
2009-03-17 14:07:16 -07:00
if ( mIsInCache ) {
// mCacheEntry is nulled out when we have no more observers.
2009-03-04 19:56:14 -08:00
if ( mCacheEntry )
imgLoader : : RemoveFromCache ( mCacheEntry ) ;
else
2011-07-01 10:03:40 -07:00
imgLoader : : RemoveFromCache ( mURI ) ;
2009-03-04 19:56:14 -08:00
}
2009-03-17 14:07:16 -07:00
mCacheEntry = nsnull ;
2007-03-22 10:30:00 -07:00
}
2011-09-28 23:19:26 -07:00
bool imgRequest : : HaveProxyWithObserver ( imgRequestProxy * aProxyToIgnore ) const
2007-03-22 10:30:00 -07:00
{
2007-12-19 23:30:04 -08:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
2007-09-22 12:40:57 -07:00
imgRequestProxy * proxy ;
2007-12-19 23:30:04 -08:00
while ( iter . HasMore ( ) ) {
proxy = iter . GetNext ( ) ;
2007-03-22 10:30:00 -07:00
if ( proxy = = aProxyToIgnore ) {
continue ;
}
if ( proxy - > HasObserver ( ) ) {
2011-10-17 07:59:28 -07:00
return true ;
2007-03-22 10:30:00 -07:00
}
}
2011-10-17 07:59:28 -07:00
return false ;
2007-03-22 10:30:00 -07:00
}
PRInt32 imgRequest : : Priority ( ) const
{
PRInt32 priority = nsISupportsPriority : : PRIORITY_NORMAL ;
nsCOMPtr < nsISupportsPriority > p = do_QueryInterface ( mRequest ) ;
if ( p )
p - > GetPriority ( & priority ) ;
return priority ;
}
void imgRequest : : AdjustPriority ( imgRequestProxy * proxy , PRInt32 delta )
{
// only the first proxy is allowed to modify the priority of this image load.
//
// XXX(darin): this is probably not the most optimal algorithm as we may want
// to increase the priority of requests that have a lot of proxies. the key
// concern though is that image loads remain lower priority than other pieces
// of content such as link clicks, CSS, and JS.
//
2007-12-19 23:30:04 -08:00
if ( mObservers . SafeElementAt ( 0 , nsnull ) ! = proxy )
2007-03-22 10:30:00 -07:00
return ;
nsCOMPtr < nsISupportsPriority > p = do_QueryInterface ( mRequest ) ;
if ( p )
p - > AdjustPriority ( delta ) ;
}
2011-09-28 23:19:26 -07:00
void imgRequest : : SetIsInCache ( bool incache )
2009-03-04 19:56:14 -08:00
{
2009-03-17 14:07:16 -07:00
LOG_FUNC_WITH_PARAM ( gImgLog , " imgRequest::SetIsCacheable " , " incache " , incache ) ;
mIsInCache = incache ;
2009-03-04 19:56:14 -08:00
}
2009-09-12 15:44:18 -07:00
void imgRequest : : UpdateCacheEntrySize ( )
2007-03-22 10:30:00 -07:00
{
2009-09-12 15:44:18 -07:00
if ( mCacheEntry ) {
2012-02-19 19:51:48 -08:00
mCacheEntry - > SetDataSize ( mImage - > SizeOfData ( ) ) ;
2007-03-22 10:30:00 -07:00
2009-09-12 15:44:18 -07:00
# ifdef DEBUG_joe
nsCAutoString url ;
mURI - > GetSpec ( url ) ;
printf ( " CACHEPUT: %d %s %d \n " , time ( NULL ) , url . get ( ) , imageSize ) ;
# endif
}
2007-03-22 10:30:00 -07:00
}
2011-07-01 10:03:33 -07:00
void imgRequest : : SetCacheValidation ( imgCacheEntry * aCacheEntry , nsIRequest * aRequest )
{
/* get the expires info */
if ( aCacheEntry ) {
nsCOMPtr < nsICachingChannel > cacheChannel ( do_QueryInterface ( aRequest ) ) ;
if ( cacheChannel ) {
nsCOMPtr < nsISupports > cacheToken ;
cacheChannel - > GetCacheToken ( getter_AddRefs ( cacheToken ) ) ;
if ( cacheToken ) {
nsCOMPtr < nsICacheEntryInfo > entryDesc ( do_QueryInterface ( cacheToken ) ) ;
if ( entryDesc ) {
PRUint32 expiration ;
/* get the expiration time from the caching channel's token */
entryDesc - > GetExpirationTime ( & expiration ) ;
// Expiration time defaults to 0. We set the expiration time on our
// entry if it hasn't been set yet.
if ( aCacheEntry - > GetExpiryTime ( ) = = 0 )
aCacheEntry - > SetExpiryTime ( expiration ) ;
}
}
}
2011-07-01 10:03:35 -07:00
// Determine whether the cache entry must be revalidated when we try to use it.
2011-07-01 10:03:33 -07:00
// Currently, only HTTP specifies this information...
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( aRequest ) ) ;
if ( httpChannel ) {
2011-09-28 23:19:26 -07:00
bool bMustRevalidate = false ;
2011-07-01 10:03:33 -07:00
httpChannel - > IsNoStoreResponse ( & bMustRevalidate ) ;
if ( ! bMustRevalidate ) {
httpChannel - > IsNoCacheResponse ( & bMustRevalidate ) ;
}
if ( ! bMustRevalidate ) {
nsCAutoString cacheHeader ;
httpChannel - > GetResponseHeader ( NS_LITERAL_CSTRING ( " Cache-Control " ) ,
cacheHeader ) ;
if ( PL_strcasestr ( cacheHeader . get ( ) , " must-revalidate " ) ) {
2011-10-17 07:59:28 -07:00
bMustRevalidate = true ;
2011-07-01 10:03:33 -07:00
}
}
// Cache entries default to not needing to validate. We ensure that
// multiple calls to this function don't override an earlier decision to
// validate by making validation a one-way decision.
if ( bMustRevalidate )
2011-07-01 10:03:35 -07:00
aCacheEntry - > SetMustValidate ( bMustRevalidate ) ;
2011-07-01 10:03:33 -07:00
}
2011-07-01 10:03:37 -07:00
// We always need to validate file URIs.
nsCOMPtr < nsIChannel > channel = do_QueryInterface ( aRequest ) ;
if ( channel ) {
nsCOMPtr < nsIURI > uri ;
channel - > GetURI ( getter_AddRefs ( uri ) ) ;
2011-09-28 23:19:26 -07:00
bool isfile = false ;
2011-07-01 10:03:37 -07:00
uri - > SchemeIs ( " file " , & isfile ) ;
if ( isfile )
aCacheEntry - > SetMustValidate ( isfile ) ;
}
2011-07-01 10:03:33 -07:00
}
}
2009-09-15 17:33:14 -07:00
nsresult
imgRequest : : LockImage ( )
{
2010-05-14 13:47:59 -07:00
return mImage - > LockImage ( ) ;
2009-09-15 17:33:14 -07:00
}
nsresult
imgRequest : : UnlockImage ( )
{
2010-05-14 13:47:59 -07:00
return mImage - > UnlockImage ( ) ;
2009-09-15 17:33:14 -07:00
}
nsresult
imgRequest : : RequestDecode ( )
{
2010-05-14 13:47:59 -07:00
// If we've initialized our image, we can request a decode.
2010-08-23 15:44:07 -07:00
if ( mImage ) {
2009-09-15 17:33:14 -07:00
return mImage - > RequestDecode ( ) ;
}
// Otherwise, flag to do it when we get the image
2011-10-17 07:59:28 -07:00
mDecodeRequested = true ;
2009-09-15 17:33:14 -07:00
return NS_OK ;
}
2007-03-22 10:30:00 -07:00
/** imgIContainerObserver methods **/
2012-01-06 04:32:38 -08:00
/* [noscript] void frameChanged (in imgIRequest request,
in imgIContainer container ,
in nsIntRect dirtyRect ) ; */
NS_IMETHODIMP imgRequest : : FrameChanged ( imgIRequest * request ,
imgIContainer * container ,
2010-08-13 21:09:48 -07:00
const nsIntRect * dirtyRect )
2007-03-22 10:30:00 -07:00
{
LOG_SCOPE ( gImgLog , " imgRequest::FrameChanged " ) ;
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mImage ,
" FrameChanged callback before we've created our image " ) ;
2007-03-22 10:30:00 -07:00
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . RecordFrameChanged ( container , dirtyRect ) ;
2007-12-19 23:30:04 -08:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . SendFrameChanged ( iter . GetNext ( ) , container , dirtyRect ) ;
2007-03-22 10:30:00 -07:00
}
return NS_OK ;
}
/** imgIDecoderObserver methods **/
/* void onStartDecode (in imgIRequest request); */
NS_IMETHODIMP imgRequest : : OnStartDecode ( imgIRequest * request )
{
LOG_SCOPE ( gImgLog , " imgRequest::OnStartDecode " ) ;
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mImage ,
" OnStartDecode callback before we've created our image " ) ;
2007-03-22 10:30:00 -07:00
2012-04-07 10:36:49 -07:00
mImage - > GetStatusTracker ( ) . RecordStartDecode ( ) ;
2007-03-22 10:30:00 -07:00
2007-12-19 23:30:04 -08:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
2012-04-07 10:36:49 -07:00
mImage - > GetStatusTracker ( ) . SendStartDecode ( iter . GetNext ( ) ) ;
2007-03-22 10:30:00 -07:00
}
/* 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 ;
2010-08-23 15:44:07 -07:00
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 " ) ;
2010-08-12 08:59:37 -07:00
mImage - > GetStatusTracker ( ) . RecordStartContainer ( image ) ;
2010-05-14 13:47:59 -07:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
mImage - > GetStatusTracker ( ) . SendStartContainer ( iter . GetNext ( ) , image ) ;
2007-03-22 10:30:00 -07:00
}
return NS_OK ;
}
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
/* void onStartFrame (in imgIRequest request, in unsigned long frame); */
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP imgRequest : : OnStartFrame ( imgIRequest * request ,
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
PRUint32 frame )
2007-03-22 10:30:00 -07:00
{
LOG_SCOPE ( gImgLog , " imgRequest::OnStartFrame " ) ;
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mImage ,
" OnStartFrame callback before we've created our image " ) ;
2007-03-22 10:30:00 -07:00
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . RecordStartFrame ( frame ) ;
2007-12-19 23:30:04 -08:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . SendStartFrame ( iter . GetNext ( ) , frame ) ;
2007-03-22 10:30:00 -07:00
}
return NS_OK ;
}
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
/* [noscript] void onDataAvailable (in imgIRequest request, in boolean aCurrentFrame, [const] in nsIntRect rect); */
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP imgRequest : : OnDataAvailable ( imgIRequest * request ,
2011-09-28 23:19:26 -07:00
bool aCurrentFrame ,
2007-03-22 10:30:00 -07:00
const nsIntRect * rect )
{
LOG_SCOPE ( gImgLog , " imgRequest::OnDataAvailable " ) ;
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mImage ,
" OnDataAvailable callback before we've created our image " ) ;
2007-03-22 10:30:00 -07:00
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . RecordDataAvailable ( aCurrentFrame , rect ) ;
2007-12-19 23:30:04 -08:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . SendDataAvailable ( iter . GetNext ( ) , aCurrentFrame , rect ) ;
2007-03-22 10:30:00 -07:00
}
return NS_OK ;
}
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
/* void onStopFrame (in imgIRequest request, in unsigned long frame); */
2007-03-22 10:30:00 -07:00
NS_IMETHODIMP imgRequest : : OnStopFrame ( imgIRequest * request ,
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-20 18:50:15 -07:00
PRUint32 frame )
2007-03-22 10:30:00 -07:00
{
LOG_SCOPE ( gImgLog , " imgRequest::OnStopFrame " ) ;
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mImage ,
" OnStopFrame callback before we've created our image " ) ;
2007-03-22 10:30:00 -07:00
2012-04-07 10:36:49 -07:00
mImage - > GetStatusTracker ( ) . RecordStopFrame ( frame ) ;
2007-03-22 10:30:00 -07:00
2007-12-19 23:30:04 -08:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
2012-04-07 10:36:49 -07:00
mImage - > GetStatusTracker ( ) . SendStopFrame ( iter . GetNext ( ) , frame ) ;
2007-03-22 10:30:00 -07:00
}
return NS_OK ;
}
/* void onStopContainer (in imgIRequest request, in imgIContainer image); */
NS_IMETHODIMP imgRequest : : OnStopContainer ( imgIRequest * request ,
imgIContainer * image )
{
LOG_SCOPE ( gImgLog , " imgRequest::OnStopContainer " ) ;
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mImage ,
" OnDataContainer callback before we've created our image " ) ;
2007-03-22 10:30:00 -07:00
2012-04-07 10:36:49 -07:00
mImage - > GetStatusTracker ( ) . RecordStopContainer ( image ) ;
2009-12-14 02:35:47 -08:00
2007-12-19 23:30:04 -08:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
2012-04-07 10:36:49 -07:00
mImage - > GetStatusTracker ( ) . SendStopContainer ( iter . GetNext ( ) , image ) ;
2007-03-22 10:30:00 -07:00
}
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 " ) ;
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mImage ,
" OnDataDecode callback before we've created our image " ) ;
2007-03-22 10:30:00 -07:00
2009-09-12 15:44:18 -07:00
// We finished the decode, and thus have the decoded frames. Update the cache
// entry size to take this into account.
UpdateCacheEntrySize ( ) ;
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . RecordStopDecode ( aStatus , aStatusArg ) ;
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
mImage - > GetStatusTracker ( ) . SendStopDecode ( iter . GetNext ( ) , aStatus ,
aStatusArg ) ;
}
2009-10-06 21:39:30 -07:00
2012-03-22 16:39:32 -07:00
if ( NS_FAILED ( aStatus ) ) {
// Some kind of problem has happened with image decoding.
2012-04-09 07:22:07 -07:00
// Report the URI to net:failed-to-process-uri-conent observers.
2012-03-22 16:39:32 -07:00
nsCOMPtr < nsIObserverService > os = mozilla : : services : : GetObserverService ( ) ;
if ( os )
2012-04-09 07:22:07 -07:00
os - > NotifyObservers ( mURI , " net:failed-to-process-uri-content " , nsnull ) ;
2012-03-22 16:39:32 -07:00
}
2010-08-13 21:09:51 -07:00
// RasterImage and everything below it is completely correct and
2009-09-12 15:44:18 -07:00
// 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_).
2010-05-14 13:47:59 -07:00
// Within imgStatusTracker, we ignore OnStopDecode notifications from the
2010-08-13 21:09:51 -07:00
// decoder and RasterImage and generate our own every time we send
2010-05-14 13:47:59 -07:00
// OnStopRequest. From within SendStopDecode, we actually send
// OnStopContainer. For more information, see bug 435296.
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
NS_IMETHODIMP imgRequest : : OnStopRequest ( imgIRequest * aRequest ,
2011-09-28 23:19:26 -07:00
bool aLastPart )
2007-03-22 10:30:00 -07:00
{
NS_NOTREACHED ( " imgRequest(imgIDecoderObserver)::OnStopRequest " ) ;
return NS_OK ;
}
2009-09-12 15:44:18 -07:00
/* void onDiscard (in imgIRequest request); */
NS_IMETHODIMP imgRequest : : OnDiscard ( imgIRequest * aRequest )
{
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mImage ,
" OnDiscard callback before we've created our image " ) ;
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . RecordDiscard ( ) ;
2009-09-12 15:44:18 -07:00
// Update the cache entry size, since we just got rid of frame data
UpdateCacheEntrySize ( ) ;
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
2010-05-14 13:47:59 -07:00
mImage - > GetStatusTracker ( ) . SendDiscard ( iter . GetNext ( ) ) ;
2009-09-12 15:44:18 -07:00
}
return NS_OK ;
}
2011-11-09 13:39:15 -08:00
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 ;
}
2007-03-22 10:30:00 -07:00
/** nsIRequestObserver methods **/
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
NS_IMETHODIMP imgRequest : : OnStartRequest ( nsIRequest * aRequest , nsISupports * ctxt )
{
LOG_SCOPE ( gImgLog , " imgRequest::OnStartRequest " ) ;
2009-09-12 15:44:18 -07:00
// Figure out if we're multipart
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIMultiPartChannel > mpchan ( do_QueryInterface ( aRequest ) ) ;
if ( mpchan )
2011-10-17 07:59:28 -07:00
mIsMultiPartChannel = true ;
2007-03-22 10:30:00 -07:00
2009-09-12 15:44:18 -07:00
// If we're not multipart, we shouldn't have an image yet
2010-08-23 15:44:07 -07:00
NS_ABORT_IF_FALSE ( mIsMultiPartChannel | | ! mImage ,
2009-09-12 15:44:18 -07:00
" Already have an image for non-multipart request " ) ;
2010-05-14 13:47:59 -07:00
// If we're multipart, and our image is initialized, fix things up for another round
2010-09-08 13:40:38 -07:00
if ( mIsMultiPartChannel & & mImage ) {
2012-05-19 12:32:37 -07:00
// Update the content type for this new part
nsCOMPtr < nsIChannel > partChan ( do_QueryInterface ( aRequest ) ) ;
partChan - > GetContentType ( mContentType ) ;
if ( mContentType . EqualsLiteral ( SVG_MIMETYPE ) | |
mImage - > GetType ( ) = = imgIContainer : : TYPE_VECTOR ) {
// mImage won't be reusable due to format change or a new SVG part
// Reset the tracker and forget that we have data for OnDataAvailable to
// treat its next call as a fresh image.
mStatusTracker = new imgStatusTracker ( nsnull ) ;
mGotData = false ;
} else if ( mImage - > GetType ( ) = = imgIContainer : : TYPE_RASTER ) {
2010-09-08 13:40:38 -07:00
// Inform the RasterImage that we have new source data
2012-05-19 12:32:37 -07:00
static_cast < RasterImage * > ( mImage . get ( ) ) - > NewSourceData ( mContentType . get ( ) ) ;
2010-09-08 13:40:38 -07:00
}
2009-09-12 15:44:18 -07:00
}
2008-09-29 13:46:53 -07:00
/*
* If mRequest is null here , then we need to set it so that we ' ll be able to
* cancel it if our Cancel ( ) method is called . Note that this can only
* happen for multipart channels . We could simply not null out mRequest for
* non - last parts , if GetIsLastPart ( ) were reliable , but it ' s not . See
* https : //bugzilla.mozilla.org/show_bug.cgi?id=339610
*/
if ( ! mRequest ) {
NS_ASSERTION ( mpchan ,
" We should have an mRequest here unless we're multipart " ) ;
nsCOMPtr < nsIChannel > chan ;
mpchan - > GetBaseChannel ( getter_AddRefs ( chan ) ) ;
mRequest = chan ;
}
2010-08-23 15:44:07 -07:00
imgStatusTracker & statusTracker = GetStatusTracker ( ) ;
statusTracker . RecordStartRequest ( ) ;
2007-03-22 10:30:00 -07:00
2008-09-01 13:53:59 -07:00
nsCOMPtr < nsIChannel > channel ( do_QueryInterface ( aRequest ) ) ;
if ( channel )
channel - > GetSecurityInfo ( getter_AddRefs ( mSecurityInfo ) ) ;
2007-12-19 23:30:04 -08:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
2010-08-23 15:44:07 -07:00
statusTracker . SendStartRequest ( iter . GetNext ( ) ) ;
2007-03-22 10:30:00 -07:00
}
2007-11-08 18:55:41 -08:00
/* Get our principal */
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIChannel > chan ( do_QueryInterface ( aRequest ) ) ;
2007-11-08 18:55:41 -08:00
if ( chan ) {
nsCOMPtr < nsIScriptSecurityManager > secMan =
do_GetService ( " @mozilla.org/scriptsecuritymanager;1 " ) ;
if ( secMan ) {
nsresult rv = secMan - > GetChannelPrincipal ( chan ,
getter_AddRefs ( mPrincipal ) ) ;
if ( NS_FAILED ( rv ) ) {
return rv ;
}
2010-05-10 20:27:41 -07:00
// Tell all of our proxies that we have a principal.
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
iter . GetNext ( ) - > SetPrincipal ( mPrincipal ) ;
}
2007-11-08 18:55:41 -08:00
}
}
2007-03-22 10:30:00 -07:00
2011-07-01 10:03:33 -07:00
SetCacheValidation ( mCacheEntry , aRequest ) ;
2007-03-22 10:30:00 -07:00
// Shouldn't we be dead already if this gets hit? Probably multipart/x-mixed-replace...
2007-09-22 12:40:57 -07:00
if ( mObservers . IsEmpty ( ) ) {
2007-03-22 10:30:00 -07:00
this - > Cancel ( NS_IMAGELIB_ERROR_FAILURE ) ;
}
return NS_OK ;
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status); */
NS_IMETHODIMP imgRequest : : OnStopRequest ( nsIRequest * aRequest , nsISupports * ctxt , nsresult status )
{
LOG_FUNC ( gImgLog , " imgRequest::OnStopRequest " ) ;
2011-09-28 23:19:26 -07:00
bool lastPart = true ;
2007-03-22 10:30:00 -07:00
nsCOMPtr < nsIMultiPartChannel > mpchan ( do_QueryInterface ( aRequest ) ) ;
2010-05-10 20:27:41 -07:00
if ( mpchan )
mpchan - > GetIsLastPart ( & lastPart ) ;
2007-03-22 10:30:00 -07:00
// XXXldb What if this is a non-last part of a multipart request?
2008-12-22 14:20:46 -08:00
// xxx before we release our reference to mRequest, lets
2007-03-22 10:30:00 -07:00
// save the last status that we saw so that the
// imgRequestProxy will have access to it.
2008-12-22 14:20:46 -08:00
if ( mRequest ) {
2007-03-22 10:30:00 -07:00
mRequest = nsnull ; // we no longer need the request
}
2008-12-22 14:20:46 -08:00
// stop holding a ref to the channel, since we don't need it anymore
if ( mChannel ) {
mChannel - > SetNotificationCallbacks ( mPrevChannelSink ) ;
mPrevChannelSink = nsnull ;
mChannel = nsnull ;
}
2009-09-12 15:44:18 -07:00
// Tell the image that it has all of the source data. Note that this can
// trigger a failure, since the image might be waiting for more non-optional
// data and this is the point where we break the news that it's not coming.
2010-09-08 13:40:38 -07:00
if ( mImage ) {
nsresult rv ;
if ( mImage - > GetType ( ) = = imgIContainer : : TYPE_RASTER ) {
// Notify the image
rv = static_cast < RasterImage * > ( mImage . get ( ) ) - > SourceDataComplete ( ) ;
} else { // imageType == imgIContainer::TYPE_VECTOR
nsCOMPtr < nsIStreamListener > imageAsStream = do_QueryInterface ( mImage ) ;
NS_ABORT_IF_FALSE ( imageAsStream ,
" SVG-typed Image failed QI to nsIStreamListener " ) ;
rv = imageAsStream - > OnStopRequest ( aRequest , ctxt , status ) ;
}
2009-09-12 15:44:18 -07:00
2010-09-08 13:40:38 -07:00
// If we got an error in the SourceDataComplete() / OnStopRequest() call,
// we don't want to proceed as if nothing bad happened. However, we also
// want to give precedence to failure status codes from necko, since
// presumably they're more meaningful.
2009-09-12 15:44:18 -07:00
if ( NS_FAILED ( rv ) & & NS_SUCCEEDED ( status ) )
status = rv ;
2007-03-22 10:30:00 -07:00
}
2010-08-23 15:44:07 -07:00
imgStatusTracker & statusTracker = GetStatusTracker ( ) ;
statusTracker . RecordStopRequest ( lastPart , status ) ;
2009-09-12 15:44:18 -07:00
2010-05-14 13:47:59 -07:00
// If the request went through, update the cache entry size. Otherwise,
// cancel the request, which removes us from the cache.
2010-08-23 15:44:07 -07:00
if ( mImage & & NS_SUCCEEDED ( status ) ) {
2009-09-12 15:44:18 -07:00
// We update the cache entry size here because this is where we finish
// loading compressed source data, which is part of our size calculus.
UpdateCacheEntrySize ( ) ;
2007-03-22 10:30:00 -07:00
}
2010-05-14 13:47:59 -07:00
else {
// stops animations, removes from cache
this - > Cancel ( status ) ;
2009-09-12 15:44:18 -07:00
}
2010-05-14 13:47:59 -07:00
/* notify the kids */
2009-09-12 15:44:18 -07:00
nsTObserverArray < imgRequestProxy * > : : ForwardIterator srIter ( mObservers ) ;
while ( srIter . HasMore ( ) ) {
2010-08-23 15:44:07 -07:00
statusTracker . SendStopRequest ( srIter . GetNext ( ) , lastPart , status ) ;
2007-03-22 10:30:00 -07:00
}
2011-06-09 14:11:57 -07:00
mTimedChannel = nsnull ;
2007-03-22 10:30:00 -07:00
return NS_OK ;
}
2009-09-12 15:44:18 -07:00
/* prototype for these defined below */
2007-03-22 10:30:00 -07:00
static NS_METHOD sniff_mimetype_callback ( nsIInputStream * in , void * closure , const char * fromRawSegment ,
PRUint32 toOffset , PRUint32 count , PRUint32 * writeCount ) ;
/** nsIStreamListener methods **/
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt, in nsIInputStream inStr, in unsigned long sourceOffset, in unsigned long count); */
NS_IMETHODIMP imgRequest : : OnDataAvailable ( nsIRequest * aRequest , nsISupports * ctxt , nsIInputStream * inStr , PRUint32 sourceOffset , PRUint32 count )
{
LOG_SCOPE_WITH_PARAM ( gImgLog , " imgRequest::OnDataAvailable " , " count " , count ) ;
NS_ASSERTION ( aRequest , " imgRequest::OnDataAvailable -- no request! " ) ;
2009-09-12 15:44:18 -07:00
nsresult rv ;
2009-02-16 06:11:30 -08:00
2010-08-13 21:09:49 -07:00
PRUint16 imageType ;
if ( mGotData ) {
imageType = mImage - > GetType ( ) ;
} else {
2007-03-22 10:30:00 -07:00
LOG_SCOPE ( gImgLog , " imgRequest::OnDataAvailable |First time through... finding mimetype| " ) ;
2011-10-17 07:59:28 -07:00
mGotData = true ;
2010-05-14 13:47:59 -07:00
2007-03-22 10:30:00 -07:00
/* look at the first few bytes and see if we can tell what the data is from that
* since servers tend to lie . : (
*/
PRUint32 out ;
inStr - > ReadSegments ( sniff_mimetype_callback , this , count , & out ) ;
2012-06-25 12:59:42 -07:00
# ifdef DEBUG
2007-03-22 10:30:00 -07:00
/* NS_WARNING if the content type from the channel isn't the same if the sniffing */
# endif
2011-09-09 15:41:04 -07:00
nsCOMPtr < nsIChannel > chan ( do_QueryInterface ( aRequest ) ) ;
2007-03-22 10:30:00 -07:00
if ( mContentType . IsEmpty ( ) ) {
LOG_SCOPE ( gImgLog , " imgRequest::OnDataAvailable |sniffing of mimetype failed| " ) ;
2009-09-12 15:44:18 -07:00
rv = NS_ERROR_FAILURE ;
2007-03-22 10:30:00 -07:00
if ( chan ) {
rv = chan - > GetContentType ( mContentType ) ;
}
if ( NS_FAILED ( rv ) ) {
PR_LOG ( gImgLog , PR_LOG_ERROR ,
( " [this=%p] imgRequest::OnDataAvailable -- Content type unavailable from the channel \n " ,
this ) ) ;
this - > Cancel ( NS_IMAGELIB_ERROR_FAILURE ) ;
return NS_BINDING_ABORTED ;
}
LOG_MSG ( gImgLog , " imgRequest::OnDataAvailable " , " Got content type from the channel " ) ;
}
2010-08-13 21:09:49 -07:00
/* now we have mimetype, so we can infer the image type that we want */
2010-09-08 13:40:39 -07:00
if ( mContentType . EqualsLiteral ( SVG_MIMETYPE ) ) {
mImage = new VectorImage ( mStatusTracker . forget ( ) ) ;
} else {
mImage = new RasterImage ( mStatusTracker . forget ( ) ) ;
}
2011-08-24 13:44:35 -07:00
mImage - > SetInnerWindowID ( mInnerWindowId ) ;
2010-08-23 15:44:07 -07:00
imageType = mImage - > GetType ( ) ;
// Notify any imgRequestProxys that are observing us that we have an Image.
nsTObserverArray < imgRequestProxy * > : : ForwardIterator iter ( mObservers ) ;
while ( iter . HasMore ( ) ) {
iter . GetNext ( ) - > SetImage ( mImage ) ;
}
2010-08-13 21:09:49 -07:00
2007-03-22 10:30:00 -07:00
/* set our mimetype as a property */
nsCOMPtr < nsISupportsCString > contentType ( do_CreateInstance ( " @mozilla.org/supports-cstring;1 " ) ) ;
if ( contentType ) {
contentType - > SetData ( mContentType ) ;
mProperties - > Set ( " type " , contentType ) ;
}
/* set our content disposition as a property */
nsCAutoString disposition ;
2011-09-09 15:41:04 -07:00
if ( chan ) {
chan - > GetContentDispositionHeader ( disposition ) ;
2007-03-22 10:30:00 -07:00
}
if ( ! disposition . IsEmpty ( ) ) {
nsCOMPtr < nsISupportsCString > contentDisposition ( do_CreateInstance ( " @mozilla.org/supports-cstring;1 " ) ) ;
if ( contentDisposition ) {
contentDisposition - > SetData ( disposition ) ;
mProperties - > Set ( " content-disposition " , contentDisposition ) ;
}
}
LOG_MSG_WITH_PARAM ( gImgLog , " imgRequest::OnDataAvailable " , " content type " , mContentType . get ( ) ) ;
2009-09-12 15:44:18 -07:00
//
2010-08-13 21:09:51 -07:00
// Figure out our Image initialization flags
2009-09-12 15:44:18 -07:00
//
2007-03-22 10:30:00 -07:00
2009-09-12 15:44:18 -07:00
// We default to the static globals
2011-09-28 23:19:26 -07:00
bool isDiscardable = gDiscardable ;
bool doDecodeOnDraw = gDecodeOnDraw ;
2009-09-12 15:44:18 -07:00
// We want UI to be as snappy as possible and not to flicker. Disable discarding
// and decode-on-draw for chrome URLS
2011-09-28 23:19:26 -07:00
bool isChrome = false ;
2009-09-12 15:44:18 -07:00
rv = mURI - > SchemeIs ( " chrome " , & isChrome ) ;
if ( NS_SUCCEEDED ( rv ) & & isChrome )
2011-10-17 07:59:28 -07:00
isDiscardable = doDecodeOnDraw = false ;
2009-09-12 15:44:18 -07:00
// We don't want resources like the "loading" icon to be discardable or
// decode-on-draw either.
2011-09-28 23:19:26 -07:00
bool isResource = false ;
2009-09-12 15:44:18 -07:00
rv = mURI - > SchemeIs ( " resource " , & isResource ) ;
if ( NS_SUCCEEDED ( rv ) & & isResource )
2011-10-17 07:59:28 -07:00
isDiscardable = doDecodeOnDraw = false ;
2009-09-12 15:44:18 -07:00
// For multipart/x-mixed-replace, we basically want a direct channel to the
// decoder. Disable both for this case as well.
if ( mIsMultiPartChannel )
2011-10-17 07:59:28 -07:00
isDiscardable = doDecodeOnDraw = false ;
2009-09-12 15:44:18 -07:00
// We have all the information we need
2010-08-13 21:09:51 -07:00
PRUint32 imageFlags = Image : : INIT_FLAG_NONE ;
2009-09-12 15:44:18 -07:00
if ( isDiscardable )
2010-08-13 21:09:51 -07:00
imageFlags | = Image : : INIT_FLAG_DISCARDABLE ;
2009-09-12 15:44:18 -07:00
if ( doDecodeOnDraw )
2010-08-13 21:09:51 -07:00
imageFlags | = Image : : INIT_FLAG_DECODE_ON_DRAW ;
2009-09-12 15:44:18 -07:00
if ( mIsMultiPartChannel )
2010-08-13 21:09:51 -07:00
imageFlags | = Image : : INIT_FLAG_MULTIPART ;
2009-09-12 15:44:18 -07:00
2010-09-12 08:22:26 -07:00
// Get our URI string
nsCAutoString uriString ;
rv = mURI - > GetSpec ( uriString ) ;
if ( NS_FAILED ( rv ) )
uriString . Assign ( " <unknown image URI> " ) ;
2010-08-23 15:44:07 -07:00
// Initialize the image that we created above. For RasterImages, this
2010-05-14 13:47:59 -07:00
// instantiates a decoder behind the scenes, so if we don't have a decoder
// for this mimetype we'll find out about it here.
2010-09-12 08:22:26 -07:00
rv = mImage - > Init ( this , mContentType . get ( ) , uriString . get ( ) , imageFlags ) ;
2009-09-12 15:44:18 -07:00
if ( NS_FAILED ( rv ) ) { // Probably bad mimetype
this - > Cancel ( rv ) ;
2007-03-22 10:30:00 -07:00
return NS_BINDING_ABORTED ;
}
2009-09-15 17:33:14 -07:00
2010-08-13 21:09:49 -07:00
if ( imageType = = imgIContainer : : TYPE_RASTER ) {
/* Use content-length as a size hint for http channels. */
2011-09-09 15:41:04 -07:00
nsCOMPtr < nsIHttpChannel > httpChannel ( do_QueryInterface ( aRequest ) ) ;
2010-08-13 21:09:49 -07:00
if ( httpChannel ) {
2010-08-30 13:20:39 -07:00
nsCAutoString contentLength ;
rv = httpChannel - > GetResponseHeader ( NS_LITERAL_CSTRING ( " content-length " ) ,
contentLength ) ;
2010-08-13 21:09:49 -07:00
if ( NS_SUCCEEDED ( rv ) ) {
2010-08-30 13:20:39 -07:00
PRInt32 len = contentLength . ToInteger ( & rv ) ;
2010-08-13 21:09:49 -07:00
// Pass anything usable on so that the RasterImage can preallocate
// its source buffer
2010-08-30 13:20:39 -07:00
if ( len > 0 ) {
PRUint32 sizeHint = ( PRUint32 ) len ;
2011-06-02 05:56:50 -07:00
sizeHint = NS_MIN < PRUint32 > ( sizeHint , 20000000 ) ; /* Bound by something reasonable */
2010-08-13 21:09:49 -07:00
RasterImage * rasterImage = static_cast < RasterImage * > ( mImage . get ( ) ) ;
2011-06-08 19:21:53 -07:00
rv = rasterImage - > SetSourceSizeHint ( sizeHint ) ;
if ( NS_FAILED ( rv ) ) {
// Flush memory, try to get some back, and try again
2011-10-17 07:59:28 -07:00
rv = nsMemory : : HeapMinimize ( true ) ;
2011-06-08 19:21:53 -07:00
rv | = rasterImage - > SetSourceSizeHint ( sizeHint ) ;
// If we've still failed at this point, things are going downhill
if ( NS_FAILED ( rv ) ) {
NS_WARNING ( " About to hit OOM in imagelib! " ) ;
}
}
2010-08-13 21:09:49 -07:00
}
2010-06-25 11:21:40 -07:00
}
}
}
2010-09-08 13:40:38 -07:00
if ( imageType = = imgIContainer : : TYPE_RASTER ) {
// If we were waiting on the image to do something, now's our chance.
if ( mDecodeRequested ) {
mImage - > RequestDecode ( ) ;
}
} else { // imageType == imgIContainer::TYPE_VECTOR
nsCOMPtr < nsIStreamListener > imageAsStream = do_QueryInterface ( mImage ) ;
NS_ABORT_IF_FALSE ( imageAsStream ,
" SVG-typed Image failed QI to nsIStreamListener " ) ;
imageAsStream - > OnStartRequest ( aRequest , nsnull ) ;
2009-09-15 17:33:14 -07:00
}
2007-03-22 10:30:00 -07:00
}
2010-09-08 13:40:38 -07:00
if ( imageType = = imgIContainer : : TYPE_RASTER ) {
// WriteToRasterImage always consumes everything it gets
2011-06-08 19:21:53 -07:00
// if it doesn't run out of memory
2010-09-08 13:40:38 -07:00
PRUint32 bytesRead ;
rv = inStr - > ReadSegments ( RasterImage : : WriteToRasterImage ,
static_cast < void * > ( mImage ) ,
count , & bytesRead ) ;
2011-06-08 19:21:53 -07:00
NS_ABORT_IF_FALSE ( bytesRead = = count | | mImage - > HasError ( ) ,
" WriteToRasterImage should consume everything or the image must be in error! " ) ;
2010-09-08 13:40:38 -07:00
} else { // imageType == imgIContainer::TYPE_VECTOR
nsCOMPtr < nsIStreamListener > imageAsStream = do_QueryInterface ( mImage ) ;
rv = imageAsStream - > OnDataAvailable ( aRequest , ctxt , inStr ,
sourceOffset , count ) ;
}
2007-03-22 10:30:00 -07:00
if ( NS_FAILED ( rv ) ) {
PR_LOG ( gImgLog , PR_LOG_WARNING ,
2009-09-12 15:44:18 -07:00
( " [this=%p] imgRequest::OnDataAvailable -- "
2010-08-13 21:09:51 -07:00
" copy to RasterImage failed \n " , this ) ) ;
2007-03-22 10:30:00 -07:00
this - > Cancel ( NS_IMAGELIB_ERROR_FAILURE ) ;
return NS_BINDING_ABORTED ;
}
return NS_OK ;
}
static NS_METHOD sniff_mimetype_callback ( nsIInputStream * in ,
void * closure ,
const char * fromRawSegment ,
PRUint32 toOffset ,
PRUint32 count ,
PRUint32 * writeCount )
{
2007-07-08 00:08:04 -07:00
imgRequest * request = static_cast < imgRequest * > ( closure ) ;
2007-03-22 10:30:00 -07:00
NS_ASSERTION ( request , " request is null! " ) ;
if ( count > 0 )
request - > SniffMimeType ( fromRawSegment , count ) ;
* writeCount = 0 ;
return NS_ERROR_FAILURE ;
}
void
imgRequest : : SniffMimeType ( const char * buf , PRUint32 len )
{
imgLoader : : GetMimeTypeFromContent ( buf , len , mContentType ) ;
2007-09-02 09:10:57 -07:00
// The vast majority of the time, imgLoader will find a gif/jpeg/png image
// and fill mContentType with the sniffed MIME type.
if ( ! mContentType . IsEmpty ( ) )
return ;
// When our sniffing fails, we want to query registered image decoders
// to see if they can identify the image. If we always trusted the server
// to send the right MIME, images sent as text/plain would not be rendered.
const nsCOMArray < nsIContentSniffer > & sniffers = mImageSniffers . GetEntries ( ) ;
PRUint32 length = sniffers . Count ( ) ;
for ( PRUint32 i = 0 ; i < length ; + + i ) {
nsresult rv =
sniffers [ i ] - > GetMIMETypeFromContent ( nsnull , ( const PRUint8 * ) buf , len , mContentType ) ;
if ( NS_SUCCEEDED ( rv ) & & ! mContentType . IsEmpty ( ) ) {
return ;
}
}
2007-03-22 10:30:00 -07:00
}
2009-09-12 15:44:18 -07:00
2008-12-22 14:20:46 -08:00
/** nsIInterfaceRequestor methods **/
NS_IMETHODIMP
imgRequest : : GetInterface ( const nsIID & aIID , void * * aResult )
{
if ( ! mPrevChannelSink | | aIID . Equals ( NS_GET_IID ( nsIChannelEventSink ) ) )
return QueryInterface ( aIID , aResult ) ;
NS_ASSERTION ( mPrevChannelSink ! = this ,
" Infinite recursion - don't keep track of channel sinks that are us! " ) ;
return mPrevChannelSink - > GetInterface ( aIID , aResult ) ;
}
/** nsIChannelEventSink methods **/
NS_IMETHODIMP
2010-08-04 19:15:55 -07:00
imgRequest : : AsyncOnChannelRedirect ( nsIChannel * oldChannel ,
nsIChannel * newChannel , PRUint32 flags ,
nsIAsyncVerifyRedirectCallback * callback )
2008-12-22 14:20:46 -08:00
{
2010-08-04 19:15:55 -07:00
NS_ASSERTION ( mRequest & & mChannel , " Got a channel redirect after we nulled out mRequest! " ) ;
2008-12-22 14:20:46 -08:00
NS_ASSERTION ( mChannel = = oldChannel , " Got a channel redirect for an unknown channel! " ) ;
NS_ASSERTION ( newChannel , " Got a redirect to a NULL channel! " ) ;
2011-07-01 10:03:33 -07:00
SetCacheValidation ( mCacheEntry , oldChannel ) ;
2010-08-04 19:15:55 -07:00
// Prepare for callback
mRedirectCallback = callback ;
mNewRedirectChannel = newChannel ;
2008-12-22 14:20:46 -08:00
nsCOMPtr < nsIChannelEventSink > sink ( do_GetInterface ( mPrevChannelSink ) ) ;
if ( sink ) {
2010-08-04 19:15:55 -07:00
nsresult rv = sink - > AsyncOnChannelRedirect ( oldChannel , newChannel , flags ,
this ) ;
if ( NS_FAILED ( rv ) ) {
mRedirectCallback = nsnull ;
mNewRedirectChannel = nsnull ;
}
return rv ;
2008-12-22 14:20:46 -08:00
}
2011-07-01 10:03:30 -07:00
2010-08-04 19:15:55 -07:00
( void ) OnRedirectVerifyCallback ( NS_OK ) ;
return NS_OK ;
}
2008-12-22 14:20:46 -08:00
2010-08-04 19:15:55 -07:00
NS_IMETHODIMP
imgRequest : : OnRedirectVerifyCallback ( nsresult result )
{
NS_ASSERTION ( mRedirectCallback , " mRedirectCallback not set in callback " ) ;
NS_ASSERTION ( mNewRedirectChannel , " mNewRedirectChannel not set in callback " ) ;
2011-07-01 10:03:30 -07:00
2010-08-04 19:15:55 -07:00
if ( NS_FAILED ( result ) ) {
mRedirectCallback - > OnRedirectVerifyCallback ( result ) ;
mRedirectCallback = nsnull ;
mNewRedirectChannel = nsnull ;
return NS_OK ;
}
mChannel = mNewRedirectChannel ;
2011-06-09 14:11:57 -07:00
mTimedChannel = do_QueryInterface ( mChannel ) ;
2010-08-04 19:15:55 -07:00
mNewRedirectChannel = nsnull ;
2008-12-22 14:20:46 -08:00
2011-07-01 10:03:32 -07:00
# if defined(PR_LOGGING)
2009-03-17 14:07:16 -07:00
nsCAutoString oldspec ;
2011-07-01 10:03:40 -07:00
if ( mCurrentURI )
mCurrentURI - > GetSpec ( oldspec ) ;
2009-03-17 14:07:16 -07:00
LOG_MSG_WITH_PARAM ( gImgLog , " imgRequest::OnChannelRedirect " , " old " , oldspec . get ( ) ) ;
2011-07-01 10:03:32 -07:00
# endif
2009-03-17 14:07:16 -07:00
2010-02-11 13:59:00 -08:00
// make sure we have a protocol that returns data rather than opens
// an external application, e.g. mailto:
2011-07-01 10:03:40 -07:00
mChannel - > GetURI ( getter_AddRefs ( mCurrentURI ) ) ;
2011-09-28 23:19:26 -07:00
bool doesNotReturnData = false ;
2010-08-04 19:15:55 -07:00
nsresult rv =
2011-07-01 10:03:40 -07:00
NS_URIChainHasFlags ( mCurrentURI , nsIProtocolHandler : : URI_DOES_NOT_RETURN_DATA ,
2010-08-04 19:15:55 -07:00
& doesNotReturnData ) ;
if ( NS_SUCCEEDED ( rv ) & & doesNotReturnData )
rv = NS_ERROR_ABORT ;
if ( NS_FAILED ( rv ) ) {
mRedirectCallback - > OnRedirectVerifyCallback ( rv ) ;
mRedirectCallback = nsnull ;
return NS_OK ;
}
2010-02-11 13:59:00 -08:00
2010-08-04 19:15:55 -07:00
mRedirectCallback - > OnRedirectVerifyCallback ( NS_OK ) ;
mRedirectCallback = nsnull ;
return NS_OK ;
2008-12-22 14:20:46 -08:00
}