LCOV - code coverage report
Current view: top level - image - SurfacePipe.h (source / functions) Hit Total Coverage
Test: output.info Lines: 79 139 56.8 %
Date: 2017-07-14 16:53:18 Functions: 28 77 36.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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             : /**
       8             :  * A SurfacePipe is a pipeline that consists of a series of SurfaceFilters
       9             :  * terminating in a SurfaceSink. Each SurfaceFilter transforms the image data in
      10             :  * some way before the SurfaceSink ultimately writes it to the surface. This
      11             :  * design allows for each transformation to be tested independently, for the
      12             :  * transformations to be combined as needed to meet the needs of different
      13             :  * situations, and for all image decoders to share the same code for these
      14             :  * transformations.
      15             :  *
      16             :  * Writing to the SurfacePipe is done using lambdas that act as generator
      17             :  * functions. Because the SurfacePipe machinery controls where the writes take
      18             :  * place, a bug in an image decoder cannot cause a buffer overflow of the
      19             :  * underlying surface.
      20             :  */
      21             : 
      22             : #ifndef mozilla_image_SurfacePipe_h
      23             : #define mozilla_image_SurfacePipe_h
      24             : 
      25             : #include <stdint.h>
      26             : 
      27             : #include "nsDebug.h"
      28             : 
      29             : #include "mozilla/Likely.h"
      30             : #include "mozilla/Maybe.h"
      31             : #include "mozilla/Move.h"
      32             : #include "mozilla/UniquePtr.h"
      33             : #include "mozilla/Unused.h"
      34             : #include "mozilla/Variant.h"
      35             : #include "mozilla/gfx/2D.h"
      36             : 
      37             : namespace mozilla {
      38             : namespace image {
      39             : 
      40             : class Decoder;
      41             : 
      42             : /**
      43             :  * An invalid rect for a surface. Results are given both in the space of the
      44             :  * input image (i.e., before any SurfaceFilters are applied) and in the space
      45             :  * of the output surface (after all SurfaceFilters).
      46             :  */
      47        1538 : struct SurfaceInvalidRect
      48             : {
      49             :   gfx::IntRect mInputSpaceRect;   /// The invalid rect in pre-SurfacePipe space.
      50             :   gfx::IntRect mOutputSpaceRect;  /// The invalid rect in post-SurfacePipe space.
      51             : };
      52             : 
      53             : /**
      54             :  * An enum used to allow the lambdas passed to WritePixels() to communicate
      55             :  * their state to the caller.
      56             :  */
      57             : enum class WriteState : uint8_t
      58             : {
      59             :   NEED_MORE_DATA,  /// The lambda ran out of data.
      60             : 
      61             :   FINISHED,        /// The lambda is done writing to the surface; future writes
      62             :                    /// will fail.
      63             : 
      64             :   FAILURE          /// The lambda encountered an error. The caller may recover
      65             :                    /// if possible and continue to write. (This never indicates
      66             :                    /// an error in the SurfacePipe machinery itself; it's only
      67             :                    /// generated by the lambdas.)
      68             : };
      69             : 
      70             : /**
      71             :  * A template alias used to make the return value of WritePixels() lambdas
      72             :  * (which may return either a pixel value or a WriteState) easier to specify.
      73             :  */
      74             : template <typename PixelType>
      75             : using NextPixel = Variant<PixelType, WriteState>;
      76             : 
      77             : /**
      78             :  * SurfaceFilter is the abstract superclass of SurfacePipe pipeline stages.  It
      79             :  * implements the the code that actually writes to the surface - WritePixels()
      80             :  * and the other Write*() methods - which are non-virtual for efficiency.
      81             :  *
      82             :  * SurfaceFilter's API is nonpublic; only SurfacePipe and other SurfaceFilters
      83             :  * should use it. Non-SurfacePipe code should use the methods on SurfacePipe.
      84             :  *
      85             :  * To implement a SurfaceFilter, it's necessary to subclass SurfaceFilter and
      86             :  * implement, at a minimum, the pure virtual methods. It's also necessary to
      87             :  * define a Config struct with a Filter typedef member that identifies the
      88             :  * matching SurfaceFilter class, and a Configure() template method. See an
      89             :  * existing SurfaceFilter subclass, such as RemoveFrameRectFilter, for an
      90             :  * example of how the Configure() method must be implemented. It takes a list of
      91             :  * Config structs, passes the tail of the list to the next filter in the chain's
      92             :  * Configure() method, and then uses the head of the list to configure itself. A
      93             :  * SurfaceFilter's Configure() method must also call
      94             :  * SurfaceFilter::ConfigureFilter() to provide the Write*() methods with the
      95             :  * information they need to do their jobs.
      96             :  */
      97             : class SurfaceFilter
      98             : {
      99             : public:
     100          51 :   SurfaceFilter()
     101          51 :     : mRowPointer(nullptr)
     102             :     , mCol(0)
     103          51 :     , mPixelSize(0)
     104          51 :   { }
     105             : 
     106          48 :   virtual ~SurfaceFilter() { }
     107             : 
     108             :   /**
     109             :    * Reset this surface to the first row. It's legal for this filter to throw
     110             :    * away any previously written data at this point, as all rows must be written
     111             :    * to on every pass.
     112             :    *
     113             :    * @return a pointer to the buffer for the first row.
     114             :    */
     115          51 :   uint8_t* ResetToFirstRow()
     116             :   {
     117          51 :     mCol = 0;
     118          51 :     mRowPointer = DoResetToFirstRow();
     119          51 :     return mRowPointer;
     120             :   }
     121             : 
     122             :   /**
     123             :    * Called by WritePixels() to advance this filter to the next row.
     124             :    *
     125             :    * @return a pointer to the buffer for the next row, or nullptr to indicate
     126             :    *         that we've finished the entire surface.
     127             :    */
     128        1543 :   uint8_t* AdvanceRow()
     129             :   {
     130        1543 :     mCol = 0;
     131        1543 :     mRowPointer = DoAdvanceRow();
     132        1542 :     return mRowPointer;
     133             :   }
     134             : 
     135             :   /// @return a pointer to the buffer for the current row.
     136           0 :   uint8_t* CurrentRowPointer() const { return mRowPointer; }
     137             : 
     138             :   /// @return true if we've finished writing to the surface.
     139        3084 :   bool IsSurfaceFinished() const { return mRowPointer == nullptr; }
     140             : 
     141             :   /// @return the input size this filter expects.
     142        9253 :   gfx::IntSize InputSize() const { return mInputSize; }
     143             : 
     144             :   /**
     145             :    * Write pixels to the surface one at a time by repeatedly calling a lambda
     146             :    * that yields pixels. WritePixels() is completely memory safe.
     147             :    *
     148             :    * Writing continues until every pixel in the surface has been written to
     149             :    * (i.e., IsSurfaceFinished() returns true) or the lambda returns a WriteState
     150             :    * which WritePixels() will return to the caller.
     151             :    *
     152             :    * The template parameter PixelType must be uint8_t (for paletted surfaces) or
     153             :    * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
     154             :    * size passed to ConfigureFilter().
     155             :    *
     156             :    * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
     157             :    * which means we can remove the PixelType template parameter from this
     158             :    * method.
     159             :    *
     160             :    * @param aFunc A lambda that functions as a generator, yielding the next
     161             :    *              pixel in the surface each time it's called. The lambda must
     162             :    *              return a NextPixel<PixelType> value.
     163             :    *
     164             :    * @return A WriteState value indicating the lambda generator's state.
     165             :    *         WritePixels() itself will return WriteState::FINISHED if writing
     166             :    *         has finished, regardless of the lambda's internal state.
     167             :    */
     168             :   template <typename PixelType, typename Func>
     169           2 :   WriteState WritePixels(Func aFunc)
     170             :   {
     171           4 :     Maybe<WriteState> result;
     172           6 :     while (!(result = DoWritePixelsToRow<PixelType>(Forward<Func>(aFunc)))) { }
     173             : 
     174           4 :     return *result;
     175             :   }
     176             : 
     177             :   /**
     178             :    * A variant of WritePixels() that writes a single row of pixels to the
     179             :    * surface one at a time by repeatedly calling a lambda that yields pixels.
     180             :    * WritePixelsToRow() is completely memory safe.
     181             :    *
     182             :    * Writing continues until every pixel in the row has been written to. If the
     183             :    * surface is complete at that pointer, WriteState::FINISHED is returned;
     184             :    * otherwise, WritePixelsToRow() returns WriteState::NEED_MORE_DATA. The
     185             :    * lambda can terminate writing early by returning a WriteState itself, which
     186             :    * WritePixelsToRow() will return to the caller.
     187             :    *
     188             :    * The template parameter PixelType must be uint8_t (for paletted surfaces) or
     189             :    * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
     190             :    * size passed to ConfigureFilter().
     191             :    *
     192             :    * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
     193             :    * which means we can remove the PixelType template parameter from this
     194             :    * method.
     195             :    *
     196             :    * @param aFunc A lambda that functions as a generator, yielding the next
     197             :    *              pixel in the surface each time it's called. The lambda must
     198             :    *              return a NextPixel<PixelType> value.
     199             :    *
     200             :    * @return A WriteState value indicating the lambda generator's state.
     201             :    *         WritePixels() itself will return WriteState::FINISHED if writing
     202             :    *         the entire surface has finished, or WriteState::NEED_MORE_DATA if
     203             :    *         writing the row has finished, regardless of the lambda's internal
     204             :    *         state.
     205             :    */
     206             :   template <typename PixelType, typename Func>
     207        1538 :   WriteState WritePixelsToRow(Func aFunc)
     208             :   {
     209        1538 :     return DoWritePixelsToRow<PixelType>(Forward<Func>(aFunc))
     210        3076 :            .valueOr(WriteState::NEED_MORE_DATA);
     211             :   }
     212             : 
     213             :   /**
     214             :    * Write a row to the surface by copying from a buffer. This is bounds checked
     215             :    * and memory safe with respect to the surface, but care must still be taken
     216             :    * by the caller not to overread the source buffer. This variant of
     217             :    * WriteBuffer() requires a source buffer which contains |mInputSize.width|
     218             :    * pixels.
     219             :    *
     220             :    * The template parameter PixelType must be uint8_t (for paletted surfaces) or
     221             :    * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
     222             :    * size passed to ConfigureFilter().
     223             :    *
     224             :    * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
     225             :    * which means we can remove the PixelType template parameter from this
     226             :    * method.
     227             :    *
     228             :    * @param aSource A buffer to copy from. This buffer must be
     229             :    *                |mInputSize.width| pixels wide,  which means
     230             :    *                |mInputSize.width * sizeof(PixelType)| bytes. May not be
     231             :    *                null.
     232             :    *
     233             :    * @return WriteState::FINISHED if the entire surface has been written to.
     234             :    *         Otherwise, returns WriteState::NEED_MORE_DATA. If a null |aSource|
     235             :    *         value is passed, returns WriteState::FAILURE.
     236             :    */
     237             :   template <typename PixelType>
     238           0 :   WriteState WriteBuffer(const PixelType* aSource)
     239             :   {
     240           0 :     return WriteBuffer(aSource, 0, mInputSize.width);
     241             :   }
     242             : 
     243             :   /**
     244             :    * Write a row to the surface by copying from a buffer. This is bounds checked
     245             :    * and memory safe with respect to the surface, but care must still be taken
     246             :    * by the caller not to overread the source buffer. This variant of
     247             :    * WriteBuffer() reads at most @aLength pixels from the buffer and writes them
     248             :    * to the row starting at @aStartColumn. Any pixels in columns before
     249             :    * @aStartColumn or after the pixels copied from the buffer are cleared.
     250             :    *
     251             :    * Bounds checking failures produce warnings in debug builds because although
     252             :    * the bounds checking maintains safety, this kind of failure could indicate a
     253             :    * bug in the calling code.
     254             :    *
     255             :    * The template parameter PixelType must be uint8_t (for paletted surfaces) or
     256             :    * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
     257             :    * size passed to ConfigureFilter().
     258             :    *
     259             :    * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
     260             :    * which means we can remove the PixelType template parameter from this
     261             :    * method.
     262             :    *
     263             :    * @param aSource A buffer to copy from. This buffer must be @aLength pixels
     264             :    *                wide, which means |aLength * sizeof(PixelType)| bytes. May
     265             :    *                not be null.
     266             :    * @param aStartColumn The column to start writing to in the row. Columns
     267             :    *                     before this are cleared.
     268             :    * @param aLength The number of bytes, at most, which may be copied from
     269             :    *                @aSource. Fewer bytes may be copied in practice due to
     270             :    *                bounds checking.
     271             :    *
     272             :    * @return WriteState::FINISHED if the entire surface has been written to.
     273             :    *         Otherwise, returns WriteState::NEED_MORE_DATA. If a null |aSource|
     274             :    *         value is passed, returns WriteState::FAILURE.
     275             :    */
     276             :   template <typename PixelType>
     277           0 :   WriteState WriteBuffer(const PixelType* aSource,
     278             :                          const size_t aStartColumn,
     279             :                          const size_t aLength)
     280             :   {
     281           0 :     MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4);
     282           0 :     MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t));
     283           0 :     MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t));
     284             : 
     285           0 :     if (IsSurfaceFinished()) {
     286           0 :       return WriteState::FINISHED;  // Already done.
     287             :     }
     288             : 
     289           0 :     if (MOZ_UNLIKELY(!aSource)) {
     290           0 :       NS_WARNING("Passed a null pointer to WriteBuffer");
     291           0 :       return WriteState::FAILURE;
     292             :     }
     293             : 
     294           0 :     PixelType* dest = reinterpret_cast<PixelType*>(mRowPointer);
     295             : 
     296             :     // Clear the area before |aStartColumn|.
     297           0 :     const size_t prefixLength = std::min<size_t>(mInputSize.width, aStartColumn);
     298           0 :     if (MOZ_UNLIKELY(prefixLength != aStartColumn)) {
     299           0 :       NS_WARNING("Provided starting column is out-of-bounds in WriteBuffer");
     300             :     }
     301             : 
     302           0 :     memset(dest, 0, mInputSize.width * sizeof(PixelType));
     303           0 :     dest += prefixLength;
     304             : 
     305             :     // Write |aLength| pixels from |aSource| into the row, with bounds checking.
     306             :     const size_t bufferLength =
     307           0 :       std::min<size_t>(mInputSize.width - prefixLength, aLength);
     308           0 :     if (MOZ_UNLIKELY(bufferLength != aLength)) {
     309           0 :       NS_WARNING("Provided buffer length is out-of-bounds in WriteBuffer");
     310             :     }
     311             : 
     312           0 :     memcpy(dest, aSource, bufferLength * sizeof(PixelType));
     313           0 :     dest += bufferLength;
     314             : 
     315             :     // Clear the rest of the row.
     316           0 :     const size_t suffixLength = mInputSize.width - (prefixLength + bufferLength);
     317           0 :     memset(dest, 0, suffixLength * sizeof(PixelType));
     318             : 
     319           0 :     AdvanceRow();
     320             : 
     321           0 :     return IsSurfaceFinished() ? WriteState::FINISHED
     322           0 :                                : WriteState::NEED_MORE_DATA;
     323             :   }
     324             : 
     325             :   /**
     326             :    * Write an empty row to the surface. If some pixels have already been written
     327             :    * to this row, they'll be discarded.
     328             :    *
     329             :    * @return WriteState::FINISHED if the entire surface has been written to.
     330             :    *         Otherwise, returns WriteState::NEED_MORE_DATA.
     331             :    */
     332           0 :   WriteState WriteEmptyRow()
     333             :   {
     334           0 :     if (IsSurfaceFinished()) {
     335           0 :       return WriteState::FINISHED;  // Already done.
     336             :     }
     337             : 
     338           0 :     memset(mRowPointer, 0, mInputSize.width * mPixelSize);
     339           0 :     AdvanceRow();
     340             : 
     341           0 :     return IsSurfaceFinished() ? WriteState::FINISHED
     342           0 :                                : WriteState::NEED_MORE_DATA;
     343             :   }
     344             : 
     345             :   /**
     346             :    * Write a row to the surface by calling a lambda that uses a pointer to
     347             :    * directly write to the row. This is unsafe because SurfaceFilter can't
     348             :    * provide any bounds checking; that's up to the lambda itself. For this
     349             :    * reason, the other Write*() methods should be preferred whenever it's
     350             :    * possible to use them; WriteUnsafeComputedRow() should be used only when
     351             :    * it's absolutely necessary to avoid extra copies or other performance
     352             :    * penalties.
     353             :    *
     354             :    * This method should never be exposed to SurfacePipe consumers; it's strictly
     355             :    * for use in SurfaceFilters. If external code needs this method, it should
     356             :    * probably be turned into a SurfaceFilter.
     357             :    *
     358             :    * The template parameter PixelType must be uint8_t (for paletted surfaces) or
     359             :    * uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
     360             :    * size passed to ConfigureFilter().
     361             :    *
     362             :    * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
     363             :    * which means we can remove the PixelType template parameter from this
     364             :    * method.
     365             :    *
     366             :    * @param aFunc A lambda that writes directly to the row.
     367             :    *
     368             :    * @return WriteState::FINISHED if the entire surface has been written to.
     369             :    *         Otherwise, returns WriteState::NEED_MORE_DATA.
     370             :    */
     371             :   template <typename PixelType, typename Func>
     372           0 :   WriteState WriteUnsafeComputedRow(Func aFunc)
     373             :   {
     374           0 :     MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4);
     375           0 :     MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t));
     376           0 :     MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t));
     377             : 
     378           0 :     if (IsSurfaceFinished()) {
     379           0 :       return WriteState::FINISHED;  // Already done.
     380             :     }
     381             : 
     382             :     // Call the provided lambda with a pointer to the buffer for the current
     383             :     // row. This is unsafe because we can't do any bounds checking; the lambda
     384             :     // itself has to be responsible for that.
     385           0 :     PixelType* rowPtr = reinterpret_cast<PixelType*>(mRowPointer);
     386           0 :     aFunc(rowPtr, mInputSize.width);
     387           0 :     AdvanceRow();
     388             : 
     389           0 :     return IsSurfaceFinished() ? WriteState::FINISHED
     390           0 :                                : WriteState::NEED_MORE_DATA;
     391             :   }
     392             : 
     393             :   //////////////////////////////////////////////////////////////////////////////
     394             :   // Methods Subclasses Should Override
     395             :   //////////////////////////////////////////////////////////////////////////////
     396             : 
     397             :   /// @return true if this SurfaceFilter can be used with paletted surfaces.
     398           0 :   virtual bool IsValidPalettedPipe() const { return false; }
     399             : 
     400             :   /**
     401             :    * @return a SurfaceInvalidRect representing the region of the surface that
     402             :    *         has been written to since the last time TakeInvalidRect() was
     403             :    *         called, or Nothing() if the region is empty (i.e. nothing has been
     404             :    *         written).
     405             :    */
     406             :   virtual Maybe<SurfaceInvalidRect> TakeInvalidRect() = 0;
     407             : 
     408             : protected:
     409             : 
     410             :   /**
     411             :    * Called by ResetToFirstRow() to actually perform the reset. It's legal to
     412             :    * throw away any previously written data at this point, as all rows must be
     413             :    * written to on every pass.
     414             :    */
     415             :   virtual uint8_t* DoResetToFirstRow() = 0;
     416             : 
     417             :   /**
     418             :    * Called by AdvanceRow() to actually advance this filter to the next row.
     419             :    *
     420             :    * @return a pointer to the buffer for the next row, or nullptr to indicate
     421             :    *         that we've finished the entire surface.
     422             :    */
     423             :   virtual uint8_t* DoAdvanceRow() = 0;
     424             : 
     425             : 
     426             :   //////////////////////////////////////////////////////////////////////////////
     427             :   // Methods For Internal Use By Subclasses
     428             :   //////////////////////////////////////////////////////////////////////////////
     429             : 
     430             :   /**
     431             :    * Called by subclasses' Configure() methods to initialize the configuration
     432             :    * of this filter. After the filter is configured, calls ResetToFirstRow().
     433             :    *
     434             :    * @param aInputSize The input size of this filter, in pixels. The previous
     435             :    *                   filter in the chain will expect to write into rows
     436             :    *                   |aInputSize.width| pixels wide.
     437             :    * @param aPixelSize How large, in bytes, each pixel in the surface is. This
     438             :    *                   should be either 1 for paletted images or 4 for BGRA/BGRX
     439             :    *                   images.
     440             :    */
     441          51 :   void ConfigureFilter(gfx::IntSize aInputSize, uint8_t aPixelSize)
     442             :   {
     443          51 :     mInputSize = aInputSize;
     444          51 :     mPixelSize = aPixelSize;
     445             : 
     446          51 :     ResetToFirstRow();
     447          51 :   }
     448             : 
     449             : private:
     450             : 
     451             :   /**
     452             :    * An internal method used to implement both WritePixels() and
     453             :    * WritePixelsToRow(). Those methods differ only in their behavior after a row
     454             :    * is successfully written - WritePixels() continues to write another row,
     455             :    * while WritePixelsToRow() returns to the caller. This method writes a single
     456             :    * row and returns Some() if we either finished the entire surface or the
     457             :    * lambda returned a WriteState indicating that we should return to the
     458             :    * caller. If the row was successfully written without either of those things
     459             :    * happening, it returns Nothing(), allowing WritePixels() and
     460             :    * WritePixelsToRow() to implement their respective behaviors.
     461             :    */
     462             :   template <typename PixelType, typename Func>
     463        1544 :   Maybe<WriteState> DoWritePixelsToRow(Func aFunc)
     464             :   {
     465        1544 :     MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4);
     466        1544 :     MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t));
     467        1544 :     MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t));
     468             : 
     469        1544 :     if (IsSurfaceFinished()) {
     470           0 :       return Some(WriteState::FINISHED);  // We're already done.
     471             :     }
     472             : 
     473        1540 :     PixelType* rowPtr = reinterpret_cast<PixelType*>(mRowPointer);
     474             : 
     475      115996 :     for (; mCol < mInputSize.width; ++mCol) {
     476       57233 :       NextPixel<PixelType> result = aFunc();
     477       57240 :       if (result.template is<PixelType>()) {
     478       57228 :         rowPtr[mCol] = result.template as<PixelType>();
     479       57151 :         continue;
     480             :       }
     481             : 
     482           1 :       switch (result.template as<WriteState>()) {
     483             :         case WriteState::NEED_MORE_DATA:
     484           1 :           return Some(WriteState::NEED_MORE_DATA);
     485             : 
     486             :         case WriteState::FINISHED:
     487           0 :           ZeroOutRestOfSurface<PixelType>();
     488           0 :           return Some(WriteState::FINISHED);
     489             : 
     490             :         case WriteState::FAILURE:
     491             :           // Note that we don't need to record this anywhere, because this
     492             :           // indicates an error in aFunc, and there's nothing wrong with our
     493             :           // machinery. The caller can recover as needed and continue writing to
     494             :           // the row.
     495           0 :           return Some(WriteState::FAILURE);
     496             :       }
     497             :     }
     498             : 
     499        1543 :     AdvanceRow();  // We've finished the row.
     500             : 
     501        1542 :     return IsSurfaceFinished() ? Some(WriteState::FINISHED)
     502        1542 :                                : Nothing();
     503             :   }
     504             : 
     505             :   template <typename PixelType>
     506           0 :   void ZeroOutRestOfSurface()
     507             :   {
     508           0 :     WritePixels<PixelType>([]{ return AsVariant(PixelType(0)); });
     509           0 :   }
     510             : 
     511             :   gfx::IntSize mInputSize;  /// The size of the input this filter expects.
     512             :   uint8_t* mRowPointer;     /// Pointer to the current row or null if finished.
     513             :   int32_t mCol;             /// The current column we're writing to. (0-indexed)
     514             :   uint8_t  mPixelSize;      /// How large each pixel in the surface is, in bytes.
     515             : };
     516             : 
     517             : class NullSurfaceSink;
     518             : 
     519             : /// A trivial configuration struct for NullSurfaceSink.
     520             : struct NullSurfaceConfig
     521             : {
     522             :   using Filter = NullSurfaceSink;
     523             : };
     524             : 
     525             : /**
     526             :  * NullSurfaceSink is a trivial SurfaceFilter implementation that behaves as if
     527             :  * it were a zero-size SurfaceSink. It's used as the default filter chain for an
     528             :  * uninitialized SurfacePipe.
     529             :  *
     530             :  * To avoid unnecessary allocations when creating SurfacePipe objects,
     531             :  * NullSurfaceSink is a singleton. (This implies that the implementation must be
     532             :  * stateless.)
     533             :  */
     534           3 : class NullSurfaceSink final : public SurfaceFilter
     535             : {
     536             : public:
     537             :   /// Returns the singleton instance of NullSurfaceSink.
     538             :   static NullSurfaceSink* Singleton();
     539             : 
     540           0 :   virtual ~NullSurfaceSink() { }
     541             : 
     542             :   nsresult Configure(const NullSurfaceConfig& aConfig);
     543             : 
     544           0 :   Maybe<SurfaceInvalidRect> TakeInvalidRect() override { return Nothing(); }
     545             : 
     546             : protected:
     547           3 :   uint8_t* DoResetToFirstRow() override { return nullptr; }
     548           0 :   uint8_t* DoAdvanceRow() override { return nullptr; }
     549             : 
     550             : private:
     551             :   static UniquePtr<NullSurfaceSink> sSingleton;  /// The singleton instance.
     552             : };
     553             : 
     554             : 
     555             : /**
     556             :  * SurfacePipe is the public API that decoders should use to interact with a
     557             :  * SurfaceFilter pipeline.
     558             :  */
     559             : class SurfacePipe
     560             : {
     561             : public:
     562             :   /// Initialize global state used by all SurfacePipes.
     563           3 :   static void Initialize() { NullSurfaceSink::Singleton(); }
     564             : 
     565          33 :   SurfacePipe()
     566          33 :     : mHead(NullSurfaceSink::Singleton())
     567          33 :   { }
     568             : 
     569         145 :   SurfacePipe(SurfacePipe&& aOther)
     570         145 :     : mHead(Move(aOther.mHead))
     571         145 :   { }
     572             : 
     573         226 :   ~SurfacePipe()
     574         226 :   {
     575             :     // Ensure that we don't free the NullSurfaceSink singleton.
     576         226 :     if (mHead.get() == NullSurfaceSink::Singleton()) {
     577          19 :       Unused << mHead.release();
     578             :     }
     579         226 :   }
     580             : 
     581          48 :   SurfacePipe& operator=(SurfacePipe&& aOther)
     582             :   {
     583          48 :     MOZ_ASSERT(this != &aOther);
     584             : 
     585             :     // Ensure that we don't free the NullSurfaceSink singleton.
     586          48 :     if (mHead.get() == NullSurfaceSink::Singleton()) {
     587          14 :       Unused << mHead.release();
     588             :     }
     589             : 
     590          48 :     mHead = Move(aOther.mHead);
     591          48 :     return *this;
     592             :   }
     593             : 
     594             :   /// Begins a new pass, seeking to the first row of the surface.
     595           0 :   void ResetToFirstRow() { mHead->ResetToFirstRow(); }
     596             : 
     597             :   /**
     598             :    * Write pixels to the surface one at a time by repeatedly calling a lambda
     599             :    * that yields pixels. WritePixels() is completely memory safe.
     600             :    *
     601             :    * @see SurfaceFilter::WritePixels() for the canonical documentation.
     602             :    */
     603             :   template <typename PixelType, typename Func>
     604           2 :   WriteState WritePixels(Func aFunc)
     605             :   {
     606           2 :     return mHead->WritePixels<PixelType>(Forward<Func>(aFunc));
     607             :   }
     608             : 
     609             :   /**
     610             :    * A variant of WritePixels() that writes a single row of pixels to the
     611             :    * surface one at a time by repeatedly calling a lambda that yields pixels.
     612             :    * WritePixelsToRow() is completely memory safe.
     613             :    *
     614             :    * @see SurfaceFilter::WritePixelsToRow() for the canonical documentation.
     615             :    */
     616             :   template <typename PixelType, typename Func>
     617        1539 :   WriteState WritePixelsToRow(Func aFunc)
     618             :   {
     619        1539 :     return mHead->WritePixelsToRow<PixelType>(Forward<Func>(aFunc));
     620             :   }
     621             : 
     622             :   /**
     623             :    * Write a row to the surface by copying from a buffer. This is bounds checked
     624             :    * and memory safe with respect to the surface, but care must still be taken
     625             :    * by the caller not to overread the source buffer. This variant of
     626             :    * WriteBuffer() requires a source buffer which contains |mInputSize.width|
     627             :    * pixels.
     628             :    *
     629             :    * @see SurfaceFilter::WriteBuffer() for the canonical documentation.
     630             :    */
     631             :   template <typename PixelType>
     632             :   WriteState WriteBuffer(const PixelType* aSource)
     633             :   {
     634             :     return mHead->WriteBuffer<PixelType>(aSource);
     635             :   }
     636             : 
     637             :   /**
     638             :    * Write a row to the surface by copying from a buffer. This is bounds checked
     639             :    * and memory safe with respect to the surface, but care must still be taken
     640             :    * by the caller not to overread the source buffer. This variant of
     641             :    * WriteBuffer() reads at most @aLength pixels from the buffer and writes them
     642             :    * to the row starting at @aStartColumn. Any pixels in columns before
     643             :    * @aStartColumn or after the pixels copied from the buffer are cleared.
     644             :    *
     645             :    * @see SurfaceFilter::WriteBuffer() for the canonical documentation.
     646             :    */
     647             :   template <typename PixelType>
     648             :   WriteState WriteBuffer(const PixelType* aSource,
     649             :                          const size_t aStartColumn,
     650             :                          const size_t aLength)
     651             :   {
     652             :     return mHead->WriteBuffer<PixelType>(aSource, aStartColumn, aLength);
     653             :   }
     654             : 
     655             :   /**
     656             :    * Write an empty row to the surface. If some pixels have already been written
     657             :    * to this row, they'll be discarded.
     658             :    *
     659             :    * @see SurfaceFilter::WriteEmptyRow() for the canonical documentation.
     660             :    */
     661             :   WriteState WriteEmptyRow()
     662             :   {
     663             :     return mHead->WriteEmptyRow();
     664             :   }
     665             : 
     666             :   /// @return true if we've finished writing to the surface.
     667             :   bool IsSurfaceFinished() const { return mHead->IsSurfaceFinished(); }
     668             : 
     669             :   /// @see SurfaceFilter::TakeInvalidRect() for the canonical documentation.
     670        1538 :   Maybe<SurfaceInvalidRect> TakeInvalidRect() const
     671             :   {
     672        1538 :     return mHead->TakeInvalidRect();
     673             :   }
     674             : 
     675             : private:
     676             :   friend class SurfacePipeFactory;
     677             :   friend class TestSurfacePipeFactory;
     678             : 
     679          48 :   explicit SurfacePipe(UniquePtr<SurfaceFilter>&& aHead)
     680          48 :     : mHead(Move(aHead))
     681          48 :   { }
     682             : 
     683             :   SurfacePipe(const SurfacePipe&) = delete;
     684             :   SurfacePipe& operator=(const SurfacePipe&) = delete;
     685             : 
     686             :   UniquePtr<SurfaceFilter> mHead;  /// The first filter in the chain.
     687             : };
     688             : 
     689             : /**
     690             :  * AbstractSurfaceSink contains shared implementation for both SurfaceSink and
     691             :  * PalettedSurfaceSink.
     692             :  */
     693          48 : class AbstractSurfaceSink : public SurfaceFilter
     694             : {
     695             : public:
     696          48 :   AbstractSurfaceSink()
     697          48 :     : mImageData(nullptr)
     698             :     , mImageDataLength(0)
     699             :     , mRow(0)
     700          48 :     , mFlipVertically(false)
     701          48 :   { }
     702             : 
     703             :   Maybe<SurfaceInvalidRect> TakeInvalidRect() override final;
     704             : 
     705             : protected:
     706             :   uint8_t* DoResetToFirstRow() override final;
     707             :   uint8_t* DoAdvanceRow() override final;
     708             :   virtual uint8_t* GetRowPointer() const = 0;
     709             : 
     710             :   gfx::IntRect mInvalidRect;  /// The region of the surface that has been written
     711             :                               /// to since the last call to TakeInvalidRect().
     712             :   uint8_t*  mImageData;       /// A pointer to the beginning of the surface data.
     713             :   uint32_t  mImageDataLength; /// The length of the surface data.
     714             :   uint32_t  mRow;             /// The row to which we're writing. (0-indexed)
     715             :   bool      mFlipVertically;  /// If true, write the rows from top to bottom.
     716             : };
     717             : 
     718             : class SurfaceSink;
     719             : 
     720             : /// A configuration struct for SurfaceSink.
     721             : struct SurfaceConfig
     722             : {
     723             :   using Filter = SurfaceSink;
     724             :   Decoder* mDecoder;           /// Which Decoder to use to allocate the surface.
     725             :   uint32_t mFrameNum;          /// Which frame of animation this surface is for.
     726             :   gfx::IntSize mOutputSize;    /// The size of the surface.
     727             :   gfx::SurfaceFormat mFormat;  /// The surface format (BGRA or BGRX).
     728             :   bool mFlipVertically;        /// If true, write the rows from bottom to top.
     729             : };
     730             : 
     731             : /**
     732             :  * A sink for normal (i.e., non-paletted) surfaces. It handles the allocation of
     733             :  * the surface and protects against buffer overflow. This sink should be used
     734             :  * for all non-animated images and for the first frame of animated images.
     735             :  *
     736             :  * Sinks must always be at the end of the SurfaceFilter chain.
     737             :  */
     738         192 : class SurfaceSink final : public AbstractSurfaceSink
     739             : {
     740             : public:
     741             :   nsresult Configure(const SurfaceConfig& aConfig);
     742             : 
     743             : protected:
     744             :   uint8_t* GetRowPointer() const override;
     745             : };
     746             : 
     747             : class PalettedSurfaceSink;
     748             : 
     749             : struct PalettedSurfaceConfig
     750             : {
     751             :   using Filter = PalettedSurfaceSink;
     752             :   Decoder* mDecoder;           /// Which Decoder to use to allocate the surface.
     753             :   uint32_t mFrameNum;          /// Which frame of animation this surface is for.
     754             :   gfx::IntSize mOutputSize;    /// The logical size of the surface.
     755             :   gfx::IntRect mFrameRect;     /// The surface subrect which contains data.
     756             :   gfx::SurfaceFormat mFormat;  /// The surface format (BGRA or BGRX).
     757             :   uint8_t mPaletteDepth;       /// The palette depth of this surface.
     758             :   bool mFlipVertically;        /// If true, write the rows from bottom to top.
     759             : };
     760             : 
     761             : /**
     762             :  * A sink for paletted surfaces. It handles the allocation of the surface and
     763             :  * protects against buffer overflow. This sink can be used for frames of
     764             :  * animated images except the first.
     765             :  *
     766             :  * Sinks must always be at the end of the SurfaceFilter chain.
     767             :  *
     768             :  * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
     769             :  * which means we can remove PalettedSurfaceSink entirely.
     770             :  */
     771           0 : class PalettedSurfaceSink final : public AbstractSurfaceSink
     772             : {
     773             : public:
     774           0 :   bool IsValidPalettedPipe() const override { return true; }
     775             : 
     776             :   nsresult Configure(const PalettedSurfaceConfig& aConfig);
     777             : 
     778             : protected:
     779             :   uint8_t* GetRowPointer() const override;
     780             : 
     781             : private:
     782             :   /**
     783             :    * The surface subrect which contains data. Note that the surface size we
     784             :    * actually allocate is the size of the frame rect, not the logical size of
     785             :    * the surface.
     786             :    */
     787             :   gfx::IntRect mFrameRect;
     788             : };
     789             : 
     790             : } // namespace image
     791             : } // namespace mozilla
     792             : 
     793             : #endif // mozilla_image_SurfacePipe_h

Generated by: LCOV version 1.13