Bug 1181863 (Part 1) - Add support for reading from nsIInputStreams directly to SourceBuffer. r=tn
authorSeth Fowler <mark.seth.fowler@gmail.com>
Fri, 31 Jul 2015 18:10:29 -0700
changeset 287428 3e8dd82cbf50aa3a3471bde6d8d2919fa96fe769
parent 287427 05f618ac3d24b37b7582d92122e9e52441112a46
child 287429 44dc3228c00b1f809629d7d88c9df7749186d734
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1181863
milestone42.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 1181863 (Part 1) - Add support for reading from nsIInputStreams directly to SourceBuffer. r=tn
image/RasterImage.cpp
image/RasterImage.h
image/SourceBuffer.cpp
image/SourceBuffer.h
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -1183,30 +1183,26 @@ RasterImage::NotifyForLoadEvent(Progress
 
   // Notify our listeners, which will fire this image's load event.
   NotifyProgress(aProgress);
 }
 
 nsresult
 RasterImage::OnImageDataAvailable(nsIRequest*,
                                   nsISupports*,
-                                  nsIInputStream* aInStr,
-                                  uint64_t aOffset,
+                                  nsIInputStream* aInputStream,
+                                  uint64_t,
                                   uint32_t aCount)
 {
-  nsresult rv;
+  nsresult rv = mSourceBuffer->AppendFromInputStream(aInputStream, aCount);
+  MOZ_ASSERT(rv == NS_OK || rv == NS_ERROR_OUT_OF_MEMORY);
 
-  // WriteToSourceBuffer always consumes everything it gets if it doesn't run
-  // out of memory.
-  uint32_t bytesRead;
-  rv = aInStr->ReadSegments(WriteToSourceBuffer, this, aCount, &bytesRead);
-
-  MOZ_ASSERT(bytesRead == aCount || HasError() || NS_FAILED(rv),
-    "WriteToSourceBuffer should consume everything if ReadSegments succeeds or "
-    "the image must be in error!");
+  if (MOZ_UNLIKELY(rv == NS_ERROR_OUT_OF_MEMORY)) {
+    DoError();
+  }
 
   return rv;
 }
 
 nsresult
 RasterImage::SetSourceSizeHint(uint32_t aSizeHint)
 {
   return mSourceBuffer->ExpectLength(aSizeHint);
@@ -1897,46 +1893,16 @@ RasterImage::HandleErrorWorker::HandleEr
 NS_IMETHODIMP
 RasterImage::HandleErrorWorker::Run()
 {
   mImage->DoError();
 
   return NS_OK;
 }
 
-// nsIInputStream callback to copy the incoming image data directly to the
-// RasterImage without processing. The RasterImage is passed as the closure.
-// Always reads everything it gets, even if the data is erroneous.
-NS_METHOD
-RasterImage::WriteToSourceBuffer(nsIInputStream* /* unused */,
-                                 void*          aClosure,
-                                 const char*    aFromRawSegment,
-                                 uint32_t       /* unused */,
-                                 uint32_t       aCount,
-                                 uint32_t*      aWriteCount)
-{
-  // Retrieve the RasterImage
-  RasterImage* image = static_cast<RasterImage*>(aClosure);
-
-  // Copy the source data. Unless we hit OOM, we squelch the return value
-  // here, because returning an error means that ReadSegments stops
-  // reading data, violating our invariant that we read everything we get.
-  // If we hit OOM then we fail and the load is aborted.
-  nsresult rv = image->mSourceBuffer->Append(aFromRawSegment, aCount);
-  if (rv == NS_ERROR_OUT_OF_MEMORY) {
-    image->DoError();
-    return rv;
-  }
-
-  // We wrote everything we got
-  *aWriteCount = aCount;
-
-  return NS_OK;
-}
-
 bool
 RasterImage::ShouldAnimate()
 {
   return ImageResource::ShouldAnimate() && GetNumFrames() >= 2 &&
          !mAnimationFinished;
 }
 
 /* readonly attribute uint32_t framesNotified; */
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -165,22 +165,16 @@ public:
 #endif
 
   virtual nsresult StartAnimation() override;
   virtual nsresult StopAnimation() override;
 
   // Methods inherited from Image
   virtual void OnSurfaceDiscarded() override;
 
-  // Raster-specific methods
-  static NS_METHOD WriteToSourceBuffer(nsIInputStream* aIn, void* aClosure,
-                                       const char* aFromRawSegment,
-                                       uint32_t aToOffset, uint32_t aCount,
-                                       uint32_t* aWriteCount);
-
   /* The total number of frames in this image. */
   uint32_t GetNumFrames() const { return mFrameCount; }
 
   virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf)
     const override;
   virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
                                      MallocSizeOf aMallocSizeOf) const override;
 
