Bug 1462431 - Expand image downscale-on-decode to perform best effort sizing. r=tnikkel
☠☠ backed out by 7d3ae4f78bd1 ☠ ☠
authorAndrew Osmond <aosmond@mozilla.com>
Thu, 17 May 2018 19:15:18 -0400
changeset 418789 272880e5ca08
parent 418788 8ad87d070ec9
child 418790 4481e5d95c62
push id34013
push userdluca@mozilla.com
push date2018-05-18 09:56 +0000
treeherdermozilla-central@11ee70f24ea5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1462431
milestone62.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 1462431 - Expand image downscale-on-decode to perform best effort sizing. r=tnikkel When an image must be upscaled in only one dimension, we can downscale-on-decode to a closer size than the native size. For example, if an image is 32000x100, and we want 200x200, we can choose to decode at 200x100. This allows drawing to scale in only one dimension, and use less memory to store the decoded data, all the while not affecting the display quality.
image/RasterImage.cpp
image/RasterImage.h
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -335,18 +335,17 @@ RasterImage::LookupFrame(const IntSize& 
   MOZ_ASSERT(NS_IsMainThread());
 
   // If we're opaque, we don't need to care about premultiplied alpha, because
   // that can only matter for frames with transparency.
   if (IsOpaque()) {
     aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
   }
 
-  IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags)
-                        ? aSize : mSize;
+  IntSize requestedSize = GetDownscaleDecodeSize(aSize, aFlags);
   if (requestedSize.IsEmpty()) {
     // Can't decode to a surface of zero size.
     return LookupResult(MatchType::NOT_FOUND);
   }
 
   LookupResult result =
     LookupFrameInternal(requestedSize, aFlags, aPlaybackType);
 
@@ -633,21 +632,17 @@ IntSize
 RasterImage::GetImageContainerSize(LayerManager* aManager,
                                    const IntSize& aSize,
                                    uint32_t aFlags)
 {
   if (!IsImageContainerAvailableAtSize(aManager, aSize, aFlags)) {
     return IntSize(0, 0);
   }
 
-  if (!CanDownscaleDuringDecode(aSize, aFlags)) {
-    return mSize;
-  }
-
-  return aSize;
+  return GetDownscaleDecodeSize(aSize, aFlags);
 }
 
 NS_IMETHODIMP_(bool)
 RasterImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
 {
   return IsImageContainerAvailableAtSize(aManager, mSize, aFlags);
 }
 
@@ -1367,49 +1362,56 @@ HaveSkia()
 {
 #ifdef MOZ_ENABLE_SKIA
   return true;
 #else
   return false;
 #endif
 }
 
-bool
-RasterImage::CanDownscaleDuringDecode(const IntSize& aSize, uint32_t aFlags)
+IntSize
+RasterImage::GetDownscaleDecodeSize(const IntSize& aSize, uint32_t aFlags)
 {
   // Check basic requirements: downscale-during-decode is enabled, Skia is
   // available, this image isn't transient, we have all the source data and know
   // our size, and the flags allow us to do it.
-  if (!mHasSize || mTransient || !HaveSkia() ||
+  if (!mHasSize || mTransient || !HaveSkia() || aSize == mSize ||
       !gfxPrefs::ImageDownscaleDuringDecodeEnabled() ||
       !(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
-    return false;
+    return mSize;
   }
 
   // We don't downscale animated images during decode.
   if (mAnimationState) {
-    return false;
-  }
-
-  // Never upscale.
-  if (aSize.width >= mSize.width || aSize.height >= mSize.height) {
-    return false;
+    return mSize;
   }
 
   // Zero or negative width or height is unacceptable.
   if (aSize.width < 1 || aSize.height < 1) {
-    return false;
+    return mSize;
+  }
+
+  // We never upscale, but we may partially downscale nearer to the desired
+  // size if only one of the dimensions exceeds the native size.
+  IntSize decodeSize(aSize);
+  if (aSize.width > mSize.width) {
+    if (aSize.height > mSize.height) {
+      return mSize;
+    }
+    decodeSize.width = mSize.width;
+  } else if (aSize.height > mSize.height) {
+    decodeSize.height = mSize.height;
   }
 
   // There's no point in scaling if we can't store the result.
-  if (!SurfaceCache::CanHold(aSize)) {
-    return false;
+  if (!SurfaceCache::CanHold(decodeSize)) {
+    return mSize;
   }
 
-  return true;
+  return decodeSize;
 }
 
 ImgDrawResult
 RasterImage::DrawInternal(DrawableSurface&& aSurface,
                           gfxContext* aContext,
                           const IntSize& aSize,
                           const ImageRegion& aRegion,
                           SamplingFilter aSamplingFilter,
@@ -1429,17 +1431,18 @@ RasterImage::DrawInternal(DrawableSurfac
   IntSize finalSize = aSurface->GetImageSize();
   bool couldRedecodeForBetterFrame = false;
   if (finalSize != aSize) {
     gfx::Size scale(double(aSize.width) / finalSize.width,
                     double(aSize.height) / finalSize.height);
     aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
     region.Scale(1.0 / scale.width, 1.0 / scale.height);
 
-    couldRedecodeForBetterFrame = CanDownscaleDuringDecode(aSize, aFlags);
+    couldRedecodeForBetterFrame =
+      GetDownscaleDecodeSize(aSize, aFlags) != mSize;
   }
 
   if (!aSurface->Draw(aContext, region, aSamplingFilter, aFlags, aOpacity)) {
     RecoverFromInvalidFrames(aSize, aFlags);
     return ImgDrawResult::TEMPORARY_ERROR;
   }
   if (!frameIsFinished) {
     return ImgDrawResult::INCOMPLETE;
@@ -1854,21 +1857,18 @@ RasterImage::OptimalImageSizeForDest(con
   MOZ_ASSERT(aDest.width >= 0 || ceil(aDest.width) <= INT32_MAX ||
              aDest.height >= 0 || ceil(aDest.height) <= INT32_MAX,
              "Unexpected destination size");
 
   if (mSize.IsEmpty() || aDest.IsEmpty()) {
     return IntSize(0, 0);
   }
 
-  IntSize destSize = IntSize::Ceil(aDest.width, aDest.height);
-
-  if (aSamplingFilter == SamplingFilter::GOOD &&
-      CanDownscaleDuringDecode(destSize, aFlags)) {
-    return destSize;
+  if (aSamplingFilter != SamplingFilter::GOOD) {
+    return mSize;
   }
 
-  // We can't scale to this size. Use our intrinsic size for now.
-  return mSize;
+  IntSize destSize = IntSize::Ceil(aDest.width, aDest.height);
+  return GetDownscaleDecodeSize(destSize, aFlags);
 }
 
 } // namespace image
 } // namespace mozilla
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -430,19 +430,19 @@ private: // data
 
   TimeStamp mDrawStartTime;
 
 
   //////////////////////////////////////////////////////////////////////////////
   // Scaling.
   //////////////////////////////////////////////////////////////////////////////
 
-  // Determines whether we can downscale during decode with the given
-  // parameters.
-  bool CanDownscaleDuringDecode(const nsIntSize& aSize, uint32_t aFlags);
+  // Determines the decode size depending on whether we can downscale during
+  // decode with the given parameters.
+  gfx::IntSize GetDownscaleDecodeSize(const nsIntSize& aSize, uint32_t aFlags);
 
 
   // Error handling.
   void DoError();
 
   class HandleErrorWorker : public Runnable
   {
   public: