content/base/src/nsImageLoadingContent.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     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 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * A base class which implements nsIImageLoadingContent and can be
     9  * subclassed by various content nodes that want to provide image
    10  * loading functionality (eg <img>, <object>, etc).
    11  */
    13 #include "nsImageLoadingContent.h"
    14 #include "nsAutoPtr.h"
    15 #include "nsError.h"
    16 #include "nsIContent.h"
    17 #include "nsIDocument.h"
    18 #include "nsIScriptGlobalObject.h"
    19 #include "nsIDOMWindow.h"
    20 #include "nsServiceManagerUtils.h"
    21 #include "nsContentPolicyUtils.h"
    22 #include "nsIURI.h"
    23 #include "nsILoadGroup.h"
    24 #include "imgIContainer.h"
    25 #include "imgLoader.h"
    26 #include "imgRequestProxy.h"
    27 #include "nsThreadUtils.h"
    28 #include "nsNetUtil.h"
    29 #include "nsImageFrame.h"
    31 #include "nsIPresShell.h"
    33 #include "nsIChannel.h"
    34 #include "nsIStreamListener.h"
    36 #include "nsIFrame.h"
    37 #include "nsIDOMNode.h"
    39 #include "nsContentUtils.h"
    40 #include "nsLayoutUtils.h"
    41 #include "nsIContentPolicy.h"
    42 #include "nsSVGEffects.h"
    44 #include "mozAutoDocUpdate.h"
    45 #include "mozilla/AsyncEventDispatcher.h"
    46 #include "mozilla/EventStates.h"
    47 #include "mozilla/dom/Element.h"
    48 #include "mozilla/dom/ScriptSettings.h"
    50 #ifdef LoadImage
    51 // Undefine LoadImage to prevent naming conflict with Windows.
    52 #undef LoadImage
    53 #endif
    55 using namespace mozilla;
    57 #ifdef DEBUG_chb
    58 static void PrintReqURL(imgIRequest* req) {
    59   if (!req) {
    60     printf("(null req)\n");
    61     return;
    62   }
    64   nsCOMPtr<nsIURI> uri;
    65   req->GetURI(getter_AddRefs(uri));
    66   if (!uri) {
    67     printf("(null uri)\n");
    68     return;
    69   }
    71   nsAutoCString spec;
    72   uri->GetSpec(spec);
    73   printf("spec='%s'\n", spec.get());
    74 }
    75 #endif /* DEBUG_chb */
    78 nsImageLoadingContent::nsImageLoadingContent()
    79   : mCurrentRequestFlags(0),
    80     mPendingRequestFlags(0),
    81     mObserverList(nullptr),
    82     mImageBlockingStatus(nsIContentPolicy::ACCEPT),
    83     mLoadingEnabled(true),
    84     mIsImageStateForced(false),
    85     mLoading(false),
    86     // mBroken starts out true, since an image without a URI is broken....
    87     mBroken(true),
    88     mUserDisabled(false),
    89     mSuppressed(false),
    90     mFireEventsOnDecode(false),
    91     mNewRequestsWillNeedAnimationReset(false),
    92     mStateChangerDepth(0),
    93     mCurrentRequestRegistered(false),
    94     mPendingRequestRegistered(false),
    95     mFrameCreateCalled(false),
    96     mVisibleCount(0)
    97 {
    98   if (!nsContentUtils::GetImgLoaderForChannel(nullptr)) {
    99     mLoadingEnabled = false;
   100   }
   101 }
   103 void
   104 nsImageLoadingContent::DestroyImageLoadingContent()
   105 {
   106   // Cancel our requests so they won't hold stale refs to us
   107   // NB: Don't ask to discard the images here.
   108   ClearCurrentRequest(NS_BINDING_ABORTED, 0);
   109   ClearPendingRequest(NS_BINDING_ABORTED, 0);
   110 }
   112 nsImageLoadingContent::~nsImageLoadingContent()
   113 {
   114   NS_ASSERTION(!mCurrentRequest && !mPendingRequest,
   115                "DestroyImageLoadingContent not called");
   116   NS_ASSERTION(!mObserverList.mObserver && !mObserverList.mNext,
   117                "Observers still registered?");
   118 }
   120 /*
   121  * imgINotificationObserver impl
   122  */
   123 NS_IMETHODIMP
   124 nsImageLoadingContent::Notify(imgIRequest* aRequest,
   125                               int32_t aType,
   126                               const nsIntRect* aData)
   127 {
   128   if (aType == imgINotificationObserver::IS_ANIMATED) {
   129     return OnImageIsAnimated(aRequest);
   130   }
   132   if (aType == imgINotificationObserver::UNLOCKED_DRAW) {
   133     OnUnlockedDraw();
   134     return NS_OK;
   135   }
   137   if (aType == imgINotificationObserver::LOAD_COMPLETE) {
   138     // We should definitely have a request here
   139     NS_ABORT_IF_FALSE(aRequest, "no request?");
   141     NS_PRECONDITION(aRequest == mCurrentRequest || aRequest == mPendingRequest,
   142                     "Unknown request");
   143   }
   145   {
   146     nsAutoScriptBlocker scriptBlocker;
   148     for (ImageObserver* observer = &mObserverList, *next; observer;
   149          observer = next) {
   150       next = observer->mNext;
   151       if (observer->mObserver) {
   152         observer->mObserver->Notify(aRequest, aType, aData);
   153       }
   154     }
   155   }
   157   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
   158     // Have to check for state changes here, since we might have been in
   159     // the LOADING state before.
   160     UpdateImageState(true);
   161   }
   163   if (aType == imgINotificationObserver::LOAD_COMPLETE) {
   164     uint32_t reqStatus;
   165     aRequest->GetImageStatus(&reqStatus);
   166     nsresult status =
   167         reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
   168     return OnStopRequest(aRequest, status);
   169   }
   171   if (aType == imgINotificationObserver::DECODE_COMPLETE && mFireEventsOnDecode) {
   172     mFireEventsOnDecode = false;
   174     uint32_t reqStatus;
   175     aRequest->GetImageStatus(&reqStatus);
   176     if (reqStatus & imgIRequest::STATUS_ERROR) {
   177       FireEvent(NS_LITERAL_STRING("error"));
   178     } else {
   179       FireEvent(NS_LITERAL_STRING("load"));
   180     }
   182     UpdateImageState(true);
   183   }
   185   return NS_OK;
   186 }
   188 nsresult
   189 nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest,
   190                                      nsresult aStatus)
   191 {
   192   uint32_t oldStatus;
   193   aRequest->GetImageStatus(&oldStatus);
   195   //XXXjdm This occurs when we have a pending request created, then another
   196   //       pending request replaces it before the first one is finished.
   197   //       This begs the question of what the correct behaviour is; we used
   198   //       to not have to care because we ran this code in OnStopDecode which
   199   //       wasn't called when the first request was cancelled. For now, I choose
   200   //       to punt when the given request doesn't appear to have terminated in
   201   //       an expected state.
   202   if (!(oldStatus & (imgIRequest::STATUS_ERROR | imgIRequest::STATUS_LOAD_COMPLETE)))
   203     return NS_OK;
   205   // Our state may change. Watch it.
   206   AutoStateChanger changer(this, true);
   208   // If the pending request is loaded, switch to it.
   209   if (aRequest == mPendingRequest) {
   210     MakePendingRequestCurrent();
   211   }
   212   NS_ABORT_IF_FALSE(aRequest == mCurrentRequest,
   213                     "One way or another, we should be current by now");
   215   // We just loaded all the data we're going to get. If we're visible and
   216   // haven't done an initial paint (*), we want to make sure the image starts
   217   // decoding immediately, for two reasons:
   218   //
   219   // 1) This image is sitting idle but might need to be decoded as soon as we
   220   // start painting, in which case we've wasted time.
   221   //
   222   // 2) We want to block onload until all visible images are decoded. We do this
   223   // by blocking onload until all in-progress decodes get at least one frame
   224   // decoded. However, if all the data comes in while painting is suppressed
   225   // (ie, before the initial paint delay is finished), we fire onload without
   226   // doing a paint first. This means that decode-on-draw images don't start
   227   // decoding, so we can't wait for them to finish. See bug 512435.
   228   //
   229   // (*) IsPaintingSuppressed returns false if we haven't gotten the initial
   230   // reflow yet, so we have to test !DidInitialize || IsPaintingSuppressed.
   231   // It's possible for painting to be suppressed for reasons other than the
   232   // initial paint delay (for example, being in the bfcache), but we probably
   233   // aren't loading images in those situations.
   235   // XXXkhuey should this be GetOurCurrentDoc?  Decoding if we're not in
   236   // the document seems silly.
   237   bool startedDecoding = false;
   238   nsIDocument* doc = GetOurOwnerDoc();
   239   nsIPresShell* shell = doc ? doc->GetShell() : nullptr;
   240   if (shell && shell->IsVisible() &&
   241       (!shell->DidInitialize() || shell->IsPaintingSuppressed())) {
   243     // If we've gotten a frame and that frame has called FrameCreate and that
   244     // frame has been reflowed then we know that it checked it's own visibility
   245     // so we can trust our visible count and we don't start decode if we are not
   246     // visible.
   247     nsIFrame* f = GetOurPrimaryFrame();
   248     if (!mFrameCreateCalled || !f || (f->GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
   249         mVisibleCount > 0 || shell->AssumeAllImagesVisible()) {
   250       if (NS_SUCCEEDED(mCurrentRequest->StartDecoding())) {
   251         startedDecoding = true;
   252       }
   253     }
   254   }
   256   // We want to give the decoder a chance to find errors. If we haven't found
   257   // an error yet and we've started decoding, either from the above
   258   // StartDecoding or from some other place, we must only fire these events
   259   // after we finish decoding.
   260   uint32_t reqStatus;
   261   aRequest->GetImageStatus(&reqStatus);
   262   if (NS_SUCCEEDED(aStatus) && !(reqStatus & imgIRequest::STATUS_ERROR) &&
   263       (reqStatus & imgIRequest::STATUS_DECODE_STARTED ||
   264        (startedDecoding && !(reqStatus & imgIRequest::STATUS_DECODE_COMPLETE)))) {
   265     mFireEventsOnDecode = true;
   266   } else {
   267     // Fire the appropriate DOM event.
   268     if (NS_SUCCEEDED(aStatus)) {
   269       FireEvent(NS_LITERAL_STRING("load"));
   270     } else {
   271       FireEvent(NS_LITERAL_STRING("error"));
   272     }
   273   }
   275   nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   276   nsSVGEffects::InvalidateDirectRenderingObservers(thisNode->AsElement());
   278   return NS_OK;
   279 }
   281 void
   282 nsImageLoadingContent::OnUnlockedDraw()
   283 {
   284   if (mVisibleCount > 0) {
   285     // We should already be marked as visible, there is nothing more we can do.
   286     return;
   287   }
   289   nsPresContext* presContext = GetFramePresContext();
   290   if (!presContext)
   291     return;
   293   nsIPresShell* presShell = presContext->PresShell();
   294   if (!presShell)
   295     return;
   297   presShell->EnsureImageInVisibleList(this);
   298 }
   300 nsresult
   301 nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
   302 {
   303   bool* requestFlag = GetRegisteredFlagForRequest(aRequest);
   304   if (requestFlag) {
   305     nsLayoutUtils::RegisterImageRequest(GetFramePresContext(),
   306                                         aRequest, requestFlag);
   307   }
   309   return NS_OK;
   310 }
   312 /*
   313  * nsIImageLoadingContent impl
   314  */
   316 NS_IMETHODIMP
   317 nsImageLoadingContent::GetLoadingEnabled(bool *aLoadingEnabled)
   318 {
   319   *aLoadingEnabled = mLoadingEnabled;
   320   return NS_OK;
   321 }
   323 NS_IMETHODIMP
   324 nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled)
   325 {
   326   if (nsContentUtils::GetImgLoaderForChannel(nullptr)) {
   327     mLoadingEnabled = aLoadingEnabled;
   328   }
   329   return NS_OK;
   330 }
   332 NS_IMETHODIMP
   333 nsImageLoadingContent::GetImageBlockingStatus(int16_t* aStatus)
   334 {
   335   NS_PRECONDITION(aStatus, "Null out param");
   336   *aStatus = ImageBlockingStatus();
   337   return NS_OK;
   338 }
   340 NS_IMETHODIMP
   341 nsImageLoadingContent::AddObserver(imgINotificationObserver* aObserver)
   342 {
   343   NS_ENSURE_ARG_POINTER(aObserver);
   345   if (!mObserverList.mObserver) {
   346     mObserverList.mObserver = aObserver;
   347     // Don't touch the linking of the list!
   348     return NS_OK;
   349   }
   351   // otherwise we have to create a new entry
   353   ImageObserver* observer = &mObserverList;
   354   while (observer->mNext) {
   355     observer = observer->mNext;
   356   }
   358   observer->mNext = new ImageObserver(aObserver);
   359   if (! observer->mNext) {
   360     return NS_ERROR_OUT_OF_MEMORY;
   361   }
   363   return NS_OK;
   364 }
   366 NS_IMETHODIMP
   367 nsImageLoadingContent::RemoveObserver(imgINotificationObserver* aObserver)
   368 {
   369   NS_ENSURE_ARG_POINTER(aObserver);
   371   if (mObserverList.mObserver == aObserver) {
   372     mObserverList.mObserver = nullptr;
   373     // Don't touch the linking of the list!
   374     return NS_OK;
   375   }
   377   // otherwise have to find it and splice it out
   378   ImageObserver* observer = &mObserverList;
   379   while (observer->mNext && observer->mNext->mObserver != aObserver) {
   380     observer = observer->mNext;
   381   }
   383   // At this point, we are pointing to the list element whose mNext is
   384   // the right observer (assuming of course that mNext is not null)
   385   if (observer->mNext) {
   386     // splice it out
   387     ImageObserver* oldObserver = observer->mNext;
   388     observer->mNext = oldObserver->mNext;
   389     oldObserver->mNext = nullptr;  // so we don't destroy them all
   390     delete oldObserver;
   391   }
   392 #ifdef DEBUG
   393   else {
   394     NS_WARNING("Asked to remove nonexistent observer");
   395   }
   396 #endif
   397   return NS_OK;
   398 }
   400 already_AddRefed<imgIRequest>
   401 nsImageLoadingContent::GetRequest(int32_t aRequestType,
   402                                   ErrorResult& aError)
   403 {
   404   nsCOMPtr<imgIRequest> request;
   405   switch(aRequestType) {
   406   case CURRENT_REQUEST:
   407     request = mCurrentRequest;
   408     break;
   409   case PENDING_REQUEST:
   410     request = mPendingRequest;
   411     break;
   412   default:
   413     NS_ERROR("Unknown request type");
   414     aError.Throw(NS_ERROR_UNEXPECTED);
   415   }
   417   return request.forget();
   418 }
   420 NS_IMETHODIMP
   421 nsImageLoadingContent::GetRequest(int32_t aRequestType,
   422                                   imgIRequest** aRequest)
   423 {
   424   NS_ENSURE_ARG_POINTER(aRequest);
   426   ErrorResult result;
   427   *aRequest = GetRequest(aRequestType, result).take();
   429   return result.ErrorCode();
   430 }
   432 NS_IMETHODIMP_(void)
   433 nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
   434 {
   435   NS_ASSERTION(aFrame, "aFrame is null");
   437   mFrameCreateCalled = true;
   439   if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
   440     // Assume all images in popups are visible.
   441     IncrementVisibleCount();
   442   }
   444   TrackImage(mCurrentRequest);
   445   TrackImage(mPendingRequest);
   447   // We need to make sure that our image request is registered, if it should
   448   // be registered.
   449   nsPresContext* presContext = aFrame->PresContext();
   450   if (mCurrentRequest) {
   451     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mCurrentRequest,
   452                                                   &mCurrentRequestRegistered);
   453   }
   455   if (mPendingRequest) {
   456     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mPendingRequest,
   457                                                   &mPendingRequestRegistered);
   458   }
   459 }
   461 NS_IMETHODIMP_(void)
   462 nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
   463 {
   464   NS_ASSERTION(aFrame, "aFrame is null");
   466   mFrameCreateCalled = false;
   468   // We need to make sure that our image request is deregistered.
   469   nsPresContext* presContext = GetFramePresContext();
   470   if (mCurrentRequest) {
   471     nsLayoutUtils::DeregisterImageRequest(presContext,
   472                                           mCurrentRequest,
   473                                           &mCurrentRequestRegistered);
   474   }
   476   if (mPendingRequest) {
   477     nsLayoutUtils::DeregisterImageRequest(presContext,
   478                                           mPendingRequest,
   479                                           &mPendingRequestRegistered);
   480   }
   482   UntrackImage(mCurrentRequest);
   483   UntrackImage(mPendingRequest);
   485   nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr;
   486   if (presShell) {
   487     presShell->RemoveImageFromVisibleList(this);
   488   }
   490   if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
   491     // We assume all images in popups are visible, so this decrement balances
   492     // out the increment in FrameCreated above.
   493     DecrementVisibleCount();
   494   }
   495 }
   497 int32_t
   498 nsImageLoadingContent::GetRequestType(imgIRequest* aRequest,
   499                                       ErrorResult& aError)
   500 {
   501   if (aRequest == mCurrentRequest) {
   502     return CURRENT_REQUEST;
   503   }
   505   if (aRequest == mPendingRequest) {
   506     return PENDING_REQUEST;
   507   }
   509   NS_ERROR("Unknown request");
   510   aError.Throw(NS_ERROR_UNEXPECTED);
   511   return UNKNOWN_REQUEST;
   512 }
   514 NS_IMETHODIMP
   515 nsImageLoadingContent::GetRequestType(imgIRequest* aRequest,
   516                                       int32_t* aRequestType)
   517 {
   518   NS_PRECONDITION(aRequestType, "Null out param");
   520   ErrorResult result;
   521   *aRequestType = GetRequestType(aRequest, result);
   522   return result.ErrorCode();
   523 }
   525 already_AddRefed<nsIURI>
   526 nsImageLoadingContent::GetCurrentURI(ErrorResult& aError)
   527 {
   528   nsCOMPtr<nsIURI> uri;
   529   if (mCurrentRequest) {
   530     mCurrentRequest->GetURI(getter_AddRefs(uri));
   531   } else if (mCurrentURI) {
   532     nsresult rv = NS_EnsureSafeToReturn(mCurrentURI, getter_AddRefs(uri));
   533     if (NS_FAILED(rv)) {
   534       aError.Throw(rv);
   535     }
   536   }
   538   return uri.forget();
   539 }
   541 NS_IMETHODIMP
   542 nsImageLoadingContent::GetCurrentURI(nsIURI** aURI)
   543 {
   544   NS_ENSURE_ARG_POINTER(aURI);
   546   ErrorResult result;
   547   *aURI = GetCurrentURI(result).take();
   548   return result.ErrorCode();
   549 }
   551 already_AddRefed<nsIStreamListener>
   552 nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
   553                                             ErrorResult& aError)
   554 {
   555   if (!nsContentUtils::GetImgLoaderForChannel(aChannel)) {
   556     aError.Throw(NS_ERROR_NULL_POINTER);
   557     return nullptr;
   558   }
   560   nsCOMPtr<nsIDocument> doc = GetOurOwnerDoc();
   561   if (!doc) {
   562     // Don't bother
   563     return nullptr;
   564   }
   566   // XXX what should we do with content policies here, if anything?
   567   // Shouldn't that be done before the start of the load?
   568   // XXX what about shouldProcess?
   570   // Our state might change. Watch it.
   571   AutoStateChanger changer(this, true);
   573   // Do the load.
   574   nsCOMPtr<nsIStreamListener> listener;
   575   nsRefPtr<imgRequestProxy>& req = PrepareNextRequest();
   576   nsresult rv = nsContentUtils::GetImgLoaderForChannel(aChannel)->
   577     LoadImageWithChannel(aChannel, this, doc,
   578                          getter_AddRefs(listener),
   579                          getter_AddRefs(req));
   580   if (NS_SUCCEEDED(rv)) {
   581     TrackImage(req);
   582     ResetAnimationIfNeeded();
   583   } else {
   584     MOZ_ASSERT(!req, "Shouldn't have non-null request here");
   585     // If we don't have a current URI, we might as well store this URI so people
   586     // know what we tried (and failed) to load.
   587     if (!mCurrentRequest)
   588       aChannel->GetURI(getter_AddRefs(mCurrentURI));
   589     FireEvent(NS_LITERAL_STRING("error"));
   590     aError.Throw(rv);
   591   }
   592   return listener.forget();
   593 }
   595 NS_IMETHODIMP
   596 nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
   597                                             nsIStreamListener** aListener)
   598 {
   599   NS_ENSURE_ARG_POINTER(aListener);
   601   ErrorResult result;
   602   *aListener = LoadImageWithChannel(aChannel, result).take();
   603   return result.ErrorCode();
   604 }
   606 void
   607 nsImageLoadingContent::ForceReload(ErrorResult& aError)
   608 {
   609   nsCOMPtr<nsIURI> currentURI;
   610   GetCurrentURI(getter_AddRefs(currentURI));
   611   if (!currentURI) {
   612     aError.Throw(NS_ERROR_NOT_AVAILABLE);
   613     return;
   614   }
   616   nsresult rv = LoadImage(currentURI, true, true, nullptr, nsIRequest::VALIDATE_ALWAYS);
   617   if (NS_FAILED(rv)) {
   618     aError.Throw(rv);
   619   }
   620 }
   622 NS_IMETHODIMP nsImageLoadingContent::ForceReload()
   623 {
   624   ErrorResult result;
   625   ForceReload(result);
   626   return result.ErrorCode();
   627 }
   629 NS_IMETHODIMP
   630 nsImageLoadingContent::BlockOnload(imgIRequest* aRequest)
   631 {
   632   if (aRequest == mCurrentRequest) {
   633     NS_ASSERTION(!(mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD),
   634                  "Double BlockOnload!?");
   635     mCurrentRequestFlags |= REQUEST_BLOCKS_ONLOAD;
   636   } else if (aRequest == mPendingRequest) {
   637     NS_ASSERTION(!(mPendingRequestFlags & REQUEST_BLOCKS_ONLOAD),
   638                  "Double BlockOnload!?");
   639     mPendingRequestFlags |= REQUEST_BLOCKS_ONLOAD;
   640   } else {
   641     return NS_OK;
   642   }
   644   nsIDocument* doc = GetOurCurrentDoc();
   645   if (doc) {
   646     doc->BlockOnload();
   647   }
   649   return NS_OK;
   650 }
   652 NS_IMETHODIMP
   653 nsImageLoadingContent::UnblockOnload(imgIRequest* aRequest)
   654 {
   655   if (aRequest == mCurrentRequest) {
   656     NS_ASSERTION(mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD,
   657                  "Double UnblockOnload!?");
   658     mCurrentRequestFlags &= ~REQUEST_BLOCKS_ONLOAD;
   659   } else if (aRequest == mPendingRequest) {
   660     NS_ASSERTION(mPendingRequestFlags & REQUEST_BLOCKS_ONLOAD,
   661                  "Double UnblockOnload!?");
   662     mPendingRequestFlags &= ~REQUEST_BLOCKS_ONLOAD;
   663   } else {
   664     return NS_OK;
   665   }
   667   nsIDocument* doc = GetOurCurrentDoc();
   668   if (doc) {
   669     doc->UnblockOnload(false);
   670   }
   672   return NS_OK;
   673 }
   675 void
   676 nsImageLoadingContent::IncrementVisibleCount()
   677 {
   678   mVisibleCount++;
   679   if (mVisibleCount == 1) {
   680     TrackImage(mCurrentRequest);
   681     TrackImage(mPendingRequest);
   682   }
   683 }
   685 void
   686 nsImageLoadingContent::DecrementVisibleCount()
   687 {
   688   NS_ASSERTION(mVisibleCount > 0, "visible count should be positive here");
   689   mVisibleCount--;
   691   if (mVisibleCount == 0) {
   692     UntrackImage(mCurrentRequest);
   693     UntrackImage(mPendingRequest);
   694   }
   695 }
   697 uint32_t
   698 nsImageLoadingContent::GetVisibleCount()
   699 {
   700   return mVisibleCount;
   701 }
   703 /*
   704  * Non-interface methods
   705  */
   707 nsresult
   708 nsImageLoadingContent::LoadImage(const nsAString& aNewURI,
   709                                  bool aForce,
   710                                  bool aNotify)
   711 {
   712   // First, get a document (needed for security checks and the like)
   713   nsIDocument* doc = GetOurOwnerDoc();
   714   if (!doc) {
   715     // No reason to bother, I think...
   716     return NS_OK;
   717   }
   719   nsCOMPtr<nsIURI> imageURI;
   720   nsresult rv = StringToURI(aNewURI, doc, getter_AddRefs(imageURI));
   721   NS_ENSURE_SUCCESS(rv, rv);
   722   // XXXbiesi fire onerror if that failed?
   724   bool equal;
   726   if (aNewURI.IsEmpty() &&
   727       doc->GetDocumentURI() &&
   728       NS_SUCCEEDED(doc->GetDocumentURI()->EqualsExceptRef(imageURI, &equal)) &&
   729       equal)  {
   731     // Loading an embedded img from the same URI as the document URI will not work
   732     // as a resource cannot recursively embed itself. Attempting to do so generally
   733     // results in having to pre-emptively close down an in-flight HTTP transaction 
   734     // and then incurring the significant cost of establishing a new TCP channel.
   735     // This is generally triggered from <img src=""> 
   736     // In light of that, just skip loading it..
   737     // Do make sure to drop our existing image, if any
   738     CancelImageRequests(aNotify);
   739     return NS_OK;
   740   }
   742   NS_TryToSetImmutable(imageURI);
   744   return LoadImage(imageURI, aForce, aNotify, doc);
   745 }
   747 nsresult
   748 nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
   749                                  bool aForce,
   750                                  bool aNotify,
   751                                  nsIDocument* aDocument,
   752                                  nsLoadFlags aLoadFlags)
   753 {
   754   if (!mLoadingEnabled) {
   755     // XXX Why fire an error here? seems like the callers to SetLoadingEnabled
   756     // don't want/need it.
   757     FireEvent(NS_LITERAL_STRING("error"));
   758     return NS_OK;
   759   }
   761   NS_ASSERTION(!aDocument || aDocument == GetOurOwnerDoc(),
   762                "Bogus document passed in");
   763   // First, get a document (needed for security checks and the like)
   764   if (!aDocument) {
   765     aDocument = GetOurOwnerDoc();
   766     if (!aDocument) {
   767       // No reason to bother, I think...
   768       return NS_OK;
   769     }
   770   }
   772   // URI equality check.
   773   //
   774   // We skip the equality check if our current image was blocked, since in that
   775   // case we really do want to try loading again.
   776   if (!aForce && NS_CP_ACCEPTED(mImageBlockingStatus)) {
   777     nsCOMPtr<nsIURI> currentURI;
   778     GetCurrentURI(getter_AddRefs(currentURI));
   779     bool equal;
   780     if (currentURI &&
   781         NS_SUCCEEDED(currentURI->Equals(aNewURI, &equal)) &&
   782         equal) {
   783       // Nothing to do here.
   784       return NS_OK;
   785     }
   786   }
   788   // From this point on, our image state could change. Watch it.
   789   AutoStateChanger changer(this, aNotify);
   791   // Sanity check.
   792   //
   793   // We use the principal of aDocument to avoid having to QI |this| an extra
   794   // time. It should always be the same as the principal of this node.
   795 #ifdef DEBUG
   796   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   797   NS_ABORT_IF_FALSE(thisContent &&
   798                     thisContent->NodePrincipal() == aDocument->NodePrincipal(),
   799                     "Principal mismatch?");
   800 #endif
   802   // Are we blocked?
   803   int16_t cpDecision = nsIContentPolicy::REJECT_REQUEST;
   804   nsContentUtils::CanLoadImage(aNewURI,
   805                                static_cast<nsIImageLoadingContent*>(this),
   806                                aDocument,
   807                                aDocument->NodePrincipal(),
   808                                &cpDecision);
   809   if (!NS_CP_ACCEPTED(cpDecision)) {
   810     FireEvent(NS_LITERAL_STRING("error"));
   811     SetBlockedRequest(aNewURI, cpDecision);
   812     return NS_OK;
   813   }
   815   nsLoadFlags loadFlags = aLoadFlags;
   816   int32_t corsmode = GetCORSMode();
   817   if (corsmode == CORS_ANONYMOUS) {
   818     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
   819   } else if (corsmode == CORS_USE_CREDENTIALS) {
   820     loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
   821   }
   823   // Not blocked. Do the load.
   824   nsRefPtr<imgRequestProxy>& req = PrepareNextRequest();
   825   nsCOMPtr<nsIContent> content =
   826       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   827   nsresult rv;
   828   rv = nsContentUtils::LoadImage(aNewURI, aDocument,
   829                                  aDocument->NodePrincipal(),
   830                                  aDocument->GetDocumentURI(),
   831                                  this, loadFlags,
   832                                  content->LocalName(),
   833                                  getter_AddRefs(req));
   835   if (NS_SUCCEEDED(rv)) {
   836     TrackImage(req);
   837     ResetAnimationIfNeeded();
   839     // Handle cases when we just ended up with a pending request but it's
   840     // already done.  In that situation we have to synchronously switch that
   841     // request to being the current request, because websites depend on that
   842     // behavior.
   843     if (req == mPendingRequest) {
   844       uint32_t pendingLoadStatus;
   845       rv = req->GetImageStatus(&pendingLoadStatus);
   846       if (NS_SUCCEEDED(rv) &&
   847           (pendingLoadStatus & imgIRequest::STATUS_LOAD_COMPLETE)) {
   848         MakePendingRequestCurrent();
   849         MOZ_ASSERT(mCurrentRequest,
   850                    "How could we not have a current request here?");
   852         nsImageFrame *f = do_QueryFrame(GetOurPrimaryFrame());
   853         if (f) {
   854           f->NotifyNewCurrentRequest(mCurrentRequest, NS_OK);
   855         }
   856       }
   857     }
   858   } else {
   859     MOZ_ASSERT(!req, "Shouldn't have non-null request here");
   860     // If we don't have a current URI, we might as well store this URI so people
   861     // know what we tried (and failed) to load.
   862     if (!mCurrentRequest)
   863       mCurrentURI = aNewURI;
   864     FireEvent(NS_LITERAL_STRING("error"));
   865     return NS_OK;
   866   }
   868   return NS_OK;
   869 }
   871 nsresult
   872 nsImageLoadingContent::ForceImageState(bool aForce,
   873                                        EventStates::InternalType aState)
   874 {
   875   mIsImageStateForced = aForce;
   876   mForcedImageState = EventStates(aState);
   877   return NS_OK;
   878 }
   880 EventStates
   881 nsImageLoadingContent::ImageState() const
   882 {
   883   if (mIsImageStateForced) {
   884     return mForcedImageState;
   885   }
   887   EventStates states;
   889   if (mBroken) {
   890     states |= NS_EVENT_STATE_BROKEN;
   891   }
   892   if (mUserDisabled) {
   893     states |= NS_EVENT_STATE_USERDISABLED;
   894   }
   895   if (mSuppressed) {
   896     states |= NS_EVENT_STATE_SUPPRESSED;
   897   }
   898   if (mLoading) {
   899     states |= NS_EVENT_STATE_LOADING;
   900   }
   902   return states;
   903 }
   905 void
   906 nsImageLoadingContent::UpdateImageState(bool aNotify)
   907 {
   908   if (mStateChangerDepth > 0) {
   909     // Ignore this call; we'll update our state when the outermost state
   910     // changer is destroyed. Need this to work around the fact that some libpr0n
   911     // stuff is actually sync and hence we can get OnStopDecode called while
   912     // we're still under LoadImage, and OnStopDecode doesn't know anything about
   913     // aNotify.
   914     // XXX - This machinery should be removed after bug 521604.
   915     return;
   916   }
   918   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   919   if (!thisContent) {
   920     return;
   921   }
   923   mLoading = mBroken = mUserDisabled = mSuppressed = false;
   925   // If we were blocked by server-based content policy, we claim to be
   926   // suppressed.  If we were blocked by type-based content policy, we claim to
   927   // be user-disabled.  Otherwise, claim to be broken.
   928   if (mImageBlockingStatus == nsIContentPolicy::REJECT_SERVER) {
   929     mSuppressed = true;
   930   } else if (mImageBlockingStatus == nsIContentPolicy::REJECT_TYPE) {
   931     mUserDisabled = true;
   932   } else if (!mCurrentRequest) {
   933     // No current request means error, since we weren't disabled or suppressed
   934     mBroken = true;
   935   } else {
   936     uint32_t currentLoadStatus;
   937     nsresult rv = mCurrentRequest->GetImageStatus(&currentLoadStatus);
   938     if (NS_FAILED(rv) || (currentLoadStatus & imgIRequest::STATUS_ERROR)) {
   939       mBroken = true;
   940     } else if (!(currentLoadStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) {
   941       mLoading = true;
   942     }
   943   }
   945   NS_ASSERTION(thisContent->IsElement(), "Not an element?");
   946   thisContent->AsElement()->UpdateState(aNotify);
   947 }
   949 void
   950 nsImageLoadingContent::CancelImageRequests(bool aNotify)
   951 {
   952   AutoStateChanger changer(this, aNotify);
   953   ClearPendingRequest(NS_BINDING_ABORTED, REQUEST_DISCARD);
   954   ClearCurrentRequest(NS_BINDING_ABORTED, REQUEST_DISCARD);
   955 }
   957 nsresult
   958 nsImageLoadingContent::UseAsPrimaryRequest(imgRequestProxy* aRequest,
   959                                            bool aNotify)
   960 {
   961   // Our state will change. Watch it.
   962   AutoStateChanger changer(this, aNotify);
   964   // Get rid if our existing images
   965   ClearPendingRequest(NS_BINDING_ABORTED, REQUEST_DISCARD);
   966   ClearCurrentRequest(NS_BINDING_ABORTED, REQUEST_DISCARD);
   968   // Clone the request we were given.
   969   nsRefPtr<imgRequestProxy>& req = PrepareNextRequest();
   970   nsresult rv = aRequest->Clone(this, getter_AddRefs(req));
   971   if (NS_SUCCEEDED(rv)) {
   972     TrackImage(req);
   973   } else {
   974     MOZ_ASSERT(!req, "Shouldn't have non-null request here");
   975     return rv;
   976   }
   978   return NS_OK;
   979 }
   981 nsIDocument*
   982 nsImageLoadingContent::GetOurOwnerDoc()
   983 {
   984   nsCOMPtr<nsIContent> thisContent =
   985     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   986   NS_ENSURE_TRUE(thisContent, nullptr);
   988   return thisContent->OwnerDoc();
   989 }
   991 nsIDocument*
   992 nsImageLoadingContent::GetOurCurrentDoc()
   993 {
   994   nsCOMPtr<nsIContent> thisContent =
   995     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   996   NS_ENSURE_TRUE(thisContent, nullptr);
   998   return thisContent->GetCurrentDoc();
   999 }
  1001 nsIFrame*
  1002 nsImageLoadingContent::GetOurPrimaryFrame()
  1004   nsCOMPtr<nsIContent> thisContent =
  1005     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
  1006   return thisContent->GetPrimaryFrame();
  1009 nsPresContext* nsImageLoadingContent::GetFramePresContext()
  1011   nsIFrame* frame = GetOurPrimaryFrame();
  1012   if (!frame) {
  1013     return nullptr;
  1016   return frame->PresContext();
  1019 nsresult
  1020 nsImageLoadingContent::StringToURI(const nsAString& aSpec,
  1021                                    nsIDocument* aDocument,
  1022                                    nsIURI** aURI)
  1024   NS_PRECONDITION(aDocument, "Must have a document");
  1025   NS_PRECONDITION(aURI, "Null out param");
  1027   // (1) Get the base URI
  1028   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
  1029   NS_ASSERTION(thisContent, "An image loading content must be an nsIContent");
  1030   nsCOMPtr<nsIURI> baseURL = thisContent->GetBaseURI();
  1032   // (2) Get the charset
  1033   const nsAFlatCString &charset = aDocument->GetDocumentCharacterSet();
  1035   // (3) Construct the silly thing
  1036   return NS_NewURI(aURI,
  1037                    aSpec,
  1038                    charset.IsEmpty() ? nullptr : charset.get(),
  1039                    baseURL,
  1040                    nsContentUtils::GetIOService());
  1043 nsresult
  1044 nsImageLoadingContent::FireEvent(const nsAString& aEventType)
  1046   // We have to fire the event asynchronously so that we won't go into infinite
  1047   // loops in cases when onLoad handlers reset the src and the new src is in
  1048   // cache.
  1050   nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
  1052   nsRefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
  1053     new LoadBlockingAsyncEventDispatcher(thisNode, aEventType, false, false);
  1054   loadBlockingAsyncDispatcher->PostDOMEvent();
  1056   return NS_OK;
  1059 nsRefPtr<imgRequestProxy>&
  1060 nsImageLoadingContent::PrepareNextRequest()
  1062   // If we don't have a usable current request, get rid of any half-baked
  1063   // request that might be sitting there and make this one current.
  1064   if (!HaveSize(mCurrentRequest))
  1065     return PrepareCurrentRequest();
  1067   // Otherwise, make it pending.
  1068   return PreparePendingRequest();
  1071 void
  1072 nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision)
  1074   // Sanity
  1075   NS_ABORT_IF_FALSE(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?");
  1077   // We do some slightly illogical stuff here to maintain consistency with
  1078   // old behavior that people probably depend on. Even in the case where the
  1079   // new image is blocked, the old one should really be canceled with the
  1080   // reason "image source changed". However, apparently there's some abuse
  1081   // over in nsImageFrame where the displaying of the "broken" icon for the
  1082   // next image depends on the cancel reason of the previous image. ugh.
  1083   ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED, REQUEST_DISCARD);
  1085   // For the blocked case, we only want to cancel the existing current request
  1086   // if size is not available. bz says the web depends on this behavior.
  1087   if (!HaveSize(mCurrentRequest)) {
  1089     mImageBlockingStatus = aContentDecision;
  1090     ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED, REQUEST_DISCARD);
  1092     // We still want to remember what URI we were despite not having an actual
  1093     // request.
  1094     mCurrentURI = aURI;
  1098 nsRefPtr<imgRequestProxy>&
  1099 nsImageLoadingContent::PrepareCurrentRequest()
  1101   // Blocked images go through SetBlockedRequest, which is a separate path. For
  1102   // everything else, we're unblocked.
  1103   mImageBlockingStatus = nsIContentPolicy::ACCEPT;
  1105   // Get rid of anything that was there previously.
  1106   ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED, REQUEST_DISCARD);
  1108   if (mNewRequestsWillNeedAnimationReset) {
  1109     mCurrentRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
  1112   // Return a reference.
  1113   return mCurrentRequest;
  1116 nsRefPtr<imgRequestProxy>&
  1117 nsImageLoadingContent::PreparePendingRequest()
  1119   // Get rid of anything that was there previously.
  1120   ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED, REQUEST_DISCARD);
  1122   if (mNewRequestsWillNeedAnimationReset) {
  1123     mPendingRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
  1126   // Return a reference.
  1127   return mPendingRequest;
  1130 namespace {
  1132 class ImageRequestAutoLock
  1134 public:
  1135   ImageRequestAutoLock(imgIRequest* aRequest)
  1136     : mRequest(aRequest)
  1138     if (mRequest) {
  1139       mRequest->LockImage();
  1143   ~ImageRequestAutoLock()
  1145     if (mRequest) {
  1146       mRequest->UnlockImage();
  1150 private:
  1151   nsCOMPtr<imgIRequest> mRequest;
  1152 };
  1154 } // anonymous namespace
  1156 void
  1157 nsImageLoadingContent::MakePendingRequestCurrent()
  1159   MOZ_ASSERT(mPendingRequest);
  1161   // Lock mCurrentRequest for the duration of this method.  We do this because
  1162   // PrepareCurrentRequest() might unlock mCurrentRequest.  If mCurrentRequest
  1163   // and mPendingRequest are both requests for the same image, unlocking
  1164   // mCurrentRequest before we lock mPendingRequest can cause the lock count
  1165   // to go to 0 and the image to be discarded!
  1166   ImageRequestAutoLock autoLock(mCurrentRequest);
  1168   PrepareCurrentRequest() = mPendingRequest;
  1169   mPendingRequest = nullptr;
  1170   mCurrentRequestFlags = mPendingRequestFlags;
  1171   mPendingRequestFlags = 0;
  1172   ResetAnimationIfNeeded();
  1175 void
  1176 nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
  1177                                            uint32_t aFlags)
  1179   if (!mCurrentRequest) {
  1180     // Even if we didn't have a current request, we might have been keeping
  1181     // a URI as a placeholder for a failed load. Clear that now.
  1182     mCurrentURI = nullptr;
  1183     return;
  1185   NS_ABORT_IF_FALSE(!mCurrentURI,
  1186                     "Shouldn't have both mCurrentRequest and mCurrentURI!");
  1188   // Deregister this image from the refresh driver so it no longer receives
  1189   // notifications.
  1190   nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mCurrentRequest,
  1191                                         &mCurrentRequestRegistered);
  1193   // Clean up the request.
  1194   UntrackImage(mCurrentRequest, aFlags);
  1195   mCurrentRequest->CancelAndForgetObserver(aReason);
  1196   mCurrentRequest = nullptr;
  1197   mCurrentRequestFlags = 0;
  1200 void
  1201 nsImageLoadingContent::ClearPendingRequest(nsresult aReason,
  1202                                            uint32_t aFlags)
  1204   if (!mPendingRequest)
  1205     return;
  1207   // Deregister this image from the refresh driver so it no longer receives
  1208   // notifications.
  1209   nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
  1210                                         &mPendingRequestRegistered);
  1212   UntrackImage(mPendingRequest, aFlags);
  1213   mPendingRequest->CancelAndForgetObserver(aReason);
  1214   mPendingRequest = nullptr;
  1215   mPendingRequestFlags = 0;
  1218 bool*
  1219 nsImageLoadingContent::GetRegisteredFlagForRequest(imgIRequest* aRequest)
  1221   if (aRequest == mCurrentRequest) {
  1222     return &mCurrentRequestRegistered;
  1223   } else if (aRequest == mPendingRequest) {
  1224     return &mPendingRequestRegistered;
  1225   } else {
  1226     return nullptr;
  1230 void
  1231 nsImageLoadingContent::ResetAnimationIfNeeded()
  1233   if (mCurrentRequest &&
  1234       (mCurrentRequestFlags & REQUEST_NEEDS_ANIMATION_RESET)) {
  1235     nsCOMPtr<imgIContainer> container;
  1236     mCurrentRequest->GetImage(getter_AddRefs(container));
  1237     if (container)
  1238       container->ResetAnimation();
  1239     mCurrentRequestFlags &= ~REQUEST_NEEDS_ANIMATION_RESET;
  1243 bool
  1244 nsImageLoadingContent::HaveSize(imgIRequest *aImage)
  1246   // Handle the null case
  1247   if (!aImage)
  1248     return false;
  1250   // Query the image
  1251   uint32_t status;
  1252   nsresult rv = aImage->GetImageStatus(&status);
  1253   return (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_SIZE_AVAILABLE));
  1256 void
  1257 nsImageLoadingContent::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
  1258                                   nsIContent* aBindingParent,
  1259                                   bool aCompileEventHandlers)
  1261   // We may be entering the document, so if our image should be tracked,
  1262   // track it.
  1263   if (!aDocument)
  1264     return;
  1266   TrackImage(mCurrentRequest);
  1267   TrackImage(mPendingRequest);
  1269   if (mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD)
  1270     aDocument->BlockOnload();
  1273 void
  1274 nsImageLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
  1276   // We may be leaving the document, so if our image is tracked, untrack it.
  1277   nsCOMPtr<nsIDocument> doc = GetOurCurrentDoc();
  1278   if (!doc)
  1279     return;
  1281   UntrackImage(mCurrentRequest);
  1282   UntrackImage(mPendingRequest);
  1284   if (mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD)
  1285     doc->UnblockOnload(false);
  1288 void
  1289 nsImageLoadingContent::TrackImage(imgIRequest* aImage)
  1291   if (!aImage)
  1292     return;
  1294   MOZ_ASSERT(aImage == mCurrentRequest || aImage == mPendingRequest,
  1295              "Why haven't we heard of this request?");
  1297   nsIDocument* doc = GetOurCurrentDoc();
  1298   if (doc && (mFrameCreateCalled || GetOurPrimaryFrame()) &&
  1299       (mVisibleCount > 0)) {
  1300     if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
  1301       mCurrentRequestFlags |= REQUEST_IS_TRACKED;
  1302       doc->AddImage(mCurrentRequest);
  1304     if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
  1305       mPendingRequestFlags |= REQUEST_IS_TRACKED;
  1306       doc->AddImage(mPendingRequest);
  1311 void
  1312 nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 */)
  1314   if (!aImage)
  1315     return;
  1317   MOZ_ASSERT(aImage == mCurrentRequest || aImage == mPendingRequest,
  1318              "Why haven't we heard of this request?");
  1320   // We may not be in the document.  If we outlived our document that's fine,
  1321   // because the document empties out the tracker and unlocks all locked images
  1322   // on destruction.  But if we were never in the document we may need to force
  1323   // discarding the image here, since this is the only chance we have.
  1324   nsIDocument* doc = GetOurCurrentDoc();
  1325   if (aImage == mCurrentRequest) {
  1326     if (doc && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
  1327       mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
  1328       doc->RemoveImage(mCurrentRequest,
  1329                        (aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0);
  1331     else if (aFlags & REQUEST_DISCARD) {
  1332       // If we're not in the document we may still need to be discarded.
  1333       aImage->RequestDiscard();
  1336   if (aImage == mPendingRequest) {
  1337     if (doc && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
  1338       mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
  1339       doc->RemoveImage(mPendingRequest,
  1340                        (aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0);
  1342     else if (aFlags & REQUEST_DISCARD) {
  1343       // If we're not in the document we may still need to be discarded.
  1344       aImage->RequestDiscard();
  1350 void
  1351 nsImageLoadingContent::CreateStaticImageClone(nsImageLoadingContent* aDest) const
  1353   aDest->mCurrentRequest = nsContentUtils::GetStaticRequest(mCurrentRequest);
  1354   aDest->TrackImage(aDest->mCurrentRequest);
  1355   aDest->mForcedImageState = mForcedImageState;
  1356   aDest->mImageBlockingStatus = mImageBlockingStatus;
  1357   aDest->mLoadingEnabled = mLoadingEnabled;
  1358   aDest->mStateChangerDepth = mStateChangerDepth;
  1359   aDest->mIsImageStateForced = mIsImageStateForced;
  1360   aDest->mLoading = mLoading;
  1361   aDest->mBroken = mBroken;
  1362   aDest->mUserDisabled = mUserDisabled;
  1363   aDest->mSuppressed = mSuppressed;
  1366 CORSMode
  1367 nsImageLoadingContent::GetCORSMode()
  1369   return CORS_NONE;
  1372 nsImageLoadingContent::ImageObserver::ImageObserver(imgINotificationObserver* aObserver)
  1373   : mObserver(aObserver)
  1374   , mNext(nullptr)
  1376   MOZ_COUNT_CTOR(ImageObserver);
  1379 nsImageLoadingContent::ImageObserver::~ImageObserver()
  1381   MOZ_COUNT_DTOR(ImageObserver);
  1382   NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext);

mercurial