LCOV - code coverage report
Current view: top level - gfx/layers - RotatedBuffer.h (source / functions) Hit Total Coverage
Test: output.info Lines: 55 58 94.8 %
Date: 2017-07-14 16:53:18 Functions: 19 23 82.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; 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             : #ifndef ROTATEDBUFFER_H_
       7             : #define ROTATEDBUFFER_H_
       8             : 
       9             : #include "gfxTypes.h"
      10             : #include <stdint.h>                     // for uint32_t
      11             : #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
      12             : #include "mozilla/RefPtr.h"             // for RefPtr, already_AddRefed
      13             : #include "mozilla/gfx/2D.h"             // for DrawTarget, etc
      14             : #include "mozilla/gfx/MatrixFwd.h"      // for Matrix
      15             : #include "mozilla/mozalloc.h"           // for operator delete
      16             : #include "nsCOMPtr.h"                   // for already_AddRefed
      17             : #include "nsDebug.h"                    // for NS_RUNTIMEABORT
      18             : #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
      19             : #include "nsRegion.h"                   // for nsIntRegion
      20             : #include "LayersTypes.h"
      21             : 
      22             : namespace mozilla {
      23             : namespace layers {
      24             : 
      25             : class TextureClient;
      26             : class PaintedLayer;
      27             : 
      28             : /**
      29             :  * This is a cairo/Thebes surface, but with a literal twist. Scrolling
      30             :  * causes the layer's visible region to move. We want to keep
      31             :  * reusing the same surface if the region size hasn't changed, but we don't
      32             :  * want to keep moving the contents of the surface around in memory. So
      33             :  * we use a trick.
      34             :  * Consider just the vertical case, and suppose the buffer is H pixels
      35             :  * high and we're scrolling down by N pixels. Instead of copying the
      36             :  * buffer contents up by N pixels, we leave the buffer contents in place,
      37             :  * and paint content rows H to H+N-1 into rows 0 to N-1 of the buffer.
      38             :  * Then we can refresh the screen by painting rows N to H-1 of the buffer
      39             :  * at row 0 on the screen, and then painting rows 0 to N-1 of the buffer
      40             :  * at row H-N on the screen.
      41             :  * mBufferRotation.y would be N in this example.
      42             :  */
      43             : class RotatedBuffer {
      44             : public:
      45             :   typedef gfxContentType ContentType;
      46             : 
      47          13 :   RotatedBuffer(const gfx::IntRect& aBufferRect,
      48             :                 const gfx::IntPoint& aBufferRotation)
      49          13 :     : mBufferRect(aBufferRect)
      50             :     , mBufferRotation(aBufferRotation)
      51          13 :     , mDidSelfCopy(false)
      52          13 :   { }
      53          79 :   RotatedBuffer()
      54          79 :     : mDidSelfCopy(false)
      55          79 :   { }
      56             : 
      57             :   /*
      58             :    * Which buffer should be drawn to/read from.
      59             :    */
      60             :   enum ContextSource {
      61             :     BUFFER_BLACK, // The normal buffer, or buffer with black background when using component alpha.
      62             :     BUFFER_WHITE, // The buffer with white background, only valid with component alpha.
      63             :     BUFFER_BOTH // The combined black/white buffers, only valid for writing operations, not reading.
      64             :   };
      65             :   // It is the callers repsonsibility to ensure aTarget is flushed after calling
      66             :   // this method.
      67             :   void DrawBufferWithRotation(gfx::DrawTarget* aTarget, ContextSource aSource,
      68             :                               float aOpacity = 1.0,
      69             :                               gfx::CompositionOp aOperator = gfx::CompositionOp::OP_OVER,
      70             :                               gfx::SourceSurface* aMask = nullptr,
      71             :                               const gfx::Matrix* aMaskTransform = nullptr) const;
      72             : 
      73             :   /**
      74             :    * |BufferRect()| is the rect of device pixels that this
      75             :    * RotatedBuffer covers.  That is what DrawBufferWithRotation()
      76             :    * will paint when it's called.
      77             :    */
      78          66 :   const gfx::IntRect& BufferRect() const { return mBufferRect; }
      79          33 :   const gfx::IntPoint& BufferRotation() const { return mBufferRotation; }
      80             : 
      81             :   virtual bool HaveBuffer() const = 0;
      82             :   virtual bool HaveBufferOnWhite() const = 0;
      83             : 
      84             :   virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const = 0;
      85             : 
      86             : protected:
      87             : 
      88             :   enum XSide {
      89             :     LEFT, RIGHT
      90             :   };
      91             :   enum YSide {
      92             :     TOP, BOTTOM
      93             :   };
      94             :   gfx::IntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
      95             : 
      96             :   gfx::Rect GetSourceRectangle(XSide aXSide, YSide aYSide) const;
      97             : 
      98             :   /*
      99             :    * If aMask is non-null, then it is used as an alpha mask for rendering this
     100             :    * buffer. aMaskTransform must be non-null if aMask is non-null, and is used
     101             :    * to adjust the coordinate space of the mask.
     102             :    */
     103             :   void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
     104             :                           ContextSource aSource,
     105             :                           float aOpacity,
     106             :                           gfx::CompositionOp aOperator,
     107             :                           gfx::SourceSurface* aMask,
     108             :                           const gfx::Matrix* aMaskTransform) const;
     109             : 
     110             :   /** The area of the PaintedLayer that is covered by the buffer as a whole */
     111             :   gfx::IntRect             mBufferRect;
     112             :   /**
     113             :    * The x and y rotation of the buffer. Conceptually the buffer
     114             :    * has its origin translated to mBufferRect.TopLeft() - mBufferRotation,
     115             :    * is tiled to fill the plane, and the result is clipped to mBufferRect.
     116             :    * So the pixel at mBufferRotation within the buffer is what gets painted at
     117             :    * mBufferRect.TopLeft().
     118             :    * This is "rotation" in the sense of rotating items in a linear buffer,
     119             :    * where items falling off the end of the buffer are returned to the
     120             :    * buffer at the other end, not 2D rotation!
     121             :    */
     122             :   gfx::IntPoint            mBufferRotation;
     123             :   // When this is true it means that all pixels have moved inside the buffer.
     124             :   // It's not possible to sync with another buffer without a full copy.
     125             :   bool                  mDidSelfCopy;
     126             : };
     127             : 
     128          13 : class SourceRotatedBuffer : public RotatedBuffer
     129             : {
     130             : public:
     131          13 :   SourceRotatedBuffer(gfx::SourceSurface* aSource, gfx::SourceSurface* aSourceOnWhite,
     132             :                       const gfx::IntRect& aBufferRect,
     133             :                       const gfx::IntPoint& aBufferRotation)
     134          13 :     : RotatedBuffer(aBufferRect, aBufferRotation)
     135             :     , mSource(aSource)
     136          13 :     , mSourceOnWhite(aSourceOnWhite)
     137          13 :   { }
     138             : 
     139             :   virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
     140             : 
     141           0 :   virtual bool HaveBuffer() const { return !!mSource; }
     142          13 :   virtual bool HaveBufferOnWhite() const { return !!mSourceOnWhite; }
     143             : 
     144             : private:
     145             :   RefPtr<gfx::SourceSurface> mSource;
     146             :   RefPtr<gfx::SourceSurface> mSourceOnWhite;
     147             : };
     148             : 
     149             : // Mixin class for classes which need logic for loaning out a draw target.
     150             : // See comments on BorrowDrawTargetForQuadrantUpdate.
     151         152 : class BorrowDrawTarget
     152             : {
     153             : protected:
     154             :   void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
     155             : 
     156             :   // The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
     157             :   // be used, we just keep a reference to ensure it is kept alive and so we can
     158             :   // correctly restore state when it is returned.
     159             :   RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
     160             :   gfx::Matrix mLoanedTransform;
     161             : };
     162             : 
     163             : /**
     164             :  * This class encapsulates the buffer used to retain PaintedLayer contents,
     165             :  * i.e., the contents of the layer's GetVisibleRegion().
     166             :  */
     167             : class RotatedContentBuffer : public RotatedBuffer
     168             :                            , public BorrowDrawTarget
     169             : {
     170             : public:
     171             :   typedef gfxContentType ContentType;
     172             : 
     173             :   /**
     174             :    * Controls the size of the backing buffer of this.
     175             :    * - SizedToVisibleBounds: the backing buffer is exactly the same
     176             :    *   size as the bounds of PaintedLayer's visible region
     177             :    * - ContainsVisibleBounds: the backing buffer is large enough to
     178             :    *   fit visible bounds.  May be larger.
     179             :    */
     180             :   enum BufferSizePolicy {
     181             :     SizedToVisibleBounds,
     182             :     ContainsVisibleBounds
     183             :   };
     184             : 
     185          79 :   explicit RotatedContentBuffer(BufferSizePolicy aBufferSizePolicy)
     186          79 :     : mBufferProvider(nullptr)
     187             :     , mBufferProviderOnWhite(nullptr)
     188          79 :     , mBufferSizePolicy(aBufferSizePolicy)
     189             :   {
     190          79 :     MOZ_COUNT_CTOR(RotatedContentBuffer);
     191          79 :   }
     192          73 :   virtual ~RotatedContentBuffer()
     193         146 :   {
     194          73 :     MOZ_COUNT_DTOR(RotatedContentBuffer);
     195          73 :   }
     196             : 
     197             :   /**
     198             :    * Wipe out all retained contents. Call this when the entire
     199             :    * buffer becomes invalid.
     200             :    */
     201          99 :   void Clear()
     202             :   {
     203          99 :     UnlockBuffers();
     204          99 :     mDTBuffer = nullptr;
     205          99 :     mDTBufferOnWhite = nullptr;
     206          99 :     mBufferProvider = nullptr;
     207          99 :     mBufferProviderOnWhite = nullptr;
     208          99 :     mBufferRect.SetEmpty();
     209          99 :   }
     210             : 
     211             :   /**
     212             :    * This is returned by BeginPaint. The caller should draw into mTarget.
     213             :    * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
     214             :    * by RotatedContentBuffer and must be redrawn on the screen.
     215             :    * mRegionToInvalidate is set when the buffer has changed from
     216             :    * opaque to transparent or vice versa, since the details of rendering can
     217             :    * depend on the buffer type.  mDidSelfCopy is true if we kept our buffer
     218             :    * but used MovePixels() to shift its content.
     219             :    */
     220          77 :   struct PaintState {
     221          77 :     PaintState()
     222          77 :       : mRegionToDraw()
     223             :       , mRegionToInvalidate()
     224             :       , mMode(SurfaceMode::SURFACE_NONE)
     225             :       , mClip(DrawRegionClip::NONE)
     226             :       , mContentType(gfxContentType::SENTINEL)
     227          77 :       , mDidSelfCopy(false)
     228          77 :     {}
     229             : 
     230             :     nsIntRegion mRegionToDraw;
     231             :     nsIntRegion mRegionToInvalidate;
     232             :     SurfaceMode mMode;
     233             :     DrawRegionClip mClip;
     234             :     ContentType mContentType;
     235             :     bool mDidSelfCopy;
     236             :   };
     237             : 
     238             :   enum {
     239             :     PAINT_WILL_RESAMPLE = 0x01,
     240             :     PAINT_NO_ROTATION = 0x02,
     241             :     PAINT_CAN_DRAW_ROTATED = 0x04
     242             :   };
     243             :   /**
     244             :    * Start a drawing operation. This returns a PaintState describing what
     245             :    * needs to be drawn to bring the buffer up to date in the visible region.
     246             :    * This queries aLayer to get the currently valid and visible regions.
     247             :    * The returned mTarget may be null if mRegionToDraw is empty.
     248             :    * Otherwise it must not be null.
     249             :    * mRegionToInvalidate will contain mRegionToDraw.
     250             :    * @param aFlags when PAINT_WILL_RESAMPLE is passed, this indicates that
     251             :    * buffer will be resampled when rendering (i.e the effective transform
     252             :    * combined with the scale for the resolution is not just an integer
     253             :    * translation). This will disable buffer rotation (since we don't want
     254             :    * to resample across the rotation boundary) and will ensure that we
     255             :    * make the entire buffer contents valid (since we don't want to sample
     256             :    * invalid pixels outside the visible region, if the visible region doesn't
     257             :    * fill the buffer bounds).
     258             :    * PAINT_CAN_DRAW_ROTATED can be passed if the caller supports drawing
     259             :    * rotated content that crosses the physical buffer boundary. The caller
     260             :    * will need to call BorrowDrawTargetForPainting multiple times to achieve
     261             :    * this.
     262             :    */
     263             :   PaintState BeginPaint(PaintedLayer* aLayer,
     264             :                         uint32_t aFlags);
     265             : 
     266          90 :   struct DrawIterator {
     267             :     friend class RotatedContentBuffer;
     268          90 :     DrawIterator()
     269          90 :       : mCount(0)
     270          90 :     {}
     271             : 
     272             :     nsIntRegion mDrawRegion;
     273             : 
     274             :   private:
     275             :     uint32_t mCount;
     276             :   };
     277             : 
     278             :   /**
     279             :    * Fetch a DrawTarget for rendering. The DrawTarget remains owned by
     280             :    * this. See notes on BorrowDrawTargetForQuadrantUpdate.
     281             :    * May return null. If the return value is non-null, it must be
     282             :    * 'un-borrowed' using ReturnDrawTarget.
     283             :    *
     284             :    * If PAINT_CAN_DRAW_ROTATED was specified for BeginPaint, then the caller
     285             :    * must call this function repeatedly (with an iterator) until it returns
     286             :    * nullptr. The caller should draw the mDrawRegion of the iterator instead
     287             :    * of mRegionToDraw in the PaintState.
     288             :    *
     289             :    * @param aPaintState Paint state data returned by a call to BeginPaint
     290             :    * @param aIter Paint state iterator. Only required if PAINT_CAN_DRAW_ROTATED
     291             :    * was specified to BeginPaint.
     292             :    */
     293             :   gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
     294             :                                                DrawIterator* aIter = nullptr);
     295             : 
     296             :   enum {
     297             :     BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
     298             :                                   // component alpha.
     299             :   };
     300             :   /**
     301             :    * Return a new surface of |aSize| and |aType|.
     302             :    *
     303             :    * If the created buffer supports azure content, then the result(s) will
     304             :    * be returned in aBlackDT/aWhiteDT, otherwise aBlackSurface/aWhiteSurface
     305             :    * will be used.
     306             :    */
     307             :   virtual void
     308             :   CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
     309             :                RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) = 0;
     310             : 
     311             :   /**
     312             :    * Get the underlying buffer, if any. This is useful because we can pass
     313             :    * in the buffer as the default "reference surface" if there is one.
     314             :    * Don't use it for anything else!
     315             :    */
     316             :   gfx::DrawTarget* GetDTBuffer() { return mDTBuffer; }
     317             :   gfx::DrawTarget* GetDTBufferOnWhite() { return mDTBufferOnWhite; }
     318             : 
     319             :   virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
     320             : 
     321             :   /**
     322             :    * Complete the drawing operation. The region to draw must have been
     323             :    * drawn before this is called. The contents of the buffer are drawn
     324             :    * to aTarget.
     325             :    */
     326             :   void DrawTo(PaintedLayer* aLayer,
     327             :               gfx::DrawTarget* aTarget,
     328             :               float aOpacity,
     329             :               gfx::CompositionOp aOp,
     330             :               gfx::SourceSurface* aMask,
     331             :               const gfx::Matrix* aMaskTransform);
     332             : 
     333             : protected:
     334             :   // new texture client versions
     335         129 :   void SetBufferProvider(TextureClient* aClient)
     336             :   {
     337             :     // Only this buffer provider can give us a buffer.  If we
     338             :     // already have one, something has gone wrong.
     339         129 :     MOZ_ASSERT(!aClient || !mDTBuffer || !mDTBuffer->IsValid());
     340             : 
     341         129 :     mBufferProvider = aClient;
     342         129 :     if (!mBufferProvider) {
     343          77 :       mDTBuffer = nullptr;
     344             :     }
     345         129 :   }
     346             : 
     347          77 :   void SetBufferProviderOnWhite(TextureClient* aClient)
     348             :   {
     349             :     // Only this buffer provider can give us a buffer.  If we
     350             :     // already have one, something has gone wrong.
     351          77 :     MOZ_ASSERT(!aClient || !mDTBufferOnWhite || !mDTBufferOnWhite->IsValid());
     352             : 
     353          77 :     mBufferProviderOnWhite = aClient;
     354          77 :     if (!mBufferProviderOnWhite) {
     355          77 :       mDTBufferOnWhite = nullptr;
     356             :     }
     357          77 :   }
     358             : 
     359             :   /**
     360             :    * Get a draw target at the specified resolution for updating |aBounds|,
     361             :    * which must be contained within a single quadrant.
     362             :    *
     363             :    * The result should only be held temporarily by the caller (it will be kept
     364             :    * alive by this). Once used it should be returned using ReturnDrawTarget.
     365             :    * BorrowDrawTargetForQuadrantUpdate may not be called more than once without
     366             :    * first calling ReturnDrawTarget.
     367             :    *
     368             :    * ReturnDrawTarget will restore the transform on the draw target. But it is
     369             :    * the callers responsibility to restore the clip. The caller should flush the
     370             :    * draw target, if necessary.
     371             :    */
     372             :   gfx::DrawTarget*
     373             :   BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
     374             :                                     ContextSource aSource,
     375             :                                     DrawIterator* aIter);
     376             : 
     377             :   static bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);
     378             : 
     379             : protected:
     380             :   /**
     381             :    * Return the buffer's content type.  Requires a valid buffer or
     382             :    * buffer provider.
     383             :    */
     384             :   gfxContentType BufferContentType();
     385             :   bool BufferSizeOkFor(const gfx::IntSize& aSize);
     386             :   /**
     387             :    * If the buffer hasn't been mapped, map it.
     388             :    */
     389             :   bool EnsureBuffer();
     390             :   bool EnsureBufferOnWhite();
     391             : 
     392             :   // Flush our buffers if they are mapped.
     393             :   void FlushBuffers();
     394             : 
     395             :   /**
     396             :    * True if we have a buffer where we can get it (but not necessarily
     397             :    * mapped currently).
     398             :    */
     399             :   virtual bool HaveBuffer() const;
     400             :   virtual bool HaveBufferOnWhite() const;
     401             : 
     402             :   /**
     403             :    * Any actions that should be performed at the last moment before we begin
     404             :    * rendering the next frame. I.e., after we calculate what we will draw,
     405             :    * but before we rotate the buffer and possibly create new buffers.
     406             :    * aRegionToDraw is the region which is guaranteed to be overwritten when
     407             :    * drawing the next frame.
     408             :    */
     409           0 :   virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) {}
     410             : 
     411           0 :   virtual bool LockBuffers() { return true; }
     412          99 :   virtual void UnlockBuffers() {}
     413             : 
     414             :   RefPtr<gfx::DrawTarget> mDTBuffer;
     415             :   RefPtr<gfx::DrawTarget> mDTBufferOnWhite;
     416             : 
     417             :   /**
     418             :    * These members are only set transiently.  They're used to map mDTBuffer
     419             :    * when we're using surfaces that require explicit map/unmap. Only one
     420             :    * may be used at a time.
     421             :    */
     422             :   TextureClient* mBufferProvider;
     423             :   TextureClient* mBufferProviderOnWhite;
     424             : 
     425             :   BufferSizePolicy      mBufferSizePolicy;
     426             : };
     427             : 
     428             : } // namespace layers
     429             : } // namespace mozilla
     430             : 
     431             : #endif /* ROTATEDBUFFER_H_ */

Generated by: LCOV version 1.13