gfx/layers/RotatedBuffer.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial