Bug 1383404 - Part 4. imgTools::DecodeImage should set the source size hint to optimize the allocation. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Tue, 01 Aug 2017 06:59:12 -0400
changeset 420919 729621d1ffac9f5c761222c3ab3df08e97530040
parent 420918 8d5e41b9498b971f3e4b0f704fa8cd81ccdac10e
child 420920 41faadcda947800651995e706f2f4e547832db4e
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1383404
milestone56.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 1383404 - Part 4. imgTools::DecodeImage should set the source size hint to optimize the allocation. r=tnikkel
image/ImageFactory.cpp
image/ImageFactory.h
image/imgTools.cpp
--- a/image/ImageFactory.cpp
+++ b/image/ImageFactory.cpp
@@ -119,32 +119,57 @@ ImageFactory::CreateImage(nsIRequest* aR
 template <typename T>
 static already_AddRefed<Image>
 BadImage(const char* aMessage, RefPtr<T>& aImage)
 {
   aImage->SetHasError();
   return aImage.forget();
 }
 
+static void
+SetSourceSizeHint(RasterImage* aImage, uint32_t aSize)
+{
+  // Pass anything usable on so that the RasterImage can preallocate
+  // its source buffer.
+  if (aSize == 0) {
+    return;
+  }
+
+  // Bound by something reasonable
+  uint32_t sizeHint = std::min<uint32_t>(aSize, 20000000);
+  nsresult rv = aImage->SetSourceSizeHint(sizeHint);
+  if (NS_FAILED(rv)) {
+    // Flush memory, try to get some back, and try again.
+    rv = nsMemory::HeapMinimize(true);
+    nsresult rv2 = aImage->SetSourceSizeHint(sizeHint);
+    // If we've still failed at this point, things are going downhill.
+    if (NS_FAILED(rv) || NS_FAILED(rv2)) {
+      NS_WARNING("About to hit OOM in imagelib!");
+    }
+  }
+}
+
 /* static */ already_AddRefed<Image>
-ImageFactory::CreateAnonymousImage(const nsCString& aMimeType)
+ImageFactory::CreateAnonymousImage(const nsCString& aMimeType,
+                                   uint32_t aSizeHint /* = 0 */)
 {
   nsresult rv;
 
   RefPtr<RasterImage> newImage = new RasterImage();
 
   RefPtr<ProgressTracker> newTracker = new ProgressTracker();
   newTracker->SetImage(newImage);
   newImage->SetProgressTracker(newTracker);
 
   rv = newImage->Init(aMimeType.get(), Image::INIT_FLAG_SYNC_LOAD);
   if (NS_FAILED(rv)) {
     return BadImage("RasterImage::Init failed", newImage);
   }
 
+  SetSourceSizeHint(newImage, aSizeHint);
   return newImage.forget();
 }
 
 /* static */ already_AddRefed<MultipartImage>
 ImageFactory::CreateMultipartImage(Image* aFirstPart,
                                    ProgressTracker* aProgressTracker)
 {
   MOZ_ASSERT(aFirstPart);
@@ -220,35 +245,17 @@ ImageFactory::CreateRasterImage(nsIReque
 
   rv = newImage->Init(aMimeType.get(), aImageFlags);
   if (NS_FAILED(rv)) {
     return BadImage("RasterImage::Init failed", newImage);
   }
 
   newImage->SetInnerWindowID(aInnerWindowId);
 
-  uint32_t len = GetContentSize(aRequest);
-
-  // Pass anything usable on so that the RasterImage can preallocate
-  // its source buffer.
-  if (len > 0) {
-    // Bound by something reasonable
-    uint32_t sizeHint = std::min<uint32_t>(len, 20000000);
-    rv = newImage->SetSourceSizeHint(sizeHint);
-    if (NS_FAILED(rv)) {
-      // Flush memory, try to get some back, and try again.
-      rv = nsMemory::HeapMinimize(true);
-      nsresult rv2 = newImage->SetSourceSizeHint(sizeHint);
-      // If we've still failed at this point, things are going downhill.
-      if (NS_FAILED(rv) || NS_FAILED(rv2)) {
-        NS_WARNING("About to hit OOM in imagelib!");
-      }
-    }
-  }
-
+  SetSourceSizeHint(newImage, GetContentSize(aRequest));
   return newImage.forget();
 }
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateVectorImage(nsIRequest* aRequest,
                                 ProgressTracker* aProgressTracker,
                                 const nsCString& aMimeType,
                                 ImageURL* aURI,
--- a/image/ImageFactory.h
+++ b/image/ImageFactory.h
@@ -46,19 +46,20 @@ public:
                                              ImageURL* aURI,
                                              bool aIsMultiPart,
                                              uint32_t aInnerWindowId);
   /**
    * Creates a new image which isn't associated with a URI or loaded through
    * the usual image loading mechanism.
    *
    * @param aMimeType      The mimetype of the image.
+   * @param aSizeHint      The length of the source data for the image.
    */
   static already_AddRefed<Image>
-  CreateAnonymousImage(const nsCString& aMimeType);
+  CreateAnonymousImage(const nsCString& aMimeType, uint32_t aSizeHint = 0);
 
   /**
    * Creates a new multipart/x-mixed-replace image wrapper, and initializes it
    * with the first part. Subsequent parts should be passed to the existing
    * MultipartImage via MultipartImage::BeginTransitionToPart().
    *
    * @param aFirstPart       An image containing the first part of the multipart
    *                         stream.
--- a/image/imgTools.cpp
+++ b/image/imgTools.cpp
@@ -63,41 +63,42 @@ imgTools::DecodeImage(nsIInputStream* aI
                       imgIContainer** aContainer)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsresult rv;
 
   NS_ENSURE_ARG_POINTER(aInStr);
 
-  // Create a new image container to hold the decoded data.
-  nsAutoCString mimeType(aMimeType);
-  RefPtr<image::Image> image = ImageFactory::CreateAnonymousImage(mimeType);
-  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
-
-  if (image->HasError()) {
-    return NS_ERROR_FAILURE;
-  }
-
   // Prepare the input stream.
   nsCOMPtr<nsIInputStream> inStream = aInStr;
   if (!NS_InputStreamIsBuffered(aInStr)) {
     nsCOMPtr<nsIInputStream> bufStream;
     rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), aInStr, 1024);
     if (NS_SUCCEEDED(rv)) {
       inStream = bufStream;
     }
   }
 
   // Figure out how much data we've been passed.
   uint64_t length;
   rv = inStream->Available(&length);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(length <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
 
+  // Create a new image container to hold the decoded data.
+  nsAutoCString mimeType(aMimeType);
+  RefPtr<image::Image> image =
+    ImageFactory::CreateAnonymousImage(mimeType, uint32_t(length));
+  RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
+
+  if (image->HasError()) {
+    return NS_ERROR_FAILURE;
+  }
+
   // Send the source data to the Image.
   rv = image->OnImageDataAvailable(nullptr, nullptr, inStream, 0,
                                    uint32_t(length));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Let the Image know we've sent all the data.
   rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
   tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);