LCOV - code coverage report
Current view: directory - content/base/src - nsImageLoadingContent.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 446 19 4.3 %
Date: 2012-06-02 Functions: 54 5 9.3 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // vim: ft=cpp tw=78 sw=2 et ts=2
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Boris Zbarsky <bzbarsky@mit.edu>.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2003
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Christian Biesinger <cbiesinger@web.de>
      25                 :  *   Bobby Holley <bobbyholley@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : /*
      42                 :  * A base class which implements nsIImageLoadingContent and can be
      43                 :  * subclassed by various content nodes that want to provide image
      44                 :  * loading functionality (eg <img>, <object>, etc).
      45                 :  */
      46                 : 
      47                 : #include "nsImageLoadingContent.h"
      48                 : #include "nsAutoPtr.h"
      49                 : #include "nsContentErrors.h"
      50                 : #include "nsIContent.h"
      51                 : #include "nsIDocument.h"
      52                 : #include "nsIScriptGlobalObject.h"
      53                 : #include "nsIDOMWindow.h"
      54                 : #include "nsServiceManagerUtils.h"
      55                 : #include "nsContentPolicyUtils.h"
      56                 : #include "nsIURI.h"
      57                 : #include "nsILoadGroup.h"
      58                 : #include "imgIContainer.h"
      59                 : #include "imgILoader.h"
      60                 : #include "nsThreadUtils.h"
      61                 : #include "nsNetUtil.h"
      62                 : #include "nsAsyncDOMEvent.h"
      63                 : #include "nsGenericElement.h"
      64                 : 
      65                 : #include "nsIPresShell.h"
      66                 : #include "nsEventStates.h"
      67                 : #include "nsGUIEvent.h"
      68                 : 
      69                 : #include "nsIChannel.h"
      70                 : #include "nsIStreamListener.h"
      71                 : 
      72                 : #include "nsIFrame.h"
      73                 : #include "nsIDOMNode.h"
      74                 : 
      75                 : #include "nsContentUtils.h"
      76                 : #include "nsLayoutUtils.h"
      77                 : #include "nsIContentPolicy.h"
      78                 : #include "nsContentPolicyUtils.h"
      79                 : #include "nsEventDispatcher.h"
      80                 : #include "nsSVGEffects.h"
      81                 : 
      82                 : #include "mozAutoDocUpdate.h"
      83                 : #include "mozilla/dom/Element.h"
      84                 : 
      85                 : using namespace mozilla;
      86                 : 
      87                 : #ifdef DEBUG_chb
      88                 : static void PrintReqURL(imgIRequest* req) {
      89                 :   if (!req) {
      90                 :     printf("(null req)\n");
      91                 :     return;
      92                 :   }
      93                 : 
      94                 :   nsCOMPtr<nsIURI> uri;
      95                 :   req->GetURI(getter_AddRefs(uri));
      96                 :   if (!uri) {
      97                 :     printf("(null uri)\n");
      98                 :     return;
      99                 :   }
     100                 : 
     101                 :   nsCAutoString spec;
     102                 :   uri->GetSpec(spec);
     103                 :   printf("spec='%s'\n", spec.get());
     104                 : }
     105                 : #endif /* DEBUG_chb */
     106                 : 
     107                 : 
     108               1 : nsImageLoadingContent::nsImageLoadingContent()
     109                 :   : mObserverList(nsnull),
     110                 :     mImageBlockingStatus(nsIContentPolicy::ACCEPT),
     111                 :     mLoadingEnabled(true),
     112                 :     mIsImageStateForced(false),
     113                 :     mLoading(false),
     114                 :     // mBroken starts out true, since an image without a URI is broken....
     115                 :     mBroken(true),
     116                 :     mUserDisabled(false),
     117                 :     mSuppressed(false),
     118                 :     mBlockingOnload(false),
     119                 :     mNewRequestsWillNeedAnimationReset(false),
     120                 :     mPendingRequestNeedsResetAnimation(false),
     121                 :     mCurrentRequestNeedsResetAnimation(false),
     122                 :     mStateChangerDepth(0),
     123                 :     mCurrentRequestRegistered(false),
     124               1 :     mPendingRequestRegistered(false)
     125                 : {
     126               1 :   if (!nsContentUtils::GetImgLoader()) {
     127               0 :     mLoadingEnabled = false;
     128                 :   }
     129               1 : }
     130                 : 
     131                 : void
     132               1 : nsImageLoadingContent::DestroyImageLoadingContent()
     133                 : {
     134                 :   // Cancel our requests so they won't hold stale refs to us
     135               1 :   ClearCurrentRequest(NS_BINDING_ABORTED);
     136               1 :   ClearPendingRequest(NS_BINDING_ABORTED);
     137               1 : }
     138                 : 
     139               2 : nsImageLoadingContent::~nsImageLoadingContent()
     140                 : {
     141               1 :   NS_ASSERTION(!mCurrentRequest && !mPendingRequest,
     142                 :                "DestroyImageLoadingContent not called");
     143               1 :   NS_ASSERTION(!mObserverList.mObserver && !mObserverList.mNext,
     144                 :                "Observers still registered?");
     145               2 : }
     146                 : 
     147                 : // Macro to call some func on each observer.  This handles observers
     148                 : // removing themselves.
     149                 : #define LOOP_OVER_OBSERVERS(func_)                                       \
     150                 :   PR_BEGIN_MACRO                                                         \
     151                 :     for (ImageObserver* observer = &mObserverList, *next; observer;      \
     152                 :          observer = next) {                                              \
     153                 :       next = observer->mNext;                                            \
     154                 :       if (observer->mObserver) {                                         \
     155                 :         observer->mObserver->func_;                                      \
     156                 :       }                                                                  \
     157                 :     }                                                                    \
     158                 :   PR_END_MACRO
     159                 : 
     160                 : 
     161                 : /*
     162                 :  * imgIContainerObserver impl
     163                 :  */
     164                 : NS_IMETHODIMP
     165               0 : nsImageLoadingContent::FrameChanged(imgIRequest* aRequest,
     166                 :                                     imgIContainer* aContainer,
     167                 :                                     const nsIntRect* aDirtyRect)
     168                 : {
     169               0 :   LOOP_OVER_OBSERVERS(FrameChanged(aRequest, aContainer, aDirtyRect));
     170               0 :   return NS_OK;
     171                 : }
     172                 :             
     173                 : /*
     174                 :  * imgIDecoderObserver impl
     175                 :  */
     176                 : NS_IMETHODIMP
     177               0 : nsImageLoadingContent::OnStartRequest(imgIRequest* aRequest)
     178                 : {
     179               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     180                 : 
     181               0 :   LOOP_OVER_OBSERVERS(OnStartRequest(aRequest));
     182               0 :   return NS_OK;
     183                 : }
     184                 : 
     185                 : NS_IMETHODIMP
     186               0 : nsImageLoadingContent::OnStartDecode(imgIRequest* aRequest)
     187                 : {
     188               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     189                 : 
     190                 :   // Onload blocking. This only applies for the current request.
     191               0 :   if (aRequest == mCurrentRequest) {
     192                 : 
     193                 :     // Determine whether this is a background request (this can be the case
     194                 :     // with multipart/x-mixed-replace images, for example).
     195                 :     PRUint32 loadFlags;
     196               0 :     nsresult rv = aRequest->GetLoadFlags(&loadFlags);
     197                 :     bool background =
     198               0 :       (NS_SUCCEEDED(rv) && (loadFlags & nsIRequest::LOAD_BACKGROUND));
     199                 : 
     200                 :     // Block onload for non-background requests
     201               0 :     if (!background) {
     202               0 :       NS_ABORT_IF_FALSE(!mBlockingOnload, "Shouldn't already be blocking");
     203               0 :       SetBlockingOnload(true);
     204                 :     }
     205                 :   }
     206                 : 
     207               0 :   LOOP_OVER_OBSERVERS(OnStartDecode(aRequest));
     208               0 :   return NS_OK;
     209                 : }
     210                 : 
     211                 : NS_IMETHODIMP
     212               0 : nsImageLoadingContent::OnStartContainer(imgIRequest* aRequest,
     213                 :                                         imgIContainer* aContainer)
     214                 : {
     215               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     216                 : 
     217               0 :   LOOP_OVER_OBSERVERS(OnStartContainer(aRequest, aContainer));
     218                 : 
     219                 :   // Have to check for state changes here, since we might have been in
     220                 :   // the LOADING state before.
     221               0 :   UpdateImageState(true);
     222               0 :   return NS_OK;    
     223                 : }
     224                 : 
     225                 : NS_IMETHODIMP
     226               0 : nsImageLoadingContent::OnStartFrame(imgIRequest* aRequest,
     227                 :                                     PRUint32 aFrame)
     228                 : {
     229               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     230                 : 
     231               0 :   LOOP_OVER_OBSERVERS(OnStartFrame(aRequest, aFrame));
     232               0 :   return NS_OK;    
     233                 : }
     234                 : 
     235                 : NS_IMETHODIMP
     236               0 : nsImageLoadingContent::OnDataAvailable(imgIRequest* aRequest,
     237                 :                                        bool aCurrentFrame,
     238                 :                                        const nsIntRect* aRect)
     239                 : {
     240               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     241                 : 
     242               0 :   LOOP_OVER_OBSERVERS(OnDataAvailable(aRequest, aCurrentFrame, aRect));
     243               0 :   return NS_OK;
     244                 : }
     245                 : 
     246                 : NS_IMETHODIMP
     247               0 : nsImageLoadingContent::OnStopFrame(imgIRequest* aRequest,
     248                 :                                    PRUint32 aFrame)
     249                 : {
     250               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     251                 : 
     252                 :   // If we're blocking a load, one frame is enough
     253               0 :   if (aRequest == mCurrentRequest)
     254               0 :     SetBlockingOnload(false);
     255                 : 
     256               0 :   LOOP_OVER_OBSERVERS(OnStopFrame(aRequest, aFrame));
     257               0 :   return NS_OK;
     258                 : }
     259                 : 
     260                 : NS_IMETHODIMP
     261               0 : nsImageLoadingContent::OnStopContainer(imgIRequest* aRequest,
     262                 :                                        imgIContainer* aContainer)
     263                 : {
     264               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     265                 : 
     266                 :   // This is really hacky. We need to handle the case where we start decoding,
     267                 :   // block onload, but then hit an error before we get to our first frame. In
     268                 :   // theory we would just hook in at OnStopDecode, but OnStopDecode is broken
     269                 :   // until we fix bug 505385. OnStopContainer is actually going away at that
     270                 :   // point. So for now we take advantage of the fact that OnStopContainer is
     271                 :   // always fired in the decoders at the same time as OnStopDecode.
     272               0 :   if (aRequest == mCurrentRequest)
     273               0 :     SetBlockingOnload(false);
     274                 : 
     275               0 :   LOOP_OVER_OBSERVERS(OnStopContainer(aRequest, aContainer));
     276               0 :   return NS_OK;
     277                 : }
     278                 : 
     279                 : // Warning - This isn't actually fired when decode is complete. Rather, it's
     280                 : // fired when load is complete. See bug 505385, and in the mean time use
     281                 : // OnStopContainer.
     282                 : NS_IMETHODIMP
     283               0 : nsImageLoadingContent::OnStopDecode(imgIRequest* aRequest,
     284                 :                                     nsresult aStatus,
     285                 :                                     const PRUnichar* aStatusArg)
     286                 : {
     287               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     288                 : 
     289                 :   // We should definitely have a request here
     290               0 :   NS_ABORT_IF_FALSE(aRequest, "no request?");
     291                 : 
     292               0 :   NS_PRECONDITION(aRequest == mCurrentRequest || aRequest == mPendingRequest,
     293                 :                   "Unknown request");
     294               0 :   LOOP_OVER_OBSERVERS(OnStopDecode(aRequest, aStatus, aStatusArg));
     295                 : 
     296                 :   // XXXbholley - When we fix bug 505385,  everything here should go in
     297                 :   // OnStopRequest.
     298                 : 
     299                 :   // Our state may change. Watch it.
     300               0 :   AutoStateChanger changer(this, true);
     301                 : 
     302                 :   // If the pending request is loaded, switch to it.
     303               0 :   if (aRequest == mPendingRequest) {
     304               0 :     PrepareCurrentRequest() = mPendingRequest;
     305               0 :     mPendingRequest = nsnull;
     306               0 :     mCurrentRequestNeedsResetAnimation = mPendingRequestNeedsResetAnimation;
     307               0 :     mPendingRequestNeedsResetAnimation = false;
     308                 :   }
     309               0 :   NS_ABORT_IF_FALSE(aRequest == mCurrentRequest,
     310                 :                     "One way or another, we should be current by now");
     311                 : 
     312               0 :   if (mCurrentRequestNeedsResetAnimation) {
     313               0 :     nsCOMPtr<imgIContainer> container;
     314               0 :     mCurrentRequest->GetImage(getter_AddRefs(container));
     315               0 :     if (container)
     316               0 :       container->ResetAnimation();
     317               0 :     mCurrentRequestNeedsResetAnimation = false;
     318                 :   }
     319                 : 
     320                 :   // We just loaded all the data we're going to get. If we haven't done an
     321                 :   // initial paint, we want to make sure the image starts decoding for 2
     322                 :   // reasons:
     323                 :   //
     324                 :   // 1) This image is sitting idle but might need to be decoded as soon as we
     325                 :   // start painting, in which case we've wasted time.
     326                 :   //
     327                 :   // 2) We want to block onload until all visible images are decoded. We do this
     328                 :   // by blocking onload until all in progress decodes get at least one frame
     329                 :   // decoded. However, if all the data comes in while painting is suppressed
     330                 :   // (ie, before the initial paint delay is finished), we fire onload without
     331                 :   // doing a paint first. This means that decode-on-draw images don't start
     332                 :   // decoding, so we can't wait for them to finish. See bug 512435.
     333                 : 
     334                 :   // We can only do this if we have a presshell
     335               0 :   nsIDocument* doc = GetOurDocument();
     336               0 :   nsIPresShell* shell = doc ? doc->GetShell() : nsnull;
     337               0 :   if (shell) {
     338                 :     // We need to figure out whether to kick off decoding
     339               0 :     bool doRequestDecode = false;
     340                 : 
     341                 :     // If we haven't got the initial reflow yet, IsPaintingSuppressed actually
     342                 :     // returns false
     343               0 :     if (!shell->DidInitialReflow())
     344               0 :       doRequestDecode = true;
     345                 : 
     346                 :     // Figure out if painting is suppressed. Note that it's possible for painting
     347                 :     // to be suppressed for reasons other than the initial paint delay (for
     348                 :     // example - being in the bfcache), but we probably aren't loading images in
     349                 :     // those situations.
     350               0 :     if (shell->IsPaintingSuppressed())
     351               0 :       doRequestDecode = true;
     352                 : 
     353                 :     // If we're requesting a decode, do it
     354               0 :     if (doRequestDecode)
     355               0 :       mCurrentRequest->RequestDecode();
     356                 :   }
     357                 : 
     358                 :   // Fire the appropriate DOM event.
     359               0 :   if (NS_SUCCEEDED(aStatus)) {
     360               0 :     FireEvent(NS_LITERAL_STRING("load"));
     361                 :   } else {
     362               0 :     FireEvent(NS_LITERAL_STRING("error"));
     363                 :   }
     364                 : 
     365               0 :   nsCOMPtr<nsINode> thisNode = do_QueryInterface(this);
     366               0 :   nsSVGEffects::InvalidateDirectRenderingObservers(thisNode->AsElement());
     367                 : 
     368               0 :   return NS_OK;
     369                 : }
     370                 : 
     371                 : NS_IMETHODIMP
     372               0 : nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest, bool aLastPart)
     373                 : {
     374               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     375                 : 
     376               0 :   LOOP_OVER_OBSERVERS(OnStopRequest(aRequest, aLastPart));
     377                 : 
     378               0 :   return NS_OK;
     379                 : }
     380                 : 
     381                 : NS_IMETHODIMP
     382               0 : nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
     383                 : {
     384               0 :   bool* requestFlag = GetRegisteredFlagForRequest(aRequest);
     385               0 :   if (requestFlag) {
     386                 :     nsLayoutUtils::RegisterImageRequest(GetFramePresContext(),
     387               0 :                                         aRequest, requestFlag);
     388                 :   }
     389                 : 
     390               0 :   return NS_OK;
     391                 : }
     392                 : 
     393                 : NS_IMETHODIMP
     394               0 : nsImageLoadingContent::OnDiscard(imgIRequest *aRequest)
     395                 : {
     396               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     397                 : 
     398               0 :   LOOP_OVER_OBSERVERS(OnDiscard(aRequest));
     399                 : 
     400               0 :   return NS_OK;
     401                 : }
     402                 : 
     403                 : /*
     404                 :  * nsIImageLoadingContent impl
     405                 :  */
     406                 : 
     407                 : NS_IMETHODIMP
     408               0 : nsImageLoadingContent::GetLoadingEnabled(bool *aLoadingEnabled)
     409                 : {
     410               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     411                 : 
     412               0 :   *aLoadingEnabled = mLoadingEnabled;
     413               0 :   return NS_OK;
     414                 : }
     415                 : 
     416                 : NS_IMETHODIMP
     417               0 : nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled)
     418                 : {
     419               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     420                 : 
     421               0 :   if (nsContentUtils::GetImgLoader()) {
     422               0 :     mLoadingEnabled = aLoadingEnabled;
     423                 :   }
     424               0 :   return NS_OK;
     425                 : }
     426                 : 
     427                 : NS_IMETHODIMP
     428               0 : nsImageLoadingContent::GetImageBlockingStatus(PRInt16* aStatus)
     429                 : {
     430               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     431                 : 
     432               0 :   NS_PRECONDITION(aStatus, "Null out param");
     433               0 :   *aStatus = mImageBlockingStatus;
     434               0 :   return NS_OK;
     435                 : }
     436                 : 
     437                 : NS_IMETHODIMP
     438               0 : nsImageLoadingContent::AddObserver(imgIDecoderObserver* aObserver)
     439                 : {
     440               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     441                 : 
     442               0 :   NS_ENSURE_ARG_POINTER(aObserver);
     443                 : 
     444               0 :   if (!mObserverList.mObserver) {
     445               0 :     mObserverList.mObserver = aObserver;
     446                 :     // Don't touch the linking of the list!
     447               0 :     return NS_OK;
     448                 :   }
     449                 : 
     450                 :   // otherwise we have to create a new entry
     451                 : 
     452               0 :   ImageObserver* observer = &mObserverList;
     453               0 :   while (observer->mNext) {
     454               0 :     observer = observer->mNext;
     455                 :   }
     456                 : 
     457               0 :   observer->mNext = new ImageObserver(aObserver);
     458               0 :   if (! observer->mNext) {
     459               0 :     return NS_ERROR_OUT_OF_MEMORY;
     460                 :   }
     461                 : 
     462               0 :   return NS_OK;
     463                 : }
     464                 : 
     465                 : NS_IMETHODIMP
     466               0 : nsImageLoadingContent::RemoveObserver(imgIDecoderObserver* aObserver)
     467                 : {
     468               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     469                 : 
     470               0 :   NS_ENSURE_ARG_POINTER(aObserver);
     471                 : 
     472               0 :   if (mObserverList.mObserver == aObserver) {
     473               0 :     mObserverList.mObserver = nsnull;
     474                 :     // Don't touch the linking of the list!
     475               0 :     return NS_OK;
     476                 :   }
     477                 : 
     478                 :   // otherwise have to find it and splice it out
     479               0 :   ImageObserver* observer = &mObserverList;
     480               0 :   while (observer->mNext && observer->mNext->mObserver != aObserver) {
     481               0 :     observer = observer->mNext;
     482                 :   }
     483                 : 
     484                 :   // At this point, we are pointing to the list element whose mNext is
     485                 :   // the right observer (assuming of course that mNext is not null)
     486               0 :   if (observer->mNext) {
     487                 :     // splice it out
     488               0 :     ImageObserver* oldObserver = observer->mNext;
     489               0 :     observer->mNext = oldObserver->mNext;
     490               0 :     oldObserver->mNext = nsnull;  // so we don't destroy them all
     491               0 :     delete oldObserver;
     492                 :   }
     493                 : #ifdef DEBUG
     494                 :   else {
     495               0 :     NS_WARNING("Asked to remove nonexistent observer");
     496                 :   }
     497                 : #endif
     498               0 :   return NS_OK;
     499                 : }
     500                 : 
     501                 : NS_IMETHODIMP
     502               0 : nsImageLoadingContent::GetRequest(PRInt32 aRequestType,
     503                 :                                   imgIRequest** aRequest)
     504                 : {
     505               0 :   switch(aRequestType) {
     506                 :   case CURRENT_REQUEST:
     507               0 :     *aRequest = mCurrentRequest;
     508               0 :     break;
     509                 :   case PENDING_REQUEST:
     510               0 :     *aRequest = mPendingRequest;
     511               0 :     break;
     512                 :   default:
     513               0 :     NS_ERROR("Unknown request type");
     514               0 :     *aRequest = nsnull;
     515               0 :     return NS_ERROR_UNEXPECTED;
     516                 :   }
     517                 :   
     518               0 :   NS_IF_ADDREF(*aRequest);
     519               0 :   return NS_OK;
     520                 : }
     521                 : 
     522                 : NS_IMETHODIMP_(void)
     523               0 : nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
     524                 : {
     525               0 :   NS_ASSERTION(aFrame, "aFrame is null");
     526                 : 
     527                 :   // We need to make sure that our image request is registered, if it should
     528                 :   // be registered.
     529               0 :   nsPresContext* presContext = aFrame->PresContext();
     530                 : 
     531               0 :   if (mCurrentRequest) {
     532                 :     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mCurrentRequest,
     533               0 :                                                   &mCurrentRequestRegistered);
     534                 :   }
     535                 : 
     536               0 :   if (mPendingRequest) {
     537                 :     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mPendingRequest,
     538               0 :                                                   &mPendingRequestRegistered);
     539                 :   }
     540               0 : }
     541                 : 
     542                 : NS_IMETHODIMP_(void)
     543               0 : nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
     544                 : {
     545               0 :   NS_ASSERTION(aFrame, "aFrame is null");
     546                 : 
     547                 :   // We need to make sure that our image request is deregistered.
     548               0 :   if (mCurrentRequest) {
     549                 :     nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
     550                 :                                           mCurrentRequest,
     551               0 :                                           &mCurrentRequestRegistered);
     552                 :   }
     553                 : 
     554               0 :   if (mPendingRequest) {
     555                 :     nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(),
     556                 :                                           mPendingRequest,
     557               0 :                                           &mPendingRequestRegistered);
     558                 :   }
     559               0 : }
     560                 : 
     561                 : NS_IMETHODIMP
     562               0 : nsImageLoadingContent::GetRequestType(imgIRequest* aRequest,
     563                 :                                       PRInt32* aRequestType)
     564                 : {
     565               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     566                 : 
     567               0 :   NS_PRECONDITION(aRequestType, "Null out param");
     568                 :   
     569               0 :   if (aRequest == mCurrentRequest) {
     570               0 :     *aRequestType = CURRENT_REQUEST;
     571               0 :     return NS_OK;
     572                 :   }
     573                 : 
     574               0 :   if (aRequest == mPendingRequest) {
     575               0 :     *aRequestType = PENDING_REQUEST;
     576               0 :     return NS_OK;
     577                 :   }
     578                 : 
     579               0 :   *aRequestType = UNKNOWN_REQUEST;
     580               0 :   NS_ERROR("Unknown request");
     581               0 :   return NS_ERROR_UNEXPECTED;
     582                 : }
     583                 : 
     584                 : NS_IMETHODIMP
     585               0 : nsImageLoadingContent::GetCurrentURI(nsIURI** aURI)
     586                 : {
     587               0 :   if (mCurrentRequest) {
     588               0 :     return mCurrentRequest->GetURI(aURI);
     589                 :   }
     590                 : 
     591               0 :   if (!mCurrentURI) {
     592               0 :     *aURI = nsnull;
     593               0 :     return NS_OK;
     594                 :   }
     595                 :   
     596               0 :   return NS_EnsureSafeToReturn(mCurrentURI, aURI);
     597                 : }
     598                 : 
     599                 : NS_IMETHODIMP
     600               0 : nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
     601                 :                                             nsIStreamListener** aListener)
     602                 : {
     603               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     604                 : 
     605               0 :   if (!nsContentUtils::GetImgLoader()) {
     606               0 :     return NS_ERROR_NULL_POINTER;
     607                 :   }
     608                 : 
     609               0 :   nsCOMPtr<nsIDocument> doc = GetOurDocument();
     610               0 :   if (!doc) {
     611                 :     // Don't bother
     612               0 :     return NS_OK;
     613                 :   }
     614                 : 
     615                 :   // XXX what should we do with content policies here, if anything?
     616                 :   // Shouldn't that be done before the start of the load?
     617                 :   // XXX what about shouldProcess?
     618                 : 
     619                 :   // Our state might change. Watch it.
     620               0 :   AutoStateChanger changer(this, true);
     621                 : 
     622                 :   // Do the load.
     623               0 :   nsCOMPtr<imgIRequest>& req = PrepareNextRequest();
     624               0 :   nsresult rv = nsContentUtils::GetImgLoader()->
     625                 :     LoadImageWithChannel(aChannel, this, doc, aListener,
     626               0 :                          getter_AddRefs(req));
     627               0 :   if (NS_SUCCEEDED(rv)) {
     628               0 :     TrackImage(req);
     629                 :   } else {
     630                 :     // If we don't have a current URI, we might as well store this URI so people
     631                 :     // know what we tried (and failed) to load.
     632               0 :     if (!mCurrentRequest)
     633               0 :       aChannel->GetURI(getter_AddRefs(mCurrentURI));
     634               0 :     FireEvent(NS_LITERAL_STRING("error"));
     635               0 :     return rv;
     636                 :   }
     637               0 :   return NS_OK;;
     638                 : }
     639                 : 
     640               0 : NS_IMETHODIMP nsImageLoadingContent::ForceReload()
     641                 : {
     642               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     643                 : 
     644               0 :   nsCOMPtr<nsIURI> currentURI;
     645               0 :   GetCurrentURI(getter_AddRefs(currentURI));
     646               0 :   if (!currentURI) {
     647               0 :     return NS_ERROR_NOT_AVAILABLE;
     648                 :   }
     649                 : 
     650               0 :   return LoadImage(currentURI, true, true, nsnull, nsIRequest::VALIDATE_ALWAYS);
     651                 : }
     652                 : 
     653                 : /*
     654                 :  * Non-interface methods
     655                 :  */
     656                 : 
     657                 : void
     658               0 : nsImageLoadingContent::NotifyOwnerDocumentChanged(nsIDocument *aOldDoc)
     659                 : {
     660                 :   // If we had a document before, unregister ourselves with it.
     661               0 :   if (aOldDoc) {
     662               0 :     if (mCurrentRequest)
     663               0 :       aOldDoc->RemoveImage(mCurrentRequest);
     664               0 :     if (mPendingRequest)
     665               0 :       aOldDoc->RemoveImage(mPendingRequest);
     666                 :   }
     667                 : 
     668                 :   // Re-track the images
     669               0 :   TrackImage(mCurrentRequest);
     670               0 :   TrackImage(mPendingRequest);
     671               0 : }
     672                 : 
     673                 : nsresult
     674               0 : nsImageLoadingContent::LoadImage(const nsAString& aNewURI,
     675                 :                                  bool aForce,
     676                 :                                  bool aNotify)
     677                 : {
     678                 :   // First, get a document (needed for security checks and the like)
     679               0 :   nsIDocument* doc = GetOurDocument();
     680               0 :   if (!doc) {
     681                 :     // No reason to bother, I think...
     682               0 :     return NS_OK;
     683                 :   }
     684                 : 
     685               0 :   nsCOMPtr<nsIURI> imageURI;
     686               0 :   nsresult rv = StringToURI(aNewURI, doc, getter_AddRefs(imageURI));
     687               0 :   NS_ENSURE_SUCCESS(rv, rv);
     688                 :   // XXXbiesi fire onerror if that failed?
     689                 : 
     690                 :   bool equal;
     691                 : 
     692               0 :   if (aNewURI.IsEmpty() &&
     693               0 :       doc->GetDocumentURI() &&
     694               0 :       NS_SUCCEEDED(doc->GetDocumentURI()->Equals(imageURI, &equal)) && 
     695                 :       equal)  {
     696                 : 
     697                 :     // Loading an embedded img from the same URI as the document URI will not work
     698                 :     // as a resource cannot recursively embed itself. Attempting to do so generally
     699                 :     // results in having to pre-emptively close down an in-flight HTTP transaction 
     700                 :     // and then incurring the significant cost of establishing a new TCP channel.
     701                 :     // This is generally triggered from <img src=""> 
     702                 :     // In light of that, just skip loading it..
     703                 :     // Do make sure to drop our existing image, if any
     704               0 :     CancelImageRequests(aNotify);
     705               0 :     return NS_OK;
     706                 :   }
     707                 : 
     708               0 :   NS_TryToSetImmutable(imageURI);
     709                 : 
     710               0 :   return LoadImage(imageURI, aForce, aNotify, doc);
     711                 : }
     712                 : 
     713                 : nsresult
     714               0 : nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
     715                 :                                  bool aForce,
     716                 :                                  bool aNotify,
     717                 :                                  nsIDocument* aDocument,
     718                 :                                  nsLoadFlags aLoadFlags)
     719                 : {
     720               0 :   if (!mLoadingEnabled) {
     721                 :     // XXX Why fire an error here? seems like the callers to SetLoadingEnabled
     722                 :     // don't want/need it.
     723               0 :     FireEvent(NS_LITERAL_STRING("error"));
     724               0 :     return NS_OK;
     725                 :   }
     726                 : 
     727               0 :   NS_ASSERTION(!aDocument || aDocument == GetOurDocument(),
     728                 :                "Bogus document passed in");
     729                 :   // First, get a document (needed for security checks and the like)
     730               0 :   if (!aDocument) {
     731               0 :     aDocument = GetOurDocument();
     732               0 :     if (!aDocument) {
     733                 :       // No reason to bother, I think...
     734               0 :       return NS_OK;
     735                 :     }
     736                 :   }
     737                 : 
     738                 :   // URI equality check.
     739                 :   //
     740                 :   // We skip the equality check if our current image was blocked, since in that
     741                 :   // case we really do want to try loading again.
     742               0 :   if (!aForce && NS_CP_ACCEPTED(mImageBlockingStatus)) {
     743               0 :     nsCOMPtr<nsIURI> currentURI;
     744               0 :     GetCurrentURI(getter_AddRefs(currentURI));
     745                 :     bool equal;
     746               0 :     if (currentURI &&
     747               0 :         NS_SUCCEEDED(currentURI->Equals(aNewURI, &equal)) &&
     748                 :         equal) {
     749                 :       // Nothing to do here.
     750               0 :       return NS_OK;
     751                 :     }
     752                 :   }
     753                 : 
     754                 :   // From this point on, our image state could change. Watch it.
     755               0 :   AutoStateChanger changer(this, aNotify);
     756                 : 
     757                 :   // Sanity check.
     758                 :   //
     759                 :   // We use the principal of aDocument to avoid having to QI |this| an extra
     760                 :   // time. It should always be the same as the principal of this node.
     761                 : #ifdef DEBUG
     762               0 :   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
     763               0 :   NS_ABORT_IF_FALSE(thisContent &&
     764                 :                     thisContent->NodePrincipal() == aDocument->NodePrincipal(),
     765                 :                     "Principal mismatch?");
     766                 : #endif
     767                 : 
     768                 :   // Are we blocked?
     769               0 :   PRInt16 cpDecision = nsIContentPolicy::REJECT_REQUEST;
     770                 :   nsContentUtils::CanLoadImage(aNewURI, this, aDocument,
     771               0 :                                aDocument->NodePrincipal(), &cpDecision);
     772               0 :   if (!NS_CP_ACCEPTED(cpDecision)) {
     773               0 :     FireEvent(NS_LITERAL_STRING("error"));
     774               0 :     SetBlockedRequest(aNewURI, cpDecision);
     775               0 :     return NS_OK;
     776                 :   }
     777                 : 
     778               0 :   nsLoadFlags loadFlags = aLoadFlags;
     779               0 :   PRInt32 corsmode = GetCORSMode();
     780               0 :   if (corsmode == CORS_ANONYMOUS) {
     781               0 :     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
     782               0 :   } else if (corsmode == CORS_USE_CREDENTIALS) {
     783               0 :     loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
     784                 :   }
     785                 : 
     786                 :   // Not blocked. Do the load.
     787               0 :   nsCOMPtr<imgIRequest>& req = PrepareNextRequest();
     788                 :   nsresult rv;
     789                 :   rv = nsContentUtils::LoadImage(aNewURI, aDocument,
     790                 :                                  aDocument->NodePrincipal(),
     791                 :                                  aDocument->GetDocumentURI(),
     792                 :                                  this, loadFlags,
     793               0 :                                  getter_AddRefs(req));
     794               0 :   if (NS_SUCCEEDED(rv)) {
     795               0 :     TrackImage(req);
     796                 :   } else {
     797                 :     // If we don't have a current URI, we might as well store this URI so people
     798                 :     // know what we tried (and failed) to load.
     799               0 :     if (!mCurrentRequest)
     800               0 :       mCurrentURI = aNewURI;
     801               0 :     FireEvent(NS_LITERAL_STRING("error"));
     802               0 :     return NS_OK;
     803                 :   }
     804                 : 
     805               0 :   return NS_OK;
     806                 : }
     807                 : 
     808                 : nsresult
     809               0 : nsImageLoadingContent::ForceImageState(bool aForce, nsEventStates::InternalType aState)
     810                 : {
     811               0 :   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
     812                 : 
     813               0 :   mIsImageStateForced = aForce;
     814               0 :   mForcedImageState = nsEventStates(aState);
     815               0 :   return NS_OK;
     816                 : }
     817                 : 
     818                 : nsEventStates
     819               0 : nsImageLoadingContent::ImageState() const
     820                 : {
     821               0 :   if (mIsImageStateForced) {
     822               0 :     return mForcedImageState;
     823                 :   }
     824                 : 
     825               0 :   nsEventStates states;
     826                 : 
     827               0 :   if (mBroken) {
     828               0 :     states |= NS_EVENT_STATE_BROKEN;
     829                 :   }
     830               0 :   if (mUserDisabled) {
     831               0 :     states |= NS_EVENT_STATE_USERDISABLED;
     832                 :   }
     833               0 :   if (mSuppressed) {
     834               0 :     states |= NS_EVENT_STATE_SUPPRESSED;
     835                 :   }
     836               0 :   if (mLoading) {
     837               0 :     states |= NS_EVENT_STATE_LOADING;
     838                 :   }
     839                 : 
     840               0 :   return states;
     841                 : }
     842                 : 
     843                 : void
     844               0 : nsImageLoadingContent::UpdateImageState(bool aNotify)
     845                 : {
     846               0 :   if (mStateChangerDepth > 0) {
     847                 :     // Ignore this call; we'll update our state when the outermost state
     848                 :     // changer is destroyed. Need this to work around the fact that some libpr0n
     849                 :     // stuff is actually sync and hence we can get OnStopDecode called while
     850                 :     // we're still under LoadImage, and OnStopDecode doesn't know anything about
     851                 :     // aNotify.
     852                 :     // XXX - This machinery should be removed after bug 521604.
     853               0 :     return;
     854                 :   }
     855                 :   
     856               0 :   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
     857               0 :   if (!thisContent) {
     858                 :     return;
     859                 :   }
     860                 : 
     861               0 :   mLoading = mBroken = mUserDisabled = mSuppressed = false;
     862                 :   
     863                 :   // If we were blocked by server-based content policy, we claim to be
     864                 :   // suppressed.  If we were blocked by type-based content policy, we claim to
     865                 :   // be user-disabled.  Otherwise, claim to be broken.
     866               0 :   if (mImageBlockingStatus == nsIContentPolicy::REJECT_SERVER) {
     867               0 :     mSuppressed = true;
     868               0 :   } else if (mImageBlockingStatus == nsIContentPolicy::REJECT_TYPE) {
     869               0 :     mUserDisabled = true;
     870               0 :   } else if (!mCurrentRequest) {
     871                 :     // No current request means error, since we weren't disabled or suppressed
     872               0 :     mBroken = true;
     873                 :   } else {
     874                 :     PRUint32 currentLoadStatus;
     875               0 :     nsresult rv = mCurrentRequest->GetImageStatus(&currentLoadStatus);
     876               0 :     if (NS_FAILED(rv) || (currentLoadStatus & imgIRequest::STATUS_ERROR)) {
     877               0 :       mBroken = true;
     878               0 :     } else if (!(currentLoadStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) {
     879               0 :       mLoading = true;
     880                 :     }
     881                 :   }
     882                 : 
     883               0 :   NS_ASSERTION(thisContent->IsElement(), "Not an element?");
     884               0 :   thisContent->AsElement()->UpdateState(aNotify);
     885                 : }
     886                 : 
     887                 : void
     888               0 : nsImageLoadingContent::CancelImageRequests(bool aNotify)
     889                 : {
     890               0 :   AutoStateChanger changer(this, aNotify);
     891               0 :   ClearPendingRequest(NS_BINDING_ABORTED);
     892               0 :   ClearCurrentRequest(NS_BINDING_ABORTED);
     893               0 : }
     894                 : 
     895                 : nsresult
     896               0 : nsImageLoadingContent::UseAsPrimaryRequest(imgIRequest* aRequest,
     897                 :                                            bool aNotify)
     898                 : {
     899                 :   // Our state will change. Watch it.
     900               0 :   AutoStateChanger changer(this, aNotify);
     901                 : 
     902                 :   // Get rid if our existing images
     903               0 :   ClearPendingRequest(NS_BINDING_ABORTED);
     904               0 :   ClearCurrentRequest(NS_BINDING_ABORTED);
     905                 : 
     906                 :   // Clone the request we were given.
     907               0 :   nsCOMPtr<imgIRequest>& req = PrepareNextRequest();;
     908               0 :   nsresult rv = aRequest->Clone(this, getter_AddRefs(req));
     909               0 :   if (NS_SUCCEEDED(rv))
     910               0 :     TrackImage(req);
     911                 :   else
     912               0 :     return rv;
     913                 : 
     914               0 :   return NS_OK;
     915                 : }
     916                 : 
     917                 : nsIDocument*
     918               0 : nsImageLoadingContent::GetOurDocument()
     919                 : {
     920               0 :   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
     921               0 :   NS_ENSURE_TRUE(thisContent, nsnull);
     922                 : 
     923               0 :   return thisContent->OwnerDoc();
     924                 : }
     925                 : 
     926                 : nsIFrame*
     927               0 : nsImageLoadingContent::GetOurPrimaryFrame()
     928                 : {
     929               0 :   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
     930               0 :   return thisContent->GetPrimaryFrame();
     931                 : }
     932                 : 
     933               0 : nsPresContext* nsImageLoadingContent::GetFramePresContext()
     934                 : {
     935               0 :   nsIFrame* frame = GetOurPrimaryFrame();
     936               0 :   if (!frame) {
     937               0 :     return nsnull;
     938                 :   }
     939                 : 
     940               0 :   return frame->PresContext();
     941                 : }
     942                 : 
     943                 : nsresult
     944               0 : nsImageLoadingContent::StringToURI(const nsAString& aSpec,
     945                 :                                    nsIDocument* aDocument,
     946                 :                                    nsIURI** aURI)
     947                 : {
     948               0 :   NS_PRECONDITION(aDocument, "Must have a document");
     949               0 :   NS_PRECONDITION(aURI, "Null out param");
     950                 : 
     951                 :   // (1) Get the base URI
     952               0 :   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(this);
     953               0 :   NS_ASSERTION(thisContent, "An image loading content must be an nsIContent");
     954               0 :   nsCOMPtr<nsIURI> baseURL = thisContent->GetBaseURI();
     955                 : 
     956                 :   // (2) Get the charset
     957               0 :   const nsAFlatCString &charset = aDocument->GetDocumentCharacterSet();
     958                 : 
     959                 :   // (3) Construct the silly thing
     960                 :   return NS_NewURI(aURI,
     961                 :                    aSpec,
     962               0 :                    charset.IsEmpty() ? nsnull : charset.get(),
     963                 :                    baseURL,
     964               0 :                    nsContentUtils::GetIOService());
     965                 : }
     966                 : 
     967                 : nsresult
     968               0 : nsImageLoadingContent::FireEvent(const nsAString& aEventType)
     969                 : {
     970                 :   // We have to fire the event asynchronously so that we won't go into infinite
     971                 :   // loops in cases when onLoad handlers reset the src and the new src is in
     972                 :   // cache.
     973                 : 
     974               0 :   nsCOMPtr<nsINode> thisNode = do_QueryInterface(this);
     975                 : 
     976                 :   nsRefPtr<nsAsyncDOMEvent> event =
     977               0 :     new nsLoadBlockingAsyncDOMEvent(thisNode, aEventType, false, false);
     978               0 :   event->PostDOMEvent();
     979                 :   
     980               0 :   return NS_OK;
     981                 : }
     982                 : 
     983                 : nsCOMPtr<imgIRequest>&
     984               0 : nsImageLoadingContent::PrepareNextRequest()
     985                 : {
     986                 :   // If we don't have a usable current request, get rid of any half-baked
     987                 :   // request that might be sitting there and make this one current.
     988               0 :   if (!HaveSize(mCurrentRequest))
     989               0 :     return PrepareCurrentRequest();
     990                 : 
     991                 :   // Otherwise, make it pending.
     992               0 :   return PreparePendingRequest();
     993                 : }
     994                 : 
     995                 : void
     996               0 : nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, PRInt16 aContentDecision)
     997                 : {
     998                 :   // Sanity
     999               0 :   NS_ABORT_IF_FALSE(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?");
    1000                 : 
    1001                 :   // We do some slightly illogical stuff here to maintain consistency with
    1002                 :   // old behavior that people probably depend on. Even in the case where the
    1003                 :   // new image is blocked, the old one should really be canceled with the
    1004                 :   // reason "image source changed". However, apparently there's some abuse
    1005                 :   // over in nsImageFrame where the displaying of the "broken" icon for the
    1006                 :   // next image depends on the cancel reason of the previous image. ugh.
    1007               0 :   ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED);
    1008                 : 
    1009                 :   // For the blocked case, we only want to cancel the existing current request
    1010                 :   // if size is not available. bz says the web depends on this behavior.
    1011               0 :   if (!HaveSize(mCurrentRequest)) {
    1012                 : 
    1013               0 :     mImageBlockingStatus = aContentDecision;
    1014               0 :     ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED);
    1015                 : 
    1016                 :     // We still want to remember what URI we were despite not having an actual
    1017                 :     // request.
    1018               0 :     mCurrentURI = aURI;
    1019                 :   }
    1020               0 : }
    1021                 : 
    1022                 : nsCOMPtr<imgIRequest>&
    1023               0 : nsImageLoadingContent::PrepareCurrentRequest()
    1024                 : {
    1025                 :   // Blocked images go through SetBlockedRequest, which is a separate path. For
    1026                 :   // everything else, we're unblocked.
    1027               0 :   mImageBlockingStatus = nsIContentPolicy::ACCEPT;
    1028                 : 
    1029                 :   // Get rid of anything that was there previously.
    1030               0 :   ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED);
    1031                 : 
    1032               0 :   mCurrentRequestNeedsResetAnimation = mNewRequestsWillNeedAnimationReset;
    1033                 : 
    1034                 :   // Return a reference.
    1035               0 :   return mCurrentRequest;
    1036                 : }
    1037                 : 
    1038                 : nsCOMPtr<imgIRequest>&
    1039               0 : nsImageLoadingContent::PreparePendingRequest()
    1040                 : {
    1041                 :   // Get rid of anything that was there previously.
    1042               0 :   ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED);
    1043                 : 
    1044               0 :   mPendingRequestNeedsResetAnimation = mNewRequestsWillNeedAnimationReset;
    1045                 : 
    1046                 :   // Return a reference.
    1047               0 :   return mPendingRequest;
    1048                 : }
    1049                 : 
    1050                 : void
    1051               1 : nsImageLoadingContent::ClearCurrentRequest(nsresult aReason)
    1052                 : {
    1053               1 :   if (!mCurrentRequest) {
    1054                 :     // Even if we didn't have a current request, we might have been keeping
    1055                 :     // a URI as a placeholder for a failed load. Clear that now.
    1056               1 :     mCurrentURI = nsnull;
    1057               1 :     return;
    1058                 :   }
    1059               0 :   NS_ABORT_IF_FALSE(!mCurrentURI,
    1060                 :                     "Shouldn't have both mCurrentRequest and mCurrentURI!");
    1061                 : 
    1062                 :   // Deregister this image from the refresh driver so it no longer receives
    1063                 :   // notifications.
    1064                 :   nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mCurrentRequest,
    1065               0 :                                         &mCurrentRequestRegistered);
    1066                 : 
    1067                 :   // Clean up the request.
    1068               0 :   UntrackImage(mCurrentRequest);
    1069               0 :   mCurrentRequest->CancelAndForgetObserver(aReason);
    1070               0 :   mCurrentRequest = nsnull;
    1071               0 :   mCurrentRequestNeedsResetAnimation = false;
    1072                 : 
    1073                 :   // We only block onload during the decoding of "current" images. This one is
    1074                 :   // going away, so we should unblock unconditionally here.
    1075               0 :   SetBlockingOnload(false);
    1076                 : }
    1077                 : 
    1078                 : void
    1079               1 : nsImageLoadingContent::ClearPendingRequest(nsresult aReason)
    1080                 : {
    1081               1 :   if (!mPendingRequest)
    1082               1 :     return;
    1083                 : 
    1084                 :   // Push a null JSContext on the stack so that code that runs within
    1085                 :   // the below code doesn't think it's being called by JS. See bug
    1086                 :   // 604262.
    1087               0 :   nsCxPusher pusher;
    1088               0 :   pusher.PushNull();
    1089                 : 
    1090                 :   // Deregister this image from the refresh driver so it no longer receives
    1091                 :   // notifications.
    1092                 :   nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
    1093               0 :                                         &mPendingRequestRegistered);
    1094                 : 
    1095               0 :   UntrackImage(mPendingRequest);
    1096               0 :   mPendingRequest->CancelAndForgetObserver(aReason);
    1097               0 :   mPendingRequest = nsnull;
    1098               0 :   mPendingRequestNeedsResetAnimation = false;
    1099                 : }
    1100                 : 
    1101                 : bool*
    1102               0 : nsImageLoadingContent::GetRegisteredFlagForRequest(imgIRequest* aRequest)
    1103                 : {
    1104               0 :   if (aRequest == mCurrentRequest) {
    1105               0 :     return &mCurrentRequestRegistered;
    1106               0 :   } else if (aRequest == mPendingRequest) {
    1107               0 :     return &mPendingRequestRegistered;
    1108                 :   } else {
    1109               0 :     return nsnull;
    1110                 :   }
    1111                 : }
    1112                 : 
    1113                 : bool
    1114               0 : nsImageLoadingContent::HaveSize(imgIRequest *aImage)
    1115                 : {
    1116                 :   // Handle the null case
    1117               0 :   if (!aImage)
    1118               0 :     return false;
    1119                 : 
    1120                 :   // Query the image
    1121                 :   PRUint32 status;
    1122               0 :   nsresult rv = aImage->GetImageStatus(&status);
    1123               0 :   return (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_SIZE_AVAILABLE));
    1124                 : }
    1125                 : 
    1126                 : void
    1127               0 : nsImageLoadingContent::SetBlockingOnload(bool aBlocking)
    1128                 : {
    1129                 :   // If we're already in the desired state, we have nothing to do
    1130               0 :   if (mBlockingOnload == aBlocking)
    1131               0 :     return;
    1132                 : 
    1133                 :   // Get the document
    1134               0 :   nsIDocument* doc = GetOurDocument();
    1135                 : 
    1136               0 :   if (doc) {
    1137                 :     // Take the appropriate action
    1138               0 :     if (aBlocking)
    1139               0 :       doc->BlockOnload();
    1140                 :     else
    1141               0 :       doc->UnblockOnload(false);
    1142                 : 
    1143                 :     // Update our state
    1144               0 :     mBlockingOnload = aBlocking;
    1145                 :   }
    1146                 : }
    1147                 : 
    1148                 : nsresult
    1149               0 : nsImageLoadingContent::TrackImage(imgIRequest* aImage)
    1150                 : {
    1151               0 :   if (!aImage)
    1152               0 :     return NS_OK;
    1153                 : 
    1154               0 :   nsIDocument* doc = GetOurDocument();
    1155               0 :   if (doc)
    1156               0 :     return doc->AddImage(aImage);
    1157               0 :   return NS_OK;
    1158                 : }
    1159                 : 
    1160                 : nsresult
    1161               0 : nsImageLoadingContent::UntrackImage(imgIRequest* aImage)
    1162                 : {
    1163               0 :   if (!aImage)
    1164               0 :     return NS_OK;
    1165                 : 
    1166                 :   // If GetOurDocument() returns null here, we've outlived our document.
    1167                 :   // That's fine, because the document empties out the tracker and unlocks
    1168                 :   // all locked images on destruction.
    1169               0 :   nsIDocument* doc = GetOurDocument();
    1170               0 :   if (doc)
    1171               0 :     return doc->RemoveImage(aImage);
    1172               0 :   return NS_OK;
    1173                 : }
    1174                 : 
    1175                 : 
    1176                 : void
    1177               0 : nsImageLoadingContent::CreateStaticImageClone(nsImageLoadingContent* aDest) const
    1178                 : {
    1179               0 :   aDest->mCurrentRequest = nsContentUtils::GetStaticRequest(mCurrentRequest);
    1180               0 :   aDest->TrackImage(aDest->mCurrentRequest);
    1181               0 :   aDest->mForcedImageState = mForcedImageState;
    1182               0 :   aDest->mImageBlockingStatus = mImageBlockingStatus;
    1183               0 :   aDest->mLoadingEnabled = mLoadingEnabled;
    1184               0 :   aDest->mStateChangerDepth = mStateChangerDepth;
    1185               0 :   aDest->mIsImageStateForced = mIsImageStateForced;
    1186               0 :   aDest->mLoading = mLoading;
    1187               0 :   aDest->mBroken = mBroken;
    1188               0 :   aDest->mUserDisabled = mUserDisabled;
    1189               0 :   aDest->mSuppressed = mSuppressed;
    1190               0 : }
    1191                 : 
    1192                 : CORSMode
    1193               0 : nsImageLoadingContent::GetCORSMode()
    1194                 : {
    1195               0 :   return CORS_NONE;
    1196                 : }

Generated by: LCOV version 1.7