--- a/image/SourceBuffer.cpp
+++ b/image/SourceBuffer.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SourceBuffer.h"
 
 #include <algorithm>
 #include <cmath>
 #include <cstring>
 #include "mozilla/Likely.h"
+#include "nsIInputStream.h"
 #include "MainThreadUtils.h"
 #include "SurfaceCache.h"
 
 using std::max;
 using std::min;
 
 namespace mozilla {
 namespace image {
@@ -349,16 +350,56 @@ SourceBuffer::Append(const char* aData, 
 
     // Resume any waiting readers now that there's new data.
     ResumeWaitingConsumers();
   }
 
   return NS_OK;
 }
 
+static NS_METHOD
+AppendToSourceBuffer(nsIInputStream*,
+                     void* aClosure,
+                     const char* aFromRawSegment,
+                     uint32_t,
+                     uint32_t aCount,
+                     uint32_t* aWriteCount)
+{
+  SourceBuffer* sourceBuffer = static_cast<SourceBuffer*>(aClosure);
+
+  // Copy the source data. Unless we hit OOM, we squelch the return value here,
+  // because returning an error means that ReadSegments stops reading data, and
+  // we want to ensure that we read everything we get. If we hit OOM then we
+  // return a failed status to the caller.
+  nsresult rv = sourceBuffer->Append(aFromRawSegment, aCount);
+  if (rv == NS_ERROR_OUT_OF_MEMORY) {
+    return rv;
+  }
+
+  // Report that we wrote everything we got.
+  *aWriteCount = aCount;
+
+  return NS_OK;
+}
+
+nsresult
+SourceBuffer::AppendFromInputStream(nsIInputStream* aInputStream,
+                                    uint32_t aCount)
+{
+  uint32_t bytesRead;
+  nsresult rv = aInputStream->ReadSegments(AppendToSourceBuffer, this,
+                                           aCount, &bytesRead);
+
+  MOZ_ASSERT(bytesRead == aCount || rv == NS_ERROR_OUT_OF_MEMORY,
+             "AppendToSourceBuffer should consume everything unless "
+             "we run out of memory");
+
+  return rv;
+}
+
 void
 SourceBuffer::Complete(nsresult aStatus)
 {
   MutexAutoLock lock(mMutex);
 
   if (MOZ_UNLIKELY(mStatus)) {
     MOZ_ASSERT_UNREACHABLE("Called Complete more than once");
     return;
--- a/image/SourceBuffer.h
+++ b/image/SourceBuffer.h
@@ -16,16 +16,18 @@
 #include "mozilla/Mutex.h"
 #include "mozilla/Move.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/nsRefPtr.h"
 #include "nsTArray.h"
 
+class nsIInputStream;
+
 namespace mozilla {
 namespace image {
 
 class SourceBuffer;
 
 /**
  * IResumable is an interface for classes that can schedule themselves to resume
  * their work later. An implementation of IResumable generally should post a
@@ -224,16 +226,19 @@ public:
    * If the producer knows how long the source data will be, it should call
    * ExpectLength, which enables SourceBuffer to preallocate its buffer.
    */
   nsresult ExpectLength(size_t aExpectedLength);
 
   /// Append the provided data to the buffer.
   nsresult Append(const char* aData, size_t aLength);
 
+  /// Append the data available on the provided nsIInputStream to the buffer.
+  nsresult AppendFromInputStream(nsIInputStream* aInputStream, uint32_t aCount);
+
   /**
    * Mark the buffer complete, with a status that will be available to
    * consumers. Further calls to Append() are forbidden after Complete().
    */
   void Complete(nsresult aStatus);
 
   /// Returns true if the buffer is complete.
   bool IsComplete();