Bug 1282566 (Part 3) - Use StreamingLexer in the PNG decoder. r=edwin
authorSeth Fowler <mark.seth.fowler@gmail.com>
Mon, 27 Jun 2016 13:38:34 -0700
changeset 343213 3405db522027deb4b59112d9ff5f3ecde8e00cf7
parent 343212 442c01c74c5f715e2f6263257ae994a07fa1956d
child 343214 29bc719f41f04095f0f35cd5f24ed184d152e387
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
bugs1282566
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 1282566 (Part 3) - Use StreamingLexer in the PNG decoder. r=edwin
image/decoders/nsPNGDecoder.cpp
image/decoders/nsPNGDecoder.h
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -1,32 +1,34 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "ImageLogging.h" // Must appear first
+
+#include <algorithm>
+#include <cstdint>
+
 #include "gfxColor.h"
 #include "gfxPlatform.h"
 #include "imgFrame.h"
 #include "nsColor.h"
 #include "nsIInputStream.h"
 #include "nsMemory.h"
 #include "nsPNGDecoder.h"
 #include "nsRect.h"
 #include "nspr.h"
 #include "png.h"
 #include "RasterImage.h"
 #include "SurfacePipeFactory.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Telemetry.h"
 
-#include <algorithm>
-
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace image {
 
 static LazyLogModule sPNGLog("PNGDecoder");
 static LazyLogModule sPNGDecoderAccountingLog("PNGDecoderAccounting");
 
@@ -89,16 +91,19 @@ nsPNGDecoder::AnimFrameInfo::AnimFrameIn
 #endif
 
 // First 8 bytes of a PNG file
 const uint8_t
 nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
 
 nsPNGDecoder::nsPNGDecoder(RasterImage* aImage)
  : Decoder(aImage)
+ , mLexer(Transition::ToUnbuffered(State::FINISHED_PNG_DATA,
+                                   State::PNG_DATA,
+                                   SIZE_MAX))
  , mPNG(nullptr)
  , mInfo(nullptr)
  , mCMSLine(nullptr)
  , interlacebuf(nullptr)
  , mInProfile(nullptr)
  , mTransform(nullptr)
  , format(gfx::SurfaceFormat::UNKNOWN)
  , mCMSMode(0)
@@ -342,33 +347,68 @@ nsPNGDecoder::InitInternal()
                               nsPNGDecoder::end_callback);
 
 }
 
 void
 nsPNGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!");
-
-  // libpng uses setjmp/longjmp for error handling. Set it up.
-  if (setjmp(png_jmpbuf(mPNG))) {
+  MOZ_ASSERT(aBuffer);
+  MOZ_ASSERT(aCount > 0);
 
-    // We exited early due to an error. We might not really know what caused
-    // it, but it makes more sense to blame the data.
-    if (!HasError()) {
-      PostDataError();
-    }
+  Maybe<TerminalState> terminalState =
+    mLexer.Lex(aBuffer, aCount, [=](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");
+    });
 
-    return;
+  if (terminalState == Some(TerminalState::FAILURE)) {
+    PostDataError();
+  }
+}
+
+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();
   }
 
   // Pass the data off to libpng.
   png_process_data(mPNG, mInfo,
-                   reinterpret_cast<unsigned char*>(const_cast<char*>((aBuffer))),
-                   aCount);
+                   reinterpret_cast<unsigned char*>(const_cast<char*>((aData))),
+                   aLength);
+
+  if (HasError()) {
+    return Transition::TerminateFailure();
+  }
+
+  if (GetDecodeDone()) {
+    return Transition::TerminateSuccess();
+  }
+
+  // Keep reading data.
+  return Transition::ContinueUnbuffered(State::PNG_DATA);
+}
+
+LexerTransition<nsPNGDecoder::State>
+nsPNGDecoder::FinishedPNGData()
+{
+  // Since we set up an unbuffered read for SIZE_MAX bytes, if we actually read
+  // all that data something is really wrong.
+  MOZ_ASSERT_UNREACHABLE("Read the entire address space?");
+  return Transition::TerminateFailure();
 }
 
 // Sets up gamma pre-correction in libpng before our callback gets called.
 // We need to do this if we don't end up with a CMS profile.
 static void
 PNGDoGammaCorrection(png_structp png_ptr, png_infop info_ptr)
 {
   double aGamma;
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_image_decoders_nsPNGDecoder_h
 #define mozilla_image_decoders_nsPNGDecoder_h
 
 #include "Decoder.h"
 #include "png.h"
 #include "qcms.h"
+#include "StreamingLexer.h"
 #include "SurfacePipe.h"
 
 namespace mozilla {
 namespace image {
 class RasterImage;
 
 class nsPNGDecoder : public Decoder
 {
@@ -79,16 +80,27 @@ private:
       return ((png_color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
                png_color_type == PNG_COLOR_TYPE_RGB) &&
               png_bit_depth == 8);
     } else {
       return false;
     }
   }
 
+  enum class State
+  {
+    PNG_DATA,
+    FINISHED_PNG_DATA
+  };
+
+  LexerTransition<State> ReadPNGData(const char* aData, size_t aLength);
+  LexerTransition<State> FinishedPNGData();
+
+  StreamingLexer<State> mLexer;
+
 public:
   png_structp mPNG;
   png_infop mInfo;
   nsIntRect mFrameRect;
   uint8_t* mCMSLine;
   uint8_t* interlacebuf;
   qcms_profile* mInProfile;
   qcms_transform* mTransform;