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 282417 3e8dd82cbf50aa3a3471bde6d8d2919fa96fe769
parent 282416 05f618ac3d24b37b7582d92122e9e52441112a46
child 282418 44dc3228c00b1f809629d7d88c9df7749186d734
push id4000
push usercykesiopka.bmo@gmail.com
push dateMon, 03 Aug 2015 10:16:16 +0000
reviewerstn
bugs1181863
milestone42.0a1
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();