LCOV - code coverage report
Current view: top level - image - DecodedSurfaceProvider.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 57 78 73.1 %
Date: 2017-07-14 16:53:18 Functions: 10 12 83.3 %
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 "DecodedSurfaceProvider.h"
       7             : 
       8             : #include "gfxPrefs.h"
       9             : #include "nsProxyRelease.h"
      10             : 
      11             : #include "Decoder.h"
      12             : 
      13             : using namespace mozilla::gfx;
      14             : 
      15             : namespace mozilla {
      16             : namespace image {
      17             : 
      18          12 : DecodedSurfaceProvider::DecodedSurfaceProvider(NotNull<RasterImage*> aImage,
      19             :                                                const SurfaceKey& aSurfaceKey,
      20          12 :                                                NotNull<Decoder*> aDecoder)
      21          12 :   : ISurfaceProvider(ImageKey(aImage.get()), aSurfaceKey,
      22             :                      AvailabilityState::StartAsPlaceholder())
      23          12 :   , mImage(aImage.get())
      24             :   , mMutex("mozilla::image::DecodedSurfaceProvider")
      25          36 :   , mDecoder(aDecoder.get())
      26             : {
      27          12 :   MOZ_ASSERT(!mDecoder->IsMetadataDecode(),
      28             :              "Use MetadataDecodingTask for metadata decodes");
      29          12 :   MOZ_ASSERT(mDecoder->IsFirstFrameDecode(),
      30             :              "Use AnimationSurfaceProvider for animation decodes");
      31          12 : }
      32             : 
      33           0 : DecodedSurfaceProvider::~DecodedSurfaceProvider()
      34             : {
      35           0 :   DropImageReference();
      36           0 : }
      37             : 
      38             : void
      39          12 : DecodedSurfaceProvider::DropImageReference()
      40             : {
      41          12 :   if (!mImage) {
      42           0 :     return;  // Nothing to do.
      43             :   }
      44             : 
      45             :   // RasterImage objects need to be destroyed on the main thread. We also need
      46             :   // to destroy them asynchronously, because if our surface cache entry is
      47             :   // destroyed and we were the only thing keeping |mImage| alive, RasterImage's
      48             :   // destructor may call into the surface cache while whatever code caused us to
      49             :   // get evicted is holding the surface cache lock, causing deadlock.
      50          24 :   RefPtr<RasterImage> image = mImage;
      51          12 :   mImage = nullptr;
      52          12 :   NS_ReleaseOnMainThreadSystemGroup(image.forget(), /* aAlwaysProxy = */ true);
      53             : }
      54             : 
      55             : DrawableFrameRef
      56          35 : DecodedSurfaceProvider::DrawableRef(size_t aFrame)
      57             : {
      58          35 :   MOZ_ASSERT(aFrame == 0,
      59             :              "Requesting an animation frame from a DecodedSurfaceProvider?");
      60             : 
      61             :   // We depend on SurfaceCache::SurfaceAvailable() to provide synchronization
      62             :   // for methods that touch |mSurface|; after SurfaceAvailable() is called,
      63             :   // |mSurface| should be non-null and shouldn't be mutated further until we get
      64             :   // destroyed. That means that the assertions below are very important; we'll
      65             :   // end up with data races if these assumptions are violated.
      66          35 :   if (Availability().IsPlaceholder()) {
      67           0 :     MOZ_ASSERT_UNREACHABLE("Calling DrawableRef() on a placeholder");
      68             :     return DrawableFrameRef();
      69             :   }
      70             : 
      71          35 :   if (!mSurface) {
      72           0 :     MOZ_ASSERT_UNREACHABLE("Calling DrawableRef() when we have no surface");
      73             :     return DrawableFrameRef();
      74             :   }
      75             : 
      76          35 :   return mSurface->DrawableRef();
      77             : }
      78             : 
      79             : bool
      80          24 : DecodedSurfaceProvider::IsFinished() const
      81             : {
      82             :   // See DrawableRef() for commentary on these assertions.
      83          24 :   if (Availability().IsPlaceholder()) {
      84           0 :     MOZ_ASSERT_UNREACHABLE("Calling IsFinished() on a placeholder");
      85             :     return false;
      86             :   }
      87             : 
      88          24 :   if (!mSurface) {
      89           0 :     MOZ_ASSERT_UNREACHABLE("Calling IsFinished() when we have no surface");
      90             :     return false;
      91             :   }
      92             : 
      93          24 :   return mSurface->IsFinished();
      94             : }
      95             : 
      96             : void
      97          12 : DecodedSurfaceProvider::SetLocked(bool aLocked)
      98             : {
      99             :   // See DrawableRef() for commentary on these assertions.
     100          12 :   if (Availability().IsPlaceholder()) {
     101           0 :     MOZ_ASSERT_UNREACHABLE("Calling SetLocked() on a placeholder");
     102             :     return;
     103             :   }
     104             : 
     105          12 :   if (!mSurface) {
     106           0 :     MOZ_ASSERT_UNREACHABLE("Calling SetLocked() when we have no surface");
     107             :     return;
     108             :   }
     109             : 
     110          12 :   if (aLocked == IsLocked()) {
     111           0 :     return;  // Nothing to do.
     112             :   }
     113             : 
     114             :   // If we're locked, hold a DrawableFrameRef to |mSurface|, which will keep any
     115             :   // volatile buffer it owns in memory.
     116          24 :   mLockRef = aLocked ? mSurface->DrawableRef()
     117          12 :                      : DrawableFrameRef();
     118             : }
     119             : 
     120             : size_t
     121          60 : DecodedSurfaceProvider::LogicalSizeInBytes() const
     122             : {
     123             :   // Single frame images are always 32bpp.
     124          60 :   IntSize size = GetSurfaceKey().Size();
     125          60 :   return size.width * size.height * sizeof(uint32_t);
     126             : }
     127             : 
     128             : void
     129          12 : DecodedSurfaceProvider::Run()
     130             : {
     131          12 :   MutexAutoLock lock(mMutex);
     132             : 
     133          12 :   if (!mDecoder || !mImage) {
     134           0 :     MOZ_ASSERT_UNREACHABLE("Running after decoding finished?");
     135             :     return;
     136             :   }
     137             : 
     138             :   // Run the decoder.
     139          12 :   LexerResult result = mDecoder->Decode(WrapNotNull(this));
     140             : 
     141             :   // If there's a new surface available, announce it to the surface cache.
     142          12 :   CheckForNewSurface();
     143             : 
     144          12 :   if (result.is<TerminalState>()) {
     145          12 :     FinishDecoding();
     146          12 :     return;  // We're done.
     147             :   }
     148             : 
     149             :   // Notify for the progress we've made so far.
     150           0 :   if (mDecoder->HasProgress()) {
     151           0 :     NotifyProgress(WrapNotNull(mImage), WrapNotNull(mDecoder));
     152             :   }
     153             : 
     154           0 :   MOZ_ASSERT(result.is<Yield>());
     155             : 
     156           0 :   if (result == LexerResult(Yield::NEED_MORE_DATA)) {
     157             :     // We can't make any more progress right now. The decoder itself will ensure
     158             :     // that we get reenqueued when more data is available; just return for now.
     159           0 :     return;
     160             :   }
     161             : 
     162             :   // Single-frame images shouldn't yield for any reason except NEED_MORE_DATA.
     163           0 :   MOZ_ASSERT_UNREACHABLE("Unexpected yield for single-frame image");
     164             :   mDecoder->TerminateFailure();
     165             :   FinishDecoding();
     166             : }
     167             : 
     168             : void
     169          12 : DecodedSurfaceProvider::CheckForNewSurface()
     170             : {
     171          12 :   mMutex.AssertCurrentThreadOwns();
     172          12 :   MOZ_ASSERT(mDecoder);
     173             : 
     174          12 :   if (mSurface) {
     175             :     // Single-frame images should produce no more than one surface, so if we
     176             :     // have one, it should be the same one the decoder is working on.
     177           0 :     MOZ_ASSERT(mSurface.get() == mDecoder->GetCurrentFrameRef().get(),
     178             :                "DecodedSurfaceProvider and Decoder have different surfaces?");
     179           0 :     return;
     180             :   }
     181             : 
     182             :   // We don't have a surface yet; try to get one from the decoder.
     183          12 :   mSurface = mDecoder->GetCurrentFrameRef().get();
     184          12 :   if (!mSurface) {
     185           0 :     return;  // No surface yet.
     186             :   }
     187             : 
     188             :   // We just got a surface for the first time; let the surface cache know.
     189          12 :   MOZ_ASSERT(mImage);
     190          12 :   SurfaceCache::SurfaceAvailable(WrapNotNull(this));
     191             : }
     192             : 
     193             : void
     194          12 : DecodedSurfaceProvider::FinishDecoding()
     195             : {
     196          12 :   mMutex.AssertCurrentThreadOwns();
     197          12 :   MOZ_ASSERT(mImage);
     198          12 :   MOZ_ASSERT(mDecoder);
     199             : 
     200             :   // Send notifications.
     201          12 :   NotifyDecodeComplete(WrapNotNull(mImage), WrapNotNull(mDecoder));
     202             : 
     203             :   // Destroy our decoder; we don't need it anymore. (And if we don't destroy it,
     204             :   // our surface can never be optimized, because the decoder has a
     205             :   // RawAccessFrameRef to it.)
     206          12 :   mDecoder = nullptr;
     207             : 
     208             :   // We don't need a reference to our image anymore, either, and we don't want
     209             :   // one. We may be stored in the surface cache for a long time after decoding
     210             :   // finishes. If we don't drop our reference to the image, we'll end up
     211             :   // keeping it alive as long as we remain in the surface cache, which could
     212             :   // greatly extend the image's lifetime - in fact, if the image isn't
     213             :   // discardable, it'd result in a leak!
     214          12 :   DropImageReference();
     215          12 : }
     216             : 
     217             : bool
     218           3 : DecodedSurfaceProvider::ShouldPreferSyncRun() const
     219             : {
     220           3 :   return mDecoder->ShouldSyncDecode(gfxPrefs::ImageMemDecodeBytesAtATime());
     221             : }
     222             : 
     223             : } // namespace image
     224             : } // namespace mozilla

Generated by: LCOV version 1.13