Bug 1462355 - Part 1b. Update Decoder and SurfacePipe plumbing to use updated imgFrame methods. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Tue, 29 May 2018 08:36:12 -0400
changeset 474491 87a0a6e103d8151d0e40929580545e3fbcc6b490
parent 474490 259ee94de92ca9c586cfa02cb92db331aace64d1
child 474492 eb8ec97c5f5fa8555c8c9370b029807a707fc15f
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1462355
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1462355 - Part 1b. Update Decoder and SurfacePipe plumbing to use updated imgFrame methods. r=tnikkel
image/Decoder.cpp
image/Decoder.h
image/DownscalingFilter.h
image/SurfaceFilters.h
image/SurfacePipe.cpp
image/SurfacePipe.h
image/SurfacePipeFactory.h
image/test/gtest/Common.h
image/test/gtest/TestADAM7InterpolatingFilter.cpp
image/test/gtest/TestDeinterlacingFilter.cpp
image/test/gtest/TestDownscalingFilter.cpp
image/test/gtest/TestDownscalingFilterNoSkia.cpp
image/test/gtest/TestRemoveFrameRectFilter.cpp
image/test/gtest/TestSurfacePipeIntegration.cpp
image/test/gtest/TestSurfaceSink.cpp
--- a/image/Decoder.cpp
+++ b/image/Decoder.cpp
@@ -278,102 +278,103 @@ Decoder::Telemetry() const
   MOZ_ASSERT(mIterator);
   return DecoderTelemetry(SpeedHistogram(),
                           mIterator->ByteCount(),
                           mIterator->ChunkCount(),
                           mDecodeTime);
 }
 
 nsresult
-Decoder::AllocateFrame(uint32_t aFrameNum,
-                       const gfx::IntSize& aOutputSize,
+Decoder::AllocateFrame(const gfx::IntSize& aOutputSize,
                        const gfx::IntRect& aFrameRect,
                        gfx::SurfaceFormat aFormat,
-                       uint8_t aPaletteDepth)
+                       uint8_t aPaletteDepth,
+                       const Maybe<AnimationParams>& aAnimParams)
 {
-  mCurrentFrame = AllocateFrameInternal(aFrameNum, aOutputSize, aFrameRect,
-                                        aFormat, aPaletteDepth,
+  mCurrentFrame = AllocateFrameInternal(aOutputSize, aFrameRect, aFormat,
+                                        aPaletteDepth, aAnimParams,
                                         mCurrentFrame.get());
 
   if (mCurrentFrame) {
     mHasFrameToTake = true;
 
     // Gather the raw pointers the decoders will use.
     mCurrentFrame->GetImageData(&mImageData, &mImageDataLength);
     mCurrentFrame->GetPaletteData(&mColormap, &mColormapSize);
 
     // We should now be on |aFrameNum|. (Note that we're comparing the frame
     // number, which is zero-based, with the frame count, which is one-based.)
-    MOZ_ASSERT(aFrameNum + 1 == mFrameCount);
+    MOZ_ASSERT_IF(aAnimParams, aAnimParams->mFrameNum + 1 == mFrameCount);
 
     // If we're past the first frame, PostIsAnimated() should've been called.
     MOZ_ASSERT_IF(mFrameCount > 1, HasAnimation());
 
     // Update our state to reflect the new frame.
     MOZ_ASSERT(!mInFrame, "Starting new frame but not done with old one!");
     mInFrame = true;
   }
 
   return mCurrentFrame ? NS_OK : NS_ERROR_FAILURE;
 }
 
 RawAccessFrameRef
-Decoder::AllocateFrameInternal(uint32_t aFrameNum,
-                               const gfx::IntSize& aOutputSize,
+Decoder::AllocateFrameInternal(const gfx::IntSize& aOutputSize,
                                const gfx::IntRect& aFrameRect,
                                SurfaceFormat aFormat,
                                uint8_t aPaletteDepth,
+                               const Maybe<AnimationParams>& aAnimParams,
                                imgFrame* aPreviousFrame)
 {
   if (HasError()) {
     return RawAccessFrameRef();
   }
 
-  if (aFrameNum != mFrameCount) {
+  uint32_t frameNum = aAnimParams ? aAnimParams->mFrameNum : 0;
+  if (frameNum != mFrameCount) {
     MOZ_ASSERT_UNREACHABLE("Allocating frames out of order");
     return RawAccessFrameRef();
   }
 
   if (aOutputSize.width <= 0 || aOutputSize.height <= 0 ||
       aFrameRect.Width() <= 0 || aFrameRect.Height() <= 0) {
     NS_WARNING("Trying to add frame with zero or negative size");
     return RawAccessFrameRef();
   }
 
   auto frame = MakeNotNull<RefPtr<imgFrame>>();
   bool nonPremult = bool(mSurfaceFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
   if (NS_FAILED(frame->InitForDecoder(aOutputSize, aFrameRect, aFormat,
                                       aPaletteDepth, nonPremult,
-                                      aFrameNum > 0))) {
+                                      aAnimParams))) {
     NS_WARNING("imgFrame::Init should succeed");
     return RawAccessFrameRef();
   }
 
   RawAccessFrameRef ref = frame->RawAccessRef();
   if (!ref) {
     frame->Abort();
     return RawAccessFrameRef();
   }
 
-  if (aFrameNum == 1) {
+  if (frameNum == 1) {
     MOZ_ASSERT(aPreviousFrame, "Must provide a previous frame when animated");
     aPreviousFrame->SetRawAccessOnly();
 
     // If we dispose of the first frame by clearing it, then the first frame's
     // refresh area is all of itself.
     // RESTORE_PREVIOUS is invalid (assumed to be DISPOSE_CLEAR).
-    AnimationData previousFrameData = aPreviousFrame->GetAnimationData();
-    if (previousFrameData.mDisposalMethod == DisposalMethod::CLEAR ||
-        previousFrameData.mDisposalMethod == DisposalMethod::CLEAR_ALL ||
-        previousFrameData.mDisposalMethod == DisposalMethod::RESTORE_PREVIOUS) {
-      mFirstFrameRefreshArea = previousFrameData.mRect;
+    DisposalMethod prevDisposal = aPreviousFrame->GetDisposalMethod();
+    if (prevDisposal == DisposalMethod::CLEAR ||
+        prevDisposal == DisposalMethod::CLEAR_ALL ||
+        prevDisposal == DisposalMethod::RESTORE_PREVIOUS) {
+      mFirstFrameRefreshArea = aPreviousFrame->GetRect();
     }
   }
 
-  if (aFrameNum > 0) {
+  if (frameNum > 0) {
     ref->SetRawAccessOnly();
 
     // Some GIFs are huge but only have a small area that they animate. We only
     // need to refresh that small area when frame 0 comes around again.
     mFirstFrameRefreshArea.UnionRect(mFirstFrameRefreshArea, frame->GetRect());
   }
 
   mFrameCount++;
@@ -448,39 +449,32 @@ void
 Decoder::PostIsAnimated(FrameTimeout aFirstFrameTimeout)
 {
   mProgress |= FLAG_IS_ANIMATED;
   mImageMetadata.SetHasAnimation();
   mImageMetadata.SetFirstFrameTimeout(aFirstFrameTimeout);
 }
 
 void
-Decoder::PostFrameStop(Opacity aFrameOpacity
-                         /* = Opacity::SOME_TRANSPARENCY */,
-                       DisposalMethod aDisposalMethod
-                         /* = DisposalMethod::KEEP */,
-                       FrameTimeout aTimeout /* = FrameTimeout::Forever() */,
-                       BlendMethod aBlendMethod /* = BlendMethod::OVER */,
-                       const Maybe<nsIntRect>& aBlendRect /* = Nothing() */)
+Decoder::PostFrameStop(Opacity aFrameOpacity)
 {
   // We should be mid-frame
   MOZ_ASSERT(!IsMetadataDecode(), "Stopping frame during metadata decode");
   MOZ_ASSERT(mInFrame, "Stopping frame when we didn't start one");
   MOZ_ASSERT(mCurrentFrame, "Stopping frame when we don't have one");
 
   // Update our state.
   mInFrame = false;
   mFinishedNewFrame = true;
 
-  mCurrentFrame->Finish(aFrameOpacity, aDisposalMethod, aTimeout,
-                        aBlendMethod, aBlendRect, mFinalizeFrames);
+  mCurrentFrame->Finish(aFrameOpacity, mFinalizeFrames);
 
   mProgress |= FLAG_FRAME_COMPLETE;
 
-  mLoopLength += aTimeout;
+  mLoopLength += mCurrentFrame->GetTimeout();
 
   // If we're not sending partial invalidations, then we send an invalidation
   // here when the first frame is complete.
   if (!ShouldSendPartialInvalidations() && mFrameCount == 1) {
     mInvalidRect.UnionRect(mInvalidRect,
                            IntRect(IntPoint(), Size()));
   }
 }
--- a/image/Decoder.h
+++ b/image/Decoder.h
@@ -6,32 +6,35 @@
 #ifndef mozilla_image_Decoder_h
 #define mozilla_image_Decoder_h
 
 #include "FrameAnimator.h"
 #include "RasterImage.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/RefPtr.h"
+#include "AnimationParams.h"
 #include "DecoderFlags.h"
 #include "Downscaler.h"
 #include "ImageMetadata.h"
 #include "Orientation.h"
 #include "SourceBuffer.h"
 #include "StreamingLexer.h"
 #include "SurfaceFlags.h"
 
 namespace mozilla {
 
 namespace Telemetry {
   enum HistogramID : uint32_t;
 } // namespace Telemetry
 
 namespace image {
 
+class imgFrame;
+
 struct DecoderFinalStatus final
 {
   DecoderFinalStatus(bool aWasMetadataDecode,
                      bool aFinished,
                      bool aHadError,
                      bool aShouldReportError)
     : mWasMetadataDecode(aWasMetadataDecode)
     , mFinished(aFinished)
@@ -472,21 +475,17 @@ protected:
   //                 we advance to the next frame.
   void PostIsAnimated(FrameTimeout aFirstFrameTimeout);
 
   // Called by decoders when they end a frame. Informs the image, sends
   // notifications, and does internal book-keeping.
   // Specify whether this frame is opaque as an optimization.
   // For animated images, specify the disposal, blend method and timeout for
   // this frame.
-  void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY,
-                     DisposalMethod aDisposalMethod = DisposalMethod::KEEP,
-                     FrameTimeout aTimeout = FrameTimeout::Forever(),
-                     BlendMethod aBlendMethod = BlendMethod::OVER,
-                     const Maybe<nsIntRect>& aBlendRect = Nothing());
+  void PostFrameStop(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY);
 
   /**
    * Called by the decoders when they have a region to invalidate. We may not
    * actually pass these invalidations on right away.
    *
    * @param aRect The invalidation rect in the coordinate system of the unscaled
    *              image (that is, the image at its intrinsic size).
    * @param aRectAtOutputSize If not Nothing(), the invalidation rect in the
@@ -505,26 +504,23 @@ protected:
   //
   // For animated images, specify the loop count. -1 means loop forever, 0
   // means a single iteration, stopping on the last frame.
   void PostDecodeDone(int32_t aLoopCount = 0);
 
   /**
    * Allocates a new frame, making it our current frame if successful.
    *
-   * The @aFrameNum parameter only exists as a sanity check; it's illegal to
-   * create a new frame anywhere but immediately after the existing frames.
-   *
    * If a non-paletted frame is desired, pass 0 for aPaletteDepth.
    */
-  nsresult AllocateFrame(uint32_t aFrameNum,
-                         const gfx::IntSize& aOutputSize,
+  nsresult AllocateFrame(const gfx::IntSize& aOutputSize,
                          const gfx::IntRect& aFrameRect,
                          gfx::SurfaceFormat aFormat,
-                         uint8_t aPaletteDepth = 0);
+                         uint8_t aPaletteDepth = 0,
+                         const Maybe<AnimationParams>& aAnimParams = Nothing());
 
 private:
   /// Report that an error was encountered while decoding.
   void PostError();
 
   /**
    * CompleteDecode() finishes up the decoding process after Decode() determines
    * that we're finished. It records final progress and does all the cleanup
@@ -538,21 +534,21 @@ private:
   {
     if (mFrameCount == 0) {
       return 0;
     }
 
     return mInFrame ? mFrameCount - 1 : mFrameCount;
   }
 
-  RawAccessFrameRef AllocateFrameInternal(uint32_t aFrameNum,
-                                          const gfx::IntSize& aOutputSize,
+  RawAccessFrameRef AllocateFrameInternal(const gfx::IntSize& aOutputSize,
                                           const gfx::IntRect& aFrameRect,
                                           gfx::SurfaceFormat aFormat,
                                           uint8_t aPaletteDepth,
+                                          const Maybe<AnimationParams>& aAnimParams,
                                           imgFrame* aPreviousFrame);
 
 protected:
   Maybe<Downscaler> mDownscaler;
 
   uint8_t* mImageData;  // Pointer to image data in either Cairo or 8bit format
   uint32_t mImageDataLength;
   uint32_t* mColormap;  // Current colormap to be used in Cairo format
--- a/image/DownscalingFilter.h
+++ b/image/DownscalingFilter.h
@@ -65,17 +65,17 @@ struct DownscalingConfig
  */
 template <typename Next>
 class DownscalingFilter final : public SurfaceFilter
 {
 public:
   Maybe<SurfaceInvalidRect> TakeInvalidRect() override { return Nothing(); }
 
   template <typename... Rest>
-  nsresult Configure(const DownscalingConfig& aConfig, Rest... aRest)
+  nsresult Configure(const DownscalingConfig& aConfig, const Rest&... aRest)
   {
     return NS_ERROR_FAILURE;
   }
 
 protected:
   uint8_t* DoResetToFirstRow() override { MOZ_CRASH(); return nullptr; }
   uint8_t* DoAdvanceRow() override { MOZ_CRASH(); return nullptr; }
 };
@@ -101,17 +101,17 @@ public:
   { }
 
   ~DownscalingFilter()
   {
     ReleaseWindow();
   }
 
   template <typename... Rest>
-  nsresult Configure(const DownscalingConfig& aConfig, Rest... aRest)
+  nsresult Configure(const DownscalingConfig& aConfig, const Rest&... aRest)
   {
     nsresult rv = mNext.Configure(aRest...);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (mNext.IsValidPalettedPipe()) {
       NS_WARNING("Created a downscaler for a paletted surface?");
--- a/image/SurfaceFilters.h
+++ b/image/SurfaceFilters.h
@@ -65,17 +65,17 @@ public:
   DeinterlacingFilter()
     : mInputRow(0)
     , mOutputRow(0)
     , mPass(0)
     , mProgressiveDisplay(true)
   { }
 
   template <typename... Rest>
-  nsresult Configure(const DeinterlacingConfig<PixelType>& aConfig, Rest... aRest)
+  nsresult Configure(const DeinterlacingConfig<PixelType>& aConfig, const Rest&... aRest)
   {
     nsresult rv = mNext.Configure(aRest...);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (sizeof(PixelType) == 1 && !mNext.IsValidPalettedPipe()) {
       NS_WARNING("Paletted DeinterlacingFilter used with non-paletted pipe?");
@@ -355,17 +355,17 @@ template <typename Next>
 class RemoveFrameRectFilter final : public SurfaceFilter
 {
 public:
   RemoveFrameRectFilter()
     : mRow(0)
   { }
 
   template <typename... Rest>
-  nsresult Configure(const RemoveFrameRectConfig& aConfig, Rest... aRest)
+  nsresult Configure(const RemoveFrameRectConfig& aConfig, const Rest&... aRest)
   {
     nsresult rv = mNext.Configure(aRest...);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (mNext.IsValidPalettedPipe()) {
       NS_WARNING("RemoveFrameRectFilter used with paletted pipe?");
@@ -585,17 +585,17 @@ class ADAM7InterpolatingFilter final : p
 public:
   ADAM7InterpolatingFilter()
     : mPass(0)  // The current pass, in the range 1..7. Starts at 0 so that
                 // DoResetToFirstRow() doesn't have to special case the first pass.
     , mRow(0)
   { }
 
   template <typename... Rest>
-  nsresult Configure(const ADAM7InterpolatingConfig& aConfig, Rest... aRest)
+  nsresult Configure(const ADAM7InterpolatingConfig& aConfig, const Rest&... aRest)
   {
     nsresult rv = mNext.Configure(aRest...);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (mNext.IsValidPalettedPipe()) {
       NS_WARNING("ADAM7InterpolatingFilter used with paletted pipe?");
--- a/image/SurfacePipe.cpp
+++ b/image/SurfacePipe.cpp
@@ -70,20 +70,21 @@ SurfaceSink::Configure(const SurfaceConf
   // Non-paletted surfaces should not have frame rects, so we just pass
   // AllocateFrame() a frame rect which covers the entire surface.
   IntRect frameRect(0, 0, surfaceSize.width, surfaceSize.height);
 
   // Allocate the frame.
   // XXX(seth): Once every Decoder subclass uses SurfacePipe, we probably want
   // to allocate the frame directly here and get rid of Decoder::AllocateFrame
   // altogether.
-  nsresult rv = aConfig.mDecoder->AllocateFrame(aConfig.mFrameNum,
-                                                surfaceSize,
+  nsresult rv = aConfig.mDecoder->AllocateFrame(surfaceSize,
                                                 frameRect,
-                                                aConfig.mFormat);
+                                                aConfig.mFormat,
+                                                /* aPaletteDepth */ 0,
+                                                aConfig.mAnimParams);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   mImageData = aConfig.mDecoder->mImageData;
   mImageDataLength = aConfig.mDecoder->mImageDataLength;
   mFlipVertically = aConfig.mFlipVertically;
 
@@ -122,21 +123,21 @@ PalettedSurfaceSink::Configure(const Pal
 
   // For paletted surfaces, the surface size is the size of the frame rect.
   IntSize surfaceSize = aConfig.mFrameRect.Size();
 
   // Allocate the frame.
   // XXX(seth): Once every Decoder subclass uses SurfacePipe, we probably want
   // to allocate the frame directly here and get rid of Decoder::AllocateFrame
   // altogether.
-  nsresult rv = aConfig.mDecoder->AllocateFrame(aConfig.mFrameNum,
-                                                aConfig.mOutputSize,
+  nsresult rv = aConfig.mDecoder->AllocateFrame(aConfig.mOutputSize,
                                                 aConfig.mFrameRect,
                                                 aConfig.mFormat,
-                                                aConfig.mPaletteDepth);
+                                                aConfig.mPaletteDepth,
+                                                aConfig.mAnimParams);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   mImageData = aConfig.mDecoder->mImageData;
   mImageDataLength = aConfig.mDecoder->mImageDataLength;
   mFlipVertically = aConfig.mFlipVertically;
   mFrameRect = aConfig.mFrameRect;
--- a/image/SurfacePipe.h
+++ b/image/SurfacePipe.h
@@ -30,16 +30,18 @@
 #include "mozilla/Maybe.h"
 #include "mozilla/Move.h"
 #include "mozilla/Tuple.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Variant.h"
 #include "mozilla/gfx/2D.h"
 
+#include "AnimationParams.h"
+
 namespace mozilla {
 namespace image {
 
 class Decoder;
 
 /**
  * An invalid rect for a surface. Results are given both in the space of the
  * input image (i.e., before any SurfaceFilters are applied) and in the space
@@ -770,20 +772,20 @@ protected:
 
 class SurfaceSink;
 
 /// A configuration struct for SurfaceSink.
 struct SurfaceConfig
 {
   using Filter = SurfaceSink;
   Decoder* mDecoder;           /// Which Decoder to use to allocate the surface.
-  uint32_t mFrameNum;          /// Which frame of animation this surface is for.
   gfx::IntSize mOutputSize;    /// The size of the surface.
   gfx::SurfaceFormat mFormat;  /// The surface format (BGRA or BGRX).
   bool mFlipVertically;        /// If true, write the rows from bottom to top.
+  Maybe<AnimationParams> mAnimParams; /// Given for animated images.
 };
 
 /**
  * A sink for normal (i.e., non-paletted) surfaces. It handles the allocation of
  * the surface and protects against buffer overflow. This sink should be used
  * for all non-animated images and for the first frame of animated images.
  *
  * Sinks must always be at the end of the SurfaceFilter chain.
@@ -798,22 +800,22 @@ protected:
 };
 
 class PalettedSurfaceSink;
 
 struct PalettedSurfaceConfig
 {
   using Filter = PalettedSurfaceSink;
   Decoder* mDecoder;           /// Which Decoder to use to allocate the surface.
-  uint32_t mFrameNum;          /// Which frame of animation this surface is for.
   gfx::IntSize mOutputSize;    /// The logical size of the surface.
   gfx::IntRect mFrameRect;     /// The surface subrect which contains data.
   gfx::SurfaceFormat mFormat;  /// The surface format (BGRA or BGRX).
   uint8_t mPaletteDepth;       /// The palette depth of this surface.
   bool mFlipVertically;        /// If true, write the rows from bottom to top.
+  Maybe<AnimationParams> mAnimParams; /// Given for animated images.
 };
 
 /**
  * A sink for paletted surfaces. It handles the allocation of the surface and
  * protects against buffer overflow. This sink can be used for frames of
  * animated images except the first.
  *
  * Sinks must always be at the end of the SurfaceFilter chain.
--- a/image/SurfacePipeFactory.h
+++ b/image/SurfacePipeFactory.h
@@ -65,40 +65,39 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Su
 class SurfacePipeFactory
 {
 public:
   /**
    * Creates and initializes a normal (i.e., non-paletted) SurfacePipe.
    *
    * @param aDecoder The decoder whose current frame the SurfacePipe will write
    *                 to.
-   * @param aFrameNum Which frame the SurfacePipe will write to. This will be 0
-   *                  for non-animated images.
    * @param aInputSize The original size of the image.
    * @param aOutputSize The size the SurfacePipe should output. Must be the same
    *                    as @aInputSize or smaller. If smaller, the image will be
    *                    downscaled during decoding.
    * @param aFrameRect The portion of the image that actually contains data.
    * @param aFormat The surface format of the image; generally B8G8R8A8 or
    *                B8G8R8X8.
+   * @param aAnimParams Extra parameters used by animated images.
    * @param aFlags Flags enabling or disabling various functionality for the
    *               SurfacePipe; see the SurfacePipeFlags documentation for more
    *               information.
    *
    * @return A SurfacePipe if the parameters allowed one to be created
    *         successfully, or Nothing() if the SurfacePipe could not be
    *         initialized.
    */
   static Maybe<SurfacePipe>
   CreateSurfacePipe(Decoder* aDecoder,
-                    uint32_t aFrameNum,
                     const nsIntSize& aInputSize,
                     const nsIntSize& aOutputSize,
                     const nsIntRect& aFrameRect,
                     gfx::SurfaceFormat aFormat,
+                    const Maybe<AnimationParams>& aAnimParams,
                     SurfacePipeFlags aFlags)
   {
     const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
     const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
     const bool progressiveDisplay = bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY);
     const bool downscale = aInputSize != aOutputSize;
     const bool removeFrameRect =
       !aFrameRect.IsEqualEdges(nsIntRect(0, 0, aInputSize.width, aInputSize.height));
@@ -120,18 +119,18 @@ public:
     // input rows, before any other transformations, and we want to remove the
     // frame rect (which may involve adding blank rows or columns to the image)
     // before any downscaling, so that the new rows and columns are taken into
     // account.
     DeinterlacingConfig<uint32_t> deinterlacingConfig { progressiveDisplay };
     ADAM7InterpolatingConfig interpolatingConfig;
     RemoveFrameRectConfig removeFrameRectConfig { aFrameRect };
     DownscalingConfig downscalingConfig { aInputSize, aFormat };
-    SurfaceConfig surfaceConfig { aDecoder, aFrameNum, aOutputSize,
-                                  aFormat, flipVertically };
+    SurfaceConfig surfaceConfig { aDecoder, aOutputSize, aFormat,
+                                  flipVertically, aAnimParams };
 
     Maybe<SurfacePipe> pipe;
 
     if (downscale) {
       if (removeFrameRect) {
         if (deinterlace) {
           pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
                           downscalingConfig, surfaceConfig);
@@ -176,65 +175,64 @@ public:
   /**
    * Creates and initializes a paletted SurfacePipe.
    *
    * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
    * which means we can remove CreatePalettedSurfacePipe() entirely.
    *
    * @param aDecoder The decoder whose current frame the SurfacePipe will write
    *                 to.
-   * @param aFrameNum Which frame the SurfacePipe will write to. This will be 0
-   *                  for non-animated images.
    * @param aInputSize The original size of the image.
    * @param aFrameRect The portion of the image that actually contains data.
    * @param aFormat The surface format of the image; generally B8G8R8A8 or
    *                B8G8R8X8.
    * @param aPaletteDepth The palette depth of the image.
+   * @param aAnimParams Extra parameters used by animated images.
    * @param aFlags Flags enabling or disabling various functionality for the
    *               SurfacePipe; see the SurfacePipeFlags documentation for more
    *               information.
    *
    * @return A SurfacePipe if the parameters allowed one to be created
    *         successfully, or Nothing() if the SurfacePipe could not be
    *         initialized.
    */
   static Maybe<SurfacePipe>
   CreatePalettedSurfacePipe(Decoder* aDecoder,
-                            uint32_t aFrameNum,
                             const nsIntSize& aInputSize,
                             const nsIntRect& aFrameRect,
                             gfx::SurfaceFormat aFormat,
                             uint8_t aPaletteDepth,
+                            const Maybe<AnimationParams>& aAnimParams,
                             SurfacePipeFlags aFlags)
   {
     const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
     const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
     const bool progressiveDisplay = bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY);
 
     // Construct configurations for the SurfaceFilters.
     DeinterlacingConfig<uint8_t> deinterlacingConfig { progressiveDisplay };
-    PalettedSurfaceConfig palettedSurfaceConfig { aDecoder, aFrameNum, aInputSize,
-                                                  aFrameRect, aFormat, aPaletteDepth,
-                                                  flipVertically };
+    PalettedSurfaceConfig palettedSurfaceConfig { aDecoder, aInputSize, aFrameRect,
+                                                  aFormat, aPaletteDepth,
+                                                  flipVertically, aAnimParams };
 
     Maybe<SurfacePipe> pipe;
 
     if (deinterlace) {
       pipe = MakePipe(deinterlacingConfig, palettedSurfaceConfig);
     } else {
       pipe = MakePipe(palettedSurfaceConfig);
     }
 
     return pipe;
   }
 
 private:
   template <typename... Configs>
   static Maybe<SurfacePipe>
-  MakePipe(Configs... aConfigs)
+  MakePipe(const Configs&... aConfigs)
   {
     auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
     nsresult rv = pipe->Configure(aConfigs...);
     if (NS_FAILED(rv)) {
       return Nothing();
     }
 
     return Some(SurfacePipe { Move(pipe) } );
--- a/image/test/gtest/Common.h
+++ b/image/test/gtest/Common.h
@@ -236,17 +236,17 @@ already_AddRefed<Decoder> CreateTrivialD
  * it to the provided lambda @aFunc. Assertions that the pipeline is constructly
  * correctly and cleanup of any allocated surfaces is handled automatically.
  *
  * @param aDecoder The decoder to use for allocating surfaces.
  * @param aFunc The lambda function to pass the filter pipeline to.
  * @param aConfigs The configuration for the pipeline.
  */
 template <typename Func, typename... Configs>
-void WithFilterPipeline(Decoder* aDecoder, Func aFunc, Configs... aConfigs)
+void WithFilterPipeline(Decoder* aDecoder, Func aFunc, const Configs&... aConfigs)
 {
   auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
   nsresult rv = pipe->Configure(aConfigs...);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 
   aFunc(aDecoder, pipe.get());
 
   RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
@@ -259,17 +259,17 @@ void WithFilterPipeline(Decoder* aDecode
  * Creates a pipeline of SurfaceFilters from a list of Config structs and
  * asserts that configuring it fails. Cleanup of any allocated surfaces is
  * handled automatically.
  *
  * @param aDecoder The decoder to use for allocating surfaces.
  * @param aConfigs The configuration for the pipeline.
  */
 template <typename... Configs>
-void AssertConfiguringPipelineFails(Decoder* aDecoder, Configs... aConfigs)
+void AssertConfiguringPipelineFails(Decoder* aDecoder, const Configs&... aConfigs)
 {
   auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
   nsresult rv = pipe->Configure(aConfigs...);
 
   // Callers expect configuring the pipeline to fail.
   ASSERT_TRUE(NS_FAILED(rv));
 
   RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
--- a/image/test/gtest/TestADAM7InterpolatingFilter.cpp
+++ b/image/test/gtest/TestADAM7InterpolatingFilter.cpp
@@ -28,29 +28,29 @@ using std::vector;
 template <typename Func> void
 WithADAM7InterpolatingFilter(const IntSize& aSize, Func aFunc)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(bool(decoder));
 
   WithFilterPipeline(decoder, Forward<Func>(aFunc),
                      ADAM7InterpolatingConfig { },
-                     SurfaceConfig { decoder, 0, aSize,
+                     SurfaceConfig { decoder, aSize,
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 void
 AssertConfiguringADAM7InterpolatingFilterFails(const IntSize& aSize)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(bool(decoder));
 
   AssertConfiguringPipelineFails(decoder,
                                  ADAM7InterpolatingConfig { },
-                                 SurfaceConfig { decoder, 0, aSize,
+                                 SurfaceConfig { decoder, aSize,
                                                  SurfaceFormat::B8G8R8A8, false });
 }
 
 uint8_t
 InterpolateByte(uint8_t aByteA, uint8_t aByteB, float aWeight)
 {
   return uint8_t(aByteA * aWeight + aByteB * (1.0f - aWeight));
 }
@@ -659,13 +659,13 @@ TEST(ImageADAM7InterpolatingFilter, Conf
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   // ADAM7InterpolatingFilter does not support paletted images, so configuration
   // should fail.
   AssertConfiguringPipelineFails(decoder,
                                  ADAM7InterpolatingConfig { },
-                                 PalettedSurfaceConfig { decoder, 0, IntSize(100, 100),
+                                 PalettedSurfaceConfig { decoder, IntSize(100, 100),
                                                          IntRect(0, 0, 50, 50),
                                                          SurfaceFormat::B8G8R8A8, 8,
                                                          false });
 }
--- a/image/test/gtest/TestDeinterlacingFilter.cpp
+++ b/image/test/gtest/TestDeinterlacingFilter.cpp
@@ -23,44 +23,44 @@ WithDeinterlacingFilter(const IntSize& a
                         bool aProgressiveDisplay,
                         Func aFunc)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(bool(decoder));
 
   WithFilterPipeline(decoder, Forward<Func>(aFunc),
                      DeinterlacingConfig<uint32_t> { aProgressiveDisplay },
-                     SurfaceConfig { decoder, 0, aSize,
+                     SurfaceConfig { decoder, aSize,
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 template <typename Func> void
 WithPalettedDeinterlacingFilter(const IntSize& aSize,
                                 Func aFunc)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   WithFilterPipeline(decoder, Forward<Func>(aFunc),
                      DeinterlacingConfig<uint8_t> { /* mProgressiveDisplay = */ true },
-                     PalettedSurfaceConfig { decoder, 0, aSize,
+                     PalettedSurfaceConfig { decoder, aSize,
                                              IntRect(0, 0, 100, 100),
                                              SurfaceFormat::B8G8R8A8, 8,
                                              false });
 }
 
 void
 AssertConfiguringDeinterlacingFilterFails(const IntSize& aSize)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   AssertConfiguringPipelineFails(decoder,
                                  DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true},
-                                 SurfaceConfig { decoder, 0, aSize,
+                                 SurfaceConfig { decoder, aSize,
                                                  SurfaceFormat::B8G8R8A8, false });
 }
 
 class ImageDeinterlacingFilter : public ::testing::Test
 {
 protected:
   AutoInitializeImageLib mInit;
 };
--- a/image/test/gtest/TestDownscalingFilter.cpp
+++ b/image/test/gtest/TestDownscalingFilter.cpp
@@ -24,31 +24,31 @@ WithDownscalingFilter(const IntSize& aIn
                       Func aFunc)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   WithFilterPipeline(decoder, Forward<Func>(aFunc),
                      DownscalingConfig { aInputSize,
                                          SurfaceFormat::B8G8R8A8 },
-                     SurfaceConfig { decoder, 0, aOutputSize,
+                     SurfaceConfig { decoder, aOutputSize,
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 void
 AssertConfiguringDownscalingFilterFails(const IntSize& aInputSize,
                                         const IntSize& aOutputSize)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   AssertConfiguringPipelineFails(decoder,
                                  DownscalingConfig { aInputSize,
                                                      SurfaceFormat::B8G8R8A8 },
-                                 SurfaceConfig { decoder, 0, aOutputSize,
+                                 SurfaceConfig { decoder, aOutputSize,
                                                  SurfaceFormat::B8G8R8A8, false });
 }
 
 TEST(ImageDownscalingFilter, WritePixels100_100to99_99)
 {
   WithDownscalingFilter(IntSize(100, 100), IntSize(99, 99),
                         [](Decoder* aDecoder, SurfaceFilter* aFilter) {
     CheckWritePixels(aDecoder, aFilter,
@@ -219,13 +219,13 @@ TEST(ImageDownscalingFilter, Configuring
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   // DownscalingFilter does not support paletted images, so configuration should
   // fail.
   AssertConfiguringPipelineFails(decoder,
                                  DownscalingConfig { IntSize(100, 100),
                                                      SurfaceFormat::B8G8R8A8 },
-                                 PalettedSurfaceConfig { decoder, 0, IntSize(20, 20),
+                                 PalettedSurfaceConfig { decoder, IntSize(20, 20),
                                                          IntRect(0, 0, 20, 20),
                                                          SurfaceFormat::B8G8R8A8, 8,
                                                          false });
 }
--- a/image/test/gtest/TestDownscalingFilterNoSkia.cpp
+++ b/image/test/gtest/TestDownscalingFilterNoSkia.cpp
@@ -47,11 +47,11 @@ TEST(ImageDownscalingFilter, NoSkia)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(bool(decoder));
 
   // Configuring a DownscalingFilter should fail without Skia.
   AssertConfiguringPipelineFails(decoder,
                                  DownscalingConfig { IntSize(100, 100),
                                                      SurfaceFormat::B8G8R8A8 },
-                                 SurfaceConfig { decoder, 0, IntSize(50, 50),
+                                 SurfaceConfig { decoder, IntSize(50, 50),
                                                  SurfaceFormat::B8G8R8A8, false });
 }
--- a/image/test/gtest/TestRemoveFrameRectFilter.cpp
+++ b/image/test/gtest/TestRemoveFrameRectFilter.cpp
@@ -23,30 +23,30 @@ WithRemoveFrameRectFilter(const IntSize&
                           const IntRect& aFrameRect,
                           Func aFunc)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   WithFilterPipeline(decoder, Forward<Func>(aFunc),
                      RemoveFrameRectConfig { aFrameRect },
-                     SurfaceConfig { decoder, 0, aSize,
+                     SurfaceConfig { decoder, aSize,
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 void
 AssertConfiguringRemoveFrameRectFilterFails(const IntSize& aSize,
                                             const IntRect& aFrameRect)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   AssertConfiguringPipelineFails(decoder,
                                  RemoveFrameRectConfig { aFrameRect },
-                                 SurfaceConfig { decoder, 0, aSize,
+                                 SurfaceConfig { decoder, aSize,
                                                  SurfaceFormat::B8G8R8A8, false });
 }
 
 TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_0_0_100_100)
 {
   WithRemoveFrameRectFilter(IntSize(100, 100),
                             IntRect(0, 0, 100, 100),
                             [](Decoder* aDecoder, SurfaceFilter* aFilter) {
@@ -315,13 +315,13 @@ TEST(ImageRemoveFrameRectFilter, Configu
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   // RemoveFrameRectFilter does not support paletted images, so configuration
   // should fail.
   AssertConfiguringPipelineFails(decoder,
                                  RemoveFrameRectConfig { IntRect(0, 0, 50, 50) },
-                                 PalettedSurfaceConfig { decoder, 0, IntSize(100, 100),
+                                 PalettedSurfaceConfig { decoder, IntSize(100, 100),
                                                          IntRect(0, 0, 50, 50),
                                                          SurfaceFormat::B8G8R8A8, 8,
                                                          false });
 }
--- a/image/test/gtest/TestSurfacePipeIntegration.cpp
+++ b/image/test/gtest/TestSurfacePipeIntegration.cpp
@@ -144,17 +144,17 @@ TEST_F(ImageSurfacePipeIntegration, Surf
   pipe = TestSurfacePipeFactory::SimpleSurfacePipe();
 
   // Test that SurfacePipe objects can be initialized with a pipeline.
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   auto sink = MakeUnique<SurfaceSink>();
   nsresult rv =
-    sink->Configure(SurfaceConfig { decoder, 0, IntSize(100, 100),
+    sink->Configure(SurfaceConfig { decoder, IntSize(100, 100),
                                     SurfaceFormat::B8G8R8A8, false });
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 
   pipe = TestSurfacePipeFactory::SurfacePipeFromPipeline(sink);
 
   // Test that WritePixels() gets passed through to the underlying pipeline.
   {
     uint32_t count = 0;
@@ -238,17 +238,17 @@ TEST_F(ImageSurfacePipeIntegration, Surf
 TEST_F(ImageSurfacePipeIntegration, PalettedSurfacePipe)
 {
   // Create a SurfacePipe containing a PalettedSurfaceSink.
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   auto sink = MakeUnique<PalettedSurfaceSink>();
   nsresult rv =
-    sink->Configure(PalettedSurfaceConfig { decoder, 0, IntSize(100, 100),
+    sink->Configure(PalettedSurfaceConfig { decoder, IntSize(100, 100),
                                             IntRect(0, 0, 100, 100),
                                             SurfaceFormat::B8G8R8A8,
                                             8, false });
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 
   SurfacePipe pipe = TestSurfacePipeFactory::SurfacePipeFromPipeline(sink);
 
   // Test that WritePixels() gets passed through to the underlying pipeline.
@@ -340,17 +340,17 @@ TEST_F(ImageSurfacePipeIntegration, Dein
     CheckWritePixels(aDecoder, aFilter,
                      /* aOutputRect = */ Some(IntRect(0, 0, 25, 25)));
   };
 
   WithFilterPipeline(decoder, test,
                      DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true },
                      DownscalingConfig { IntSize(100, 100),
                                          SurfaceFormat::B8G8R8A8 },
-                     SurfaceConfig { decoder, 0, IntSize(25, 25),
+                     SurfaceConfig { decoder, IntSize(25, 25),
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 TEST_F(ImageSurfacePipeIntegration, RemoveFrameRectBottomRightDownscaleWritePixels)
 {
   // This test case uses a frame rect that extends beyond the borders of the
   // image to the bottom and to the right. It looks roughly like this (with the
   // box made of '#'s representing the frame rect):
@@ -396,17 +396,17 @@ TEST_F(ImageSurfacePipeIntegration, Remo
                      /* aOutputWriteRect = */ Some(IntRect(10, 10, 10, 10)),
                      /* aFuzz = */ 0x33);
   };
 
   WithFilterPipeline(decoder, test,
                      RemoveFrameRectConfig { IntRect(50, 50, 100, 100) },
                      DownscalingConfig { IntSize(100, 100),
                                          SurfaceFormat::B8G8R8A8 },
-                     SurfaceConfig { decoder, 0, IntSize(20, 20),
+                     SurfaceConfig { decoder, IntSize(20, 20),
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 TEST_F(ImageSurfacePipeIntegration, RemoveFrameRectTopLeftDownscaleWritePixels)
 {
   // This test case uses a frame rect that extends beyond the borders of the
   // image to the top and to the left. It looks roughly like this (with the
   // box made of '#'s representing the frame rect):
@@ -430,17 +430,17 @@ TEST_F(ImageSurfacePipeIntegration, Remo
                      /* aOutputWriteRect = */ Some(IntRect(0, 0, 10, 10)),
                      /* aFuzz = */ 0x21);
   };
 
   WithFilterPipeline(decoder, test,
                      RemoveFrameRectConfig { IntRect(-50, -50, 100, 100) },
                      DownscalingConfig { IntSize(100, 100),
                                          SurfaceFormat::B8G8R8A8 },
-                     SurfaceConfig { decoder, 0, IntSize(20, 20),
+                     SurfaceConfig { decoder, IntSize(20, 20),
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 TEST_F(ImageSurfacePipeIntegration, DeinterlaceRemoveFrameRectWritePixels)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
@@ -454,17 +454,17 @@ TEST_F(ImageSurfacePipeIntegration, Dein
                      /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
                      /* aInputWriteRect = */ Some(IntRect(50, 50, 100, 100)),
                      /* aOutputWriteRect = */ Some(IntRect(50, 50, 50, 50)));
   };
 
   WithFilterPipeline(decoder, test,
                      DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true },
                      RemoveFrameRectConfig { IntRect(50, 50, 100, 100) },
-                     SurfaceConfig { decoder, 0, IntSize(100, 100),
+                     SurfaceConfig { decoder, IntSize(100, 100),
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 TEST_F(ImageSurfacePipeIntegration, DeinterlaceRemoveFrameRectDownscaleWritePixels)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
@@ -477,49 +477,49 @@ TEST_F(ImageSurfacePipeIntegration, Dein
                      /* aFuzz = */ 33);
   };
 
   WithFilterPipeline(decoder, test,
                      DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true },
                      RemoveFrameRectConfig { IntRect(50, 50, 100, 100) },
                      DownscalingConfig { IntSize(100, 100),
                                          SurfaceFormat::B8G8R8A8 },
-                     SurfaceConfig { decoder, 0, IntSize(20, 20),
+                     SurfaceConfig { decoder, IntSize(20, 20),
                                      SurfaceFormat::B8G8R8A8, false });
 }
 
 TEST_F(ImageSurfacePipeIntegration, ConfiguringPalettedRemoveFrameRectDownscaleFails)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   // This is an invalid pipeline for paletted images, so configuration should
   // fail.
   AssertConfiguringPipelineFails(decoder,
                                  RemoveFrameRectConfig { IntRect(0, 0, 50, 50) },
                                  DownscalingConfig { IntSize(100, 100),
                                                      SurfaceFormat::B8G8R8A8 },
-                                 PalettedSurfaceConfig { decoder, 0, IntSize(100, 100),
+                                 PalettedSurfaceConfig { decoder, IntSize(100, 100),
                                                          IntRect(0, 0, 50, 50),
                                                          SurfaceFormat::B8G8R8A8, 8,
                                                          false });
 }
 
 TEST_F(ImageSurfacePipeIntegration, ConfiguringPalettedDeinterlaceDownscaleFails)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   // This is an invalid pipeline for paletted images, so configuration should
   // fail.
   AssertConfiguringPipelineFails(decoder,
                                  DeinterlacingConfig<uint8_t> { /* mProgressiveDisplay = */ true},
                                  DownscalingConfig { IntSize(100, 100),
                                                      SurfaceFormat::B8G8R8A8 },
-                                 PalettedSurfaceConfig { decoder, 0, IntSize(100, 100),
+                                 PalettedSurfaceConfig { decoder, IntSize(100, 100),
                                                          IntRect(0, 0, 20, 20),
                                                          SurfaceFormat::B8G8R8A8, 8,
                                                          false });
 }
 
 TEST_F(ImageSurfacePipeIntegration, ConfiguringHugeDeinterlacingBufferFails)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
@@ -530,11 +530,11 @@ TEST_F(ImageSurfacePipeIntegration, Conf
   // version of the image. However, regardless of downscaling,
   // DeinterlacingFilter needs to allocate a buffer as large as the size of the
   // input. This can cause OOMs on operating systems that allow overcommit. This
   // test makes sure that we reject such allocations.
   AssertConfiguringPipelineFails(decoder,
                                  DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true},
                                  DownscalingConfig { IntSize(60000, 60000),
                                                      SurfaceFormat::B8G8R8A8 },
-                                 SurfaceConfig { decoder, 0, IntSize(600, 600),
+                                 SurfaceConfig { decoder, IntSize(600, 600),
                                                  SurfaceFormat::B8G8R8A8, false });
 }
--- a/image/test/gtest/TestSurfaceSink.cpp
+++ b/image/test/gtest/TestSurfaceSink.cpp
@@ -27,28 +27,28 @@ template <Orient Orientation, typename F
 WithSurfaceSink(Func aFunc)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   const bool flipVertically = Orientation == Orient::FLIP_VERTICALLY;
 
   WithFilterPipeline(decoder, Forward<Func>(aFunc),
-                     SurfaceConfig { decoder, 0, IntSize(100, 100),
+                     SurfaceConfig { decoder, IntSize(100, 100),
                                      SurfaceFormat::B8G8R8A8, flipVertically });
 }
 
 template <typename Func> void
 WithPalettedSurfaceSink(const IntRect& aFrameRect, Func aFunc)
 {
   RefPtr<Decoder> decoder = CreateTrivialDecoder();
   ASSERT_TRUE(decoder != nullptr);
 
   WithFilterPipeline(decoder, Forward<Func>(aFunc),
-                     PalettedSurfaceConfig { decoder, 0, IntSize(100, 100),
+                     PalettedSurfaceConfig { decoder, IntSize(100, 100),
                                              aFrameRect, SurfaceFormat::B8G8R8A8,
                                              8, false });
 }
 
 void
 ResetForNextPass(SurfaceFilter* aSink)
 {
   aSink->ResetToFirstRow();