LCOV - code coverage report
Current view: top level - image - ProgressTracker.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 207 268 77.2 %
Date: 2017-07-14 16:53:18 Functions: 65 96 67.7 %
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 "ImageLogging.h"
       8             : #include "ProgressTracker.h"
       9             : 
      10             : #include "imgIContainer.h"
      11             : #include "imgINotificationObserver.h"
      12             : #include "imgIRequest.h"
      13             : #include "Image.h"
      14             : #include "nsNetUtil.h"
      15             : #include "nsIObserverService.h"
      16             : 
      17             : #include "mozilla/Assertions.h"
      18             : #include "mozilla/Services.h"
      19             : 
      20             : using mozilla::WeakPtr;
      21             : 
      22             : namespace mozilla {
      23             : namespace image {
      24             : 
      25             : static void
      26         195 : CheckProgressConsistency(Progress aOldProgress, Progress aNewProgress, bool aIsMultipart)
      27             : {
      28             :   // Check preconditions for every progress bit.
      29             : 
      30             :   // Error's do not get propagated from the tracker for each image part to the
      31             :   // tracker for the multipart image because we don't want one bad part to
      32             :   // prevent the remaining parts from showing. So we need to consider whether
      33             :   // this is a tracker for a multipart image for these assertions to work.
      34             : 
      35         195 :   if (aNewProgress & FLAG_SIZE_AVAILABLE) {
      36             :     // No preconditions.
      37             :   }
      38         195 :   if (aNewProgress & FLAG_DECODE_COMPLETE) {
      39          61 :     MOZ_ASSERT(aNewProgress & FLAG_SIZE_AVAILABLE);
      40          61 :     MOZ_ASSERT(aIsMultipart || aNewProgress & (FLAG_FRAME_COMPLETE | FLAG_HAS_ERROR));
      41             :   }
      42         195 :   if (aNewProgress & FLAG_FRAME_COMPLETE) {
      43          95 :     MOZ_ASSERT(aNewProgress & FLAG_SIZE_AVAILABLE);
      44             :   }
      45         195 :   if (aNewProgress & FLAG_LOAD_COMPLETE) {
      46         135 :     MOZ_ASSERT(aIsMultipart || aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
      47             :   }
      48         195 :   if (aNewProgress & FLAG_ONLOAD_BLOCKED) {
      49             :     // No preconditions.
      50             :   }
      51         195 :   if (aNewProgress & FLAG_ONLOAD_UNBLOCKED) {
      52         114 :     MOZ_ASSERT(aNewProgress & FLAG_ONLOAD_BLOCKED);
      53         114 :     MOZ_ASSERT(aIsMultipart || aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
      54             :   }
      55         195 :   if (aNewProgress & FLAG_IS_ANIMATED) {
      56             :     // No preconditions; like FLAG_HAS_TRANSPARENCY, we should normally never
      57             :     // discover this *after* FLAG_SIZE_AVAILABLE, but unfortunately some corrupt
      58             :     // GIFs may fool us.
      59             :   }
      60         195 :   if (aNewProgress & FLAG_HAS_TRANSPARENCY) {
      61             :     // XXX We'd like to assert that transparency is only set during metadata
      62             :     // decode but we don't have any way to assert that until bug 1254892 is fixed.
      63             :   }
      64         195 :   if (aNewProgress & FLAG_LAST_PART_COMPLETE) {
      65         135 :     MOZ_ASSERT(aNewProgress & FLAG_LOAD_COMPLETE);
      66             :   }
      67         195 :   if (aNewProgress & FLAG_HAS_ERROR) {
      68             :     // No preconditions.
      69             :   }
      70         195 : }
      71             : 
      72             : void
      73          41 : ProgressTracker::SetImage(Image* aImage)
      74             : {
      75          82 :   MutexAutoLock lock(mImageMutex);
      76          41 :   MOZ_ASSERT(aImage, "Setting null image");
      77          41 :   MOZ_ASSERT(!mImage, "Setting image when we already have one");
      78          41 :   mImage = aImage;
      79          41 : }
      80             : 
      81             : void
      82           1 : ProgressTracker::ResetImage()
      83             : {
      84           2 :   MutexAutoLock lock(mImageMutex);
      85           1 :   MOZ_ASSERT(mImage, "Resetting image when it's already null!");
      86           1 :   mImage = nullptr;
      87           1 : }
      88             : 
      89             : uint32_t
      90         659 : ProgressTracker::GetImageStatus() const
      91             : {
      92         659 :   uint32_t status = imgIRequest::STATUS_NONE;
      93             : 
      94             :   // Translate our current state to a set of imgIRequest::STATE_* flags.
      95         659 :   if (mProgress & FLAG_SIZE_AVAILABLE) {
      96         644 :     status |= imgIRequest::STATUS_SIZE_AVAILABLE;
      97             :   }
      98         659 :   if (mProgress & FLAG_DECODE_COMPLETE) {
      99         613 :     status |= imgIRequest::STATUS_DECODE_COMPLETE;
     100             :   }
     101         659 :   if (mProgress & FLAG_FRAME_COMPLETE) {
     102         614 :     status |= imgIRequest::STATUS_FRAME_COMPLETE;
     103             :   }
     104         659 :   if (mProgress & FLAG_LOAD_COMPLETE) {
     105         645 :     status |= imgIRequest::STATUS_LOAD_COMPLETE;
     106             :   }
     107         659 :   if (mProgress & FLAG_IS_ANIMATED) {
     108          13 :     status |= imgIRequest::STATUS_IS_ANIMATED;
     109             :   }
     110         659 :   if (mProgress & FLAG_HAS_TRANSPARENCY) {
     111         644 :     status |= imgIRequest::STATUS_HAS_TRANSPARENCY;
     112             :   }
     113         659 :   if (mProgress & FLAG_HAS_ERROR) {
     114           1 :     status |= imgIRequest::STATUS_ERROR;
     115             :   }
     116             : 
     117         659 :   return status;
     118             : }
     119             : 
     120             : // A helper class to allow us to call SyncNotify asynchronously.
     121           6 : class AsyncNotifyRunnable : public Runnable
     122             : {
     123             :   public:
     124           2 :     AsyncNotifyRunnable(ProgressTracker* aTracker,
     125             :                         IProgressObserver* aObserver)
     126           2 :      : Runnable("ProgressTracker::AsyncNotifyRunnable")
     127           2 :      , mTracker(aTracker)
     128             :     {
     129           2 :       MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
     130           2 :       MOZ_ASSERT(aTracker, "aTracker should not be null");
     131           2 :       MOZ_ASSERT(aObserver, "aObserver should not be null");
     132           2 :       mObservers.AppendElement(aObserver);
     133           2 :     }
     134             : 
     135           2 :     NS_IMETHOD Run() override
     136             :     {
     137           2 :       MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
     138           2 :       MOZ_ASSERT(mTracker, "mTracker should not be null");
     139           6 :       for (uint32_t i = 0; i < mObservers.Length(); ++i) {
     140           4 :         mObservers[i]->SetNotificationsDeferred(false);
     141           4 :         mTracker->SyncNotify(mObservers[i]);
     142             :       }
     143             : 
     144           2 :       mTracker->mRunnable = nullptr;
     145           2 :       return NS_OK;
     146             :     }
     147             : 
     148           2 :     void AddObserver(IProgressObserver* aObserver)
     149             :     {
     150           2 :       mObservers.AppendElement(aObserver);
     151           2 :     }
     152             : 
     153           0 :     void RemoveObserver(IProgressObserver* aObserver)
     154             :     {
     155           0 :       mObservers.RemoveElement(aObserver);
     156           0 :     }
     157             : 
     158             :   private:
     159             :     friend class ProgressTracker;
     160             : 
     161             :     RefPtr<ProgressTracker> mTracker;
     162             :     nsTArray<RefPtr<IProgressObserver>> mObservers;
     163             : };
     164             : 
     165             : void
     166           4 : ProgressTracker::Notify(IProgressObserver* aObserver)
     167             : {
     168           4 :   MOZ_ASSERT(NS_IsMainThread());
     169             : 
     170           4 :   if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
     171           0 :     RefPtr<Image> image = GetImage();
     172           0 :     if (image && image->GetURI()) {
     173           0 :       RefPtr<ImageURL> uri(image->GetURI());
     174           0 :       nsAutoCString spec;
     175           0 :       uri->GetSpec(spec);
     176             :       LOG_FUNC_WITH_PARAM(gImgLog,
     177           0 :                           "ProgressTracker::Notify async", "uri", spec.get());
     178             :     } else {
     179             :       LOG_FUNC_WITH_PARAM(gImgLog,
     180           0 :                           "ProgressTracker::Notify async", "uri", "<unknown>");
     181             :     }
     182             :   }
     183             : 
     184           4 :   aObserver->SetNotificationsDeferred(true);
     185             : 
     186             :   // If we have an existing runnable that we can use, we just append this
     187             :   // observer to its list of observers to be notified. This ensures we don't
     188             :   // unnecessarily delay onload.
     189             :   AsyncNotifyRunnable* runnable =
     190           4 :     static_cast<AsyncNotifyRunnable*>(mRunnable.get());
     191             : 
     192           4 :   if (runnable) {
     193           2 :     runnable->AddObserver(aObserver);
     194             :   } else {
     195           2 :     mRunnable = new AsyncNotifyRunnable(this, aObserver);
     196           2 :     NS_DispatchToCurrentThread(mRunnable);
     197             :   }
     198           4 : }
     199             : 
     200             : // A helper class to allow us to call SyncNotify asynchronously for a given,
     201             : // fixed, state.
     202           0 : class AsyncNotifyCurrentStateRunnable : public Runnable
     203             : {
     204             :   public:
     205           0 :     AsyncNotifyCurrentStateRunnable(ProgressTracker* aProgressTracker,
     206             :                                     IProgressObserver* aObserver)
     207           0 :       : Runnable("image::AsyncNotifyCurrentStateRunnable")
     208             :       , mProgressTracker(aProgressTracker)
     209           0 :       , mObserver(aObserver)
     210             :     {
     211           0 :       MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
     212           0 :       MOZ_ASSERT(mProgressTracker, "mProgressTracker should not be null");
     213           0 :       MOZ_ASSERT(mObserver, "mObserver should not be null");
     214           0 :       mImage = mProgressTracker->GetImage();
     215           0 :     }
     216             : 
     217           0 :     NS_IMETHOD Run() override
     218             :     {
     219           0 :       MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
     220           0 :       mObserver->SetNotificationsDeferred(false);
     221             : 
     222           0 :       mProgressTracker->SyncNotify(mObserver);
     223           0 :       return NS_OK;
     224             :     }
     225             : 
     226             :   private:
     227             :     RefPtr<ProgressTracker> mProgressTracker;
     228             :     RefPtr<IProgressObserver> mObserver;
     229             : 
     230             :     // We have to hold on to a reference to the tracker's image, just in case
     231             :     // it goes away while we're in the event queue.
     232             :     RefPtr<Image> mImage;
     233             : };
     234             : 
     235             : void
     236           0 : ProgressTracker::NotifyCurrentState(IProgressObserver* aObserver)
     237             : {
     238           0 :   MOZ_ASSERT(NS_IsMainThread());
     239             : 
     240           0 :   if (MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) {
     241           0 :     RefPtr<Image> image = GetImage();
     242           0 :     nsAutoCString spec;
     243           0 :     if (image && image->GetURI()) {
     244           0 :       image->GetURI()->GetSpec(spec);
     245             :     }
     246             :     LOG_FUNC_WITH_PARAM(gImgLog,
     247           0 :                         "ProgressTracker::NotifyCurrentState", "uri", spec.get());
     248             :   }
     249             : 
     250           0 :   aObserver->SetNotificationsDeferred(true);
     251             : 
     252             :   nsCOMPtr<nsIRunnable> ev = new AsyncNotifyCurrentStateRunnable(this,
     253           0 :                                                                  aObserver);
     254           0 :   NS_DispatchToCurrentThread(ev);
     255           0 : }
     256             : 
     257             : /**
     258             :  * ImageObserverNotifier is a helper type that abstracts over the difference
     259             :  * between sending notifications to all of the observers in an ObserverTable,
     260             :  * and sending them to a single observer. This allows the same notification code
     261             :  * to be used for both cases.
     262             :  */
     263             : template <typename T> struct ImageObserverNotifier;
     264             : 
     265             : template <>
     266             : struct MOZ_STACK_CLASS ImageObserverNotifier<const ObserverTable*>
     267             : {
     268         236 :   explicit ImageObserverNotifier(const ObserverTable* aObservers,
     269             :                                  bool aIgnoreDeferral = false)
     270         236 :     : mObservers(aObservers)
     271         236 :     , mIgnoreDeferral(aIgnoreDeferral)
     272         236 :   { }
     273             : 
     274             :   template <typename Lambda>
     275         403 :   void operator()(Lambda aFunc)
     276             :   {
     277        1577 :     for (auto iter = mObservers->ConstIter(); !iter.Done(); iter.Next()) {
     278        2348 :       RefPtr<IProgressObserver> observer = iter.Data().get();
     279        3518 :       if (observer &&
     280        2232 :           (mIgnoreDeferral || !observer->NotificationsDeferred())) {
     281        1170 :         aFunc(observer);
     282             :       }
     283             :     }
     284         403 :   }
     285             : 
     286             : private:
     287             :   const ObserverTable* mObservers;
     288             :   const bool mIgnoreDeferral;
     289             : };
     290             : 
     291             : template <>
     292             : struct MOZ_STACK_CLASS ImageObserverNotifier<IProgressObserver*>
     293             : {
     294          96 :   explicit ImageObserverNotifier(IProgressObserver* aObserver)
     295          96 :     : mObserver(aObserver)
     296          96 :   { }
     297             : 
     298             :   template <typename Lambda>
     299         144 :   void operator()(Lambda aFunc)
     300             :   {
     301         144 :     if (mObserver && !mObserver->NotificationsDeferred()) {
     302         144 :       aFunc(mObserver);
     303             :     }
     304         144 :   }
     305             : 
     306             : private:
     307             :   IProgressObserver* mObserver;
     308             : };
     309             : 
     310             : template <typename T> void
     311         291 : SyncNotifyInternal(const T& aObservers,
     312             :                    bool aHasImage,
     313             :                    Progress aProgress,
     314             :                    const nsIntRect& aDirtyRect)
     315             : {
     316         291 :   MOZ_ASSERT(NS_IsMainThread());
     317             : 
     318             :   typedef imgINotificationObserver I;
     319         291 :   ImageObserverNotifier<T> notify(aObservers);
     320             : 
     321         291 :   if (aProgress & FLAG_SIZE_AVAILABLE) {
     322         189 :     notify([](IProgressObserver* aObs) { aObs->Notify(I::SIZE_AVAILABLE); });
     323             :   }
     324             : 
     325         291 :   if (aProgress & FLAG_ONLOAD_BLOCKED) {
     326         248 :     notify([](IProgressObserver* aObs) { aObs->BlockOnload(); });
     327             :   }
     328             : 
     329         291 :   if (aHasImage) {
     330             :     // OnFrameUpdate
     331             :     // If there's any content in this frame at all (always true for
     332             :     // vector images, true for raster images that have decoded at
     333             :     // least one frame) then send OnFrameUpdate.
     334         216 :     if (!aDirtyRect.IsEmpty()) {
     335         287 :       notify([&](IProgressObserver* aObs) {
     336         205 :         aObs->Notify(I::FRAME_UPDATE, &aDirtyRect);
     337         205 :       });
     338             :     }
     339             : 
     340         216 :     if (aProgress & FLAG_FRAME_COMPLETE) {
     341         174 :       notify([](IProgressObserver* aObs) { aObs->Notify(I::FRAME_COMPLETE); });
     342             :     }
     343             : 
     344         216 :     if (aProgress & FLAG_HAS_TRANSPARENCY) {
     345         189 :       notify([](IProgressObserver* aObs) { aObs->Notify(I::HAS_TRANSPARENCY); });
     346             :     }
     347             : 
     348         216 :     if (aProgress & FLAG_IS_ANIMATED) {
     349           8 :       notify([](IProgressObserver* aObs) { aObs->Notify(I::IS_ANIMATED); });
     350             :     }
     351             :   }
     352             : 
     353             :   // Send UnblockOnload before OnStopDecode and OnStopRequest. This allows
     354             :   // observers that can fire events when they receive those notifications to do
     355             :   // so then, instead of being forced to wait for UnblockOnload.
     356         291 :   if (aProgress & FLAG_ONLOAD_UNBLOCKED) {
     357         244 :     notify([](IProgressObserver* aObs) { aObs->UnblockOnload(); });
     358             :   }
     359             : 
     360         291 :   if (aProgress & FLAG_DECODE_COMPLETE) {
     361          52 :     MOZ_ASSERT(aHasImage, "Stopped decoding without ever having an image?");
     362         174 :     notify([](IProgressObserver* aObs) { aObs->Notify(I::DECODE_COMPLETE); });
     363             :   }
     364             : 
     365         291 :   if (aProgress & FLAG_LOAD_COMPLETE) {
     366         191 :     notify([=](IProgressObserver* aObs) {
     367         133 :       aObs->OnLoadComplete(aProgress & FLAG_LAST_PART_COMPLETE);
     368         133 :     });
     369             :   }
     370         291 : }
     371             : 
     372             : void
     373         195 : ProgressTracker::SyncNotifyProgress(Progress aProgress,
     374             :                                     const nsIntRect& aInvalidRect
     375             :                                                   /* = nsIntRect() */)
     376             : {
     377         195 :   MOZ_ASSERT(NS_IsMainThread(), "Use mObservers on main thread only");
     378             : 
     379             :   // Don't unblock onload if we're not blocked.
     380         195 :   Progress progress = Difference(aProgress);
     381         195 :   if (!((mProgress | progress) & FLAG_ONLOAD_BLOCKED)) {
     382           3 :     progress &= ~FLAG_ONLOAD_UNBLOCKED;
     383             :   }
     384             : 
     385         195 :   CheckProgressConsistency(mProgress, mProgress | progress, mIsMultipart);
     386             : 
     387             :   // XXX(seth): Hack to work around the fact that some observers have bugs and
     388             :   // need to get onload blocking notifications multiple times. We should fix
     389             :   // those observers and remove this.
     390         230 :   if ((aProgress & FLAG_DECODE_COMPLETE) &&
     391          70 :       (mProgress & FLAG_ONLOAD_BLOCKED) &&
     392          35 :       (mProgress & FLAG_ONLOAD_UNBLOCKED)) {
     393          14 :     progress |= FLAG_ONLOAD_BLOCKED | FLAG_ONLOAD_UNBLOCKED;
     394             :   }
     395             : 
     396             :   // Apply the changes.
     397         195 :   mProgress |= progress;
     398             : 
     399             :   // Send notifications.
     400         390 :   mObservers.Read([&](const ObserverTable* aTable) {
     401         195 :     SyncNotifyInternal(aTable, HasImage(), progress, aInvalidRect);
     402         585 :   });
     403             : 
     404         195 :   if (progress & FLAG_HAS_ERROR) {
     405           1 :     FireFailureNotification();
     406             :   }
     407         195 : }
     408             : 
     409             : void
     410          96 : ProgressTracker::SyncNotify(IProgressObserver* aObserver)
     411             : {
     412          96 :   MOZ_ASSERT(NS_IsMainThread());
     413             : 
     414         192 :   RefPtr<Image> image = GetImage();
     415             : 
     416         192 :   nsAutoCString spec;
     417          96 :   if (image && image->GetURI()) {
     418          21 :     image->GetURI()->GetSpec(spec);
     419             :   }
     420         192 :   LOG_SCOPE_WITH_PARAM(gImgLog,
     421             :                        "ProgressTracker::SyncNotify", "uri", spec.get());
     422             : 
     423          96 :   nsIntRect rect;
     424          96 :   if (image) {
     425          38 :     if (NS_FAILED(image->GetWidth(&rect.width)) ||
     426          17 :         NS_FAILED(image->GetHeight(&rect.height))) {
     427             :       // Either the image has no intrinsic size, or it has an error.
     428           4 :       rect = GetMaxSizedIntRect();
     429             :     }
     430             :   }
     431             : 
     432          96 :   SyncNotifyInternal(aObserver, !!image, mProgress, rect);
     433          96 : }
     434             : 
     435             : void
     436          29 : ProgressTracker::EmulateRequestFinished(IProgressObserver* aObserver)
     437             : {
     438          29 :   MOZ_ASSERT(NS_IsMainThread(),
     439             :              "SyncNotifyState and mObservers are not threadsafe");
     440          58 :   RefPtr<IProgressObserver> kungFuDeathGrip(aObserver);
     441             : 
     442          29 :   if (mProgress & FLAG_ONLOAD_BLOCKED && !(mProgress & FLAG_ONLOAD_UNBLOCKED)) {
     443           0 :     aObserver->UnblockOnload();
     444             :   }
     445             : 
     446          29 :   if (!(mProgress & FLAG_LOAD_COMPLETE)) {
     447           4 :     aObserver->OnLoadComplete(true);
     448             :   }
     449          29 : }
     450             : 
     451             : void
     452         137 : ProgressTracker::AddObserver(IProgressObserver* aObserver)
     453             : {
     454         137 :   MOZ_ASSERT(NS_IsMainThread());
     455         274 :   RefPtr<IProgressObserver> observer = aObserver;
     456             : 
     457         548 :   mObservers.Write([=](ObserverTable* aTable) {
     458         137 :     MOZ_ASSERT(!aTable->Get(observer, nullptr),
     459             :                "Adding duplicate entry for image observer");
     460             : 
     461         274 :     WeakPtr<IProgressObserver> weakPtr = observer.get();
     462         137 :     aTable->Put(observer, weakPtr);
     463         274 :   });
     464         137 : }
     465             : 
     466             : bool
     467          58 : ProgressTracker::RemoveObserver(IProgressObserver* aObserver)
     468             : {
     469          58 :   MOZ_ASSERT(NS_IsMainThread());
     470         116 :   RefPtr<IProgressObserver> observer = aObserver;
     471             : 
     472             :   // Remove the observer from the list.
     473         232 :   bool removed = mObservers.Write([=](ObserverTable* aTable) {
     474          58 :     return aTable->Remove(observer);
     475         116 :   });
     476             : 
     477             :   // Observers can get confused if they don't get all the proper teardown
     478             :   // notifications. Part ways on good terms.
     479          58 :   if (removed && !aObserver->NotificationsDeferred()) {
     480          29 :     EmulateRequestFinished(aObserver);
     481             :   }
     482             : 
     483             :   // Make sure we don't give callbacks to an observer that isn't interested in
     484             :   // them any more.
     485             :   AsyncNotifyRunnable* runnable =
     486          58 :     static_cast<AsyncNotifyRunnable*>(mRunnable.get());
     487             : 
     488          58 :   if (aObserver->NotificationsDeferred() && runnable) {
     489           0 :     runnable->RemoveObserver(aObserver);
     490           0 :     aObserver->SetNotificationsDeferred(false);
     491             :   }
     492             : 
     493         116 :   return removed;
     494             : }
     495             : 
     496             : uint32_t
     497         207 : ProgressTracker::ObserverCount() const
     498             : {
     499         207 :   MOZ_ASSERT(NS_IsMainThread());
     500         621 :   return mObservers.Read([](const ObserverTable* aTable) {
     501         207 :     return aTable->Count();
     502         621 :   });
     503             : }
     504             : 
     505             : void
     506           0 : ProgressTracker::OnUnlockedDraw()
     507             : {
     508           0 :   MOZ_ASSERT(NS_IsMainThread());
     509           0 :   mObservers.Read([](const ObserverTable* aTable) {
     510           0 :     ImageObserverNotifier<const ObserverTable*> notify(aTable);
     511           0 :     notify([](IProgressObserver* aObs) {
     512           0 :       aObs->Notify(imgINotificationObserver::UNLOCKED_DRAW);
     513           0 :     });
     514           0 :   });
     515           0 : }
     516             : 
     517             : void
     518           0 : ProgressTracker::ResetForNewRequest()
     519             : {
     520           0 :   MOZ_ASSERT(NS_IsMainThread());
     521           0 :   mProgress = NoProgress;
     522           0 : }
     523             : 
     524             : void
     525           0 : ProgressTracker::OnDiscard()
     526             : {
     527           0 :   MOZ_ASSERT(NS_IsMainThread());
     528           0 :   mObservers.Read([](const ObserverTable* aTable) {
     529           0 :     ImageObserverNotifier<const ObserverTable*> notify(aTable);
     530           0 :     notify([](IProgressObserver* aObs) {
     531           0 :       aObs->Notify(imgINotificationObserver::DISCARD);
     532           0 :     });
     533           0 :   });
     534           0 : }
     535             : 
     536             : void
     537          41 : ProgressTracker::OnImageAvailable()
     538             : {
     539          41 :   MOZ_ASSERT(NS_IsMainThread());
     540             :   // Notify any imgRequestProxys that are observing us that we have an Image.
     541         123 :   mObservers.Read([](const ObserverTable* aTable) {
     542             :     ImageObserverNotifier<const ObserverTable*>
     543          41 :       notify(aTable, /* aIgnoreDeferral = */ true);
     544         157 :     notify([](IProgressObserver* aObs) {
     545         116 :       aObs->SetHasImage();
     546         157 :     });
     547          82 :   });
     548          41 : }
     549             : 
     550             : void
     551           1 : ProgressTracker::FireFailureNotification()
     552             : {
     553           1 :   MOZ_ASSERT(NS_IsMainThread());
     554             : 
     555             :   // Some kind of problem has happened with image decoding.
     556             :   // Report the URI to net:failed-to-process-uri-conent observers.
     557           2 :   RefPtr<Image> image = GetImage();
     558           1 :   if (image) {
     559             :     // Should be on main thread, so ok to create a new nsIURI.
     560           2 :     nsCOMPtr<nsIURI> uri;
     561             :     {
     562           2 :       RefPtr<ImageURL> threadsafeUriData = image->GetURI();
     563           1 :       uri = threadsafeUriData ? threadsafeUriData->ToIURI() : nullptr;
     564             :     }
     565           1 :     if (uri) {
     566           2 :       nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     567           1 :       if (os) {
     568           1 :         os->NotifyObservers(uri, "net:failed-to-process-uri-content", nullptr);
     569             :       }
     570             :     }
     571             :   }
     572           1 : }
     573             : 
     574             : } // namespace image
     575             : } // namespace mozilla

Generated by: LCOV version 1.13