LCOV - app.info - content/base/src/nsImageLoadingContent.cpp

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-07-07 | 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