LCOV - code coverage report
Current view: top level - image - imgFrame.h (source / functions) Hit Total Coverage
Test: output.info Lines: 68 84 81.0 %
Date: 2017-07-14 16:53:18 Functions: 28 32 87.5 %
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             : #ifndef mozilla_image_imgFrame_h
       8             : #define mozilla_image_imgFrame_h
       9             : 
      10             : #include "mozilla/Maybe.h"
      11             : #include "mozilla/MemoryReporting.h"
      12             : #include "mozilla/Monitor.h"
      13             : #include "mozilla/Move.h"
      14             : #include "FrameTimeout.h"
      15             : #include "gfxDrawable.h"
      16             : #include "imgIContainer.h"
      17             : #include "MainThreadUtils.h"
      18             : #include "nsAutoPtr.h"
      19             : 
      20             : namespace mozilla {
      21             : namespace image {
      22             : 
      23             : class ImageRegion;
      24             : class DrawableFrameRef;
      25             : class RawAccessFrameRef;
      26             : 
      27             : enum class BlendMethod : int8_t {
      28             :   // All color components of the frame, including alpha, overwrite the current
      29             :   // contents of the frame's output buffer region.
      30             :   SOURCE,
      31             : 
      32             :   // The frame should be composited onto the output buffer based on its alpha,
      33             :   // using a simple OVER operation.
      34             :   OVER
      35             : };
      36             : 
      37             : enum class DisposalMethod : int8_t {
      38             :   CLEAR_ALL = -1,  // Clear the whole image, revealing what's underneath.
      39             :   NOT_SPECIFIED,   // Leave the frame and let the new frame draw on top.
      40             :   KEEP,            // Leave the frame and let the new frame draw on top.
      41             :   CLEAR,           // Clear the frame's area, revealing what's underneath.
      42             :   RESTORE_PREVIOUS // Restore the previous (composited) frame.
      43             : };
      44             : 
      45             : enum class Opacity : uint8_t {
      46             :   FULLY_OPAQUE,
      47             :   SOME_TRANSPARENCY
      48             : };
      49             : 
      50             : /**
      51             :  * AnimationData contains all of the information necessary for using an imgFrame
      52             :  * as part of an animation.
      53             :  *
      54             :  * It includes pointers to the raw image data of the underlying imgFrame, but
      55             :  * does not own that data. A RawAccessFrameRef for the underlying imgFrame must
      56             :  * outlive the AnimationData for it to remain valid.
      57             :  */
      58         144 : struct AnimationData
      59             : {
      60         144 :   AnimationData(uint8_t* aRawData, uint32_t aPaletteDataLength,
      61             :                 FrameTimeout aTimeout, const nsIntRect& aRect,
      62             :                 BlendMethod aBlendMethod, const Maybe<gfx::IntRect>& aBlendRect,
      63             :                 DisposalMethod aDisposalMethod, bool aHasAlpha)
      64         144 :     : mRawData(aRawData)
      65             :     , mPaletteDataLength(aPaletteDataLength)
      66             :     , mTimeout(aTimeout)
      67             :     , mRect(aRect)
      68             :     , mBlendMethod(aBlendMethod)
      69             :     , mBlendRect(aBlendRect)
      70             :     , mDisposalMethod(aDisposalMethod)
      71         144 :     , mHasAlpha(aHasAlpha)
      72         144 :   { }
      73             : 
      74             :   uint8_t* mRawData;
      75             :   uint32_t mPaletteDataLength;
      76             :   FrameTimeout mTimeout;
      77             :   nsIntRect mRect;
      78             :   BlendMethod mBlendMethod;
      79             :   Maybe<gfx::IntRect> mBlendRect;
      80             :   DisposalMethod mDisposalMethod;
      81             :   bool mHasAlpha;
      82             : };
      83             : 
      84             : class imgFrame
      85             : {
      86             :   typedef gfx::Color Color;
      87             :   typedef gfx::DataSourceSurface DataSourceSurface;
      88             :   typedef gfx::DrawTarget DrawTarget;
      89             :   typedef gfx::SamplingFilter SamplingFilter;
      90             :   typedef gfx::IntPoint IntPoint;
      91             :   typedef gfx::IntRect IntRect;
      92             :   typedef gfx::IntSize IntSize;
      93             :   typedef gfx::SourceSurface SourceSurface;
      94             :   typedef gfx::SurfaceFormat SurfaceFormat;
      95             : 
      96             : public:
      97             :   MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame)
      98        1146 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame)
      99             : 
     100             :   imgFrame();
     101             : 
     102             :   /**
     103             :    * Initialize this imgFrame with an empty surface and prepare it for being
     104             :    * written to by a decoder.
     105             :    *
     106             :    * This is appropriate for use with decoded images, but it should not be used
     107             :    * when drawing content into an imgFrame, as it may use a different graphics
     108             :    * backend than normal content drawing.
     109             :    */
     110             :   nsresult InitForDecoder(const nsIntSize& aImageSize,
     111             :                           const nsIntRect& aRect,
     112             :                           SurfaceFormat aFormat,
     113             :                           uint8_t aPaletteDepth = 0,
     114             :                           bool aNonPremult = false,
     115             :                           bool aIsAnimated = false);
     116             : 
     117           2 :   nsresult InitForAnimator(const nsIntSize& aSize,
     118             :                            SurfaceFormat aFormat)
     119             :   {
     120           4 :     return InitForDecoder(aSize, nsIntRect(0, 0, aSize.width, aSize.height),
     121           4 :                           aFormat, 0, false, true);
     122             :   }
     123             : 
     124             : 
     125             :   /**
     126             :    * Initialize this imgFrame with a new surface and draw the provided
     127             :    * gfxDrawable into it.
     128             :    *
     129             :    * This is appropriate to use when drawing content into an imgFrame, as it
     130             :    * uses the same graphics backend as normal content drawing. The downside is
     131             :    * that the underlying surface may not be stored in a volatile buffer on all
     132             :    * platforms, and raw access to the surface (using RawAccessRef()) may be much
     133             :    * more expensive than in the InitForDecoder() case.
     134             :    *
     135             :    * aBackend specifies the DrawTarget backend type this imgFrame is supposed
     136             :    *          to be drawn to.
     137             :    */
     138             :   nsresult InitWithDrawable(gfxDrawable* aDrawable,
     139             :                             const nsIntSize& aSize,
     140             :                             const SurfaceFormat aFormat,
     141             :                             SamplingFilter aSamplingFilter,
     142             :                             uint32_t aImageFlags,
     143             :                             gfx::BackendType aBackend);
     144             : 
     145             :   DrawableFrameRef DrawableRef();
     146             :   RawAccessFrameRef RawAccessRef();
     147             : 
     148             :   /**
     149             :    * Make this imgFrame permanently available for raw access.
     150             :    *
     151             :    * This is irrevocable, and should be avoided whenever possible, since it
     152             :    * prevents this imgFrame from being optimized and makes it impossible for its
     153             :    * volatile buffer to be freed.
     154             :    *
     155             :    * It is an error to call this without already holding a RawAccessFrameRef to
     156             :    * this imgFrame.
     157             :    */
     158             :   void SetRawAccessOnly();
     159             : 
     160             :   bool Draw(gfxContext* aContext, const ImageRegion& aRegion,
     161             :             SamplingFilter aSamplingFilter, uint32_t aImageFlags,
     162             :             float aOpacity);
     163             : 
     164             :   nsresult ImageUpdated(const nsIntRect& aUpdateRect);
     165             : 
     166             :   /**
     167             :    * Mark this imgFrame as completely decoded, and set final options.
     168             :    *
     169             :    * You must always call either Finish() or Abort() before releasing the last
     170             :    * RawAccessFrameRef pointing to an imgFrame.
     171             :    *
     172             :    * @param aFrameOpacity    Whether this imgFrame is opaque.
     173             :    * @param aDisposalMethod  For animation frames, how this imgFrame is cleared
     174             :    *                         from the compositing frame before the next frame is
     175             :    *                         displayed.
     176             :    * @param aTimeout         For animation frames, the timeout before the next
     177             :    *                         frame is displayed.
     178             :    * @param aBlendMethod     For animation frames, a blending method to be used
     179             :    *                         when compositing this frame.
     180             :    * @param aBlendRect       For animation frames, if present, the subrect in
     181             :    *                         which @aBlendMethod applies. Outside of this
     182             :    *                         subrect, BlendMethod::OVER is always used.
     183             :    * @param aFinalize        Finalize the underlying surface (e.g. so that it
     184             :    *                         may be marked as read only if possible).
     185             :    */
     186             :   void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
     187             :               DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
     188             :               FrameTimeout aTimeout = FrameTimeout::FromRawMilliseconds(0),
     189             :               BlendMethod aBlendMethod = BlendMethod::OVER,
     190             :               const Maybe<IntRect>& aBlendRect = Nothing(),
     191             :               bool aFinalize = true);
     192             : 
     193             :   /**
     194             :    * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't
     195             :    * completely decoded now, it never will be.
     196             :    *
     197             :    * You must always call either Finish() or Abort() before releasing the last
     198             :    * RawAccessFrameRef pointing to an imgFrame.
     199             :    */
     200             :   void Abort();
     201             : 
     202             :   /**
     203             :    * Returns true if this imgFrame has been aborted.
     204             :    */
     205             :   bool IsAborted() const;
     206             : 
     207             :   /**
     208             :    * Returns true if this imgFrame is completely decoded.
     209             :    */
     210             :   bool IsFinished() const;
     211             : 
     212             :   /**
     213             :    * Blocks until this imgFrame is either completely decoded, or is marked as
     214             :    * aborted.
     215             :    *
     216             :    * Note that calling this on the main thread _blocks the main thread_. Be very
     217             :    * careful in your use of this method to avoid excessive main thread jank or
     218             :    * deadlock.
     219             :    */
     220             :   void WaitUntilFinished() const;
     221             : 
     222             :   /**
     223             :    * Returns the number of bytes per pixel this imgFrame requires.  This is a
     224             :    * worst-case value that does not take into account the effects of format
     225             :    * changes caused by Optimize(), since an imgFrame is not optimized throughout
     226             :    * its lifetime.
     227             :    */
     228          36 :   uint32_t GetBytesPerPixel() const { return GetIsPaletted() ? 1 : 4; }
     229             : 
     230          35 :   IntSize GetImageSize() const { return mImageSize; }
     231         266 :   IntRect GetRect() const { return mFrameRect; }
     232         109 :   IntSize GetSize() const { return mFrameRect.Size(); }
     233             :   void GetImageData(uint8_t** aData, uint32_t* length) const;
     234             :   uint8_t* GetImageData() const;
     235             : 
     236             :   bool GetIsPaletted() const;
     237             :   void GetPaletteData(uint32_t** aPalette, uint32_t* length) const;
     238             :   uint32_t* GetPaletteData() const;
     239             :   uint8_t GetPaletteDepth() const { return mPaletteDepth; }
     240             : 
     241             :   AnimationData GetAnimationData() const;
     242             : 
     243             :   bool GetCompositingFailed() const;
     244             :   void SetCompositingFailed(bool val);
     245             : 
     246             :   void SetOptimizable();
     247             : 
     248             :   void FinalizeSurface();
     249             :   already_AddRefed<SourceSurface> GetSourceSurface();
     250             : 
     251             :   void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut,
     252             :                               size_t& aNonHeapSizeOut,
     253             :                               size_t& aSharedHandlesOut) const;
     254             : 
     255             : private: // methods
     256             : 
     257             :   ~imgFrame();
     258             : 
     259             :   nsresult LockImageData();
     260             :   nsresult UnlockImageData();
     261             :   nsresult Optimize(gfx::DrawTarget* aTarget);
     262             : 
     263             :   void AssertImageDataLocked() const;
     264             : 
     265             :   bool AreAllPixelsWritten() const;
     266             :   nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
     267             :   void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
     268             :   uint32_t GetImageBytesPerRow() const;
     269             :   uint32_t GetImageDataLength() const;
     270             :   void FinalizeSurfaceInternal();
     271             :   already_AddRefed<SourceSurface> GetSourceSurfaceInternal();
     272             : 
     273         144 :   uint32_t PaletteDataLength() const
     274             :   {
     275         144 :     return mPaletteDepth ? (size_t(1) << mPaletteDepth) * sizeof(uint32_t)
     276         144 :                          : 0;
     277             :   }
     278             : 
     279          35 :   struct SurfaceWithFormat {
     280             :     RefPtr<gfxDrawable> mDrawable;
     281             :     SurfaceFormat mFormat;
     282           0 :     SurfaceWithFormat() { }
     283          35 :     SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat)
     284          35 :       : mDrawable(aDrawable), mFormat(aFormat)
     285          35 :     { }
     286          35 :     bool IsValid() { return !!mDrawable; }
     287             :   };
     288             : 
     289             :   SurfaceWithFormat SurfaceForDrawing(bool               aDoPartialDecode,
     290             :                                       bool               aDoTile,
     291             :                                       ImageRegion&       aRegion,
     292             :                                       SourceSurface*     aSurface);
     293             : 
     294             : private: // data
     295             :   friend class DrawableFrameRef;
     296             :   friend class RawAccessFrameRef;
     297             :   friend class UnlockImageDataRunnable;
     298             : 
     299             :   //////////////////////////////////////////////////////////////////////////////
     300             :   // Thread-safe mutable data, protected by mMonitor.
     301             :   //////////////////////////////////////////////////////////////////////////////
     302             : 
     303             :   mutable Monitor mMonitor;
     304             : 
     305             :   /**
     306             :    * Surface which contains either a weak or a strong reference to its
     307             :    * underlying data buffer. If it is a weak reference, and there are no strong
     308             :    * references, the buffer may be released due to events such as low memory.
     309             :    */
     310             :   RefPtr<DataSourceSurface> mRawSurface;
     311             : 
     312             :   /**
     313             :    * Refers to the same data as mRawSurface, but when set, it guarantees that
     314             :    * we hold a strong reference to the underlying data buffer.
     315             :    */
     316             :   RefPtr<DataSourceSurface> mLockedSurface;
     317             : 
     318             :   /**
     319             :    * Optimized copy of mRawSurface for the DrawTarget that will render it. This
     320             :    * is unused if the DrawTarget is able to render DataSourceSurface buffers
     321             :    * directly.
     322             :    */
     323             :   RefPtr<SourceSurface> mOptSurface;
     324             : 
     325             :   nsIntRect mDecoded;
     326             : 
     327             :   //! Number of RawAccessFrameRefs currently alive for this imgFrame.
     328             :   int32_t mLockCount;
     329             : 
     330             :   //! The timeout for this frame.
     331             :   FrameTimeout mTimeout;
     332             : 
     333             :   DisposalMethod mDisposalMethod;
     334             :   BlendMethod    mBlendMethod;
     335             :   Maybe<IntRect> mBlendRect;
     336             :   SurfaceFormat  mFormat;
     337             : 
     338             :   bool mAborted;
     339             :   bool mFinished;
     340             :   bool mOptimizable;
     341             : 
     342             : 
     343             :   //////////////////////////////////////////////////////////////////////////////
     344             :   // Effectively const data, only mutated in the Init methods.
     345             :   //////////////////////////////////////////////////////////////////////////////
     346             : 
     347             :   IntSize      mImageSize;
     348             :   IntRect      mFrameRect;
     349             : 
     350             :   // The palette and image data for images that are paletted, since Cairo
     351             :   // doesn't support these images.
     352             :   // The paletted data comes first, then the image data itself.
     353             :   // Total length is PaletteDataLength() + GetImageDataLength().
     354             :   uint8_t*     mPalettedImageData;
     355             :   uint8_t      mPaletteDepth;
     356             : 
     357             :   bool mNonPremult;
     358             : 
     359             : 
     360             :   //////////////////////////////////////////////////////////////////////////////
     361             :   // Main-thread-only mutable data.
     362             :   //////////////////////////////////////////////////////////////////////////////
     363             : 
     364             :   bool mCompositingFailed;
     365             : };
     366             : 
     367             : /**
     368             :  * A reference to an imgFrame that holds the imgFrame's surface in memory,
     369             :  * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns
     370             :  * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed.
     371             :  */
     372         692 : class DrawableFrameRef final
     373             : {
     374             :   typedef gfx::DataSourceSurface DataSourceSurface;
     375             : 
     376             : public:
     377         168 :   DrawableFrameRef() { }
     378             : 
     379         284 :   explicit DrawableFrameRef(imgFrame* aFrame)
     380         284 :     : mFrame(aFrame)
     381             :   {
     382         284 :     MOZ_ASSERT(aFrame);
     383         568 :     MonitorAutoLock lock(aFrame->mMonitor);
     384             : 
     385             :     // Paletted images won't have a surface so there is no strong reference
     386             :     // to hold on to. Since Draw() and GetSourceSurface() calls will not work
     387             :     // in that case, we should be using RawAccessFrameRef exclusively instead.
     388             :     // See FrameAnimator::GetRawFrame for an example of this behaviour.
     389         284 :     if (aFrame->mRawSurface) {
     390             :       mRef = new DataSourceSurface::ScopedMap(aFrame->mRawSurface,
     391         422 :                                               DataSourceSurface::READ_WRITE);
     392         211 :       if (!mRef->IsMapped()) {
     393           0 :         mFrame = nullptr;
     394           0 :         mRef = nullptr;
     395             :       }
     396             :     } else {
     397          73 :       MOZ_ASSERT(aFrame->mOptSurface || aFrame->GetIsPaletted());
     398             :     }
     399         284 :   }
     400             : 
     401         270 :   DrawableFrameRef(DrawableFrameRef&& aOther)
     402         540 :     : mFrame(aOther.mFrame.forget())
     403         540 :     , mRef(Move(aOther.mRef))
     404         270 :   { }
     405             : 
     406         213 :   DrawableFrameRef& operator=(DrawableFrameRef&& aOther)
     407             :   {
     408         213 :     MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
     409         213 :     mFrame = aOther.mFrame.forget();
     410         213 :     mRef = Move(aOther.mRef);
     411         213 :     return *this;
     412             :   }
     413             : 
     414        1456 :   explicit operator bool() const { return bool(mFrame); }
     415             : 
     416           0 :   imgFrame* operator->()
     417             :   {
     418           0 :     MOZ_ASSERT(mFrame);
     419           0 :     return mFrame;
     420             :   }
     421             : 
     422             :   const imgFrame* operator->() const
     423             :   {
     424             :     MOZ_ASSERT(mFrame);
     425             :     return mFrame;
     426             :   }
     427             : 
     428         496 :   imgFrame* get() { return mFrame; }
     429             :   const imgFrame* get() const { return mFrame; }
     430             : 
     431             :   void reset()
     432             :   {
     433             :     mFrame = nullptr;
     434             :     mRef = nullptr;
     435             :   }
     436             : 
     437             : private:
     438             :   DrawableFrameRef(const DrawableFrameRef& aOther) = delete;
     439             : 
     440             :   RefPtr<imgFrame> mFrame;
     441             :   nsAutoPtr<DataSourceSurface::ScopedMap> mRef;
     442             : };
     443             : 
     444             : /**
     445             :  * A reference to an imgFrame that holds the imgFrame's surface in memory in a
     446             :  * format appropriate for access as raw data. If you have a RawAccessFrameRef
     447             :  * |ref| and |if (ref)| is true, then calls to GetImageData() and
     448             :  * GetPaletteData() are guaranteed to succeed. This guarantee is stronger than
     449             :  * DrawableFrameRef, so everything that a valid DrawableFrameRef guarantees is
     450             :  * also guaranteed by a valid RawAccessFrameRef.
     451             :  *
     452             :  * This may be considerably more expensive than is necessary just for drawing,
     453             :  * so only use this when you need to read or write the raw underlying image data
     454             :  * that the imgFrame holds.
     455             :  *
     456             :  * Once all an imgFrame's RawAccessFrameRefs go out of scope, new
     457             :  * RawAccessFrameRefs cannot be created.
     458             :  */
     459             : class RawAccessFrameRef final
     460             : {
     461             : public:
     462          37 :   RawAccessFrameRef() { }
     463             : 
     464         240 :   explicit RawAccessFrameRef(imgFrame* aFrame)
     465         240 :     : mFrame(aFrame)
     466             :   {
     467         240 :     MOZ_ASSERT(mFrame, "Need a frame");
     468             : 
     469         240 :     if (NS_FAILED(mFrame->LockImageData())) {
     470           0 :       mFrame->UnlockImageData();
     471           0 :       mFrame = nullptr;
     472             :     }
     473         240 :   }
     474             : 
     475          84 :   RawAccessFrameRef(RawAccessFrameRef&& aOther)
     476          84 :     : mFrame(aOther.mFrame.forget())
     477          84 :   { }
     478             : 
     479         321 :   ~RawAccessFrameRef()
     480         321 :   {
     481         321 :     if (mFrame) {
     482         168 :       mFrame->UnlockImageData();
     483             :     }
     484         321 :   }
     485             : 
     486          50 :   RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther)
     487             :   {
     488          50 :     MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
     489             : 
     490          50 :     if (mFrame) {
     491          34 :       mFrame->UnlockImageData();
     492             :     }
     493             : 
     494          50 :     mFrame = aOther.mFrame.forget();
     495             : 
     496          50 :     return *this;
     497             :   }
     498             : 
     499        2162 :   explicit operator bool() const { return bool(mFrame); }
     500             : 
     501        1020 :   imgFrame* operator->()
     502             :   {
     503        1020 :     MOZ_ASSERT(mFrame);
     504        1020 :     return mFrame.get();
     505             :   }
     506             : 
     507           0 :   const imgFrame* operator->() const
     508             :   {
     509           0 :     MOZ_ASSERT(mFrame);
     510           0 :     return mFrame;
     511             :   }
     512             : 
     513         128 :   imgFrame* get() { return mFrame; }
     514             :   const imgFrame* get() const { return mFrame; }
     515             : 
     516           0 :   void reset()
     517             :   {
     518           0 :     if (mFrame) {
     519           0 :       mFrame->UnlockImageData();
     520             :     }
     521           0 :     mFrame = nullptr;
     522           0 :   }
     523             : 
     524             : private:
     525             :   RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete;
     526             : 
     527             :   RefPtr<imgFrame> mFrame;
     528             : };
     529             : 
     530             : void MarkSurfaceShared(gfx::SourceSurface* aSurface);
     531             : 
     532             : } // namespace image
     533             : } // namespace mozilla
     534             : 
     535             : #endif // mozilla_image_imgFrame_h

Generated by: LCOV version 1.13