LCOV - code coverage report
Current view: top level - image - MultipartImage.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 153 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 35 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             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "MultipartImage.h"
       7             : 
       8             : #include "imgINotificationObserver.h"
       9             : 
      10             : namespace mozilla {
      11             : 
      12             : using gfx::IntSize;
      13             : using gfx::SourceSurface;
      14             : 
      15             : namespace image {
      16             : 
      17             : ///////////////////////////////////////////////////////////////////////////////
      18             : // Helpers
      19             : ///////////////////////////////////////////////////////////////////////////////
      20             : 
      21             : class NextPartObserver : public IProgressObserver
      22             : {
      23             : public:
      24             :   MOZ_DECLARE_REFCOUNTED_TYPENAME(NextPartObserver)
      25           0 :   NS_INLINE_DECL_REFCOUNTING(NextPartObserver, override)
      26             : 
      27           0 :   explicit NextPartObserver(MultipartImage* aOwner)
      28           0 :     : mOwner(aOwner)
      29             :   {
      30           0 :     MOZ_ASSERT(mOwner);
      31           0 :   }
      32             : 
      33           0 :   void BeginObserving(Image* aImage)
      34             :   {
      35           0 :     MOZ_ASSERT(aImage);
      36           0 :     mImage = aImage;
      37             : 
      38           0 :     RefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
      39           0 :     tracker->AddObserver(this);
      40           0 :   }
      41             : 
      42           0 :   void BlockUntilDecodedAndFinishObserving()
      43             :   {
      44             :     // Use GetFrame() to block until our image finishes decoding.
      45             :     RefPtr<SourceSurface> surface =
      46           0 :       mImage->GetFrame(imgIContainer::FRAME_CURRENT,
      47           0 :                        imgIContainer::FLAG_SYNC_DECODE);
      48             : 
      49             :     // GetFrame() should've sent synchronous notifications that would have
      50             :     // caused us to call FinishObserving() (and null out mImage) already. If for
      51             :     // some reason it didn't, we should do so here.
      52           0 :     if (mImage) {
      53           0 :       FinishObserving();
      54             :     }
      55           0 :   }
      56             : 
      57           0 :   virtual void Notify(int32_t aType,
      58             :                       const nsIntRect* aRect = nullptr) override
      59             :   {
      60           0 :     if (!mImage) {
      61             :       // We've already finished observing the last image we were given.
      62           0 :       return;
      63             :     }
      64             : 
      65           0 :     if (aType == imgINotificationObserver::FRAME_COMPLETE) {
      66           0 :       FinishObserving();
      67             :     }
      68             :   }
      69             : 
      70           0 :   virtual void OnLoadComplete(bool aLastPart) override
      71             :   {
      72           0 :     if (!mImage) {
      73             :       // We've already finished observing the last image we were given.
      74           0 :       return;
      75             :     }
      76             : 
      77             :     // Retrieve the image's intrinsic size.
      78           0 :     int32_t width = 0;
      79           0 :     int32_t height = 0;
      80           0 :     mImage->GetWidth(&width);
      81           0 :     mImage->GetHeight(&height);
      82             : 
      83             :     // Request decoding at the intrinsic size.
      84           0 :     mImage->RequestDecodeForSize(IntSize(width, height),
      85           0 :                                  imgIContainer::DECODE_FLAGS_DEFAULT);
      86             : 
      87             :     // If there's already an error, we may never get a FRAME_COMPLETE
      88             :     // notification, so go ahead and notify our owner right away.
      89           0 :     RefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
      90           0 :     if (tracker->GetProgress() & FLAG_HAS_ERROR) {
      91           0 :       FinishObserving();
      92             :     }
      93             :   }
      94             : 
      95             :   // Other notifications are ignored.
      96           0 :   virtual void BlockOnload() override { }
      97           0 :   virtual void UnblockOnload() override { }
      98           0 :   virtual void SetHasImage() override { }
      99           0 :   virtual bool NotificationsDeferred() const override { return false; }
     100           0 :   virtual void SetNotificationsDeferred(bool) override { }
     101             : 
     102             : private:
     103           0 :   virtual ~NextPartObserver() { }
     104             : 
     105           0 :   void FinishObserving()
     106             :   {
     107           0 :     MOZ_ASSERT(mImage);
     108             : 
     109           0 :     RefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
     110           0 :     tracker->RemoveObserver(this);
     111           0 :     mImage = nullptr;
     112             : 
     113           0 :     mOwner->FinishTransition();
     114           0 :   }
     115             : 
     116             :   MultipartImage* mOwner;
     117             :   RefPtr<Image> mImage;
     118             : };
     119             : 
     120             : 
     121             : ///////////////////////////////////////////////////////////////////////////////
     122             : // Implementation
     123             : ///////////////////////////////////////////////////////////////////////////////
     124             : 
     125           0 : MultipartImage::MultipartImage(Image* aFirstPart)
     126             :   : ImageWrapper(aFirstPart)
     127           0 :   , mDeferNotifications(false)
     128             : {
     129           0 :   mNextPartObserver = new NextPartObserver(this);
     130           0 : }
     131             : 
     132             : void
     133           0 : MultipartImage::Init()
     134             : {
     135           0 :   MOZ_ASSERT(NS_IsMainThread());
     136           0 :   MOZ_ASSERT(mTracker, "Should've called SetProgressTracker() by now");
     137             : 
     138             :   // Start observing the first part.
     139             :   RefPtr<ProgressTracker> firstPartTracker =
     140           0 :     InnerImage()->GetProgressTracker();
     141           0 :   firstPartTracker->AddObserver(this);
     142           0 :   InnerImage()->IncrementAnimationConsumers();
     143           0 : }
     144             : 
     145           0 : MultipartImage::~MultipartImage()
     146             : {
     147             :   // Ask our ProgressTracker to drop its weak reference to us.
     148           0 :   mTracker->ResetImage();
     149           0 : }
     150             : 
     151           0 : NS_IMPL_ISUPPORTS_INHERITED0(MultipartImage, ImageWrapper)
     152             : 
     153             : void
     154           0 : MultipartImage::BeginTransitionToPart(Image* aNextPart)
     155             : {
     156           0 :   MOZ_ASSERT(NS_IsMainThread());
     157           0 :   MOZ_ASSERT(aNextPart);
     158             : 
     159           0 :   if (mNextPart) {
     160             :     // Let the decoder catch up so we don't drop frames.
     161           0 :     mNextPartObserver->BlockUntilDecodedAndFinishObserving();
     162           0 :     MOZ_ASSERT(!mNextPart);
     163             :   }
     164             : 
     165           0 :   mNextPart = aNextPart;
     166             : 
     167             :   // Start observing the next part; we'll complete the transition when
     168             :   // NextPartObserver calls FinishTransition.
     169           0 :   mNextPartObserver->BeginObserving(mNextPart);
     170           0 :   mNextPart->IncrementAnimationConsumers();
     171           0 : }
     172             : 
     173             : static Progress
     174           0 : FilterProgress(Progress aProgress)
     175             : {
     176             :   // Filter out onload blocking notifications, since we don't want to block
     177             :   // onload for multipart images.
     178             :   // Filter out errors, since we don't want errors in one part to error out
     179             :   // the whole stream.
     180           0 :   return aProgress & ~(FLAG_ONLOAD_BLOCKED | FLAG_ONLOAD_UNBLOCKED | FLAG_HAS_ERROR);
     181             : }
     182             : 
     183             : void
     184           0 : MultipartImage::FinishTransition()
     185             : {
     186           0 :   MOZ_ASSERT(NS_IsMainThread());
     187           0 :   MOZ_ASSERT(mNextPart, "Should have a next part here");
     188             : 
     189             :   RefPtr<ProgressTracker> newCurrentPartTracker =
     190           0 :     mNextPart->GetProgressTracker();
     191           0 :   if (newCurrentPartTracker->GetProgress() & FLAG_HAS_ERROR) {
     192             :     // This frame has an error; drop it.
     193           0 :     mNextPart = nullptr;
     194             : 
     195             :     // We still need to notify, though.
     196           0 :     mTracker->ResetForNewRequest();
     197             :     RefPtr<ProgressTracker> currentPartTracker =
     198           0 :       InnerImage()->GetProgressTracker();
     199             :     mTracker
     200           0 :       ->SyncNotifyProgress(FilterProgress(currentPartTracker->GetProgress()));
     201             : 
     202           0 :     return;
     203             :   }
     204             : 
     205             :   // Stop observing the current part.
     206             :   {
     207             :     RefPtr<ProgressTracker> currentPartTracker =
     208           0 :       InnerImage()->GetProgressTracker();
     209           0 :     currentPartTracker->RemoveObserver(this);
     210             :   }
     211             : 
     212             :   // Make the next part become the current part.
     213           0 :   mTracker->ResetForNewRequest();
     214           0 :   SetInnerImage(mNextPart);
     215           0 :   mNextPart = nullptr;
     216           0 :   newCurrentPartTracker->AddObserver(this);
     217             : 
     218             :   // Finally, send all the notifications for the new current part and send a
     219             :   // FRAME_UPDATE notification so that observers know to redraw.
     220             :   mTracker
     221           0 :     ->SyncNotifyProgress(FilterProgress(newCurrentPartTracker->GetProgress()),
     222           0 :                          GetMaxSizedIntRect());
     223             : }
     224             : 
     225             : already_AddRefed<imgIContainer>
     226           0 : MultipartImage::Unwrap()
     227             : {
     228             :   // Although we wrap another image, we don't allow callers to unwrap as. As far
     229             :   // as external code is concerned, MultipartImage is atomic.
     230           0 :   nsCOMPtr<imgIContainer> image = this;
     231           0 :   return image.forget();
     232             : }
     233             : 
     234             : already_AddRefed<ProgressTracker>
     235           0 : MultipartImage::GetProgressTracker()
     236             : {
     237           0 :   MOZ_ASSERT(mTracker);
     238           0 :   RefPtr<ProgressTracker> tracker = mTracker;
     239           0 :   return tracker.forget();
     240             : }
     241             : 
     242             : void
     243           0 : MultipartImage::SetProgressTracker(ProgressTracker* aTracker)
     244             : {
     245           0 :   MOZ_ASSERT(aTracker);
     246           0 :   MOZ_ASSERT(!mTracker);
     247           0 :   mTracker = aTracker;
     248           0 : }
     249             : 
     250             : nsresult
     251           0 : MultipartImage::OnImageDataAvailable(nsIRequest* aRequest,
     252             :                                      nsISupports* aContext,
     253             :                                      nsIInputStream* aInStr,
     254             :                                      uint64_t aSourceOffset,
     255             :                                      uint32_t aCount)
     256             : {
     257             :   // Note that this method is special in that we forward it to the next part if
     258             :   // one exists, and *not* the current part.
     259             : 
     260             :   // We may trigger notifications that will free mNextPart, so keep it alive.
     261           0 :   RefPtr<Image> nextPart = mNextPart;
     262           0 :   if (nextPart) {
     263           0 :     nextPart->OnImageDataAvailable(aRequest, aContext, aInStr,
     264           0 :                                    aSourceOffset, aCount);
     265             :   } else {
     266           0 :     InnerImage()->OnImageDataAvailable(aRequest, aContext, aInStr,
     267           0 :                                        aSourceOffset, aCount);
     268             :   }
     269             : 
     270           0 :   return NS_OK;
     271             : }
     272             : 
     273             : nsresult
     274           0 : MultipartImage::OnImageDataComplete(nsIRequest* aRequest,
     275             :                                     nsISupports* aContext,
     276             :                                     nsresult aStatus,
     277             :                                     bool aLastPart)
     278             : {
     279             :   // Note that this method is special in that we forward it to the next part if
     280             :   // one exists, and *not* the current part.
     281             : 
     282             :   // We may trigger notifications that will free mNextPart, so keep it alive.
     283           0 :   RefPtr<Image> nextPart = mNextPart;
     284           0 :   if (nextPart) {
     285           0 :     nextPart->OnImageDataComplete(aRequest, aContext, aStatus, aLastPart);
     286             :   } else {
     287           0 :     InnerImage()->OnImageDataComplete(aRequest, aContext, aStatus, aLastPart);
     288             :   }
     289             : 
     290           0 :   return NS_OK;
     291             : }
     292             : 
     293             : void
     294           0 : MultipartImage::Notify(int32_t aType, const nsIntRect* aRect /* = nullptr*/)
     295             : {
     296           0 :   if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     297           0 :     mTracker->SyncNotifyProgress(FLAG_SIZE_AVAILABLE);
     298           0 :   } else if (aType == imgINotificationObserver::FRAME_UPDATE) {
     299           0 :     mTracker->SyncNotifyProgress(NoProgress, *aRect);
     300           0 :   } else if (aType == imgINotificationObserver::FRAME_COMPLETE) {
     301           0 :     mTracker->SyncNotifyProgress(FLAG_FRAME_COMPLETE);
     302           0 :   } else if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     303           0 :     mTracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
     304           0 :   } else if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     305           0 :     mTracker->SyncNotifyProgress(FLAG_DECODE_COMPLETE);
     306           0 :   } else if (aType == imgINotificationObserver::DISCARD) {
     307           0 :     mTracker->OnDiscard();
     308           0 :   } else if (aType == imgINotificationObserver::UNLOCKED_DRAW) {
     309           0 :     mTracker->OnUnlockedDraw();
     310           0 :   } else if (aType == imgINotificationObserver::IS_ANIMATED) {
     311           0 :     mTracker->SyncNotifyProgress(FLAG_IS_ANIMATED);
     312           0 :   } else if (aType == imgINotificationObserver::HAS_TRANSPARENCY) {
     313           0 :     mTracker->SyncNotifyProgress(FLAG_HAS_TRANSPARENCY);
     314             :   } else {
     315           0 :     NS_NOTREACHED("Notification list should be exhaustive");
     316             :   }
     317           0 : }
     318             : 
     319             : void
     320           0 : MultipartImage::OnLoadComplete(bool aLastPart)
     321             : {
     322           0 :   Progress progress = FLAG_LOAD_COMPLETE;
     323           0 :   if (aLastPart) {
     324           0 :     progress |= FLAG_LAST_PART_COMPLETE;
     325             :   }
     326           0 :   mTracker->SyncNotifyProgress(progress);
     327           0 : }
     328             : 
     329             : void
     330           0 : MultipartImage::SetHasImage()
     331             : {
     332           0 :   mTracker->OnImageAvailable();
     333           0 : }
     334             : 
     335             : bool
     336           0 : MultipartImage::NotificationsDeferred() const
     337             : {
     338           0 :   return mDeferNotifications;
     339             : }
     340             : 
     341             : void
     342           0 : MultipartImage::SetNotificationsDeferred(bool aDeferNotifications)
     343             : {
     344           0 :   mDeferNotifications = aDeferNotifications;
     345           0 : }
     346             : 
     347             : } // namespace image
     348             : } // namespace mozilla

Generated by: LCOV version 1.13