Bug 1285865 (Part 5) - Return a Maybe<TerminalState> from Decoder::DoDecode(). r=edwin
authorSeth Fowler <mark.seth.fowler@gmail.com>
Mon, 11 Jul 2016 00:07:07 -0700
changeset 344585 1c717a8dc382b5aeee20f4231488c5ea2320e890
parent 344584 6735ebca30843305e2a4fff37e72f630a2620417
child 344586 940b6ad95cfc5340ee8aa6fd4b7301f974fc2ea0
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin
bugs1285865
milestone50.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 1285865 (Part 5) - Return a Maybe<TerminalState> from Decoder::DoDecode(). r=edwin
image/Decoder.cpp
image/Decoder.h
image/decoders/nsBMPDecoder.cpp
image/decoders/nsBMPDecoder.h
image/decoders/nsGIFDecoder2.cpp
image/decoders/nsGIFDecoder2.h
image/decoders/nsICODecoder.cpp
image/decoders/nsICODecoder.h
image/decoders/nsIconDecoder.cpp
image/decoders/nsIconDecoder.h
image/decoders/nsJPEGDecoder.cpp
image/decoders/nsJPEGDecoder.h
image/decoders/nsPNGDecoder.cpp
image/decoders/nsPNGDecoder.h
--- a/image/Decoder.cpp
+++ b/image/Decoder.cpp
@@ -147,17 +147,22 @@ Decoder::Decode(NotNull<IResumable*> aOn
 
     {
       PROFILER_LABEL("ImageDecoder", "Write",
         js::ProfileEntry::Category::GRAPHICS);
 
       AutoRecordDecoderTelemetry telemetry(this, mIterator->Length());
 
       // Pass the data along to the implementation.
-      DoDecode(mIterator->Data(), mIterator->Length());
+      Maybe<TerminalState> terminalState =
+        DoDecode(mIterator->Data(), mIterator->Length());
+
+      if (terminalState == Some(TerminalState::FAILURE)) {
+        PostDataError();
+      }
     }
   }
 
   CompleteDecode();
   return HasError() ? NS_ERROR_FAILURE : NS_OK;
 }
 
 bool
--- a/image/Decoder.h
+++ b/image/Decoder.h
@@ -3,24 +3,26 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #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 "DecodePool.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 ID : uint32_t;
 } // namespace Telemetry
 
@@ -283,17 +285,17 @@ protected:
    * Internal hooks. Decoder implementations may override these and
    * only these methods.
    *
    * BeforeFinishInternal() can be used to detect if decoding is in an
    * incomplete state, e.g. due to file truncation, in which case it should
    * call PostDataError().
    */
   virtual void InitInternal();
-  virtual void DoDecode(const char* aBuffer, size_t aLength) = 0;
+  virtual Maybe<TerminalState> DoDecode(const char* aBuffer, size_t aLength) = 0;
   virtual void BeforeFinishInternal();
   virtual void FinishInternal();
   virtual void FinishWithErrorInternal();
 
   /*
    * Progress notifications.
    */
 
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -430,46 +430,41 @@ nsBMPDecoder::FinishRow()
                        Some(invalidRect.mTargetSizeRect));
     }
   } else {
     PostInvalidation(IntRect(0, mCurrentRow, mH.mWidth, 1));
   }
   mCurrentRow--;
 }
 
-void
+Maybe<TerminalState>
 nsBMPDecoder::DoDecode(const char* aBuffer, size_t aLength)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
   MOZ_ASSERT(aBuffer);
   MOZ_ASSERT(aLength > 0);
 
