Bug 1370412 - Part 5. Add ImageSurfaceCache factor of 2 mode size calculations. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Tue, 05 Sep 2017 07:58:45 -0400
changeset 430939 536e6a1d3b4f990917a5d97765b29b25180512b7
parent 430938 fcc167260154d23e5588efcd316121f647d1a1e6
child 430940 9d1a5ce9c33350d2deb004808e8c65248ac1dc7a
push id1567
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 12:36:05 +0000
treeherdermozilla-release@e512c14a0406 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1370412
milestone57.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 1370412 - Part 5. Add ImageSurfaceCache factor of 2 mode size calculations. r=tnikkel
image/SurfaceCache.cpp
--- a/image/SurfaceCache.cpp
+++ b/image/SurfaceCache.cpp
@@ -397,19 +397,76 @@ public:
     // we do not prevent decoding of the image at all its native sizes. It does
     // not guarantee we will provide a surface at that size however (i.e. many
     // other sized surfaces are requested, in addition to the native sizes).
     thresholdSurfaces += nativeSizes;
     if (mSurfaces.Count() <= static_cast<uint32_t>(thresholdSurfaces)) {
       return;
     }
 
+    // Get our native size. While we know the image should be fully decoded,
+    // if it is an SVG, it is valid to have a zero size. We can't do compacting
+    // in that case because we need to know the width/height ratio to define a
+    // candidate set.
+    IntSize nativeSize;
+    if (NS_FAILED(image->GetWidth(&nativeSize.width)) ||
+        NS_FAILED(image->GetHeight(&nativeSize.height)) ||
+        nativeSize.IsEmpty()) {
+      return;
+    }
+
+    // We have a valid size, we can change modes.
     mFactor2Mode = true;
   }
 
+  IntSize SuggestedSize(const IntSize& aSize) const
+  {
+    // When not in factor of 2 mode, we can always decode at the given size.
+    if (!mFactor2Mode) {
+      return aSize;
+    }
+
+    MOZ_ASSERT(!IsEmpty());
+
+    // This bit of awkwardness gets the largest native size of the image.
+    auto iter = ConstIter();
+    NotNull<CachedSurface*> firstSurface = WrapNotNull(iter.UserData());
+    Image* image = static_cast<Image*>(firstSurface->GetImageKey());
+    IntSize factorSize;
+    if (NS_FAILED(image->GetWidth(&factorSize.width)) ||
+        NS_FAILED(image->GetHeight(&factorSize.height)) ||
+        factorSize.IsEmpty()) {
+      // We should not have entered factor of 2 mode without a valid size, and
+      // several successfully decoded surfaces.
+      MOZ_ASSERT_UNREACHABLE("Expected valid native size!");
+      return aSize;
+    }
+
+    // Start with the native size as the best first guess.
+    IntSize bestSize = factorSize;
+    factorSize.width /= 2;
+    factorSize.height /= 2;
+
+    while (!factorSize.IsEmpty()) {
+      if (!CompareArea(aSize, bestSize, factorSize)) {
+        // This size is not better than the last. Since we proceed from largest
+        // to smallest, we know that the next size will not be better if the
+        // previous size was rejected. Break early.
+        break;
+      }
+
+      // The current factor of 2 size is better than the last selected size.
+      bestSize = factorSize;
+      factorSize.width /= 2;
+      factorSize.height /= 2;
+    }
+
+    return bestSize;
+  }
+
   bool CompareArea(const IntSize& aIdealSize,
                    const IntSize& aBestSize,
                    const IntSize& aSize) const
   {
     // Compare sizes. We use an area-based heuristic here instead of computing a
     // truly optimal answer, since it seems very unlikely to make a difference
     // for realistic sizes.
     int64_t idealArea = AreaOfIntSize(aIdealSize);