LCOV - code coverage report
Current view: top level - dom/base - nsImageLoadingContent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 225 680 33.1 %
Date: 2017-07-14 16:53:18 Functions: 28 69 40.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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/. */
       6             : 
       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             :  */
      12             : 
      13             : #include "nsImageLoadingContent.h"
      14             : #include "nsError.h"
      15             : #include "nsIContent.h"
      16             : #include "nsIDocument.h"
      17             : #include "nsIScriptGlobalObject.h"
      18             : #include "nsIDOMWindow.h"
      19             : #include "nsServiceManagerUtils.h"
      20             : #include "nsContentPolicyUtils.h"
      21             : #include "nsIURI.h"
      22             : #include "nsILoadGroup.h"
      23             : #include "imgIContainer.h"
      24             : #include "imgLoader.h"
      25             : #include "imgRequestProxy.h"
      26             : #include "nsThreadUtils.h"
      27             : #include "nsNetUtil.h"
      28             : #include "nsImageFrame.h"
      29             : #include "nsSVGImageFrame.h"
      30             : 
      31             : #include "nsIPresShell.h"
      32             : 
      33             : #include "nsIChannel.h"
      34             : #include "nsIStreamListener.h"
      35             : 
      36             : #include "nsIFrame.h"
      37             : #include "nsIDOMNode.h"
      38             : 
      39             : #include "nsContentUtils.h"
      40             : #include "nsLayoutUtils.h"
      41             : #include "nsIContentPolicy.h"
      42             : #include "nsSVGEffects.h"
      43             : 
      44             : #include "gfxPrefs.h"
      45             : 
      46             : #include "mozAutoDocUpdate.h"
      47             : #include "mozilla/AsyncEventDispatcher.h"
      48             : #include "mozilla/AutoRestore.h"
      49             : #include "mozilla/EventStateManager.h"
      50             : #include "mozilla/EventStates.h"
      51             : #include "mozilla/dom/Element.h"
      52             : #include "mozilla/dom/ImageTracker.h"
      53             : #include "mozilla/dom/ScriptSettings.h"
      54             : #include "mozilla/Preferences.h"
      55             : 
      56             : #ifdef LoadImage
      57             : // Undefine LoadImage to prevent naming conflict with Windows.
      58             : #undef LoadImage
      59             : #endif
      60             : 
      61             : using namespace mozilla;
      62             : using namespace mozilla::dom;
      63             : 
      64             : #ifdef DEBUG_chb
      65             : static void PrintReqURL(imgIRequest* req) {
      66             :   if (!req) {
      67             :     printf("(null req)\n");
      68             :     return;
      69             :   }
      70             : 
      71             :   nsCOMPtr<nsIURI> uri;
      72             :   req->GetURI(getter_AddRefs(uri));
      73             :   if (!uri) {
      74             :     printf("(null uri)\n");
      75             :     return;
      76             :   }
      77             : 
      78             :   nsAutoCString spec;
      79             :   uri->GetSpec(spec);
      80             :   printf("spec='%s'\n", spec.get());
      81             : }
      82             : #endif /* DEBUG_chb */
      83             : 
      84             : 
      85          11 : nsImageLoadingContent::nsImageLoadingContent()
      86             :   : mCurrentRequestFlags(0),
      87             :     mPendingRequestFlags(0),
      88             :     mObserverList(nullptr),
      89             :     mImageBlockingStatus(nsIContentPolicy::ACCEPT),
      90             :     mLoadingEnabled(true),
      91             :     mIsImageStateForced(false),
      92             :     mLoading(false),
      93             :     // mBroken starts out true, since an image without a URI is broken....
      94             :     mBroken(true),
      95             :     mUserDisabled(false),
      96             :     mSuppressed(false),
      97             :     mNewRequestsWillNeedAnimationReset(false),
      98             :     mUseUrgentStartForChannel(false),
      99             :     mStateChangerDepth(0),
     100             :     mCurrentRequestRegistered(false),
     101             :     mPendingRequestRegistered(false),
     102          11 :     mIsStartingImageLoad(false)
     103             : {
     104          11 :   if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
     105           0 :     mLoadingEnabled = false;
     106             :   }
     107             : 
     108          11 :   mMostRecentRequestChange = TimeStamp::ProcessCreation();
     109          11 : }
     110             : 
     111             : void
     112           0 : nsImageLoadingContent::DestroyImageLoadingContent()
     113             : {
     114             :   // Cancel our requests so they won't hold stale refs to us
     115             :   // NB: Don't ask to discard the images here.
     116           0 :   ClearCurrentRequest(NS_BINDING_ABORTED);
     117           0 :   ClearPendingRequest(NS_BINDING_ABORTED);
     118           0 : }
     119             : 
     120           0 : nsImageLoadingContent::~nsImageLoadingContent()
     121             : {
     122           0 :   NS_ASSERTION(!mCurrentRequest && !mPendingRequest,
     123             :                "DestroyImageLoadingContent not called");
     124           0 :   NS_ASSERTION(!mObserverList.mObserver && !mObserverList.mNext,
     125             :                "Observers still registered?");
     126           0 : }
     127             : 
     128             : /*
     129             :  * imgINotificationObserver impl
     130             :  */
     131             : NS_IMETHODIMP
     132          27 : nsImageLoadingContent::Notify(imgIRequest* aRequest,
     133             :                               int32_t aType,
     134             :                               const nsIntRect* aData)
     135             : {
     136          27 :   if (aType == imgINotificationObserver::IS_ANIMATED) {
     137           0 :     return OnImageIsAnimated(aRequest);
     138             :   }
     139             : 
     140          27 :   if (aType == imgINotificationObserver::UNLOCKED_DRAW) {
     141           0 :     OnUnlockedDraw();
     142           0 :     return NS_OK;
     143             :   }
     144             : 
     145          27 :   if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     146             :     // We should definitely have a request here
     147           4 :     MOZ_ASSERT(aRequest, "no request?");
     148             : 
     149           4 :     NS_PRECONDITION(aRequest == mCurrentRequest || aRequest == mPendingRequest,
     150             :                     "Unknown request");
     151             :   }
     152             : 
     153             :   {
     154             :     // Calling Notify on observers can modify the list of observers so make
     155             :     // a local copy.
     156          54 :     AutoTArray<nsCOMPtr<imgINotificationObserver>, 2> observers;
     157          54 :     for (ImageObserver* observer = &mObserverList, *next; observer;
     158          27 :          observer = next) {
     159          27 :       next = observer->mNext;
     160          27 :       if (observer->mObserver) {
     161           0 :         observers.AppendElement(observer->mObserver);
     162             :       }
     163             :     }
     164             : 
     165          54 :     nsAutoScriptBlocker scriptBlocker;
     166             : 
     167          27 :     for (auto& observer : observers) {
     168           0 :         observer->Notify(aRequest, aType, aData);
     169             :     }
     170             :   }
     171             : 
     172          27 :   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     173             :     // Have to check for state changes here, since we might have been in
     174             :     // the LOADING state before.
     175           4 :     UpdateImageState(true);
     176             :   }
     177             : 
     178          27 :   if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     179             :     uint32_t reqStatus;
     180           4 :     aRequest->GetImageStatus(&reqStatus);
     181             :     /* triage STATUS_ERROR */
     182           4 :     if (reqStatus & imgIRequest::STATUS_ERROR) {
     183           0 :       nsresult errorCode = NS_OK;
     184           0 :       aRequest->GetImageErrorCode(&errorCode);
     185             : 
     186             :       /* Handle image not loading error because source was a tracking URL.
     187             :        * We make a note of this image node by including it in a dedicated
     188             :        * array of blocked tracking nodes under its parent document.
     189             :        */
     190           0 :       if (errorCode == NS_ERROR_TRACKING_URI) {
     191             :         nsCOMPtr<nsIContent> thisNode
     192           0 :           = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
     193             : 
     194           0 :         nsIDocument *doc = GetOurOwnerDoc();
     195           0 :         doc->AddBlockedTrackingNode(thisNode);
     196             :       }
     197             :     }
     198             :     nsresult status =
     199           4 :         reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
     200           4 :     return OnLoadComplete(aRequest, status);
     201             :   }
     202             : 
     203          23 :   if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     204           8 :     nsCOMPtr<imgIContainer> container;
     205           4 :     aRequest->GetImage(getter_AddRefs(container));
     206           4 :     if (container) {
     207           4 :       container->PropagateUseCounters(GetOurOwnerDoc());
     208             :     }
     209             : 
     210           4 :     UpdateImageState(true);
     211             :   }
     212             : 
     213          23 :   return NS_OK;
     214             : }
     215             : 
     216             : nsresult
     217           4 : nsImageLoadingContent::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
     218             : {
     219             :   uint32_t oldStatus;
     220           4 :   aRequest->GetImageStatus(&oldStatus);
     221             : 
     222             :   //XXXjdm This occurs when we have a pending request created, then another
     223             :   //       pending request replaces it before the first one is finished.
     224             :   //       This begs the question of what the correct behaviour is; we used
     225             :   //       to not have to care because we ran this code in OnStopDecode which
     226             :   //       wasn't called when the first request was cancelled. For now, I choose
     227             :   //       to punt when the given request doesn't appear to have terminated in
     228             :   //       an expected state.
     229           4 :   if (!(oldStatus & (imgIRequest::STATUS_ERROR | imgIRequest::STATUS_LOAD_COMPLETE)))
     230           0 :     return NS_OK;
     231             : 
     232             :   // Our state may change. Watch it.
     233           8 :   AutoStateChanger changer(this, true);
     234             : 
     235             :   // If the pending request is loaded, switch to it.
     236           4 :   if (aRequest == mPendingRequest) {
     237           0 :     MakePendingRequestCurrent();
     238             :   }
     239           4 :   MOZ_ASSERT(aRequest == mCurrentRequest,
     240             :              "One way or another, we should be current by now");
     241             : 
     242             :   // Fire the appropriate DOM event.
     243           4 :   if (NS_SUCCEEDED(aStatus)) {
     244           4 :     FireEvent(NS_LITERAL_STRING("load"));
     245             : 
     246             :     // Do not fire loadend event for multipart/x-mixed-replace image streams.
     247             :     bool isMultipart;
     248           4 :     if (NS_FAILED(aRequest->GetMultipart(&isMultipart)) || !isMultipart) {
     249           4 :       FireEvent(NS_LITERAL_STRING("loadend"));
     250             :     }
     251             :   } else {
     252           0 :     FireEvent(NS_LITERAL_STRING("error"));
     253           0 :     FireEvent(NS_LITERAL_STRING("loadend"));
     254             :   }
     255             : 
     256           8 :   nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
     257           4 :   nsSVGEffects::InvalidateDirectRenderingObservers(thisNode->AsElement());
     258             : 
     259           4 :   return NS_OK;
     260             : }
     261             : 
     262             : static bool
     263           0 : ImageIsAnimated(imgIRequest* aRequest)
     264             : {
     265           0 :   if (!aRequest) {
     266           0 :     return false;
     267             :   }
     268             : 
     269           0 :   nsCOMPtr<imgIContainer> image;
     270           0 :   if (NS_SUCCEEDED(aRequest->GetImage(getter_AddRefs(image)))) {
     271           0 :     bool isAnimated = false;
     272           0 :     nsresult rv = image->GetAnimated(&isAnimated);
     273           0 :     if (NS_SUCCEEDED(rv) && isAnimated) {
     274           0 :       return true;
     275             :     }
     276             :   }
     277             : 
     278           0 :   return false;
     279             : }
     280             : 
     281             : void
     282           0 : nsImageLoadingContent::OnUnlockedDraw()
     283             : {
     284             :   // It's OK for non-animated images to wait until the next frame visibility
     285             :   // update to become locked. (And that's preferable, since in the case of
     286             :   // scrolling it keeps memory usage minimal.) For animated images, though, we
     287             :   // want to mark them visible right away so we can call
     288             :   // IncrementAnimationConsumers() on them and they'll start animating.
     289           0 :   if (!ImageIsAnimated(mCurrentRequest) && !ImageIsAnimated(mPendingRequest)) {
     290           0 :     return;
     291             :   }
     292             : 
     293           0 :   nsIFrame* frame = GetOurPrimaryFrame();
     294           0 :   if (!frame) {
     295           0 :     return;
     296             :   }
     297             : 
     298           0 :   if (frame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE) {
     299             :     // This frame is already marked visible; there's nothing to do.
     300           0 :     return;
     301             :   }
     302             : 
     303           0 :   nsPresContext* presContext = frame->PresContext();
     304           0 :   if (!presContext) {
     305           0 :     return;
     306             :   }
     307             : 
     308           0 :   nsIPresShell* presShell = presContext->PresShell();
     309           0 :   if (!presShell) {
     310           0 :     return;
     311             :   }
     312             : 
     313           0 :   presShell->EnsureFrameInApproximatelyVisibleList(frame);
     314             : }
     315             : 
     316             : nsresult
     317           0 : nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
     318             : {
     319           0 :   bool* requestFlag = GetRegisteredFlagForRequest(aRequest);
     320           0 :   if (requestFlag) {
     321           0 :     nsLayoutUtils::RegisterImageRequest(GetFramePresContext(),
     322           0 :                                         aRequest, requestFlag);
     323             :   }
     324             : 
     325           0 :   return NS_OK;
     326             : }
     327             : 
     328             : /*
     329             :  * nsIImageLoadingContent impl
     330             :  */
     331             : 
     332             : NS_IMETHODIMP
     333           0 : nsImageLoadingContent::GetLoadingEnabled(bool *aLoadingEnabled)
     334             : {
     335           0 :   *aLoadingEnabled = mLoadingEnabled;
     336           0 :   return NS_OK;
     337             : }
     338             : 
     339             : NS_IMETHODIMP
     340           0 : nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled)
     341             : {
     342           0 :   if (nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
     343           0 :     mLoadingEnabled = aLoadingEnabled;
     344             :   }
     345           0 :   return NS_OK;
     346             : }
     347             : 
     348             : NS_IMETHODIMP
     349           0 : nsImageLoadingContent::GetImageBlockingStatus(int16_t* aStatus)
     350             : {
     351           0 :   NS_PRECONDITION(aStatus, "Null out param");
     352           0 :   *aStatus = ImageBlockingStatus();
     353           0 :   return NS_OK;
     354             : }
     355             : 
     356             : static void
     357           0 : ReplayImageStatus(imgIRequest* aRequest, imgINotificationObserver* aObserver)
     358             : {
     359           0 :   if (!aRequest) {
     360           0 :     return;
     361             :   }
     362             : 
     363           0 :   uint32_t status = 0;
     364           0 :   nsresult rv = aRequest->GetImageStatus(&status);
     365           0 :   if (NS_FAILED(rv)) {
     366           0 :     return;
     367             :   }
     368             : 
     369           0 :   if (status & imgIRequest::STATUS_SIZE_AVAILABLE) {
     370           0 :     aObserver->Notify(aRequest, imgINotificationObserver::SIZE_AVAILABLE, nullptr);
     371             :   }
     372           0 :   if (status & imgIRequest::STATUS_FRAME_COMPLETE) {
     373           0 :     aObserver->Notify(aRequest, imgINotificationObserver::FRAME_COMPLETE, nullptr);
     374             :   }
     375           0 :   if (status & imgIRequest::STATUS_HAS_TRANSPARENCY) {
     376           0 :     aObserver->Notify(aRequest, imgINotificationObserver::HAS_TRANSPARENCY, nullptr);
     377             :   }
     378           0 :   if (status & imgIRequest::STATUS_IS_ANIMATED) {
     379           0 :     aObserver->Notify(aRequest, imgINotificationObserver::IS_ANIMATED, nullptr);
     380             :   }
     381           0 :   if (status & imgIRequest::STATUS_DECODE_COMPLETE) {
     382           0 :     aObserver->Notify(aRequest, imgINotificationObserver::DECODE_COMPLETE, nullptr);
     383             :   }
     384           0 :   if (status & imgIRequest::STATUS_LOAD_COMPLETE) {
     385           0 :     aObserver->Notify(aRequest, imgINotificationObserver::LOAD_COMPLETE, nullptr);
     386             :   }
     387             : }
     388             : 
     389             : NS_IMETHODIMP
     390           0 : nsImageLoadingContent::AddObserver(imgINotificationObserver* aObserver)
     391             : {
     392           0 :   NS_ENSURE_ARG_POINTER(aObserver);
     393             : 
     394           0 :   if (!mObserverList.mObserver) {
     395             :     // Don't touch the linking of the list!
     396           0 :     mObserverList.mObserver = aObserver;
     397             : 
     398           0 :     ReplayImageStatus(mCurrentRequest, aObserver);
     399           0 :     ReplayImageStatus(mPendingRequest, aObserver);
     400             : 
     401           0 :     return NS_OK;
     402             :   }
     403             : 
     404             :   // otherwise we have to create a new entry
     405             : 
     406           0 :   ImageObserver* observer = &mObserverList;
     407           0 :   while (observer->mNext) {
     408           0 :     observer = observer->mNext;
     409             :   }
     410             : 
     411           0 :   observer->mNext = new ImageObserver(aObserver);
     412           0 :   ReplayImageStatus(mCurrentRequest, aObserver);
     413           0 :   ReplayImageStatus(mPendingRequest, aObserver);
     414             : 
     415           0 :   return NS_OK;
     416             : }
     417             : 
     418             : NS_IMETHODIMP
     419           0 : nsImageLoadingContent::RemoveObserver(imgINotificationObserver* aObserver)
     420             : {
     421           0 :   NS_ENSURE_ARG_POINTER(aObserver);
     422             : 
     423           0 :   if (mObserverList.mObserver == aObserver) {
     424           0 :     mObserverList.mObserver = nullptr;
     425             :     // Don't touch the linking of the list!
     426           0 :     return NS_OK;
     427             :   }
     428             : 
     429             :   // otherwise have to find it and splice it out
     430           0 :   ImageObserver* observer = &mObserverList;
     431           0 :   while (observer->mNext && observer->mNext->mObserver != aObserver) {
     432           0 :     observer = observer->mNext;
     433             :   }
     434             : 
     435             :   // At this point, we are pointing to the list element whose mNext is
     436             :   // the right observer (assuming of course that mNext is not null)
     437           0 :   if (observer->mNext) {
     438             :     // splice it out
     439           0 :     ImageObserver* oldObserver = observer->mNext;
     440           0 :     observer->mNext = oldObserver->mNext;
     441           0 :     oldObserver->mNext = nullptr;  // so we don't destroy them all
     442           0 :     delete oldObserver;
     443             :   }
     444             : #ifdef DEBUG
     445             :   else {
     446           0 :     NS_WARNING("Asked to remove nonexistent observer");
     447             :   }
     448             : #endif
     449           0 :   return NS_OK;
     450             : }
     451             : 
     452             : already_AddRefed<imgIRequest>
     453           0 : nsImageLoadingContent::GetRequest(int32_t aRequestType,
     454             :                                   ErrorResult& aError)
     455             : {
     456           0 :   nsCOMPtr<imgIRequest> request;
     457           0 :   switch(aRequestType) {
     458             :   case CURRENT_REQUEST:
     459           0 :     request = mCurrentRequest;
     460           0 :     break;
     461             :   case PENDING_REQUEST:
     462           0 :     request = mPendingRequest;
     463           0 :     break;
     464             :   default:
     465           0 :     NS_ERROR("Unknown request type");
     466           0 :     aError.Throw(NS_ERROR_UNEXPECTED);
     467             :   }
     468             : 
     469           0 :   return request.forget();
     470             : }
     471             : 
     472             : NS_IMETHODIMP
     473           0 : nsImageLoadingContent::GetRequest(int32_t aRequestType,
     474             :                                   imgIRequest** aRequest)
     475             : {
     476           0 :   NS_ENSURE_ARG_POINTER(aRequest);
     477             : 
     478           0 :   ErrorResult result;
     479           0 :   *aRequest = GetRequest(aRequestType, result).take();
     480             : 
     481           0 :   return result.StealNSResult();
     482             : }
     483             : 
     484             : NS_IMETHODIMP_(bool)
     485           0 : nsImageLoadingContent::CurrentRequestHasSize()
     486             : {
     487           0 :   return HaveSize(mCurrentRequest);
     488             : }
     489             : 
     490             : NS_IMETHODIMP_(void)
     491           0 : nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
     492             : {
     493           0 :   NS_ASSERTION(aFrame, "aFrame is null");
     494             : 
     495           0 :   TrackImage(mCurrentRequest, aFrame);
     496           0 :   TrackImage(mPendingRequest, aFrame);
     497             : 
     498             :   // We need to make sure that our image request is registered, if it should
     499             :   // be registered.
     500           0 :   nsPresContext* presContext = aFrame->PresContext();
     501           0 :   if (mCurrentRequest) {
     502           0 :     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mCurrentRequest,
     503           0 :                                                   &mCurrentRequestRegistered);
     504             :   }
     505             : 
     506           0 :   if (mPendingRequest) {
     507           0 :     nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mPendingRequest,
     508           0 :                                                   &mPendingRequestRegistered);
     509             :   }
     510           0 : }
     511             : 
     512             : NS_IMETHODIMP_(void)
     513           0 : nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
     514             : {
     515           0 :   NS_ASSERTION(aFrame, "aFrame is null");
     516             : 
     517             :   // We need to make sure that our image request is deregistered.
     518           0 :   nsPresContext* presContext = GetFramePresContext();
     519           0 :   if (mCurrentRequest) {
     520           0 :     nsLayoutUtils::DeregisterImageRequest(presContext,
     521             :                                           mCurrentRequest,
     522           0 :                                           &mCurrentRequestRegistered);
     523             :   }
     524             : 
     525           0 :   if (mPendingRequest) {
     526           0 :     nsLayoutUtils::DeregisterImageRequest(presContext,
     527             :                                           mPendingRequest,
     528           0 :                                           &mPendingRequestRegistered);
     529             :   }
     530             : 
     531           0 :   UntrackImage(mCurrentRequest);
     532           0 :   UntrackImage(mPendingRequest);
     533             : 
     534           0 :   nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr;
     535           0 :   if (presShell) {
     536           0 :     presShell->RemoveFrameFromApproximatelyVisibleList(aFrame);
     537             :   }
     538           0 : }
     539             : 
     540             : /* static */
     541             : nsContentPolicyType
     542           4 : nsImageLoadingContent::PolicyTypeForLoad(ImageLoadType aImageLoadType)
     543             : {
     544           4 :   if (aImageLoadType == eImageLoadType_Imageset) {
     545           0 :     return nsIContentPolicy::TYPE_IMAGESET;
     546             :   }
     547             : 
     548           4 :   MOZ_ASSERT(aImageLoadType == eImageLoadType_Normal,
     549             :              "Unknown ImageLoadType type in PolicyTypeForLoad");
     550           4 :   return nsIContentPolicy::TYPE_INTERNAL_IMAGE;
     551             : }
     552             : 
     553             : int32_t
     554           0 : nsImageLoadingContent::GetRequestType(imgIRequest* aRequest,
     555             :                                       ErrorResult& aError)
     556             : {
     557           0 :   if (aRequest == mCurrentRequest) {
     558           0 :     return CURRENT_REQUEST;
     559             :   }
     560             : 
     561           0 :   if (aRequest == mPendingRequest) {
     562           0 :     return PENDING_REQUEST;
     563             :   }
     564             : 
     565           0 :   NS_ERROR("Unknown request");
     566           0 :   aError.Throw(NS_ERROR_UNEXPECTED);
     567           0 :   return UNKNOWN_REQUEST;
     568             : }
     569             : 
     570             : NS_IMETHODIMP
     571           0 : nsImageLoadingContent::GetRequestType(imgIRequest* aRequest,
     572             :                                       int32_t* aRequestType)
     573             : {
     574           0 :   NS_PRECONDITION(aRequestType, "Null out param");
     575             : 
     576           0 :   ErrorResult result;
     577           0 :   *aRequestType = GetRequestType(aRequest, result);
     578           0 :   return result.StealNSResult();
     579             : }
     580             : 
     581             : already_AddRefed<nsIURI>
     582           4 : nsImageLoadingContent::GetCurrentURI(ErrorResult& aError)
     583             : {
     584           8 :   nsCOMPtr<nsIURI> uri;
     585           4 :   if (mCurrentRequest) {
     586           0 :     mCurrentRequest->GetURI(getter_AddRefs(uri));
     587           4 :   } else if (mCurrentURI) {
     588           0 :     nsresult rv = NS_EnsureSafeToReturn(mCurrentURI, getter_AddRefs(uri));
     589           0 :     if (NS_FAILED(rv)) {
     590           0 :       aError.Throw(rv);
     591             :     }
     592             :   }
     593             : 
     594           8 :   return uri.forget();
     595             : }
     596             : 
     597             : NS_IMETHODIMP
     598           4 : nsImageLoadingContent::GetCurrentURI(nsIURI** aURI)
     599             : {
     600           4 :   NS_ENSURE_ARG_POINTER(aURI);
     601             : 
     602           8 :   ErrorResult result;
     603           4 :   *aURI = GetCurrentURI(result).take();
     604           4 :   return result.StealNSResult();
     605             : }
     606             : 
     607             : NS_IMETHODIMP
     608           0 : nsImageLoadingContent::LoadImageWithChannel(nsIChannel* aChannel,
     609             :                                             nsIStreamListener** aListener)
     610             : {
     611             :   imgLoader* loader =
     612           0 :     nsContentUtils::GetImgLoaderForChannel(aChannel, GetOurOwnerDoc());
     613           0 :   if (!loader) {
     614           0 :     return NS_ERROR_NULL_POINTER;
     615             :   }
     616             : 
     617           0 :   nsCOMPtr<nsIDocument> doc = GetOurOwnerDoc();
     618           0 :   if (!doc) {
     619             :     // Don't bother
     620           0 :     *aListener = nullptr;
     621           0 :     return NS_OK;
     622             :   }
     623             : 
     624             :   // XXX what should we do with content policies here, if anything?
     625             :   // Shouldn't that be done before the start of the load?
     626             :   // XXX what about shouldProcess?
     627             : 
     628             :   // Our state might change. Watch it.
     629           0 :   AutoStateChanger changer(this, true);
     630             : 
     631             :   // Do the load.
     632           0 :   RefPtr<imgRequestProxy>& req = PrepareNextRequest(eImageLoadType_Normal);
     633             :   nsresult rv = loader->
     634           0 :     LoadImageWithChannel(aChannel, this, doc, aListener, getter_AddRefs(req));
     635           0 :   if (NS_SUCCEEDED(rv)) {
     636           0 :     TrackImage(req);
     637           0 :     ResetAnimationIfNeeded();
     638           0 :     return NS_OK;
     639             :   }
     640             : 
     641           0 :   MOZ_ASSERT(!req, "Shouldn't have non-null request here");
     642             :   // If we don't have a current URI, we might as well store this URI so people
     643             :   // know what we tried (and failed) to load.
     644           0 :   if (!mCurrentRequest)
     645           0 :     aChannel->GetURI(getter_AddRefs(mCurrentURI));
     646             : 
     647           0 :   FireEvent(NS_LITERAL_STRING("error"));
     648           0 :   FireEvent(NS_LITERAL_STRING("loadend"));
     649           0 :   return rv;
     650             : }
     651             : 
     652             : void
     653           0 : nsImageLoadingContent::ForceReload(const mozilla::dom::Optional<bool>& aNotify,
     654             :                                    mozilla::ErrorResult& aError)
     655             : {
     656           0 :   nsCOMPtr<nsIURI> currentURI;
     657           0 :   GetCurrentURI(getter_AddRefs(currentURI));
     658           0 :   if (!currentURI) {
     659           0 :     aError.Throw(NS_ERROR_NOT_AVAILABLE);
     660           0 :     return;
     661             :   }
     662             : 
     663             :   // defaults to true
     664           0 :   bool notify = !aNotify.WasPassed() || aNotify.Value();
     665             : 
     666             :   // We keep this flag around along with the old URI even for failed requests
     667             :   // without a live request object
     668             :   ImageLoadType loadType = \
     669           0 :     (mCurrentRequestFlags & REQUEST_IS_IMAGESET) ? eImageLoadType_Imageset
     670           0 :                                                  : eImageLoadType_Normal;
     671           0 :   nsresult rv = LoadImage(currentURI, true, notify, loadType, true, nullptr,
     672           0 :                           nsIRequest::VALIDATE_ALWAYS);
     673           0 :   if (NS_FAILED(rv)) {
     674           0 :     aError.Throw(rv);
     675             :   }
     676             : }
     677             : 
     678             : NS_IMETHODIMP
     679           0 : nsImageLoadingContent::ForceReload(bool aNotify /* = true */,
     680             :                                    uint8_t aArgc)
     681             : {
     682           0 :   mozilla::dom::Optional<bool> notify;
     683           0 :   if (aArgc >= 1) {
     684           0 :     notify.Construct() = aNotify;
     685             :   }
     686             : 
     687           0 :   ErrorResult result;
     688           0 :   ForceReload(notify, result);
     689           0 :   return result.StealNSResult();
     690             : }
     691             : 
     692             : NS_IMETHODIMP
     693           4 : nsImageLoadingContent::BlockOnload(imgIRequest* aRequest)
     694             : {
     695           4 :   if (aRequest == mCurrentRequest) {
     696           4 :     NS_ASSERTION(!(mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD),
     697             :                  "Double BlockOnload!?");
     698           4 :     mCurrentRequestFlags |= REQUEST_BLOCKS_ONLOAD;
     699           0 :   } else if (aRequest == mPendingRequest) {
     700           0 :     NS_ASSERTION(!(mPendingRequestFlags & REQUEST_BLOCKS_ONLOAD),
     701             :                  "Double BlockOnload!?");
     702           0 :     mPendingRequestFlags |= REQUEST_BLOCKS_ONLOAD;
     703             :   } else {
     704           0 :     return NS_OK;
     705             :   }
     706             : 
     707           4 :   nsIDocument* doc = GetOurCurrentDoc();
     708           4 :   if (doc) {
     709           4 :     doc->BlockOnload();
     710             :   }
     711             : 
     712           4 :   return NS_OK;
     713             : }
     714             : 
     715             : NS_IMETHODIMP
     716           4 : nsImageLoadingContent::UnblockOnload(imgIRequest* aRequest)
     717             : {
     718           4 :   if (aRequest == mCurrentRequest) {
     719           4 :     NS_ASSERTION(mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD,
     720             :                  "Double UnblockOnload!?");
     721           4 :     mCurrentRequestFlags &= ~REQUEST_BLOCKS_ONLOAD;
     722           0 :   } else if (aRequest == mPendingRequest) {
     723           0 :     NS_ASSERTION(mPendingRequestFlags & REQUEST_BLOCKS_ONLOAD,
     724             :                  "Double UnblockOnload!?");
     725           0 :     mPendingRequestFlags &= ~REQUEST_BLOCKS_ONLOAD;
     726             :   } else {
     727           0 :     return NS_OK;
     728             :   }
     729             : 
     730           4 :   nsIDocument* doc = GetOurCurrentDoc();
     731           4 :   if (doc) {
     732           4 :     doc->UnblockOnload(false);
     733             :   }
     734             : 
     735           4 :   return NS_OK;
     736             : }
     737             : 
     738             : /*
     739             :  * Non-interface methods
     740             :  */
     741             : 
     742             : nsresult
     743           4 : nsImageLoadingContent::LoadImage(const nsAString& aNewURI,
     744             :                                  bool aForce,
     745             :                                  bool aNotify,
     746             :                                  ImageLoadType aImageLoadType)
     747             : {
     748             :   // First, get a document (needed for security checks and the like)
     749           4 :   nsIDocument* doc = GetOurOwnerDoc();
     750           4 :   if (!doc) {
     751             :     // No reason to bother, I think...
     752           0 :     return NS_OK;
     753             :   }
     754             : 
     755             :   // Pending load/error events need to be canceled in some situations. This
     756             :   // is not documented in the spec, but can cause site compat problems if not
     757             :   // done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
     758           4 :   CancelPendingEvent();
     759             : 
     760           4 :   if (aNewURI.IsEmpty()) {
     761             :     // Cancel image requests and then fire only error event per spec.
     762           0 :     CancelImageRequests(aNotify);
     763             :     // Mark error event as cancelable only for src="" case, since only this
     764             :     // error causes site compat problem (bug 1308069) for now.
     765           0 :     FireEvent(NS_LITERAL_STRING("error"), true);
     766           0 :     return NS_OK;
     767             :   }
     768             : 
     769             :   // Fire loadstart event
     770           4 :   FireEvent(NS_LITERAL_STRING("loadstart"));
     771             : 
     772             :   // Parse the URI string to get image URI
     773           8 :   nsCOMPtr<nsIURI> imageURI;
     774           4 :   nsresult rv = StringToURI(aNewURI, doc, getter_AddRefs(imageURI));
     775           4 :   NS_ENSURE_SUCCESS(rv, rv);
     776             :   // XXXbiesi fire onerror if that failed?
     777             : 
     778           4 :   NS_TryToSetImmutable(imageURI);
     779             : 
     780           4 :   return LoadImage(imageURI, aForce, aNotify, aImageLoadType, false, doc);
     781             : }
     782             : 
     783             : nsresult
     784           4 : nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
     785             :                                  bool aForce,
     786             :                                  bool aNotify,
     787             :                                  ImageLoadType aImageLoadType,
     788             :                                  bool aLoadStart,
     789             :                                  nsIDocument* aDocument,
     790             :                                  nsLoadFlags aLoadFlags)
     791             : {
     792           4 :   MOZ_ASSERT(!mIsStartingImageLoad, "some evil code is reentering LoadImage.");
     793           4 :   if (mIsStartingImageLoad) {
     794           0 :     return NS_OK;
     795             :   }
     796             : 
     797             :   // Pending load/error events need to be canceled in some situations. This
     798             :   // is not documented in the spec, but can cause site compat problems if not
     799             :   // done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
     800           4 :   CancelPendingEvent();
     801             : 
     802             :   // Fire loadstart event if required
     803           4 :   if (aLoadStart) {
     804           0 :     FireEvent(NS_LITERAL_STRING("loadstart"));
     805             :   }
     806             : 
     807           4 :   if (!mLoadingEnabled) {
     808             :     // XXX Why fire an error here? seems like the callers to SetLoadingEnabled
     809             :     // don't want/need it.
     810           0 :     FireEvent(NS_LITERAL_STRING("error"));
     811           0 :     FireEvent(NS_LITERAL_STRING("loadend"));
     812           0 :     return NS_OK;
     813             :   }
     814             : 
     815           4 :   NS_ASSERTION(!aDocument || aDocument == GetOurOwnerDoc(),
     816             :                "Bogus document passed in");
     817             :   // First, get a document (needed for security checks and the like)
     818           4 :   if (!aDocument) {
     819           0 :     aDocument = GetOurOwnerDoc();
     820           0 :     if (!aDocument) {
     821             :       // No reason to bother, I think...
     822           0 :       return NS_OK;
     823             :     }
     824             :   }
     825             : 
     826           8 :   AutoRestore<bool> guard(mIsStartingImageLoad);
     827           4 :   mIsStartingImageLoad = true;
     828             : 
     829             :   // Data documents, or documents from DOMParser shouldn't perform image loading.
     830           4 :   if (aDocument->IsLoadedAsData()) {
     831           0 :     SetBlockedRequest(nsIContentPolicy::REJECT_REQUEST);
     832             : 
     833           0 :     FireEvent(NS_LITERAL_STRING("error"));
     834           0 :     FireEvent(NS_LITERAL_STRING("loadend"));
     835           0 :     return NS_OK;
     836             :   }
     837             : 
     838             :   // URI equality check.
     839             :   //
     840             :   // We skip the equality check if our current image was blocked, since in that
     841             :   // case we really do want to try loading again.
     842           4 :   if (!aForce && NS_CP_ACCEPTED(mImageBlockingStatus)) {
     843           8 :     nsCOMPtr<nsIURI> currentURI;
     844           4 :     GetCurrentURI(getter_AddRefs(currentURI));
     845             :     bool equal;
     846           4 :     if (currentURI &&
     847           4 :         NS_SUCCEEDED(currentURI->Equals(aNewURI, &equal)) &&
     848             :         equal) {
     849             :       // Nothing to do here.
     850           0 :       return NS_OK;
     851             :     }
     852             :   }
     853             : 
     854             :   // From this point on, our image state could change. Watch it.
     855           8 :   AutoStateChanger changer(this, aNotify);
     856             : 
     857             :   // Sanity check.
     858             :   //
     859             :   // We use the principal of aDocument to avoid having to QI |this| an extra
     860             :   // time. It should always be the same as the principal of this node.
     861             : #ifdef DEBUG
     862           4 :   nsIContent* thisContent = AsContent();
     863           4 :   MOZ_ASSERT(thisContent->NodePrincipal() == aDocument->NodePrincipal(),
     864             :              "Principal mismatch?");
     865             : #endif
     866             : 
     867           4 :   nsContentPolicyType policyType = PolicyTypeForLoad(aImageLoadType);
     868             : 
     869           4 :   nsLoadFlags loadFlags = aLoadFlags;
     870           4 :   int32_t corsmode = GetCORSMode();
     871           4 :   if (corsmode == CORS_ANONYMOUS) {
     872           0 :     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
     873           4 :   } else if (corsmode == CORS_USE_CREDENTIALS) {
     874           0 :     loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
     875             :   }
     876             : 
     877             :   // get document wide referrer policy
     878             :   // if referrer attributes are enabled in preferences, load img referrer attribute
     879             :   // if the image does not provide a referrer attribute, ignore this
     880           4 :   net::ReferrerPolicy referrerPolicy = aDocument->GetReferrerPolicy();
     881           4 :   net::ReferrerPolicy imgReferrerPolicy = GetImageReferrerPolicy();
     882           4 :   if (imgReferrerPolicy != net::RP_Unset) {
     883           0 :     referrerPolicy = imgReferrerPolicy;
     884             :   }
     885             : 
     886           4 :   RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
     887             :   nsCOMPtr<nsIContent> content =
     888           8 :       do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
     889             :   nsCOMPtr<nsINode> thisNode =
     890           8 :     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
     891          12 :   nsresult rv = nsContentUtils::LoadImage(aNewURI,
     892             :                                           thisNode,
     893             :                                           aDocument,
     894             :                                           aDocument->NodePrincipal(),
     895             :                                           aDocument->GetDocumentURI(),
     896             :                                           referrerPolicy,
     897             :                                           this, loadFlags,
     898           4 :                                           content->LocalName(),
     899           8 :                                           getter_AddRefs(req),
     900             :                                           policyType,
     901           8 :                                           mUseUrgentStartForChannel);
     902             : 
     903             :   // Reset the flag to avoid loading from XPCOM or somewhere again else without
     904             :   // initiated by user interaction.
     905           4 :   mUseUrgentStartForChannel = false;
     906             : 
     907             :   // Tell the document to forget about the image preload, if any, for
     908             :   // this URI, now that we might have another imgRequestProxy for it.
     909             :   // That way if we get canceled later the image load won't continue.
     910           4 :   aDocument->ForgetImagePreload(aNewURI);
     911             : 
     912           4 :   if (NS_SUCCEEDED(rv)) {
     913           4 :     TrackImage(req);
     914           4 :     ResetAnimationIfNeeded();
     915             : 
     916             :     // Handle cases when we just ended up with a pending request but it's
     917             :     // already done.  In that situation we have to synchronously switch that
     918             :     // request to being the current request, because websites depend on that
     919             :     // behavior.
     920           4 :     if (req == mPendingRequest) {
     921             :       uint32_t pendingLoadStatus;
     922           0 :       rv = req->GetImageStatus(&pendingLoadStatus);
     923           0 :       if (NS_SUCCEEDED(rv) &&
     924           0 :           (pendingLoadStatus & imgIRequest::STATUS_LOAD_COMPLETE)) {
     925           0 :         MakePendingRequestCurrent();
     926           0 :         MOZ_ASSERT(mCurrentRequest,
     927             :                    "How could we not have a current request here?");
     928             : 
     929           0 :         nsImageFrame *f = do_QueryFrame(GetOurPrimaryFrame());
     930           0 :         if (f) {
     931           0 :           f->NotifyNewCurrentRequest(mCurrentRequest, NS_OK);
     932             :         }
     933             :       }
     934             :     }
     935             :   } else {
     936           0 :     MOZ_ASSERT(!req, "Shouldn't have non-null request here");
     937             :     // If we don't have a current URI, we might as well store this URI so people
     938             :     // know what we tried (and failed) to load.
     939           0 :     if (!mCurrentRequest)
     940           0 :       mCurrentURI = aNewURI;
     941             : 
     942           0 :     FireEvent(NS_LITERAL_STRING("error"));
     943           0 :     FireEvent(NS_LITERAL_STRING("loadend"));
     944             :   }
     945             : 
     946           4 :   return NS_OK;
     947             : }
     948             : 
     949             : nsresult
     950           0 : nsImageLoadingContent::ForceImageState(bool aForce,
     951             :                                        EventStates::InternalType aState)
     952             : {
     953           0 :   mIsImageStateForced = aForce;
     954           0 :   mForcedImageState = EventStates(aState);
     955           0 :   return NS_OK;
     956             : }
     957             : 
     958             : NS_IMETHODIMP
     959           0 : nsImageLoadingContent::GetNaturalWidth(uint32_t* aNaturalWidth)
     960             : {
     961           0 :   NS_ENSURE_ARG_POINTER(aNaturalWidth);
     962             : 
     963           0 :   nsCOMPtr<imgIContainer> image;
     964           0 :   if (mCurrentRequest) {
     965           0 :     mCurrentRequest->GetImage(getter_AddRefs(image));
     966             :   }
     967             : 
     968             :   int32_t width;
     969           0 :   if (image && NS_SUCCEEDED(image->GetWidth(&width))) {
     970           0 :     *aNaturalWidth = width;
     971             :   } else {
     972           0 :     *aNaturalWidth = 0;
     973             :   }
     974             : 
     975           0 :   return NS_OK;
     976             : }
     977             : 
     978             : NS_IMETHODIMP
     979           0 : nsImageLoadingContent::GetNaturalHeight(uint32_t* aNaturalHeight)
     980             : {
     981           0 :   NS_ENSURE_ARG_POINTER(aNaturalHeight);
     982             : 
     983           0 :   nsCOMPtr<imgIContainer> image;
     984           0 :   if (mCurrentRequest) {
     985           0 :     mCurrentRequest->GetImage(getter_AddRefs(image));
     986             :   }
     987             : 
     988             :   int32_t height;
     989           0 :   if (image && NS_SUCCEEDED(image->GetHeight(&height))) {
     990           0 :     *aNaturalHeight = height;
     991             :   } else {
     992           0 :     *aNaturalHeight = 0;
     993             :   }
     994             : 
     995           0 :   return NS_OK;
     996             : }
     997             : 
     998             : EventStates
     999          24 : nsImageLoadingContent::ImageState() const
    1000             : {
    1001          24 :   if (mIsImageStateForced) {
    1002           0 :     return mForcedImageState;
    1003             :   }
    1004             : 
    1005          24 :   EventStates states;
    1006             : 
    1007          24 :   if (mBroken) {
    1008           8 :     states |= NS_EVENT_STATE_BROKEN;
    1009             :   }
    1010          24 :   if (mUserDisabled) {
    1011           0 :     states |= NS_EVENT_STATE_USERDISABLED;
    1012             :   }
    1013          24 :   if (mSuppressed) {
    1014           0 :     states |= NS_EVENT_STATE_SUPPRESSED;
    1015             :   }
    1016          24 :   if (mLoading) {
    1017           4 :     states |= NS_EVENT_STATE_LOADING;
    1018             :   }
    1019             : 
    1020          24 :   return states;
    1021             : }
    1022             : 
    1023             : void
    1024          16 : nsImageLoadingContent::UpdateImageState(bool aNotify)
    1025             : {
    1026          16 :   if (mStateChangerDepth > 0) {
    1027             :     // Ignore this call; we'll update our state when the outermost state changer
    1028             :     // is destroyed. Need this to work around the fact that some ImageLib
    1029             :     // stuff is actually sync and hence we can get OnStopDecode called while
    1030             :     // we're still under LoadImage, and OnStopDecode doesn't know anything about
    1031             :     // aNotify.
    1032             :     // XXX - This machinery should be removed after bug 521604.
    1033           0 :     return;
    1034             :   }
    1035             : 
    1036          16 :   nsIContent* thisContent = AsContent();
    1037             : 
    1038          16 :   mLoading = mBroken = mUserDisabled = mSuppressed = false;
    1039             : 
    1040             :   // If we were blocked by server-based content policy, we claim to be
    1041             :   // suppressed.  If we were blocked by type-based content policy, we claim to
    1042             :   // be user-disabled.  Otherwise, claim to be broken.
    1043          16 :   if (mImageBlockingStatus == nsIContentPolicy::REJECT_SERVER) {
    1044           0 :     mSuppressed = true;
    1045          16 :   } else if (mImageBlockingStatus == nsIContentPolicy::REJECT_TYPE) {
    1046           0 :     mUserDisabled = true;
    1047          16 :   } else if (!mCurrentRequest) {
    1048             :     // No current request means error, since we weren't disabled or suppressed
    1049           0 :     mBroken = true;
    1050             :   } else {
    1051             :     uint32_t currentLoadStatus;
    1052          16 :     nsresult rv = mCurrentRequest->GetImageStatus(&currentLoadStatus);
    1053          16 :     if (NS_FAILED(rv) || (currentLoadStatus & imgIRequest::STATUS_ERROR)) {
    1054           0 :       mBroken = true;
    1055          16 :     } else if (!(currentLoadStatus & imgIRequest::STATUS_SIZE_AVAILABLE)) {
    1056           4 :       mLoading = true;
    1057             :     }
    1058             :   }
    1059             : 
    1060          16 :   NS_ASSERTION(thisContent->IsElement(), "Not an element?");
    1061          16 :   thisContent->AsElement()->UpdateState(aNotify);
    1062             : }
    1063             : 
    1064             : void
    1065           0 : nsImageLoadingContent::CancelImageRequests(bool aNotify)
    1066             : {
    1067           0 :   AutoStateChanger changer(this, aNotify);
    1068           0 :   ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
    1069           0 :   ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
    1070           0 : }
    1071             : 
    1072             : nsresult
    1073           0 : nsImageLoadingContent::UseAsPrimaryRequest(imgRequestProxy* aRequest,
    1074             :                                            bool aNotify,
    1075             :                                            ImageLoadType aImageLoadType)
    1076             : {
    1077             :   // Our state will change. Watch it.
    1078           0 :   AutoStateChanger changer(this, aNotify);
    1079             : 
    1080             :   // Get rid if our existing images
    1081           0 :   ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
    1082           0 :   ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
    1083             : 
    1084             :   // Clone the request we were given.
    1085           0 :   RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
    1086           0 :   nsresult rv = aRequest->Clone(this, getter_AddRefs(req));
    1087           0 :   if (NS_SUCCEEDED(rv)) {
    1088           0 :     TrackImage(req);
    1089             :   } else {
    1090           0 :     MOZ_ASSERT(!req, "Shouldn't have non-null request here");
    1091           0 :     return rv;
    1092             :   }
    1093             : 
    1094           0 :   return NS_OK;
    1095             : }
    1096             : 
    1097             : nsIDocument*
    1098          28 : nsImageLoadingContent::GetOurOwnerDoc()
    1099             : {
    1100          28 :   return AsContent()->OwnerDoc();
    1101             : }
    1102             : 
    1103             : nsIDocument*
    1104          14 : nsImageLoadingContent::GetOurCurrentDoc()
    1105             : {
    1106          14 :   return AsContent()->GetComposedDoc();
    1107             : }
    1108             : 
    1109             : nsIFrame*
    1110          12 : nsImageLoadingContent::GetOurPrimaryFrame()
    1111             : {
    1112          12 :   return AsContent()->GetPrimaryFrame();
    1113             : }
    1114             : 
    1115           0 : nsPresContext* nsImageLoadingContent::GetFramePresContext()
    1116             : {
    1117           0 :   nsIFrame* frame = GetOurPrimaryFrame();
    1118           0 :   if (!frame) {
    1119           0 :     return nullptr;
    1120             :   }
    1121             : 
    1122           0 :   return frame->PresContext();
    1123             : }
    1124             : 
    1125             : nsresult
    1126           8 : nsImageLoadingContent::StringToURI(const nsAString& aSpec,
    1127             :                                    nsIDocument* aDocument,
    1128             :                                    nsIURI** aURI)
    1129             : {
    1130           8 :   NS_PRECONDITION(aDocument, "Must have a document");
    1131           8 :   NS_PRECONDITION(aURI, "Null out param");
    1132             : 
    1133             :   // (1) Get the base URI
    1134           8 :   nsIContent* thisContent = AsContent();
    1135          16 :   nsCOMPtr<nsIURI> baseURL = thisContent->GetBaseURI();
    1136             : 
    1137             :   // (2) Get the charset
    1138           8 :   auto encoding = aDocument->GetDocumentCharacterSet();
    1139             : 
    1140             :   // (3) Construct the silly thing
    1141           8 :   return NS_NewURI(aURI,
    1142             :                    aSpec,
    1143             :                    encoding,
    1144             :                    baseURL,
    1145          16 :                    nsContentUtils::GetIOService());
    1146             : }
    1147             : 
    1148             : nsresult
    1149          12 : nsImageLoadingContent::FireEvent(const nsAString& aEventType, bool aIsCancelable)
    1150             : {
    1151          12 :   if (nsContentUtils::DocumentInactiveForImageLoads(GetOurOwnerDoc())) {
    1152             :     // Don't bother to fire any events, especially error events.
    1153           0 :     return NS_OK;
    1154             :   }
    1155             : 
    1156             :   // We have to fire the event asynchronously so that we won't go into infinite
    1157             :   // loops in cases when onLoad handlers reset the src and the new src is in
    1158             :   // cache.
    1159             : 
    1160          24 :   nsCOMPtr<nsINode> thisNode = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
    1161             : 
    1162             :   RefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
    1163          36 :     new LoadBlockingAsyncEventDispatcher(thisNode, aEventType, false, false);
    1164          12 :   loadBlockingAsyncDispatcher->PostDOMEvent();
    1165             : 
    1166          12 :   if (aIsCancelable) {
    1167           0 :     mPendingEvent = loadBlockingAsyncDispatcher;
    1168             :   }
    1169             : 
    1170          12 :   return NS_OK;
    1171             : }
    1172             : 
    1173             : void
    1174          14 : nsImageLoadingContent::AsyncEventRunning(AsyncEventDispatcher* aEvent)
    1175             : {
    1176          14 :   if (mPendingEvent == aEvent) {
    1177           0 :     mPendingEvent = nullptr;
    1178             :   }
    1179          14 : }
    1180             : 
    1181             : void
    1182           8 : nsImageLoadingContent::CancelPendingEvent()
    1183             : {
    1184           8 :   if (mPendingEvent) {
    1185           0 :     mPendingEvent->Cancel();
    1186           0 :     mPendingEvent = nullptr;
    1187             :   }
    1188           8 : }
    1189             : 
    1190             : RefPtr<imgRequestProxy>&
    1191           4 : nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
    1192             : {
    1193           4 :   nsImageFrame* imageFrame = do_QueryFrame(GetOurPrimaryFrame());
    1194           4 :   nsSVGImageFrame* svgImageFrame = do_QueryFrame(GetOurPrimaryFrame());
    1195           4 :   if (imageFrame || svgImageFrame) {
    1196             :     // Detect JavaScript-based animations created by changing the |src|
    1197             :     // attribute on a timer.
    1198           0 :     TimeStamp now = TimeStamp::Now();
    1199             :     TimeDuration threshold =
    1200             :       TimeDuration::FromMilliseconds(
    1201           0 :         gfxPrefs::ImageInferSrcAnimationThresholdMS());
    1202             : 
    1203             :     // If the length of time between request changes is less than the threshold,
    1204             :     // then force sync decoding to eliminate flicker from the animation.
    1205           0 :     bool forceSync = (now - mMostRecentRequestChange < threshold);
    1206           0 :     if (imageFrame) {
    1207           0 :       imageFrame->SetForceSyncDecoding(forceSync);
    1208             :     } else {
    1209           0 :       svgImageFrame->SetForceSyncDecoding(forceSync);
    1210             :     }
    1211             : 
    1212           0 :     mMostRecentRequestChange = now;
    1213             :   }
    1214             : 
    1215             :   // We only want to cancel the existing current request if size is not
    1216             :   // available. bz says the web depends on this behavior.
    1217             :   // Otherwise, we get rid of any half-baked request that might be sitting there
    1218             :   // and make this one current.
    1219             :   // TODO: Bug 583491
    1220             :   // Investigate/Cleanup NS_ERROR_IMAGE_SRC_CHANGED use in nsImageFrame.cpp
    1221           4 :   return HaveSize(mCurrentRequest) ?
    1222             :            PreparePendingRequest(aImageLoadType) :
    1223           4 :            PrepareCurrentRequest(aImageLoadType);
    1224             : }
    1225             : 
    1226             : nsresult
    1227           0 : nsImageLoadingContent::SetBlockedRequest(int16_t aContentDecision)
    1228             : {
    1229             :   // If this is not calling from LoadImage, for example, from ServiceWorker,
    1230             :   // bail out.
    1231           0 :   if (!mIsStartingImageLoad) {
    1232           0 :     return NS_OK;
    1233             :   }
    1234             : 
    1235             :   // Sanity
    1236           0 :   MOZ_ASSERT(!NS_CP_ACCEPTED(aContentDecision), "Blocked but not?");
    1237             : 
    1238             :   // We should never have a pending request after we got blocked.
    1239           0 :   MOZ_ASSERT(!mPendingRequest, "mPendingRequest should be null.");
    1240             : 
    1241           0 :   if (HaveSize(mCurrentRequest)) {
    1242             :     // PreparePendingRequest set mPendingRequestFlags, now since we've decided
    1243             :     // to block it, we reset it back to 0.
    1244           0 :     mPendingRequestFlags = 0;
    1245             :   } else {
    1246           0 :     mImageBlockingStatus = aContentDecision;
    1247             :   }
    1248             : 
    1249           0 :   return NS_OK;
    1250             : }
    1251             : 
    1252             : RefPtr<imgRequestProxy>&
    1253           4 : nsImageLoadingContent::PrepareCurrentRequest(ImageLoadType aImageLoadType)
    1254             : {
    1255             :   // Blocked images go through SetBlockedRequest, which is a separate path. For
    1256             :   // everything else, we're unblocked.
    1257           4 :   mImageBlockingStatus = nsIContentPolicy::ACCEPT;
    1258             : 
    1259             :   // Get rid of anything that was there previously.
    1260             :   ClearCurrentRequest(NS_BINDING_ABORTED,
    1261           4 :                       Some(OnNonvisible::DISCARD_IMAGES));
    1262             : 
    1263           4 :   if (mNewRequestsWillNeedAnimationReset) {
    1264           0 :     mCurrentRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
    1265             :   }
    1266             : 
    1267           4 :   if (aImageLoadType == eImageLoadType_Imageset) {
    1268           0 :     mCurrentRequestFlags |= REQUEST_IS_IMAGESET;
    1269             :   }
    1270             : 
    1271             :   // Return a reference.
    1272           4 :   return mCurrentRequest;
    1273             : }
    1274             : 
    1275             : RefPtr<imgRequestProxy>&
    1276           0 : nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType)
    1277             : {
    1278             :   // Get rid of anything that was there previously.
    1279             :   ClearPendingRequest(NS_BINDING_ABORTED,
    1280           0 :                       Some(OnNonvisible::DISCARD_IMAGES));
    1281             : 
    1282           0 :   if (mNewRequestsWillNeedAnimationReset) {
    1283           0 :     mPendingRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
    1284             :   }
    1285             : 
    1286           0 :   if (aImageLoadType == eImageLoadType_Imageset) {
    1287           0 :     mPendingRequestFlags |= REQUEST_IS_IMAGESET;
    1288             :   }
    1289             : 
    1290             :   // Return a reference.
    1291           0 :   return mPendingRequest;
    1292             : }
    1293             : 
    1294             : namespace {
    1295             : 
    1296             : class ImageRequestAutoLock
    1297             : {
    1298             : public:
    1299           0 :   explicit ImageRequestAutoLock(imgIRequest* aRequest)
    1300           0 :     : mRequest(aRequest)
    1301             :   {
    1302           0 :     if (mRequest) {
    1303           0 :       mRequest->LockImage();
    1304             :     }
    1305           0 :   }
    1306             : 
    1307           0 :   ~ImageRequestAutoLock()
    1308           0 :   {
    1309           0 :     if (mRequest) {
    1310           0 :       mRequest->UnlockImage();
    1311             :     }
    1312           0 :   }
    1313             : 
    1314             : private:
    1315             :   nsCOMPtr<imgIRequest> mRequest;
    1316             : };
    1317             : 
    1318             : } // namespace
    1319             : 
    1320             : void
    1321           0 : nsImageLoadingContent::MakePendingRequestCurrent()
    1322             : {
    1323           0 :   MOZ_ASSERT(mPendingRequest);
    1324             : 
    1325             :   // Lock mCurrentRequest for the duration of this method.  We do this because
    1326             :   // PrepareCurrentRequest() might unlock mCurrentRequest.  If mCurrentRequest
    1327             :   // and mPendingRequest are both requests for the same image, unlocking
    1328             :   // mCurrentRequest before we lock mPendingRequest can cause the lock count
    1329             :   // to go to 0 and the image to be discarded!
    1330           0 :   ImageRequestAutoLock autoLock(mCurrentRequest);
    1331             : 
    1332             :   ImageLoadType loadType = \
    1333           0 :     (mPendingRequestFlags & REQUEST_IS_IMAGESET) ? eImageLoadType_Imageset
    1334           0 :                                                  : eImageLoadType_Normal;
    1335             : 
    1336           0 :   PrepareCurrentRequest(loadType) = mPendingRequest;
    1337           0 :   mPendingRequest = nullptr;
    1338           0 :   mCurrentRequestFlags = mPendingRequestFlags;
    1339           0 :   mPendingRequestFlags = 0;
    1340           0 :   mCurrentRequestRegistered = mPendingRequestRegistered;
    1341           0 :   mPendingRequestRegistered = false;
    1342           0 :   ResetAnimationIfNeeded();
    1343           0 : }
    1344             : 
    1345             : void
    1346           4 : nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
    1347             :                                            const Maybe<OnNonvisible>& aNonvisibleAction)
    1348             : {
    1349           4 :   if (!mCurrentRequest) {
    1350             :     // Even if we didn't have a current request, we might have been keeping
    1351             :     // a URI and flags as a placeholder for a failed load. Clear that now.
    1352           4 :     mCurrentURI = nullptr;
    1353           4 :     mCurrentRequestFlags = 0;
    1354           4 :     return;
    1355             :   }
    1356           0 :   MOZ_ASSERT(!mCurrentURI,
    1357             :              "Shouldn't have both mCurrentRequest and mCurrentURI!");
    1358             : 
    1359             :   // Deregister this image from the refresh driver so it no longer receives
    1360             :   // notifications.
    1361           0 :   nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mCurrentRequest,
    1362           0 :                                         &mCurrentRequestRegistered);
    1363             : 
    1364             :   // Clean up the request.
    1365           0 :   UntrackImage(mCurrentRequest, aNonvisibleAction);
    1366           0 :   mCurrentRequest->CancelAndForgetObserver(aReason);
    1367           0 :   mCurrentRequest = nullptr;
    1368           0 :   mCurrentRequestFlags = 0;
    1369             : }
    1370             : 
    1371             : void
    1372           0 : nsImageLoadingContent::ClearPendingRequest(nsresult aReason,
    1373             :                                            const Maybe<OnNonvisible>& aNonvisibleAction)
    1374             : {
    1375           0 :   if (!mPendingRequest)
    1376           0 :     return;
    1377             : 
    1378             :   // Deregister this image from the refresh driver so it no longer receives
    1379             :   // notifications.
    1380           0 :   nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
    1381           0 :                                         &mPendingRequestRegistered);
    1382             : 
    1383           0 :   UntrackImage(mPendingRequest, aNonvisibleAction);
    1384           0 :   mPendingRequest->CancelAndForgetObserver(aReason);
    1385           0 :   mPendingRequest = nullptr;
    1386           0 :   mPendingRequestFlags = 0;
    1387             : }
    1388             : 
    1389             : bool*
    1390           0 : nsImageLoadingContent::GetRegisteredFlagForRequest(imgIRequest* aRequest)
    1391             : {
    1392           0 :   if (aRequest == mCurrentRequest) {
    1393           0 :     return &mCurrentRequestRegistered;
    1394             :   }
    1395           0 :   if (aRequest == mPendingRequest) {
    1396           0 :     return &mPendingRequestRegistered;
    1397             :   }
    1398           0 :   return nullptr;
    1399             : }
    1400             : 
    1401             : void
    1402           4 : nsImageLoadingContent::ResetAnimationIfNeeded()
    1403             : {
    1404           8 :   if (mCurrentRequest &&
    1405           8 :       (mCurrentRequestFlags & REQUEST_NEEDS_ANIMATION_RESET)) {
    1406           0 :     nsCOMPtr<imgIContainer> container;
    1407           0 :     mCurrentRequest->GetImage(getter_AddRefs(container));
    1408           0 :     if (container)
    1409           0 :       container->ResetAnimation();
    1410           0 :     mCurrentRequestFlags &= ~REQUEST_NEEDS_ANIMATION_RESET;
    1411             :   }
    1412           4 : }
    1413             : 
    1414             : bool
    1415           4 : nsImageLoadingContent::HaveSize(imgIRequest *aImage)
    1416             : {
    1417             :   // Handle the null case
    1418           4 :   if (!aImage)
    1419           4 :     return false;
    1420             : 
    1421             :   // Query the image
    1422             :   uint32_t status;
    1423           0 :   nsresult rv = aImage->GetImageStatus(&status);
    1424           0 :   return (NS_SUCCEEDED(rv) && (status & imgIRequest::STATUS_SIZE_AVAILABLE));
    1425             : }
    1426             : 
    1427             : void
    1428          25 : nsImageLoadingContent::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
    1429             :                                   nsIContent* aBindingParent,
    1430             :                                   bool aCompileEventHandlers)
    1431             : {
    1432             :   // We may be entering the document, so if our image should be tracked,
    1433             :   // track it.
    1434          25 :   if (!aDocument)
    1435          14 :     return;
    1436             : 
    1437          11 :   TrackImage(mCurrentRequest);
    1438          11 :   TrackImage(mPendingRequest);
    1439             : 
    1440          11 :   if (mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD)
    1441           0 :     aDocument->BlockOnload();
    1442             : }
    1443             : 
    1444             : void
    1445           2 : nsImageLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
    1446             : {
    1447             :   // We may be leaving the document, so if our image is tracked, untrack it.
    1448           2 :   nsCOMPtr<nsIDocument> doc = GetOurCurrentDoc();
    1449           2 :   if (!doc)
    1450           2 :     return;
    1451             : 
    1452           0 :   UntrackImage(mCurrentRequest);
    1453           0 :   UntrackImage(mPendingRequest);
    1454             : 
    1455           0 :   if (mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD)
    1456           0 :     doc->UnblockOnload(false);
    1457             : }
    1458             : 
    1459             : void
    1460           0 : nsImageLoadingContent::OnVisibilityChange(Visibility aNewVisibility,
    1461             :                                           const Maybe<OnNonvisible>& aNonvisibleAction)
    1462             : {
    1463           0 :   switch (aNewVisibility) {
    1464             :     case Visibility::APPROXIMATELY_VISIBLE:
    1465           0 :       TrackImage(mCurrentRequest);
    1466           0 :       TrackImage(mPendingRequest);
    1467           0 :       break;
    1468             : 
    1469             :     case Visibility::APPROXIMATELY_NONVISIBLE:
    1470           0 :       UntrackImage(mCurrentRequest, aNonvisibleAction);
    1471           0 :       UntrackImage(mPendingRequest, aNonvisibleAction);
    1472           0 :       break;
    1473             : 
    1474             :     case Visibility::UNTRACKED:
    1475           0 :       MOZ_ASSERT_UNREACHABLE("Shouldn't notify for untracked visibility");
    1476             :       break;
    1477             :   }
    1478           0 : }
    1479             : 
    1480             : void
    1481          26 : nsImageLoadingContent::TrackImage(imgIRequest* aImage,
    1482             :                                   nsIFrame* aFrame /*= nullptr */)
    1483             : {
    1484          26 :   if (!aImage)
    1485          22 :     return;
    1486             : 
    1487           4 :   MOZ_ASSERT(aImage == mCurrentRequest || aImage == mPendingRequest,
    1488             :              "Why haven't we heard of this request?");
    1489             : 
    1490           4 :   nsIDocument* doc = GetOurCurrentDoc();
    1491           4 :   if (!doc) {
    1492           0 :     return;
    1493             :   }
    1494             : 
    1495           4 :   if (!aFrame) {
    1496           4 :     aFrame = GetOurPrimaryFrame();
    1497             :   }
    1498             : 
    1499             :   /* This line is deceptively simple. It hides a lot of subtlety. Before we
    1500             :    * create an nsImageFrame we call nsImageFrame::ShouldCreateImageFrameFor
    1501             :    * to determine if we should create an nsImageFrame or create a frame based
    1502             :    * on the display of the element (ie inline, block, etc). Inline, block, etc
    1503             :    * frames don't register for visibility tracking so they will return UNTRACKED
    1504             :    * from GetVisibility(). So this line is choosing to mark such images as
    1505             :    * visible. Once the image loads we will get an nsImageFrame and the proper
    1506             :    * visibility. This is a pitfall of tracking the visibility on the frames
    1507             :    * instead of the content node.
    1508             :    */
    1509           4 :   if (!aFrame || aFrame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) {
    1510           4 :     return;
    1511             :   }
    1512             : 
    1513           0 :   if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
    1514           0 :     mCurrentRequestFlags |= REQUEST_IS_TRACKED;
    1515           0 :     doc->ImageTracker()->Add(mCurrentRequest);
    1516             :   }
    1517           0 :   if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
    1518           0 :     mPendingRequestFlags |= REQUEST_IS_TRACKED;
    1519           0 :     doc->ImageTracker()->Add(mPendingRequest);
    1520             :   }
    1521             : }
    1522             : 
    1523             : void
    1524           0 : nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
    1525             :                                     const Maybe<OnNonvisible>& aNonvisibleAction
    1526             :                                       /* = Nothing() */)
    1527             : {
    1528           0 :   if (!aImage)
    1529           0 :     return;
    1530             : 
    1531           0 :   MOZ_ASSERT(aImage == mCurrentRequest || aImage == mPendingRequest,
    1532             :              "Why haven't we heard of this request?");
    1533             : 
    1534             :   // We may not be in the document.  If we outlived our document that's fine,
    1535             :   // because the document empties out the tracker and unlocks all locked images
    1536             :   // on destruction.  But if we were never in the document we may need to force
    1537             :   // discarding the image here, since this is the only chance we have.
    1538           0 :   nsIDocument* doc = GetOurCurrentDoc();
    1539           0 :   if (aImage == mCurrentRequest) {
    1540           0 :     if (doc && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
    1541           0 :       mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
    1542           0 :       doc->ImageTracker()->Remove(
    1543             :         mCurrentRequest,
    1544           0 :         aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
    1545             :           ? ImageTracker::REQUEST_DISCARD
    1546           0 :           : 0);
    1547           0 :     } else if (aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)) {
    1548             :       // If we're not in the document we may still need to be discarded.
    1549           0 :       aImage->RequestDiscard();
    1550             :     }
    1551             :   }
    1552           0 :   if (aImage == mPendingRequest) {
    1553           0 :     if (doc && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
    1554           0 :       mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
    1555           0 :       doc->ImageTracker()->Remove(
    1556             :         mPendingRequest,
    1557           0 :         aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
    1558             :           ? ImageTracker::REQUEST_DISCARD
    1559           0 :           : 0);
    1560           0 :     } else if (aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)) {
    1561             :       // If we're not in the document we may still need to be discarded.
    1562           0 :       aImage->RequestDiscard();
    1563             :     }
    1564             :   }
    1565             : }
    1566             : 
    1567             : 
    1568             : void
    1569           0 : nsImageLoadingContent::CreateStaticImageClone(nsImageLoadingContent* aDest) const
    1570             : {
    1571           0 :   aDest->mCurrentRequest = nsContentUtils::GetStaticRequest(mCurrentRequest);
    1572           0 :   aDest->TrackImage(aDest->mCurrentRequest);
    1573           0 :   aDest->mForcedImageState = mForcedImageState;
    1574           0 :   aDest->mImageBlockingStatus = mImageBlockingStatus;
    1575           0 :   aDest->mLoadingEnabled = mLoadingEnabled;
    1576           0 :   aDest->mStateChangerDepth = mStateChangerDepth;
    1577           0 :   aDest->mIsImageStateForced = mIsImageStateForced;
    1578           0 :   aDest->mLoading = mLoading;
    1579           0 :   aDest->mBroken = mBroken;
    1580           0 :   aDest->mUserDisabled = mUserDisabled;
    1581           0 :   aDest->mSuppressed = mSuppressed;
    1582           0 : }
    1583             : 
    1584             : CORSMode
    1585           0 : nsImageLoadingContent::GetCORSMode()
    1586             : {
    1587           0 :   return CORS_NONE;
    1588             : }
    1589             : 
    1590          11 : nsImageLoadingContent::ImageObserver::ImageObserver(imgINotificationObserver* aObserver)
    1591             :   : mObserver(aObserver)
    1592          11 :   , mNext(nullptr)
    1593             : {
    1594          11 :   MOZ_COUNT_CTOR(ImageObserver);
    1595          11 : }
    1596             : 
    1597           0 : nsImageLoadingContent::ImageObserver::~ImageObserver()
    1598             : {
    1599           0 :   MOZ_COUNT_DTOR(ImageObserver);
    1600           0 :   NS_CONTENT_DELETE_LIST_MEMBER(ImageObserver, this, mNext);
    1601           0 : }
    1602             : 
    1603             : // Only HTMLInputElement.h overrides this for <img> tags
    1604             : // all other subclasses use this one, i.e. ignore referrer attributes
    1605             : mozilla::net::ReferrerPolicy
    1606           0 : nsImageLoadingContent::GetImageReferrerPolicy()
    1607             : {
    1608           0 :   return mozilla::net::RP_Unset;
    1609             : };

Generated by: LCOV version 1.13