-  Maybe<TerminalState> terminalState =
-    mLexer.Lex(aBuffer, aLength, [=](State aState,
-                                     const char* aData, size_t aLength) {
-      switch (aState) {
-        case State::FILE_HEADER:      return ReadFileHeader(aData, aLength);
-        case State::INFO_HEADER_SIZE: return ReadInfoHeaderSize(aData, aLength);
-        case State::INFO_HEADER_REST: return ReadInfoHeaderRest(aData, aLength);
-        case State::BITFIELDS:        return ReadBitfields(aData, aLength);
-        case State::COLOR_TABLE:      return ReadColorTable(aData, aLength);
-        case State::GAP:              return SkipGap();
-        case State::AFTER_GAP:        return AfterGap();
-        case State::PIXEL_ROW:        return ReadPixelRow(aData);
-        case State::RLE_SEGMENT:      return ReadRLESegment(aData);
-        case State::RLE_DELTA:        return ReadRLEDelta(aData);
-        case State::RLE_ABSOLUTE:     return ReadRLEAbsolute(aData, aLength);
-        default:
-          MOZ_CRASH("Unknown State");
-      }
-    });
-
-  if (terminalState == Some(TerminalState::FAILURE)) {
-    PostDataError();
-  }
+  return mLexer.Lex(aBuffer, aLength,
+                    [=](State aState, const char* aData, size_t aLength) {
+    switch (aState) {
+      case State::FILE_HEADER:      return ReadFileHeader(aData, aLength);
+      case State::INFO_HEADER_SIZE: return ReadInfoHeaderSize(aData, aLength);
+      case State::INFO_HEADER_REST: return ReadInfoHeaderRest(aData, aLength);
+      case State::BITFIELDS:        return ReadBitfields(aData, aLength);
+      case State::COLOR_TABLE:      return ReadColorTable(aData, aLength);
+      case State::GAP:              return SkipGap();
+      case State::AFTER_GAP:        return AfterGap();
+      case State::PIXEL_ROW:        return ReadPixelRow(aData);
+      case State::RLE_SEGMENT:      return ReadRLESegment(aData);
+      case State::RLE_DELTA:        return ReadRLEDelta(aData);
+      case State::RLE_ABSOLUTE:     return ReadRLEAbsolute(aData, aLength);
+      default:
+        MOZ_CRASH("Unknown State");
+    }
+  });
 }
 
 LexerTransition<nsBMPDecoder::State>
 nsBMPDecoder::ReadFileHeader(const char* aData, size_t aLength)
 {
   mPreGapLength += aLength;
 
   bool signatureOk = aData[0] == 'B' && aData[1] == 'M';
--- a/image/decoders/nsBMPDecoder.h
+++ b/image/decoders/nsBMPDecoder.h
@@ -144,17 +144,17 @@ public:
 
   /// Force transparency from outside. (Used by the ICO decoder.)
   void SetHasTransparency()
   {
     mMayHaveTransparency = true;
     mDoesHaveTransparency = true;
   }
 
-  void DoDecode(const char* aBuffer, size_t aLength) override;
+  Maybe<TerminalState> DoDecode(const char* aBuffer, size_t aLength) override;
   virtual void BeforeFinishInternal() override;
   virtual void FinishInternal() override;
 
 private:
   friend class DecoderFactory;
 
   enum class State {
     FILE_HEADER,
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -449,77 +449,72 @@ ConvertColormap(uint32_t* aColormap, uin
   // copy remaining pixel(s)
   // NB: can't use 32-bit reads, they might read off the end of the buffer
   while (c--) {
     from -= 3;
     *--to = gfxPackedPixel(0xFF, from[0], from[1], from[2]);
   }
 }
 
-void
+Maybe<TerminalState>
 nsGIFDecoder2::DoDecode(const char* aBuffer, size_t aLength)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
   MOZ_ASSERT(aBuffer);
   MOZ_ASSERT(aLength > 0);
 
-  Maybe<TerminalState> terminalState =
-    mLexer.Lex(aBuffer, aLength, [=](State aState,
-                                     const char* aData, size_t aLength) {
-        switch(aState) {
-          case State::GIF_HEADER:
-            return ReadGIFHeader(aData);
-          case State::SCREEN_DESCRIPTOR:
-            return ReadScreenDescriptor(aData);
-          case State::GLOBAL_COLOR_TABLE:
-            return ReadGlobalColorTable(aData, aLength);
-          case State::FINISHED_GLOBAL_COLOR_TABLE:
-            return FinishedGlobalColorTable();
-          case State::BLOCK_HEADER:
-            return ReadBlockHeader(aData);
-          case State::EXTENSION_HEADER:
-            return ReadExtensionHeader(aData);
-          case State::GRAPHIC_CONTROL_EXTENSION:
-            return ReadGraphicControlExtension(aData);
-          case State::APPLICATION_IDENTIFIER:
-            return ReadApplicationIdentifier(aData);
-          case State::NETSCAPE_EXTENSION_SUB_BLOCK:
-            return ReadNetscapeExtensionSubBlock(aData);
-          case State::NETSCAPE_EXTENSION_DATA:
-            return ReadNetscapeExtensionData(aData);
-          case State::IMAGE_DESCRIPTOR:
-            return ReadImageDescriptor(aData);
-          case State::LOCAL_COLOR_TABLE:
-            return ReadLocalColorTable(aData, aLength);
-          case State::FINISHED_LOCAL_COLOR_TABLE:
-            return FinishedLocalColorTable();
-          case State::IMAGE_DATA_BLOCK:
-            return ReadImageDataBlock(aData);
-          case State::IMAGE_DATA_SUB_BLOCK:
-            return ReadImageDataSubBlock(aData);
-          case State::LZW_DATA:
-            return ReadLZWData(aData, aLength);
-          case State::SKIP_LZW_DATA:
-            return Transition::ContinueUnbuffered(State::SKIP_LZW_DATA);
-          case State::FINISHED_LZW_DATA:
-            return Transition::To(State::IMAGE_DATA_SUB_BLOCK, SUB_BLOCK_HEADER_LEN);
-          case State::SKIP_SUB_BLOCKS:
-            return SkipSubBlocks(aData);
-          case State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS:
-            return Transition::ContinueUnbuffered(State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS);
-          case State::FINISHED_SKIPPING_DATA:
-            return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
-          default:
-            MOZ_CRASH("Unknown State");
-        }
-      });
-
-  if (terminalState == Some(TerminalState::FAILURE)) {
-    PostDataError();
-  }
+  return mLexer.Lex(aBuffer, aLength,
+                    [=](State aState, const char* aData, size_t aLength) {
+    switch(aState) {
+      case State::GIF_HEADER:
+        return ReadGIFHeader(aData);
+      case State::SCREEN_DESCRIPTOR:
+        return ReadScreenDescriptor(aData);
+      case State::GLOBAL_COLOR_TABLE:
+        return ReadGlobalColorTable(aData, aLength);
+      case State::FINISHED_GLOBAL_COLOR_TABLE:
+        return FinishedGlobalColorTable();
+      case State::BLOCK_HEADER:
+        return ReadBlockHeader(aData);
+      case State::EXTENSION_HEADER:
+        return ReadExtensionHeader(aData);
+      case State::GRAPHIC_CONTROL_EXTENSION:
+        return ReadGraphicControlExtension(aData);
+      case State::APPLICATION_IDENTIFIER:
+        return ReadApplicationIdentifier(aData);
+      case State::NETSCAPE_EXTENSION_SUB_BLOCK:
+        return ReadNetscapeExtensionSubBlock(aData);
+      case State::NETSCAPE_EXTENSION_DATA:
+        return ReadNetscapeExtensionData(aData);
+      case State::IMAGE_DESCRIPTOR:
+        return ReadImageDescriptor(aData);
+      case State::LOCAL_COLOR_TABLE:
+        return ReadLocalColorTable(aData, aLength);
+      case State::FINISHED_LOCAL_COLOR_TABLE:
+        return FinishedLocalColorTable();
+      case State::IMAGE_DATA_BLOCK:
+        return ReadImageDataBlock(aData);
+      case State::IMAGE_DATA_SUB_BLOCK:
+        return ReadImageDataSubBlock(aData);
+      case State::LZW_DATA:
+        return ReadLZWData(aData, aLength);
+      case State::SKIP_LZW_DATA:
+        return Transition::ContinueUnbuffered(State::SKIP_LZW_DATA);
+      case State::FINISHED_LZW_DATA:
+        return Transition::To(State::IMAGE_DATA_SUB_BLOCK, SUB_BLOCK_HEADER_LEN);
+      case State::SKIP_SUB_BLOCKS:
+        return SkipSubBlocks(aData);
+      case State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS:
+        return Transition::ContinueUnbuffered(State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS);
+      case State::FINISHED_SKIPPING_DATA:
+        return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
+      default:
+        MOZ_CRASH("Unknown State");
+    }
+  });
 }
 
 LexerTransition<nsGIFDecoder2::State>
 nsGIFDecoder2::ReadGIFHeader(const char* aData)
 {
   // We retrieve the version here but because many GIF encoders set header
   // fields incorrectly, we barely use it; features which should only appear in
   // GIF89a are always accepted.
--- a/image/decoders/nsGIFDecoder2.h
+++ b/image/decoders/nsGIFDecoder2.h
@@ -19,17 +19,17 @@ class RasterImage;
 //////////////////////////////////////////////////////////////////////
 // nsGIFDecoder2 Definition
 
 class nsGIFDecoder2 : public Decoder
 {
 public:
   ~nsGIFDecoder2();
 
-  void DoDecode(const char* aBuffer, size_t aLength) override;
+  Maybe<TerminalState> DoDecode(const char* aBuffer, size_t aLength) override;
   virtual void FinishInternal() override;
   virtual Telemetry::ID SpeedHistogram() override;
 
 private:
   friend class DecoderFactory;
 
   // Decoders should only be instantiated via DecoderFactory.
   explicit nsGIFDecoder2(RasterImage* aImage);
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -592,61 +592,56 @@ nsICODecoder::FinishResource()
   if (mContainedDecoder->HasSize() &&
       mContainedDecoder->GetSize() != GetRealSize()) {
     return Transition::TerminateFailure();
   }
 
   return Transition::TerminateSuccess();
 }
 
-void
+Maybe<TerminalState>
 nsICODecoder::DoDecode(const char* aBuffer, size_t aLength)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
   MOZ_ASSERT(aBuffer);
   MOZ_ASSERT(aLength > 0);
 
-  Maybe<TerminalState> terminalState =
-    mLexer.Lex(aBuffer, aLength,
-               [=](ICOState aState, const char* aData, size_t aLength) {
-      switch (aState) {
-        case ICOState::HEADER:
-          return ReadHeader(aData);
-        case ICOState::DIR_ENTRY:
-          return ReadDirEntry(aData);
-        case ICOState::SKIP_TO_RESOURCE:
-          return Transition::ContinueUnbuffered(ICOState::SKIP_TO_RESOURCE);
-        case ICOState::FOUND_RESOURCE:
-          return Transition::To(ICOState::SNIFF_RESOURCE, PNGSIGNATURESIZE);
-        case ICOState::SNIFF_RESOURCE:
-          return SniffResource(aData);
-        case ICOState::READ_PNG:
-          return ReadPNG(aData, aLength);
-        case ICOState::READ_BIH:
-          return ReadBIH(aData);
-        case ICOState::READ_BMP:
-          return ReadBMP(aData, aLength);
-        case ICOState::PREPARE_FOR_MASK:
-          return PrepareForMask();
-        case ICOState::READ_MASK_ROW:
-          return ReadMaskRow(aData);
-        case ICOState::FINISH_MASK:
-          return FinishMask();
-        case ICOState::SKIP_MASK:
-          return Transition::ContinueUnbuffered(ICOState::SKIP_MASK);
-        case ICOState::FINISHED_RESOURCE:
-          return FinishResource();
-        default:
-          MOZ_CRASH("Unknown ICOState");
-      }
-    });
-
-  if (terminalState == Some(TerminalState::FAILURE)) {
-    PostDataError();
-  }
+  return mLexer.Lex(aBuffer, aLength,
+                    [=](ICOState aState, const char* aData, size_t aLength) {
+    switch (aState) {
+      case ICOState::HEADER:
+        return ReadHeader(aData);
+      case ICOState::DIR_ENTRY:
+        return ReadDirEntry(aData);
+      case ICOState::SKIP_TO_RESOURCE:
+        return Transition::ContinueUnbuffered(ICOState::SKIP_TO_RESOURCE);
+      case ICOState::FOUND_RESOURCE:
+        return Transition::To(ICOState::SNIFF_RESOURCE, PNGSIGNATURESIZE);
+      case ICOState::SNIFF_RESOURCE:
+        return SniffResource(aData);
+      case ICOState::READ_PNG:
+        return ReadPNG(aData, aLength);
+      case ICOState::READ_BIH:
+        return ReadBIH(aData);
+      case ICOState::READ_BMP:
+        return ReadBMP(aData, aLength);
+      case ICOState::PREPARE_FOR_MASK:
+        return PrepareForMask();
+      case ICOState::READ_MASK_ROW:
+        return ReadMaskRow(aData);
+      case ICOState::FINISH_MASK:
+        return FinishMask();
+      case ICOState::SKIP_MASK:
+        return Transition::ContinueUnbuffered(ICOState::SKIP_MASK);
+      case ICOState::FINISHED_RESOURCE:
+        return FinishResource();
+      default:
+        MOZ_CRASH("Unknown ICOState");
+    }
+  });
 }
 
 bool
 nsICODecoder::WriteToContainedDecoder(const char* aBuffer, uint32_t aCount)
 {
   MOZ_ASSERT(mContainedDecoder);
   MOZ_ASSERT(mContainedSourceBuffer);
 
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -65,17 +65,17 @@ public:
   gfx::IntSize GetRealSize() const
   {
     return gfx::IntSize(GetRealWidth(), GetRealHeight());
   }
 
   /// @return The offset from the beginning of the ICO to the first resource.
   size_t FirstResourceOffset() const;
 
-  void DoDecode(const char* aBuffer, size_t aLength) override;
+  Maybe<TerminalState> DoDecode(const char* aBuffer, size_t aLength) override;
   virtual void FinishInternal() override;
   virtual void FinishWithErrorInternal() override;
 
 private:
   friend class DecoderFactory;
 
   // Decoders should only be instantiated via DecoderFactory.
   explicit nsICODecoder(RasterImage* aImage);
--- a/image/decoders/nsIconDecoder.cpp
+++ b/image/decoders/nsIconDecoder.cpp
@@ -21,41 +21,36 @@ nsIconDecoder::nsIconDecoder(RasterImage
  , mBytesPerRow()   // set by ReadHeader()
 {
   // Nothing to do
 }
 
 nsIconDecoder::~nsIconDecoder()
 { }
 
-void
+Maybe<TerminalState>
 nsIconDecoder::DoDecode(const char* aBuffer, size_t aLength)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
   MOZ_ASSERT(aBuffer);
   MOZ_ASSERT(aLength > 0);
 
-  Maybe<TerminalState> terminalState =
-    mLexer.Lex(aBuffer, aLength, [=](State aState,
-                                     const char* aData, size_t aLength) {
-      switch (aState) {
-        case State::HEADER:
-          return ReadHeader(aData);
-        case State::ROW_OF_PIXELS:
-          return ReadRowOfPixels(aData, aLength);
-        case State::FINISH:
-          return Finish();
-        default:
-          MOZ_CRASH("Unknown State");
-      }
-    });
-
-  if (terminalState == Some(TerminalState::FAILURE)) {
-    PostDataError();
-  }
+  return mLexer.Lex(aBuffer, aLength,
+                    [=](State aState, const char* aData, size_t aLength) {
+    switch (aState) {
+      case State::HEADER:
+        return ReadHeader(aData);
+      case State::ROW_OF_PIXELS:
+        return ReadRowOfPixels(aData, aLength);
+      case State::FINISH:
+        return Finish();
+      default:
+        MOZ_CRASH("Unknown State");
+    }
+  });
 }
 
 LexerTransition<nsIconDecoder::State>
 nsIconDecoder::ReadHeader(const char* aData)
 {
   // Grab the width and height.
   uint8_t width  = uint8_t(aData[0]);
   uint8_t height = uint8_t(aData[1]);
--- a/image/decoders/nsIconDecoder.h
+++ b/image/decoders/nsIconDecoder.h
@@ -32,17 +32,17 @@ class RasterImage;
 //
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsIconDecoder : public Decoder
 {
 public:
   virtual ~nsIconDecoder();
 
-  void DoDecode(const char* aBuffer, size_t aLength) override;
+  Maybe<TerminalState> DoDecode(const char* aBuffer, size_t aLength) override;
 
 private:
   friend class DecoderFactory;
 
   // Decoders should only be instantiated via DecoderFactory.
   explicit nsIconDecoder(RasterImage* aImage);
 
   enum class State {
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -174,38 +174,33 @@ nsJPEGDecoder::FinishInternal()
   // If we're not in any sort of error case, force our state to JPEG_DONE.
   if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
       (mState != JPEG_ERROR) &&
       !IsMetadataDecode()) {
     mState = JPEG_DONE;
   }
 }
 
-void
+Maybe<TerminalState>
 nsJPEGDecoder::DoDecode(const char* aBuffer, size_t aLength)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
   MOZ_ASSERT(aBuffer);
   MOZ_ASSERT(aLength > 0);
 
-  Maybe<TerminalState> terminalState =
-    mLexer.Lex(aBuffer, aLength, [=](State aState,
-                                     const char* aData, size_t aLength) {
-      switch (aState) {
-        case State::JPEG_DATA:
-          return ReadJPEGData(aData, aLength);
-        case State::FINISHED_JPEG_DATA:
-          return FinishedJPEGData();
-      }
-      MOZ_CRASH("Unknown State");
-    });
-
-  if (terminalState == Some(TerminalState::FAILURE)) {
-    PostDataError();
-  }
+  return mLexer.Lex(aBuffer, aLength,
+                    [=](State aState, const char* aData, size_t aLength) {
+    switch (aState) {
+      case State::JPEG_DATA:
+        return ReadJPEGData(aData, aLength);
+      case State::FINISHED_JPEG_DATA:
+        return FinishedJPEGData();
+    }
+    MOZ_CRASH("Unknown State");
+  });
 }
 
 LexerTransition<nsJPEGDecoder::State>
 nsJPEGDecoder::ReadJPEGData(const char* aData, size_t aLength)
 {
   mSegment = reinterpret_cast<const JOCTET*>(aData);
   mSegmentLen = aLength;
 
--- a/image/decoders/nsJPEGDecoder.h
+++ b/image/decoders/nsJPEGDecoder.h
@@ -53,17 +53,17 @@ public:
   virtual ~nsJPEGDecoder();
 
   virtual void SetSampleSize(int aSampleSize) override
   {
     mSampleSize = aSampleSize;
   }
 
   virtual void InitInternal() override;
-  void DoDecode(const char* aBuffer, size_t aLength) override;
+  Maybe<TerminalState> DoDecode(const char* aBuffer, size_t aLength) override;
   virtual void FinishInternal() override;
 
   virtual Telemetry::ID SpeedHistogram() override;
   void NotifyDone();
 
 protected:
   Orientation ReadOrientationFromEXIF();
   void OutputScanlines(bool* suspend);
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -343,38 +343,33 @@ nsPNGDecoder::InitInternal()
   // use this as libpng "progressive pointer" (retrieve in callbacks)
   png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this),
                               nsPNGDecoder::info_callback,
                               nsPNGDecoder::row_callback,
                               nsPNGDecoder::end_callback);
 
 }
 
