Bug 1146663 (Part 4) - Make all RasterImages support downscale-during-decode. r=tn
authorSeth Fowler <mark.seth.fowler@gmail.com>
Sat, 19 Sep 2015 16:21:05 -0700
changeset 263439 07d6fcc70e7c0476088f45264963505a63ebec53
parent 263438 77357a5a1ad1a0306b1f1f4688baf2d5312b315b
child 263440 c0d3f6e2a3e33f8b45bf4039126cbbe004448e3e
push id65309
push usermfowler@mozilla.com
push dateSat, 19 Sep 2015 23:21:39 +0000
treeherdermozilla-inbound@c0d3f6e2a3e3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1146663
milestone43.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 1146663 (Part 4) - Make all RasterImages support downscale-during-decode. r=tn
image/Image.h
image/ImageFactory.cpp
image/RasterImage.cpp
image/RasterImage.h
--- a/image/Image.h
+++ b/image/Image.h
@@ -142,29 +142,24 @@ public:
    * possible, regardless of what our heuristics say.
    *
    * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time
    * before being destroyed. (For example, containers for
    * multipart/x-mixed-replace image parts fall into this category.) If this
    * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must
    * not be set.
    *
-   * INIT_FLAG_DOWNSCALE_DURING_DECODE: The container should attempt to
-   * downscale images during decoding instead of decoding them to their
-   * intrinsic size.
-   *
    * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so
    * it should avoid relying on async workers to get the container ready.
    */
   static const uint32_t INIT_FLAG_NONE                     = 0x0;
   static const uint32_t INIT_FLAG_DISCARDABLE              = 0x1;
   static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY       = 0x2;
   static const uint32_t INIT_FLAG_TRANSIENT                = 0x4;
-  static const uint32_t INIT_FLAG_DOWNSCALE_DURING_DECODE  = 0x8;
-  static const uint32_t INIT_FLAG_SYNC_LOAD                = 0x10;
+  static const uint32_t INIT_FLAG_SYNC_LOAD                = 0x8;
 
   virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0;
   virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {}
 
   /**
    * The size, in bytes, occupied by the compressed source data of the image.
    * If MallocSizeOf does not work on this platform, uses a fallback approach to
    * ensure that something reasonable is always returned.
--- a/image/ImageFactory.cpp
+++ b/image/ImageFactory.cpp
@@ -27,78 +27,57 @@
 
 namespace mozilla {
 namespace image {
 
 /*static*/ void
 ImageFactory::Initialize()
 { }
 
