LCOV - code coverage report
Current view: top level - image - imgRequestProxy.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 60 533 11.3 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       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/. */
       6             : 
       7             : #include "imgRequestProxy.h"
       8             : 
       9             : #include "ImageLogging.h"
      10             : #include "imgLoader.h"
      11             : #include "Image.h"
      12             : #include "ImageOps.h"
      13             : #include "nsError.h"
      14             : #include "nsCRTGlue.h"
      15             : #include "imgINotificationObserver.h"
      16             : #include "mozilla/dom/TabGroup.h"       // for TabGroup
      17             : #include "mozilla/dom/DocGroup.h"       // for DocGroup
      18             : #include "mozilla/Move.h"
      19             : #include "mozilla/Telemetry.h"          // for Telemetry
      20             : 
      21             : using namespace mozilla;
      22             : using namespace mozilla::image;
      23             : 
      24             : // The split of imgRequestProxy and imgRequestProxyStatic means that
      25             : // certain overridden functions need to be usable in the destructor.
      26             : // Since virtual functions can't be used in that way, this class
      27             : // provides a behavioural trait for each class to use instead.
      28             : class ProxyBehaviour
      29             : {
      30             :  public:
      31             :   virtual ~ProxyBehaviour() = default;
      32             : 
      33             :   virtual already_AddRefed<mozilla::image::Image> GetImage() const = 0;
      34             :   virtual bool HasImage() const = 0;
      35             :   virtual already_AddRefed<ProgressTracker> GetProgressTracker() const = 0;
      36             :   virtual imgRequest* GetOwner() const = 0;
      37             :   virtual void SetOwner(imgRequest* aOwner) = 0;
      38             : };
      39             : 
      40           0 : class RequestBehaviour : public ProxyBehaviour
      41             : {
      42             :  public:
      43           0 :   RequestBehaviour() : mOwner(nullptr), mOwnerHasImage(false) {}
      44             : 
      45             :   already_AddRefed<mozilla::image::Image>GetImage() const override;
      46             :   bool HasImage() const override;
      47             :   already_AddRefed<ProgressTracker> GetProgressTracker() const override;
      48             : 
      49           0 :   imgRequest* GetOwner() const override {
      50           0 :     return mOwner;
      51             :   }
      52             : 
      53           0 :   void SetOwner(imgRequest* aOwner) override {
      54           0 :     mOwner = aOwner;
      55             : 
      56           0 :     if (mOwner) {
      57           0 :       RefPtr<ProgressTracker> ownerProgressTracker = GetProgressTracker();
      58           0 :       mOwnerHasImage = ownerProgressTracker && ownerProgressTracker->HasImage();
      59             :     } else {
      60           0 :       mOwnerHasImage = false;
      61             :     }
      62           0 :   }
      63             : 
      64             :  private:
      65             :   // We maintain the following invariant:
      66             :   // The proxy is registered at most with a single imgRequest as an observer,
      67             :   // and whenever it is, mOwner points to that object. This helps ensure that
      68             :   // imgRequestProxy::~imgRequestProxy unregisters the proxy as an observer
      69             :   // from whatever request it was registered with (if any). This, in turn,
      70             :   // means that imgRequest::mObservers will not have any stale pointers in it.
      71             :   RefPtr<imgRequest> mOwner;
      72             : 
      73             :   bool mOwnerHasImage;
      74             : };
      75             : 
      76             : already_AddRefed<mozilla::image::Image>
      77           0 : RequestBehaviour::GetImage() const
      78             : {
      79           0 :   if (!mOwnerHasImage) {
      80             :     return nullptr;
      81             :   }
      82           0 :   RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
      83           0 :   return progressTracker->GetImage();
      84             : }
      85             : 
      86             : already_AddRefed<ProgressTracker>
      87           0 : RequestBehaviour::GetProgressTracker() const
      88             : {
      89             :   // NOTE: It's possible that our mOwner has an Image that it didn't notify
      90             :   // us about, if we were Canceled before its Image was constructed.
      91             :   // (Canceling removes us as an observer, so mOwner has no way to notify us).
      92             :   // That's why this method uses mOwner->GetProgressTracker() instead of just
      93             :   // mOwner->mProgressTracker -- we might have a null mImage and yet have an
      94             :   // mOwner with a non-null mImage (and a null mProgressTracker pointer).
      95           0 :   return mOwner->GetProgressTracker();
      96             : }
      97             : 
      98           0 : NS_IMPL_ADDREF(imgRequestProxy)
      99           0 : NS_IMPL_RELEASE(imgRequestProxy)
     100             : 
     101           0 : NS_INTERFACE_MAP_BEGIN(imgRequestProxy)
     102           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, imgIRequest)
     103           0 :   NS_INTERFACE_MAP_ENTRY(imgIRequest)
     104           0 :   NS_INTERFACE_MAP_ENTRY(nsIRequest)
     105           0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
     106           0 :   NS_INTERFACE_MAP_ENTRY(nsISecurityInfoProvider)
     107           0 :   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsITimedChannel,
     108             :                                      TimedChannel() != nullptr)
     109           0 : NS_INTERFACE_MAP_END
     110             : 
     111           0 : imgRequestProxy::imgRequestProxy() :
     112           0 :   mBehaviour(new RequestBehaviour),
     113             :   mURI(nullptr),
     114             :   mListener(nullptr),
     115             :   mLoadFlags(nsIRequest::LOAD_NORMAL),
     116             :   mLockCount(0),
     117             :   mAnimationConsumers(0),
     118             :   mCanceled(false),
     119             :   mIsInLoadGroup(false),
     120             :   mForceDispatchLoadGroup(false),
     121             :   mListenerIsStrongRef(false),
     122             :   mDecodeRequested(false),
     123             :   mPendingNotify(false),
     124             :   mValidating(false),
     125             :   mHadListener(false),
     126           0 :   mHadDispatch(false)
     127             : {
     128             :   /* member initializers and constructor code */
     129           0 :   LOG_FUNC(gImgLog, "imgRequestProxy::imgRequestProxy");
     130           0 : }
     131             : 
     132           0 : imgRequestProxy::~imgRequestProxy()
     133             : {
     134             :   /* destructor code */
     135           0 :   MOZ_ASSERT(!mListener,
     136             :                   "Someone forgot to properly cancel this request!");
     137             : 
     138             :   // If we had a listener, that means we would have issued notifications. With
     139             :   // bug 1359833, we added support for main thread scheduler groups. Each
     140             :   // imgRequestProxy may have its own associated listener, document and/or
     141             :   // scheduler group. Typically most imgRequestProxy belong to the same
     142             :   // document, or have no listener, which means we will want to execute all main
     143             :   // thread code in that shared scheduler group. Less frequently, there may be
     144             :   // multiple imgRequests and they have separate documents, which means that
     145             :   // when we issue state notifications, some or all need to be dispatched to the
     146             :   // appropriate scheduler group for each request. This should be rare, so we
     147             :   // want to monitor the frequency of dispatching in the wild.
     148           0 :   if (mHadListener) {
     149           0 :     mozilla::Telemetry::Accumulate(mozilla::Telemetry::IMAGE_REQUEST_DISPATCHED,
     150           0 :                                    mHadDispatch);
     151             :   }
     152             : 
     153             :   // Unlock the image the proper number of times if we're holding locks on
     154             :   // it. Note that UnlockImage() decrements mLockCount each time it's called.
     155           0 :   while (mLockCount) {
     156           0 :     UnlockImage();
     157             :   }
     158             : 
     159           0 :   ClearAnimationConsumers();
     160             : 
     161             :   // Explicitly set mListener to null to ensure that the RemoveProxy
     162             :   // call below can't send |this| to an arbitrary listener while |this|
     163             :   // is being destroyed.  This is all belt-and-suspenders in view of the
     164             :   // above assert.
     165           0 :   NullOutListener();
     166             : 
     167             :   /* Call RemoveProxy with a successful status.  This will keep the
     168             :      channel, if still downloading data, from being canceled if 'this' is
     169             :      the last observer.  This allows the image to continue to download and
     170             :      be cached even if no one is using it currently.
     171             :   */
     172           0 :   mCanceled = true;
     173           0 :   RemoveFromOwner(NS_OK);
     174             : 
     175           0 :   RemoveFromLoadGroup();
     176           0 :   LOG_FUNC(gImgLog, "imgRequestProxy::~imgRequestProxy");
     177           0 : }
     178             : 
     179             : nsresult
     180           0 : imgRequestProxy::Init(imgRequest* aOwner,
     181             :                       nsILoadGroup* aLoadGroup,
     182             :                       nsIDocument* aLoadingDocument,
     183             :                       nsIURI* aURI,
     184             :                       imgINotificationObserver* aObserver)
     185             : {
     186           0 :   MOZ_ASSERT(!GetOwner() && !mListener,
     187             :              "imgRequestProxy is already initialized");
     188             : 
     189           0 :   LOG_SCOPE_WITH_PARAM(gImgLog, "imgRequestProxy::Init", "request",
     190             :                        aOwner);
     191             : 
     192           0 :   MOZ_ASSERT(mAnimationConsumers == 0, "Cannot have animation before Init");
     193             : 
     194           0 :   mBehaviour->SetOwner(aOwner);
     195           0 :   mListener = aObserver;
     196             :   // Make sure to addref mListener before the AddToOwner call below, since
     197             :   // that call might well want to release it if the imgRequest has
     198             :   // already seen OnStopRequest.
     199           0 :   if (mListener) {
     200           0 :     mHadListener = true;
     201           0 :     mListenerIsStrongRef = true;
     202           0 :     NS_ADDREF(mListener);
     203             :   }
     204           0 :   mLoadGroup = aLoadGroup;
     205           0 :   mURI = aURI;
     206             : 
     207             :   // Note: AddToOwner won't send all the On* notifications immediately
     208           0 :   AddToOwner(aLoadingDocument);
     209             : 
     210           0 :   return NS_OK;
     211             : }
     212             : 
     213             : nsresult
     214           0 : imgRequestProxy::ChangeOwner(imgRequest* aNewOwner)
     215             : {
     216           0 :   MOZ_ASSERT(GetOwner(),
     217             :                   "Cannot ChangeOwner on a proxy without an owner!");
     218             : 
     219           0 :   if (mCanceled) {
     220             :     // Ensure that this proxy has received all notifications to date
     221             :     // before we clean it up when removing it from the old owner below.
     222           0 :     SyncNotifyListener();
     223             :   }
     224             : 
     225             :   // If we're holding locks, unlock the old image.
     226             :   // Note that UnlockImage decrements mLockCount each time it's called.
     227           0 :   uint32_t oldLockCount = mLockCount;
     228           0 :   while (mLockCount) {
     229           0 :     UnlockImage();
     230             :   }
     231             : 
     232             :   // If we're holding animation requests, undo them.
     233           0 :   uint32_t oldAnimationConsumers = mAnimationConsumers;
     234           0 :   ClearAnimationConsumers();
     235             : 
     236           0 :   GetOwner()->RemoveProxy(this, NS_OK);
     237             : 
     238           0 :   mBehaviour->SetOwner(aNewOwner);
     239           0 :   MOZ_ASSERT(!GetValidator(), "New owner cannot be validating!");
     240             : 
     241             :   // If we were locked, apply the locks here
     242           0 :   for (uint32_t i = 0; i < oldLockCount; i++) {
     243           0 :     LockImage();
     244             :   }
     245             : 
     246             :   // If we had animation requests, restore them here. Note that we
     247             :   // do this *after* RemoveProxy, which clears out animation consumers
     248             :   // (see bug 601723).
     249           0 :   for (uint32_t i = 0; i < oldAnimationConsumers; i++) {
     250           0 :     IncrementAnimationConsumers();
     251             :   }
     252             : 
     253           0 :   AddToOwner(nullptr);
     254           0 :   return NS_OK;
     255             : }
     256             : 
     257             : void
     258           0 : imgRequestProxy::MarkValidating()
     259             : {
     260           0 :   MOZ_ASSERT(GetValidator());
     261           0 :   mValidating = true;
     262           0 : }
     263             : 
     264             : void
     265           0 : imgRequestProxy::ClearValidating()
     266             : {
     267           0 :   MOZ_ASSERT(mValidating);
     268           0 :   MOZ_ASSERT(!GetValidator());
     269           0 :   mValidating = false;
     270             : 
     271             :   // If we'd previously requested a synchronous decode, request a decode on the
     272             :   // new image.
     273           0 :   if (mDecodeRequested) {
     274           0 :     mDecodeRequested = false;
     275           0 :     StartDecoding(imgIContainer::FLAG_NONE);
     276             :   }
     277           0 : }
     278             : 
     279             : bool
     280           0 : imgRequestProxy::IsOnEventTarget() const
     281             : {
     282             :   // Ensure we are in some main thread context because the scheduler group
     283             :   // methods are only safe to call on the main thread.
     284           0 :   MOZ_ASSERT(NS_IsMainThread());
     285             : 
     286           0 :   if (mTabGroup) {
     287           0 :     MOZ_ASSERT(mEventTarget);
     288           0 :     return mTabGroup->IsSafeToRun();
     289             :   }
     290             : 
     291           0 :   if (mListener) {
     292             :     // If we have no scheduler group but we do have a listener, then we know
     293             :     // that the listener requires unlabelled dispatch.
     294           0 :     MOZ_ASSERT(mEventTarget);
     295           0 :     return mozilla::SchedulerGroup::IsSafeToRunUnlabeled();
     296             :   }
     297             : 
     298             :   // No listener means it is always safe, as there is nothing to do.
     299             :   return true;
     300             : }
     301             : 
     302             : already_AddRefed<nsIEventTarget>
     303           0 : imgRequestProxy::GetEventTarget() const
     304             : {
     305           0 :   nsCOMPtr<nsIEventTarget> target(mEventTarget);
     306           0 :   return target.forget();
     307             : }
     308             : 
     309             : nsresult
     310           0 : imgRequestProxy::DispatchWithTargetIfAvailable(already_AddRefed<nsIRunnable> aEvent)
     311             : {
     312           0 :   LOG_FUNC(gImgLog, "imgRequestProxy::DispatchWithTargetIfAvailable");
     313             : 
     314             :   // This method should only be used when it is *expected* that we are
     315             :   // dispatching an event (e.g. we want to handle an event asynchronously)
     316             :   // rather we need to (e.g. we are in the wrong scheduler group context).
     317             :   // As such, we do not set mHadDispatch for telemetry purposes.
     318           0 :   if (mEventTarget) {
     319           0 :     mEventTarget->Dispatch(std::move(aEvent), NS_DISPATCH_NORMAL);
     320           0 :     return NS_OK;
     321             :   }
     322             : 
     323           0 :   return NS_DispatchToMainThread(std::move(aEvent));
     324             : }
     325             : 
     326             : void
     327           0 : imgRequestProxy::DispatchWithTarget(already_AddRefed<nsIRunnable> aEvent)
     328             : {
     329           0 :   LOG_FUNC(gImgLog, "imgRequestProxy::DispatchWithTarget");
     330             : 
     331           0 :   MOZ_ASSERT(mListener || mTabGroup);
     332           0 :   MOZ_ASSERT(mEventTarget);
     333             : 
     334           0 :   mHadDispatch = true;
     335           0 :   mEventTarget->Dispatch(std::move(aEvent), NS_DISPATCH_NORMAL);
     336           0 : }
     337             : 
     338             : void
     339           0 : imgRequestProxy::AddToOwner(nsIDocument* aLoadingDocument)
     340             : {
     341             :   // An imgRequestProxy can be initialized with neither a listener nor a
     342             :   // document. The caller could follow up later by cloning the canonical
     343             :   // imgRequestProxy with the actual listener. This is possible because
     344             :   // imgLoader::LoadImage does not require a valid listener to be provided.
     345             :   //
     346             :   // Without a listener, we don't need to set our scheduler group, because
     347             :   // we have nothing to signal. However if we were told what document this
     348             :   // is for, it is likely that future listeners will belong to the same
     349             :   // scheduler group.
     350             :   //
     351             :   // With a listener, we always need to update our scheduler group. A null
     352             :   // scheduler group is valid with or without a document, but that means
     353             :   // we will use the most generic event target possible on dispatch.
     354           0 :   if (aLoadingDocument) {
     355           0 :     RefPtr<mozilla::dom::DocGroup> docGroup = aLoadingDocument->GetDocGroup();
     356           0 :     if (docGroup) {
     357           0 :       mTabGroup = docGroup->GetTabGroup();
     358           0 :       MOZ_ASSERT(mTabGroup);
     359             : 
     360           0 :       mEventTarget = docGroup->EventTargetFor(mozilla::TaskCategory::Other);
     361           0 :       MOZ_ASSERT(mEventTarget);
     362             :     }
     363             :   }
     364             : 
     365           0 :   if (mListener && !mEventTarget) {
     366           0 :     mEventTarget = do_GetMainThread();
     367             :   }
     368             : 
     369           0 :   imgRequest* owner = GetOwner();
     370           0 :   if (!owner) {
     371             :     return;
     372             :   }
     373             : 
     374           0 :   owner->AddProxy(this);
     375             : }
     376             : 
     377             : void
     378           0 : imgRequestProxy::RemoveFromOwner(nsresult aStatus)
     379             : {
     380           0 :   imgRequest* owner = GetOwner();
     381           0 :   if (owner) {
     382           0 :     if (mValidating) {
     383           0 :       imgCacheValidator* validator = owner->GetValidator();
     384           0 :       MOZ_ASSERT(validator);
     385           0 :       validator->RemoveProxy(this);
     386           0 :       mValidating = false;
     387             :     }
     388             : 
     389           0 :     owner->RemoveProxy(this, aStatus);
     390             :   }
     391           0 : }
     392             : 
     393             : void
     394           0 : imgRequestProxy::AddToLoadGroup()
     395             : {
     396           0 :   NS_ASSERTION(!mIsInLoadGroup, "Whaa, we're already in the loadgroup!");
     397           0 :   MOZ_ASSERT(!mForceDispatchLoadGroup);
     398             : 
     399             :   /* While in theory there could be a dispatch outstanding to remove this
     400             :      request from the load group, in practice we only add to the load group
     401             :      (when previously not in a load group) at initialization. */
     402           0 :   if (!mIsInLoadGroup && mLoadGroup) {
     403           0 :     LOG_FUNC(gImgLog, "imgRequestProxy::AddToLoadGroup");
     404           0 :     mLoadGroup->AddRequest(this, nullptr);
     405           0 :     mIsInLoadGroup = true;
     406             :   }
     407           0 : }
     408             : 
     409             : void
     410           0 : imgRequestProxy::RemoveFromLoadGroup()
     411             : {
     412           0 :   if (!mIsInLoadGroup || !mLoadGroup) {
     413           0 :     return;
     414             :   }
     415             : 
     416             :   /* Sometimes we may not be able to remove ourselves from the load group in
     417             :      the current context. This is because our listeners are not re-entrant (e.g.
     418             :      we are in the middle of CancelAndForgetObserver or SyncClone). */
     419           0 :   if (mForceDispatchLoadGroup) {
     420           0 :     LOG_FUNC(gImgLog, "imgRequestProxy::RemoveFromLoadGroup -- dispatch");
     421             : 
     422             :     /* We take away the load group from the request temporarily; this prevents
     423             :        additional dispatches via RemoveFromLoadGroup occurring, as well as
     424             :        MoveToBackgroundInLoadGroup from removing and readding. This is safe
     425             :        because we know that once we get here, blocking the load group at all is
     426             :        unnecessary. */
     427           0 :     mIsInLoadGroup = false;
     428           0 :     nsCOMPtr<nsILoadGroup> loadGroup = std::move(mLoadGroup);
     429           0 :     RefPtr<imgRequestProxy> self(this);
     430           0 :     DispatchWithTargetIfAvailable(NS_NewRunnableFunction(
     431             :       "imgRequestProxy::RemoveFromLoadGroup",
     432           0 :       [self, loadGroup]() -> void {
     433           0 :         loadGroup->RemoveRequest(self, nullptr, NS_OK);
     434           0 :       }));
     435             :     return;
     436             :   }
     437             : 
     438           0 :   LOG_FUNC(gImgLog, "imgRequestProxy::RemoveFromLoadGroup");
     439             : 
     440             :   /* calling RemoveFromLoadGroup may cause the document to finish
     441             :      loading, which could result in our death.  We need to make sure
     442             :      that we stay alive long enough to fight another battle... at
     443             :      least until we exit this function. */
     444           0 :   nsCOMPtr<imgIRequest> kungFuDeathGrip(this);
     445           0 :   mLoadGroup->RemoveRequest(this, nullptr, NS_OK);
     446           0 :   mLoadGroup = nullptr;
     447           0 :   mIsInLoadGroup = false;
     448             : }
     449             : 
     450             : void
     451           0 : imgRequestProxy::MoveToBackgroundInLoadGroup()
     452             : {
     453             :   /* Even if we are still in the load group, we may have taken away the load
     454             :      group reference itself because we are in the process of leaving the group.
     455             :      In that case, there is no need to background the request. */
     456           0 :   if (!mLoadGroup) {
     457           0 :     return;
     458             :   }
     459             : 
     460             :   /* There is no need to dispatch if we only need to add ourselves to the load
     461             :      group without removal. It is the removal which causes the problematic
     462             :      callbacks (see RemoveFromLoadGroup). */
     463           0 :   if (mIsInLoadGroup && mForceDispatchLoadGroup) {
     464           0 :     LOG_FUNC(gImgLog, "imgRequestProxy::MoveToBackgroundInLoadGroup -- dispatch");
     465             : 
     466           0 :     RefPtr<imgRequestProxy> self(this);
     467           0 :     DispatchWithTargetIfAvailable(NS_NewRunnableFunction(
     468             :       "imgRequestProxy::MoveToBackgroundInLoadGroup",
     469           0 :       [self]() -> void {
     470           0 :         self->MoveToBackgroundInLoadGroup();
     471           0 :       }));
     472             :     return;
     473             :   }
     474             : 
     475           0 :   LOG_FUNC(gImgLog, "imgRequestProxy::MoveToBackgroundInLoadGroup");
     476           0 :   nsCOMPtr<imgIRequest> kungFuDeathGrip(this);
     477           0 :   if (mIsInLoadGroup) {
     478           0 :     mLoadGroup->RemoveRequest(this, nullptr, NS_OK);
     479             :   }
     480             : 
     481           0 :   mLoadFlags |= nsIRequest::LOAD_BACKGROUND;
     482           0 :   mLoadGroup->AddRequest(this, nullptr);
     483             : }
     484             : 
     485             : /**  nsIRequest / imgIRequest methods **/
     486             : 
     487             : NS_IMETHODIMP
     488           0 : imgRequestProxy::GetName(nsACString& aName)
     489             : {
     490           0 :   aName.Truncate();
     491             : 
     492           0 :   if (mURI) {
     493           0 :     mURI->GetSpec(aName);
     494             :   }
     495             : 
     496           0 :   return NS_OK;
     497             : }
     498             : 
     499             : NS_IMETHODIMP
     500           0 : imgRequestProxy::IsPending(bool* _retval)
     501             : {
     502           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     503             : }
     504             : 
     505             : NS_IMETHODIMP
     506           0 : imgRequestProxy::GetStatus(nsresult* aStatus)
     507             : {
     508           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     509             : }
     510             : 
     511             : NS_IMETHODIMP
     512           0 : imgRequestProxy::Cancel(nsresult status)
     513             : {
     514           0 :   if (mCanceled) {
     515             :     return NS_ERROR_FAILURE;
     516             :   }
     517             : 
     518           0 :   LOG_SCOPE(gImgLog, "imgRequestProxy::Cancel");
     519             : 
     520           0 :   mCanceled = true;
     521             : 
     522           0 :   nsCOMPtr<nsIRunnable> ev = new imgCancelRunnable(this, status);
     523           0 :   return DispatchWithTargetIfAvailable(ev.forget());
     524             : }
     525             : 
     526             : void
     527           0 : imgRequestProxy::DoCancel(nsresult status)
     528             : {
     529           0 :   RemoveFromOwner(status);
     530           0 :   RemoveFromLoadGroup();
     531           0 :   NullOutListener();
     532           0 : }
     533             : 
     534             : NS_IMETHODIMP
     535           0 : imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
     536             : {
     537             :   // If mCanceled is true but mListener is non-null, that means
     538             :   // someone called Cancel() on us but the imgCancelRunnable is still
     539             :   // pending.  We still need to null out mListener before returning
     540             :   // from this function in this case.  That means we want to do the
     541             :   // RemoveProxy call right now, because we need to deliver the
     542             :   // onStopRequest.
     543           0 :   if (mCanceled && !mListener) {
     544             :     return NS_ERROR_FAILURE;
     545             :   }
     546             : 
     547           0 :   LOG_SCOPE(gImgLog, "imgRequestProxy::CancelAndForgetObserver");
     548             : 
     549           0 :   mCanceled = true;
     550           0 :   mForceDispatchLoadGroup = true;
     551           0 :   RemoveFromOwner(aStatus);
     552           0 :   RemoveFromLoadGroup();
     553           0 :   mForceDispatchLoadGroup = false;
     554             : 
     555           0 :   NullOutListener();
     556             : 
     557             :   return NS_OK;
     558             : }
     559             : 
     560             : NS_IMETHODIMP
     561           0 : imgRequestProxy::StartDecoding(uint32_t aFlags)
     562             : {
     563             :   // Flag this, so we know to request after validation if pending.
     564           0 :   if (IsValidating()) {
     565           0 :     mDecodeRequested = true;
     566           0 :     return NS_OK;
     567             :   }
     568             : 
     569           0 :   RefPtr<Image> image = GetImage();
     570           0 :   if (image) {
     571           0 :     return image->StartDecoding(aFlags);
     572             :   }
     573             : 
     574           0 :   if (GetOwner()) {
     575           0 :     GetOwner()->StartDecoding();
     576             :   }
     577             : 
     578             :   return NS_OK;
     579             : }
     580             : 
     581             : bool
     582           0 : imgRequestProxy::StartDecodingWithResult(uint32_t aFlags)
     583             : {
     584             :   // Flag this, so we know to request after validation if pending.
     585           0 :   if (IsValidating()) {
     586           0 :     mDecodeRequested = true;
     587           0 :     return false;
     588             :   }
     589             : 
     590           0 :   RefPtr<Image> image = GetImage();
     591           0 :   if (image) {
     592           0 :     return image->StartDecodingWithResult(aFlags);
     593             :   }
     594             : 
     595           0 :   if (GetOwner()) {
     596           0 :     GetOwner()->StartDecoding();
     597             :   }
     598             : 
     599             :   return false;
     600             : }
     601             : 
     602             : NS_IMETHODIMP
     603           0 : imgRequestProxy::LockImage()
     604             : {
     605           0 :   mLockCount++;
     606           0 :   RefPtr<Image> image = GetImage();
     607           0 :   if (image) {
     608           0 :     return image->LockImage();
     609             :   }
     610             :   return NS_OK;
     611             : }
     612             : 
     613             : NS_IMETHODIMP
     614           0 : imgRequestProxy::UnlockImage()
     615             : {
     616           0 :   MOZ_ASSERT(mLockCount > 0, "calling unlock but no locks!");
     617             : 
     618           0 :   mLockCount--;
     619           0 :   RefPtr<Image> image = GetImage();
     620           0 :   if (image) {
     621           0 :     return image->UnlockImage();
     622             :   }
     623             :   return NS_OK;
     624             : }
     625             : 
     626             : NS_IMETHODIMP
     627           0 : imgRequestProxy::RequestDiscard()
     628             : {
     629           0 :   RefPtr<Image> image = GetImage();
     630           0 :   if (image) {
     631           0 :     return image->RequestDiscard();
     632             :   }
     633             :   return NS_OK;
     634             : }
     635             : 
     636             : NS_IMETHODIMP
     637           0 : imgRequestProxy::IncrementAnimationConsumers()
     638             : {
     639           0 :   mAnimationConsumers++;
     640           0 :   RefPtr<Image> image = GetImage();
     641           0 :   if (image) {
     642           0 :     image->IncrementAnimationConsumers();
     643             :   }
     644           0 :   return NS_OK;
     645             : }
     646             : 
     647             : NS_IMETHODIMP
     648           0 : imgRequestProxy::DecrementAnimationConsumers()
     649             : {
     650             :   // We may get here if some responsible code called Increment,
     651             :   // then called us, but we have meanwhile called ClearAnimationConsumers
     652             :   // because we needed to get rid of them earlier (see
     653             :   // imgRequest::RemoveProxy), and hence have nothing left to
     654             :   // decrement. (In such a case we got rid of the animation consumers
     655             :   // early, but not the observer.)
     656           0 :   if (mAnimationConsumers > 0) {
     657           0 :     mAnimationConsumers--;
     658           0 :     RefPtr<Image> image = GetImage();
     659           0 :     if (image) {
     660           0 :       image->DecrementAnimationConsumers();
     661             :     }
     662             :   }
     663           0 :   return NS_OK;
     664             : }
     665             : 
     666             : void
     667           0 : imgRequestProxy::ClearAnimationConsumers()
     668             : {
     669           0 :   while (mAnimationConsumers > 0) {
     670           0 :     DecrementAnimationConsumers();
     671             :   }
     672           0 : }
     673             : 
     674             : NS_IMETHODIMP
     675           0 : imgRequestProxy::Suspend()
     676             : {
     677           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     678             : }
     679             : 
     680             : NS_IMETHODIMP
     681           0 : imgRequestProxy::Resume()
     682             : {
     683           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     684             : }
     685             : 
     686             : NS_IMETHODIMP
     687           0 : imgRequestProxy::GetLoadGroup(nsILoadGroup** loadGroup)
     688             : {
     689           0 :   NS_IF_ADDREF(*loadGroup = mLoadGroup.get());
     690           0 :   return NS_OK;
     691             : }
     692             : NS_IMETHODIMP
     693           0 : imgRequestProxy::SetLoadGroup(nsILoadGroup* loadGroup)
     694             : {
     695           0 :   if (loadGroup != mLoadGroup) {
     696           0 :     MOZ_ASSERT_UNREACHABLE("Switching load groups is unsupported!");
     697             :     return NS_ERROR_NOT_IMPLEMENTED;
     698             :   }
     699             :   return NS_OK;
     700             : }
     701             : 
     702             : NS_IMETHODIMP
     703           0 : imgRequestProxy::GetLoadFlags(nsLoadFlags* flags)
     704             : {
     705           0 :   *flags = mLoadFlags;
     706           0 :   return NS_OK;
     707             : }
     708             : NS_IMETHODIMP
     709           0 : imgRequestProxy::SetLoadFlags(nsLoadFlags flags)
     710             : {
     711           0 :   mLoadFlags = flags;
     712           0 :   return NS_OK;
     713             : }
     714             : 
     715             : /**  imgIRequest methods **/
     716             : 
     717             : NS_IMETHODIMP
     718           0 : imgRequestProxy::GetImage(imgIContainer** aImage)
     719             : {
     720           0 :   NS_ENSURE_TRUE(aImage, NS_ERROR_NULL_POINTER);
     721             :   // It's possible that our owner has an image but hasn't notified us of it -
     722             :   // that'll happen if we get Canceled before the owner instantiates its image
     723             :   // (because Canceling unregisters us as a listener on mOwner). If we're
     724             :   // in that situation, just grab the image off of mOwner.
     725           0 :   RefPtr<Image> image = GetImage();
     726           0 :   nsCOMPtr<imgIContainer> imageToReturn;
     727           0 :   if (image) {
     728           0 :     imageToReturn = do_QueryInterface(image);
     729             :   }
     730           0 :   if (!imageToReturn && GetOwner()) {
     731           0 :     imageToReturn = GetOwner()->GetImage();
     732             :   }
     733           0 :   if (!imageToReturn) {
     734             :     return NS_ERROR_FAILURE;
     735             :   }
     736             : 
     737           0 :   imageToReturn.swap(*aImage);
     738             : 
     739           0 :   return NS_OK;
     740             : }
     741             : 
     742             : NS_IMETHODIMP
     743           0 : imgRequestProxy::GetImageStatus(uint32_t* aStatus)
     744             : {
     745           0 :   if (IsValidating()) {
     746             :     // We are currently validating the image, and so our status could revert if
     747             :     // we discard the cache. We should also be deferring notifications, such
     748             :     // that the caller will be notified when validation completes. Rather than
     749             :     // risk misleading the caller, return nothing.
     750           0 :     *aStatus = imgIRequest::STATUS_NONE;
     751             :   } else {
     752           0 :     RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
     753           0 :     *aStatus = progressTracker->GetImageStatus();
     754             :   }
     755             : 
     756           0 :   return NS_OK;
     757             : }
     758             : 
     759             : NS_IMETHODIMP
     760           0 : imgRequestProxy::GetImageErrorCode(nsresult* aStatus)
     761             : {
     762           0 :   if (!GetOwner()) {
     763             :     return NS_ERROR_FAILURE;
     764             :   }
     765             : 
     766           0 :   *aStatus = GetOwner()->GetImageErrorCode();
     767             : 
     768           0 :   return NS_OK;
     769             : }
     770             : 
     771             : NS_IMETHODIMP
     772           0 : imgRequestProxy::GetURI(nsIURI** aURI)
     773             : {
     774           0 :   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread to convert URI");
     775           0 :   nsCOMPtr<nsIURI> uri = mURI;
     776           0 :   uri.forget(aURI);
     777           0 :   return NS_OK;
     778             : }
     779             : 
     780             : nsresult
     781           0 : imgRequestProxy::GetFinalURI(nsIURI** aURI)
     782             : {
     783           0 :   if (!GetOwner()) {
     784             :     return NS_ERROR_FAILURE;
     785             :   }
     786             : 
     787           0 :   return GetOwner()->GetFinalURI(aURI);
     788             : }
     789             : 
     790             : NS_IMETHODIMP
     791           1 : imgRequestProxy::GetNotificationObserver(imgINotificationObserver** aObserver)
     792             : {
     793           1 :   *aObserver = mListener;
     794           4 :   NS_IF_ADDREF(*aObserver);
     795           4 :   return NS_OK;
     796             : }
     797             : 
     798             : NS_IMETHODIMP
     799           0 : imgRequestProxy::GetMimeType(char** aMimeType)
     800             : {
     801           0 :   if (!GetOwner()) {
     802             :     return NS_ERROR_FAILURE;
     803             :   }
     804             : 
     805           0 :   const char* type = GetOwner()->GetMimeType();
     806           0 :   if (!type) {
     807             :     return NS_ERROR_FAILURE;
     808             :   }
     809             : 
     810           0 :   *aMimeType = NS_strdup(type);
     811             : 
     812           0 :   return NS_OK;
     813             : }
     814             : 
     815          39 : imgRequestProxy* imgRequestProxy::NewClonedProxy()
     816             : {
     817           0 :   return new imgRequestProxy();
     818             : }
     819             : 
     820             : NS_IMETHODIMP
     821           0 : imgRequestProxy::Clone(imgINotificationObserver* aObserver,
     822             :                        imgIRequest** aClone)
     823             : {
     824             :   nsresult result;
     825             :   imgRequestProxy* proxy;
     826           0 :   result = PerformClone(aObserver, nullptr, /* aSyncNotify */ true, &proxy);
     827           0 :   *aClone = proxy;
     828           0 :   return result;
     829             : }
     830             : 
     831          39 : nsresult imgRequestProxy::SyncClone(imgINotificationObserver* aObserver,
     832             :                                     nsIDocument* aLoadingDocument,
     833             :                                     imgRequestProxy** aClone)
     834             : {
     835             :   return PerformClone(aObserver, aLoadingDocument,
     836          39 :                       /* aSyncNotify */ true, aClone);
     837             : }
     838             : 
     839           0 : nsresult imgRequestProxy::Clone(imgINotificationObserver* aObserver,
     840             :                                 nsIDocument* aLoadingDocument,
     841             :                                 imgRequestProxy** aClone)
     842             : {
     843             :   return PerformClone(aObserver, aLoadingDocument,
     844           0 :                       /* aSyncNotify */ false, aClone);
     845             : }
     846             : 
     847             : nsresult
     848           0 : imgRequestProxy::PerformClone(imgINotificationObserver* aObserver,
     849             :                               nsIDocument* aLoadingDocument,
     850             :                               bool aSyncNotify,
     851             :                               imgRequestProxy** aClone)
     852             : {
     853          39 :   MOZ_ASSERT(aClone, "Null out param");
     854             : 
     855          78 :   LOG_SCOPE(gImgLog, "imgRequestProxy::Clone");
     856             : 
     857          39 :   *aClone = nullptr;
     858          78 :   RefPtr<imgRequestProxy> clone = NewClonedProxy();
     859             : 
     860           0 :   nsCOMPtr<nsILoadGroup> loadGroup;
     861          39 :   if (aLoadingDocument) {
     862          39 :     loadGroup = aLoadingDocument->GetDocumentLoadGroup();
     863             :   }
     864             : 
     865             :   // It is important to call |SetLoadFlags()| before calling |Init()| because
     866             :   // |Init()| adds the request to the loadgroup.
     867             :   // When a request is added to a loadgroup, its load flags are merged
     868             :   // with the load flags of the loadgroup.
     869             :   // XXXldb That's not true anymore.  Stuff from imgLoader adds the
     870             :   // request to the loadgroup.
     871          39 :   clone->SetLoadFlags(mLoadFlags);
     872           0 :   nsresult rv = clone->Init(mBehaviour->GetOwner(), loadGroup,
     873           0 :                             aLoadingDocument, mURI, aObserver);
     874           0 :   if (NS_FAILED(rv)) {
     875             :     return rv;
     876             :   }
     877             : 
     878             :   // Assign to *aClone before calling Notify so that if the caller expects to
     879             :   // only be notified for requests it's already holding pointers to it won't be
     880             :   // surprised.
     881          78 :   NS_ADDREF(*aClone = clone);
     882             : 
     883           0 :   imgCacheValidator* validator = GetValidator();
     884           0 :   if (validator) {
     885             :     // Note that if we have a validator, we don't want to issue notifications at
     886             :     // here because we want to defer until that completes. AddProxy will add us
     887             :     // to the load group; we cannot avoid that in this case, because we don't
     888             :     // know when the validation will complete, and if it will cause us to
     889             :     // discard our cached state anyways. We are probably already blocked by the
     890             :     // original LoadImage(WithChannel) request in any event.
     891           0 :     clone->MarkValidating();
     892           0 :     validator->AddProxy(clone);
     893             :   } else {
     894             :     // We only want to add the request to the load group of the owning document
     895             :     // if it is still in progress. Some callers cannot handle a supurious load
     896             :     // group removal (e.g. print preview) so we must be careful. On the other
     897             :     // hand, if after cloning, the original request proxy is cancelled /
     898             :     // destroyed, we need to ensure that any clones still block the load group
     899             :     // if it is incomplete.
     900          39 :     bool addToLoadGroup = mIsInLoadGroup;
     901          39 :     if (!addToLoadGroup) {
     902           6 :       RefPtr<ProgressTracker> tracker = clone->GetProgressTracker();
     903           0 :       addToLoadGroup = tracker && !(tracker->GetProgress() & FLAG_LOAD_COMPLETE);
     904             :     }
     905             : 
     906          39 :     if (addToLoadGroup) {
     907          37 :       clone->AddToLoadGroup();
     908             :     }
     909             : 
     910          39 :     if (aSyncNotify) {
     911             :       // This is wrong!!! We need to notify asynchronously, but there's code
     912             :       // that assumes that we don't. This will be fixed in bug 580466. Note that
     913             :       // if we have a validator, we won't issue notifications anyways because
     914             :       // they are deferred, so there is no point in requesting.
     915           0 :       clone->mForceDispatchLoadGroup = true;
     916          39 :       clone->SyncNotifyListener();
     917          39 :       clone->mForceDispatchLoadGroup = false;
     918             :     } else {
     919             :       // Without a validator, we can request asynchronous notifications
     920             :       // immediately. If there was a validator, this would override the deferral
     921             :       // and that would be incorrect.
     922           0 :       clone->NotifyListener();
     923             :     }
     924             :   }
     925             : 
     926             :   return NS_OK;
     927             : }
     928             : 
     929             : NS_IMETHODIMP
     930           0 : imgRequestProxy::GetImagePrincipal(nsIPrincipal** aPrincipal)
     931             : {
     932           0 :   if (!GetOwner()) {
     933             :     return NS_ERROR_FAILURE;
     934             :   }
     935             : 
     936           0 :   nsCOMPtr<nsIPrincipal> principal = GetOwner()->GetPrincipal();
     937           0 :   principal.forget(aPrincipal);
     938             :   return NS_OK;
     939             : }
     940             : 
     941             : NS_IMETHODIMP
     942           0 : imgRequestProxy::GetMultipart(bool* aMultipart)
     943             : {
     944           0 :   if (!GetOwner()) {
     945             :     return NS_ERROR_FAILURE;
     946             :   }
     947             : 
     948           0 :   *aMultipart = GetOwner()->GetMultipart();
     949             : 
     950           0 :   return NS_OK;
     951             : }
     952             : 
     953             : NS_IMETHODIMP
     954           0 : imgRequestProxy::GetCORSMode(int32_t* aCorsMode)
     955             : {
     956           0 :   if (!GetOwner()) {
     957             :     return NS_ERROR_FAILURE;
     958             :   }
     959             : 
     960           0 :   *aCorsMode = GetOwner()->GetCORSMode();
     961             : 
     962           0 :   return NS_OK;
     963             : }
     964             : 
     965             : NS_IMETHODIMP
     966           0 : imgRequestProxy::BoostPriority(uint32_t aCategory)
     967             : {
     968           0 :   NS_ENSURE_STATE(GetOwner() && !mCanceled);
     969           0 :   GetOwner()->BoostPriority(aCategory);
     970           0 :   return NS_OK;
     971             : }
     972             : 
     973             : /** nsISupportsPriority methods **/
     974             : 
     975             : NS_IMETHODIMP
     976           0 : imgRequestProxy::GetPriority(int32_t* priority)
     977             : {
     978           0 :   NS_ENSURE_STATE(GetOwner());
     979           0 :   *priority = GetOwner()->Priority();
     980           0 :   return NS_OK;
     981             : }
     982             : 
     983             : NS_IMETHODIMP
     984           0 : imgRequestProxy::SetPriority(int32_t priority)
     985             : {
     986           0 :   NS_ENSURE_STATE(GetOwner() && !mCanceled);
     987           0 :   GetOwner()->AdjustPriority(this, priority - GetOwner()->Priority());
     988           0 :   return NS_OK;
     989             : }
     990             : 
     991             : NS_IMETHODIMP
     992           0 : imgRequestProxy::AdjustPriority(int32_t priority)
     993             : {
     994             :   // We don't require |!mCanceled| here. This may be called even if we're
     995             :   // cancelled, because it's invoked as part of the process of removing an image
     996             :   // from the load group.
     997           0 :   NS_ENSURE_STATE(GetOwner());
     998           0 :   GetOwner()->AdjustPriority(this, priority);
     999           0 :   return NS_OK;
    1000             : }
    1001             : 
    1002             : /** nsISecurityInfoProvider methods **/
    1003             : 
    1004             : NS_IMETHODIMP
    1005           0 : imgRequestProxy::GetSecurityInfo(nsISupports** _retval)
    1006             : {
    1007           0 :   if (GetOwner()) {
    1008           0 :     return GetOwner()->GetSecurityInfo(_retval);
    1009             :   }
    1010             : 
    1011           0 :   *_retval = nullptr;
    1012           0 :   return NS_OK;
    1013             : }
    1014             : 
    1015             : NS_IMETHODIMP
    1016           0 : imgRequestProxy::GetHasTransferredData(bool* hasData)
    1017             : {
    1018           0 :   if (GetOwner()) {
    1019           0 :     *hasData = GetOwner()->HasTransferredData();
    1020             :   } else {
    1021             :     // The safe thing to do is to claim we have data
    1022           0 :     *hasData = true;
    1023             :   }
    1024           0 :   return NS_OK;
    1025             : }
    1026             : 
    1027             : static const char*
    1028           0 : NotificationTypeToString(int32_t aType)
    1029             : {
    1030           0 :   switch(aType)
    1031             :   {
    1032             :     case imgINotificationObserver::SIZE_AVAILABLE: return "SIZE_AVAILABLE";
    1033          89 :     case imgINotificationObserver::FRAME_UPDATE: return "FRAME_UPDATE";
    1034           1 :     case imgINotificationObserver::FRAME_COMPLETE: return "FRAME_COMPLETE";
    1035           0 :     case imgINotificationObserver::LOAD_COMPLETE: return "LOAD_COMPLETE";
    1036           0 :     case imgINotificationObserver::DECODE_COMPLETE: return "DECODE_COMPLETE";
    1037           0 :     case imgINotificationObserver::DISCARD: return "DISCARD";
    1038           0 :     case imgINotificationObserver::UNLOCKED_DRAW: return "UNLOCKED_DRAW";
    1039           0 :     case imgINotificationObserver::IS_ANIMATED: return "IS_ANIMATED";
    1040           0 :     case imgINotificationObserver::HAS_TRANSPARENCY: return "HAS_TRANSPARENCY";
    1041             :     default:
    1042           0 :       NS_NOTREACHED("Notification list should be exhaustive");
    1043           0 :       return "(unknown notification)";
    1044             :   }
    1045             : }
    1046             : 
    1047             : void
    1048           0 : imgRequestProxy::Notify(int32_t aType, const mozilla::gfx::IntRect* aRect)
    1049             : {
    1050           0 :   MOZ_ASSERT(aType != imgINotificationObserver::LOAD_COMPLETE,
    1051             :              "Should call OnLoadComplete");
    1052             : 
    1053             :   LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::Notify", "type",
    1054           1 :                       NotificationTypeToString(aType));
    1055             : 
    1056         301 :   if (!mListener || mCanceled) {
    1057          94 :     return;
    1058             :   }
    1059             : 
    1060           0 :   if (!IsOnEventTarget()) {
    1061           0 :     RefPtr<imgRequestProxy> self(this);
    1062           0 :     if (aRect) {
    1063           0 :       const mozilla::gfx::IntRect rect = *aRect;
    1064           0 :       DispatchWithTarget(NS_NewRunnableFunction("imgRequestProxy::Notify",
    1065           0 :                                       [self, rect, aType]() -> void {
    1066           0 :         self->Notify(aType, &rect);
    1067           0 :       }));
    1068             :     } else {
    1069           0 :       DispatchWithTarget(NS_NewRunnableFunction("imgRequestProxy::Notify",
    1070           0 :                                       [self, aType]() -> void {
    1071           0 :         self->Notify(aType, nullptr);
    1072           0 :       }));
    1073             :     }
    1074             :     return;
    1075             :   }
    1076             : 
    1077             :   // Make sure the listener stays alive while we notify.
    1078           0 :   nsCOMPtr<imgINotificationObserver> listener(mListener);
    1079             : 
    1080         207 :   listener->Notify(this, aType, aRect);
    1081             : }
    1082             : 
    1083             : void
    1084           0 : imgRequestProxy::OnLoadComplete(bool aLastPart)
    1085             : {
    1086             :   LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnLoadComplete",
    1087         112 :                       "uri", mURI);
    1088             : 
    1089             :   // There's all sorts of stuff here that could kill us (the OnStopRequest call
    1090             :   // on the listener, the removal from the loadgroup, the release of the
    1091             :   // listener, etc).  Don't let them do it.
    1092           0 :   RefPtr<imgRequestProxy> self(this);
    1093             : 
    1094          56 :   if (!IsOnEventTarget()) {
    1095           0 :     DispatchWithTarget(NS_NewRunnableFunction("imgRequestProxy::OnLoadComplete",
    1096           0 :                                     [self, aLastPart]() -> void {
    1097           0 :       self->OnLoadComplete(aLastPart);
    1098           0 :     }));
    1099           0 :     return;
    1100             :   }
    1101             : 
    1102           1 :   if (mListener && !mCanceled) {
    1103             :     // Hold a ref to the listener while we call it, just in case.
    1104          74 :     nsCOMPtr<imgINotificationObserver> listener(mListener);
    1105          37 :     listener->Notify(this, imgINotificationObserver::LOAD_COMPLETE, nullptr);
    1106             :   }
    1107             : 
    1108             :   // If we're expecting more data from a multipart channel, re-add ourself
    1109             :   // to the loadgroup so that the document doesn't lose track of the load.
    1110             :   // If the request is already a background request and there's more data
    1111             :   // coming, we can just leave the request in the loadgroup as-is.
    1112           0 :   if (aLastPart || (mLoadFlags & nsIRequest::LOAD_BACKGROUND) == 0) {
    1113           0 :     if (aLastPart) {
    1114           0 :       RemoveFromLoadGroup();
    1115             :     } else {
    1116             :       // More data is coming, so change the request to be a background request
    1117             :       // and put it back in the loadgroup.
    1118           0 :       MoveToBackgroundInLoadGroup();
    1119             :     }
    1120             :   }
    1121             : 
    1122          56 :   if (mListenerIsStrongRef && aLastPart) {
    1123          39 :     MOZ_ASSERT(mListener, "How did that happen?");
    1124             :     // Drop our strong ref to the listener now that we're done with
    1125             :     // everything.  Note that this can cancel us and other fun things
    1126             :     // like that.  Don't add anything in this method after this point.
    1127          39 :     imgINotificationObserver* obs = mListener;
    1128           0 :     mListenerIsStrongRef = false;
    1129           0 :     NS_RELEASE(obs);
    1130             :   }
    1131             : }
    1132             : 
    1133             : void
    1134           0 : imgRequestProxy::NullOutListener()
    1135             : {
    1136             :   // If we have animation consumers, then they don't matter anymore
    1137           8 :   if (mListener) {
    1138           0 :     ClearAnimationConsumers();
    1139             :   }
    1140             : 
    1141           8 :   if (mListenerIsStrongRef) {
    1142             :     // Releasing could do weird reentery stuff, so just play it super-safe
    1143           0 :     nsCOMPtr<imgINotificationObserver> obs;
    1144           0 :     obs.swap(mListener);
    1145           0 :     mListenerIsStrongRef = false;
    1146             :   } else {
    1147           8 :     mListener = nullptr;
    1148             :   }
    1149             : 
    1150             :   // Note that we don't free the event target. We actually need that to ensure
    1151             :   // we get removed from the ProgressTracker properly. No harm in keeping it
    1152             :   // however.
    1153           0 :   mTabGroup = nullptr;
    1154           0 : }
    1155             : 
    1156             : NS_IMETHODIMP
    1157           0 : imgRequestProxy::GetStaticRequest(imgIRequest** aReturn)
    1158             : {
    1159             :   imgRequestProxy* proxy;
    1160           0 :   nsresult result = GetStaticRequest(nullptr, &proxy);
    1161           0 :   *aReturn = proxy;
    1162           0 :   return result;
    1163             : }
    1164             : 
    1165             : nsresult
    1166           0 : imgRequestProxy::GetStaticRequest(nsIDocument* aLoadingDocument,
    1167             :                                   imgRequestProxy** aReturn)
    1168             : {
    1169           0 :   *aReturn = nullptr;
    1170           0 :   RefPtr<Image> image = GetImage();
    1171             : 
    1172             :   bool animated;
    1173           0 :   if (!image || (NS_SUCCEEDED(image->GetAnimated(&animated)) && !animated)) {
    1174             :     // Early exit - we're not animated, so we don't have to do anything.
    1175           0 :     NS_ADDREF(*aReturn = this);
    1176           0 :     return NS_OK;
    1177             :   }
    1178             : 
    1179             :   // Check for errors in the image. Callers code rely on GetStaticRequest
    1180             :   // failing in this case, though with FrozenImage there's no technical reason
    1181             :   // for it anymore.
    1182           0 :   if (image->HasError()) {
    1183             :     return NS_ERROR_FAILURE;
    1184             :   }
    1185             : 
    1186             :   // We are animated. We need to create a frozen version of this image.
    1187           0 :   RefPtr<Image> frozenImage = ImageOps::Freeze(image);
    1188             : 
    1189             :   // Create a static imgRequestProxy with our new extracted frame.
    1190           0 :   nsCOMPtr<nsIPrincipal> currentPrincipal;
    1191           0 :   GetImagePrincipal(getter_AddRefs(currentPrincipal));
    1192             :   RefPtr<imgRequestProxy> req = new imgRequestProxyStatic(frozenImage,
    1193           0 :                                                             currentPrincipal);
    1194           0 :   req->Init(nullptr, nullptr, aLoadingDocument, mURI, nullptr);
    1195             : 
    1196           0 :   NS_ADDREF(*aReturn = req);
    1197             : 
    1198             :   return NS_OK;
    1199             : }
    1200             : 
    1201             : void
    1202           1 : imgRequestProxy::NotifyListener()
    1203             : {
    1204             :   // It would be nice to notify the observer directly in the status tracker
    1205             :   // instead of through the proxy, but there are several places we do extra
    1206             :   // processing when we receive notifications (like OnStopRequest()), and we
    1207             :   // need to check mCanceled everywhere too.
    1208             : 
    1209           0 :   RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
    1210           0 :   if (GetOwner()) {
    1211             :     // Send the notifications to our listener asynchronously.
    1212           0 :     progressTracker->Notify(this);
    1213             :   } else {
    1214             :     // We don't have an imgRequest, so we can only notify the clone of our
    1215             :     // current state, but we still have to do that asynchronously.
    1216           0 :     MOZ_ASSERT(HasImage(),
    1217             :                "if we have no imgRequest, we should have an Image");
    1218           0 :     progressTracker->NotifyCurrentState(this);
    1219             :   }
    1220           1 : }
    1221             : 
    1222             : void
    1223          39 : imgRequestProxy::SyncNotifyListener()
    1224             : {
    1225             :   // It would be nice to notify the observer directly in the status tracker
    1226             :   // instead of through the proxy, but there are several places we do extra
    1227             :   // processing when we receive notifications (like OnStopRequest()), and we
    1228             :   // need to check mCanceled everywhere too.
    1229             : 
    1230         117 :   RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
    1231          39 :   progressTracker->SyncNotify(this);
    1232           1 : }
    1233             : 
    1234             : void
    1235          52 : imgRequestProxy::SetHasImage()
    1236             : {
    1237         156 :   RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
    1238          52 :   MOZ_ASSERT(progressTracker);
    1239           0 :   RefPtr<Image> image = progressTracker->GetImage();
    1240          52 :   MOZ_ASSERT(image);
    1241             : 
    1242             :   // Force any private status related to the owner to reflect
    1243             :   // the presence of an image;
    1244          52 :   mBehaviour->SetOwner(mBehaviour->GetOwner());
    1245             : 
    1246             :   // Apply any locks we have
    1247           0 :   for (uint32_t i = 0; i < mLockCount; ++i) {
    1248           0 :     image->LockImage();
    1249             :   }
    1250             : 
    1251             :   // Apply any animation consumers we have
    1252          52 :   for (uint32_t i = 0; i < mAnimationConsumers; i++) {
    1253           0 :     image->IncrementAnimationConsumers();
    1254             :   }
    1255           0 : }
    1256             : 
    1257             : already_AddRefed<ProgressTracker>
    1258         136 : imgRequestProxy::GetProgressTracker() const
    1259             : {
    1260           0 :   return mBehaviour->GetProgressTracker();
    1261             : }
    1262             : 
    1263             : already_AddRefed<mozilla::image::Image>
    1264           0 : imgRequestProxy::GetImage() const
    1265             : {
    1266         199 :   return mBehaviour->GetImage();
    1267             : }
    1268             : 
    1269             : bool
    1270           0 : RequestBehaviour::HasImage() const
    1271             : {
    1272           0 :   if (!mOwnerHasImage) {
    1273             :     return false;
    1274             :   }
    1275           0 :   RefPtr<ProgressTracker> progressTracker = GetProgressTracker();
    1276           0 :   return progressTracker ? progressTracker->HasImage() : false;
    1277             : }
    1278             : 
    1279             : bool
    1280           0 : imgRequestProxy::HasImage() const
    1281             : {
    1282           0 :   return mBehaviour->HasImage();
    1283             : }
    1284             : 
    1285             : imgRequest*
    1286           1 : imgRequestProxy::GetOwner() const
    1287             : {
    1288           1 :   return mBehaviour->GetOwner();
    1289             : }
    1290             : 
    1291             : imgCacheValidator*
    1292           1 : imgRequestProxy::GetValidator() const
    1293             : {
    1294          39 :   imgRequest* owner = GetOwner();
    1295          39 :   if (!owner) {
    1296             :     return nullptr;
    1297             :   }
    1298           1 :   return owner->GetValidator();
    1299             : }
    1300             : 
    1301             : ////////////////// imgRequestProxyStatic methods
    1302             : 
    1303           0 : class StaticBehaviour : public ProxyBehaviour
    1304             : {
    1305             : public:
    1306           0 :   explicit StaticBehaviour(mozilla::image::Image* aImage) : mImage(aImage) {}
    1307             : 
    1308             :   already_AddRefed<mozilla::image::Image>
    1309           0 :   GetImage() const override {
    1310           0 :     RefPtr<mozilla::image::Image> image = mImage;
    1311           0 :     return image.forget();
    1312             :   }
    1313             : 
    1314           0 :   bool HasImage() const override {
    1315           0 :     return mImage;
    1316             :   }
    1317             : 
    1318           0 :   already_AddRefed<ProgressTracker> GetProgressTracker()
    1319             :     const override  {
    1320           0 :     return mImage->GetProgressTracker();
    1321             :   }
    1322             : 
    1323           0 :   imgRequest* GetOwner() const override {
    1324           0 :     return nullptr;
    1325             :   }
    1326             : 
    1327           0 :   void SetOwner(imgRequest* aOwner) override {
    1328           0 :     MOZ_ASSERT(!aOwner,
    1329             :                "We shouldn't be giving static requests a non-null owner.");
    1330           0 :   }
    1331             : 
    1332             : private:
    1333             :   // Our image. We have to hold a strong reference here, because that's normally
    1334             :   // the job of the underlying request.
    1335             :   RefPtr<mozilla::image::Image> mImage;
    1336             : };
    1337             : 
    1338           0 : imgRequestProxyStatic::imgRequestProxyStatic(mozilla::image::Image* aImage,
    1339           0 :                                              nsIPrincipal* aPrincipal)
    1340           0 : : mPrincipal(aPrincipal)
    1341             : {
    1342           0 :   mBehaviour = mozilla::MakeUnique<StaticBehaviour>(aImage);
    1343           0 : }
    1344             : 
    1345             : NS_IMETHODIMP
    1346           0 : imgRequestProxyStatic::GetImagePrincipal(nsIPrincipal** aPrincipal)
    1347             : {
    1348           0 :   if (!mPrincipal) {
    1349             :     return NS_ERROR_FAILURE;
    1350             :   }
    1351             : 
    1352           0 :   NS_ADDREF(*aPrincipal = mPrincipal);
    1353             : 
    1354           0 :   return NS_OK;
    1355             : }
    1356             : 
    1357           0 : imgRequestProxy* imgRequestProxyStatic::NewClonedProxy()
    1358             : {
    1359           0 :   nsCOMPtr<nsIPrincipal> currentPrincipal;
    1360           0 :   GetImagePrincipal(getter_AddRefs(currentPrincipal));
    1361           0 :   RefPtr<mozilla::image::Image> image = GetImage();
    1362           0 :   return new imgRequestProxyStatic(image, currentPrincipal);
    1363             : }

Generated by: LCOV version 1.13-14-ga5dd952