-void
+Maybe<TerminalState>
 nsPNGDecoder::DoDecode(const char* aBuffer, size_t aLength)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
   MOZ_ASSERT(aBuffer);
   MOZ_ASSERT(aLength > 0);
 
-  Maybe<TerminalState> terminalState =
-    mLexer.Lex(aBuffer, aLength, [=](State aState,
-                                     const char* aData, size_t aLength) {
-      switch (aState) {
-        case State::PNG_DATA:
-          return ReadPNGData(aData, aLength);
-        case State::FINISHED_PNG_DATA:
-          return FinishedPNGData();
-      }
-      MOZ_CRASH("Unknown State");
-    });
-
-  if (terminalState == Some(TerminalState::FAILURE)) {
-    PostDataError();
-  }
+  return mLexer.Lex(aBuffer, aLength,
+                    [=](State aState, const char* aData, size_t aLength) {
+    switch (aState) {
+      case State::PNG_DATA:
+        return ReadPNGData(aData, aLength);
+      case State::FINISHED_PNG_DATA:
+        return FinishedPNGData();
+    }
+    MOZ_CRASH("Unknown State");
+  });
 }
 
 LexerTransition<nsPNGDecoder::State>
 nsPNGDecoder::ReadPNGData(const char* aData, size_t aLength)
 {
   // libpng uses setjmp/longjmp for error handling.
   if (setjmp(png_jmpbuf(mPNG))) {
     return Transition::TerminateFailure();
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -18,17 +18,17 @@ namespace image {
 class RasterImage;
 
 class nsPNGDecoder : public Decoder
 {
 public:
   virtual ~nsPNGDecoder();
 
   virtual void InitInternal() override;
-  void DoDecode(const char* aBuffer, size_t aLength) override;
+  Maybe<TerminalState> DoDecode(const char* aBuffer, size_t aLength) override;
   virtual Telemetry::ID SpeedHistogram() override;
 
   /// @return true if this PNG is a valid ICO resource.
   bool IsValidICO() const;
 
 private:
   friend class DecoderFactory;