-static bool
-ShouldDownscaleDuringDecode(const nsCString& aMimeType)
-{
-  DecoderType type = DecoderFactory::GetDecoderType(aMimeType.get());
-  return type == DecoderType::JPEG ||
-         type == DecoderType::ICON ||
-         type == DecoderType::ICO ||
-         type == DecoderType::PNG ||
-         type == DecoderType::BMP ||
-         type == DecoderType::GIF;
-}
-
 static uint32_t
 ComputeImageFlags(ImageURL* uri, const nsCString& aMimeType, bool isMultiPart)
 {
   nsresult rv;
 
   // We default to the static globals.
   bool isDiscardable = gfxPrefs::ImageMemDiscardable();
   bool doDecodeImmediately = gfxPrefs::ImageDecodeImmediatelyEnabled();
-  bool doDownscaleDuringDecode = gfxPrefs::ImageDownscaleDuringDecodeEnabled();
 
   // We want UI to be as snappy as possible and not to flicker. Disable
   // discarding for chrome URLS.
   bool isChrome = false;
   rv = uri->SchemeIs("chrome", &isChrome);
   if (NS_SUCCEEDED(rv) && isChrome) {
     isDiscardable = false;
   }
 
   // We don't want resources like the "loading" icon to be discardable either.
   bool isResource = false;
   rv = uri->SchemeIs("resource", &isResource);
   if (NS_SUCCEEDED(rv) && isResource) {
     isDiscardable = false;
   }
 
-  // Downscale-during-decode is only enabled for certain content types.
-  if (doDownscaleDuringDecode && !ShouldDownscaleDuringDecode(aMimeType)) {
-    doDownscaleDuringDecode = false;
-  }
-
   // For multipart/x-mixed-replace, we basically want a direct channel to the
   // decoder. Disable everything for this case.
   if (isMultiPart) {
-    isDiscardable = doDownscaleDuringDecode = false;
+    isDiscardable = false;
   }
 
   // We have all the information we need.
   uint32_t imageFlags = Image::INIT_FLAG_NONE;
   if (isDiscardable) {
     imageFlags |= Image::INIT_FLAG_DISCARDABLE;
   }
   if (doDecodeImmediately) {
     imageFlags |= Image::INIT_FLAG_DECODE_IMMEDIATELY;
   }
   if (isMultiPart) {
     imageFlags |= Image::INIT_FLAG_TRANSIENT;
   }
-  if (doDownscaleDuringDecode) {
-    imageFlags |= Image::INIT_FLAG_DOWNSCALE_DURING_DECODE;
-  }
 
   return imageFlags;
 }
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateImage(nsIRequest* aRequest,
                           ProgressTracker* aProgressTracker,
                           const nsCString& aMimeType,
@@ -138,23 +117,17 @@ ImageFactory::CreateAnonymousImage(const
   nsresult rv;
 
   nsRefPtr<RasterImage> newImage = new RasterImage();
 
   nsRefPtr<ProgressTracker> newTracker = new ProgressTracker();
   newTracker->SetImage(newImage);
   newImage->SetProgressTracker(newTracker);
 
-  uint32_t imageFlags = Image::INIT_FLAG_SYNC_LOAD;
-  if (gfxPrefs::ImageDownscaleDuringDecodeEnabled() &&
-      ShouldDownscaleDuringDecode(aMimeType)) {
-    imageFlags |= Image::INIT_FLAG_DOWNSCALE_DURING_DECODE;
-  }
-
-  rv = newImage->Init(aMimeType.get(), imageFlags);
+  rv = newImage->Init(aMimeType.get(), Image::INIT_FLAG_SYNC_LOAD);
   if (NS_FAILED(rv)) {
     return BadImage("RasterImage::Init failed", newImage);
   }
 
   return newImage.forget();
 }
 
 /* static */ already_AddRefed<MultipartImage>
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -86,17 +86,16 @@ RasterImage::RasterImage(ImageURL* aURI 
   mSourceBuffer(new SourceBuffer()),
   mFrameCount(0),
   mHasSize(false),
   mTransient(false),
   mSyncLoad(false),
   mDiscardable(false),
   mHasSourceData(false),
   mHasBeenDecoded(false),
-  mDownscaleDuringDecode(false),
   mPendingAnimation(false),
   mAnimationFinished(false),
   mWantFullDecode(false)
 {
   Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
 }
 
 //******************************************************************************
@@ -122,33 +121,25 @@ RasterImage::Init(const char* aMimeType,
   }
 
   // Not sure an error can happen before init, but be safe
   if (mError) {
     return NS_ERROR_FAILURE;
   }
 
   // We want to avoid redecodes for transient images.
-  MOZ_ASSERT(!(aFlags & INIT_FLAG_TRANSIENT) ||
-               (!(aFlags & INIT_FLAG_DISCARDABLE) &&
-                !(aFlags & INIT_FLAG_DOWNSCALE_DURING_DECODE)),
-             "Illegal init flags for transient image");
+  MOZ_ASSERT_IF(aFlags & INIT_FLAG_TRANSIENT,
+                !(aFlags & INIT_FLAG_DISCARDABLE));
 
   // Store initialization data
   mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
   mWantFullDecode = !!(aFlags & INIT_FLAG_DECODE_IMMEDIATELY);
   mTransient = !!(aFlags & INIT_FLAG_TRANSIENT);
-  mDownscaleDuringDecode = !!(aFlags & INIT_FLAG_DOWNSCALE_DURING_DECODE);
   mSyncLoad = !!(aFlags & INIT_FLAG_SYNC_LOAD);
 
-#ifndef MOZ_ENABLE_SKIA
-  // Downscale-during-decode requires Skia.
-  mDownscaleDuringDecode = false;
-#endif
-
   // Use the MIME type to select a decoder type, and make sure there *is* a
   // decoder for this MIME type.
   NS_ENSURE_ARG_POINTER(aMimeType);
   mDecoderType = DecoderFactory::GetDecoderType(aMimeType);
   if (mDecoderType == DecoderType::UNKNOWN) {
     return NS_ERROR_FAILURE;
   }
 
@@ -1202,33 +1193,29 @@ RasterImage::RequestDecodeForSize(const 
     return NS_ERROR_FAILURE;
   }
 
   if (!mHasSize) {
     mWantFullDecode = true;
     return NS_OK;
   }
 
-  // Fall back to our intrinsic size if we don't support
-  // downscale-during-decode.
-  IntSize targetSize = mDownscaleDuringDecode ? aSize : mSize;
-
   // Decide whether to sync decode images we can decode quickly. Here we are
   // explicitly trading off flashing for responsiveness in the case that we're
   // redecoding an image (see bug 845147).
   bool shouldSyncDecodeIfFast =
     !mHasBeenDecoded && (aFlags & FLAG_SYNC_DECODE_IF_FAST);
 
   uint32_t flags = shouldSyncDecodeIfFast
                  ? aFlags
                  : aFlags & ~FLAG_SYNC_DECODE_IF_FAST;
 
   // Look up the first frame of the image, which will implicitly start decoding
   // if it's not available right now.
-  LookupFrame(0, targetSize, flags);
+  LookupFrame(0, aSize, flags);
 
   return NS_OK;
 }
 
 static void
 LaunchDecoder(Decoder* aDecoder,
               RasterImage* aImage,
               uint32_t aFlags,
@@ -1268,30 +1255,24 @@ RasterImage::Decode(const IntSize& aSize
   }
 
   // If we don't have a size yet, we can't do any other decoding.
   if (!mHasSize) {
     mWantFullDecode = true;
     return NS_OK;
   }
 
-  if (mDownscaleDuringDecode) {
-    // We're about to decode again, which may mean that some of the previous
-    // sizes we've decoded at aren't useful anymore. We can allow them to
-    // expire from the cache by unlocking them here. When the decode finishes,
-    // it will send an invalidation that will cause all instances of this image
-    // to redraw. If this image is locked, any surfaces that are still useful
-    // will become locked again when LookupFrame touches them, and the remainder
-    // will eventually expire.
-    SurfaceCache::UnlockSurfaces(ImageKey(this));
-  }
-
-  MOZ_ASSERT(mDownscaleDuringDecode || aSize == mSize,
-             "Can only decode to our intrinsic size if we're not allowed to "
-             "downscale-during-decode");
+  // We're about to decode again, which may mean that some of the previous sizes
+  // we've decoded at aren't useful anymore. We can allow them to expire from
+  // the cache by unlocking them here. When the decode finishes, it will send an
+  // invalidation that will cause all instances of this image to redraw. If this
+  // image is locked, any surfaces that are still useful will become locked
+  // again when LookupFrame touches them, and the remainder will eventually
+  // expire.
+  SurfaceCache::UnlockSurfaces(ImageKey(this));
 
   Maybe<IntSize> targetSize = mSize != aSize ? Some(aSize) : Nothing();
 
   // Determine which flags we need to decode this image with.
   DecoderFlags decoderFlags = DefaultDecoderFlags();
   if (aFlags & FLAG_ASYNC_NOTIFY) {
     decoderFlags |= DecoderFlags::ASYNC_NOTIFY;
   }
@@ -1406,23 +1387,33 @@ RasterImage::RecoverFromInvalidFrames(co
     ResetAnimation();
     return;
   }
 
   // For non-animated images, it's fine to recover using an async decode.
   Decode(aSize, aFlags);
 }
 
+static bool
+HaveSkia()
+{
+#ifdef MOZ_ENABLE_SKIA
+  return true;
+#else
+  return false;
+#endif
+}
+
 bool
 RasterImage::CanDownscaleDuringDecode(const IntSize& aSize, uint32_t aFlags)
 {
-  // Check basic requirements: downscale-during-decode is enabled for this
-  // image, we have all the source data and know our size, the flags allow us to
-  // do it, and a 'good' filter is being used.
-  if (!mDownscaleDuringDecode || !mHasSize ||
+  // 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() ||
       !gfxPrefs::ImageDownscaleDuringDecodeEnabled() ||
       !(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
     return false;
   }
 
   // We don't downscale animated images during decode.
   if (mAnim) {
     return false;
@@ -1463,18 +1454,17 @@ RasterImage::DrawInternal(DrawableFrameR
   IntSize finalSize = aFrameRef->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 = mDownscaleDuringDecode &&
-                                  CanDownscaleDuringDecode(aSize, aFlags);
+    couldRedecodeForBetterFrame = CanDownscaleDuringDecode(aSize, aFlags);
   }
 
   if (!aFrameRef->Draw(aContext, region, aFilter, aFlags)) {
     RecoverFromInvalidFrames(aSize, aFlags);
     return DrawResult::TEMPORARY_ERROR;
   }
   if (!frameIsComplete) {
     return DrawResult::INCOMPLETE;
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -300,20 +300,16 @@ private:
 
   /**
    * Creates and runs a decoder, either synchronously or asynchronously
    * according to @aFlags. Decodes at the provided target size @aSize, using
    * decode flags @aFlags.
    *
    * It's an error to call Decode() before this image's intrinsic size is
    * available. A metadata decode must successfully complete first.
-   *
-   * If downscale-during-decode is not enabled for this image (i.e., if
-   * mDownscaleDuringDecode is false), it is an error to pass an @aSize value
-   * different from this image's intrinsic size.
    */
   NS_IMETHOD Decode(const gfx::IntSize& aSize, uint32_t aFlags);
 
   /**
    * Creates and runs a metadata decoder, either synchronously or
    * asynchronously according to @aFlags.
    */
   NS_IMETHOD DecodeMetadata(uint32_t aFlags);
@@ -393,17 +389,16 @@ private: // data
 
   // Boolean flags (clustered together to conserve space):
   bool                       mHasSize:1;       // Has SetSize() been called?
   bool                       mTransient:1;     // Is the image short-lived?
   bool                       mSyncLoad:1;      // Are we loading synchronously?
   bool                       mDiscardable:1;   // Is container discardable?
   bool                       mHasSourceData:1; // Do we have source data?
   bool                       mHasBeenDecoded:1; // Decoded at least once?
-  bool                       mDownscaleDuringDecode:1;
 
   // Whether we're waiting to start animation. If we get a StartAnimation() call
   // but we don't yet have more than one frame, mPendingAnimation is set so that
   // we know to start animation later if/when we have more frames.
   bool                       mPendingAnimation:1;
 
   // Whether the animation can stop, due to running out
   // of frames, or no more owning request