tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SurfacePipe.h (33095B)


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