Backed out 4 changesets (bug 1201796) for crashes a=backout
authorWes Kocher <wkocher@mozilla.com>
Mon, 21 Sep 2015 13:16:34 -0700
changeset 296115 577c248da8de42756be578bc4f09301dbc5998b2
parent 296114 968702bfd84b2c01ecee6591e0ebcb195e7afff1
child 296116 9087b63b0cd27b6cd2dd80daaa6a5040ed5971ea
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1201796
milestone43.0a2
backs outc5f5f19feef1a2339a85f2acab0a900239011619
3685c9cadbed8c7c7460a8df12f07a08868421de
7f20c039c994ae7c3d49ee1a3765c89fd349d462
4ce4da0007104e7e45c30bb7712ff55725ca0faf
Backed out 4 changesets (bug 1201796) for crashes a=backout Backed out changeset c5f5f19feef1 (bug 1201796) Backed out changeset 3685c9cadbed (bug 1201796) Backed out changeset 7f20c039c994 (bug 1201796) Backed out changeset 4ce4da000710 (bug 1201796)
image/ClippedImage.cpp
image/ClippedImage.h
image/DynamicImage.cpp
image/FrozenImage.cpp
image/FrozenImage.h
image/ImageFactory.cpp
image/ImageWrapper.cpp
image/OrientedImage.cpp
image/OrientedImage.h
image/RasterImage.cpp
image/RasterImage.h
image/VectorImage.cpp
image/decoders/nsICODecoder.cpp
image/decoders/nsICODecoder.h
image/imgIContainer.idl
image/imgTools.cpp
image/test/crashtests/crashtests.list
image/test/crashtests/invalid_ico_height.ico
image/test/crashtests/invalid_ico_width.ico
image/test/mochitest/test_has_transparency.html
image/test/reftest/ico/cur/pointer.cur
image/test/reftest/ico/ico-bmp-corrupted/invalid_ico_height.ico
image/test/reftest/ico/ico-bmp-corrupted/invalid_ico_width.ico
image/test/reftest/ico/ico-bmp-corrupted/reftest.list
image/test/reftest/ico/ico-mixed/reftest.list
image/test/reftest/ico/ico-png/ico-size-256x256-png.ico
image/test/reftest/ico/ico-png/transparent-png.ico
image/test/unit/image1png16x16.jpg
image/test/unit/image2jpg16x16.png
image/test/unit/test_imgtools.js
toolkit/components/places/tests/favicons/expected-favicon-big32.jpg.png
toolkit/components/places/tests/favicons/expected-favicon-big64.png.png
--- a/image/ClippedImage.cpp
+++ b/image/ClippedImage.cpp
@@ -215,26 +215,16 @@ ClippedImage::GetIntrinsicRatio(nsSize* 
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 ClippedImage::GetFrame(uint32_t aWhichFrame,
                        uint32_t aFlags)
 {
   return GetFrameInternal(mClip.Size(), Nothing(), aWhichFrame, aFlags);
 }
 
-NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
-ClippedImage::GetFrameAtSize(const IntSize& aSize,
-                             uint32_t aWhichFrame,
-                             uint32_t aFlags)
-{
-  // XXX(seth): It'd be nice to support downscale-during-decode for this case,
-  // but right now we just fall back to the intrinsic size.
-  return GetFrame(aWhichFrame, aFlags);
-}
-
 already_AddRefed<SourceSurface>
 ClippedImage::GetFrameInternal(const nsIntSize& aSize,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t aWhichFrame,
                                uint32_t aFlags)
 {
   if (!ShouldClip()) {
     return InnerImage()->GetFrame(aWhichFrame, aFlags);
--- a/image/ClippedImage.h
+++ b/image/ClippedImage.h
@@ -32,20 +32,16 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetWidth(int32_t* aWidth) override;
   NS_IMETHOD GetHeight(int32_t* aHeight) override;
   NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override;
   NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
   NS_IMETHOD_(already_AddRefed<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
-  NS_IMETHOD_(already_AddRefed<SourceSurface>)
-    GetFrameAtSize(const gfx::IntSize& aSize,
-                   uint32_t aWhichFrame,
-                   uint32_t aFlags) override;
   NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
                                               uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
--- a/image/DynamicImage.cpp
+++ b/image/DynamicImage.cpp
@@ -163,36 +163,28 @@ DynamicImage::GetAnimated(bool* aAnimate
   return NS_OK;
 }
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 DynamicImage::GetFrame(uint32_t aWhichFrame,
                        uint32_t aFlags)
 {
   gfxIntSize size(mDrawable->Size());
-  return GetFrameAtSize(IntSize(size.width, size.height),
-                        aWhichFrame,
-                        aFlags);
-}
 
-NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
-DynamicImage::GetFrameAtSize(const IntSize& aSize,
-                             uint32_t aWhichFrame,
-                             uint32_t aFlags)
-{
   RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
-    CreateOffscreenContentDrawTarget(aSize, SurfaceFormat::B8G8R8A8);
+    CreateOffscreenContentDrawTarget(IntSize(size.width, size.height),
+                                     SurfaceFormat::B8G8R8A8);
   if (!dt) {
     gfxWarning() <<
       "DynamicImage::GetFrame failed in CreateOffscreenContentDrawTarget";
     return nullptr;
   }
   nsRefPtr<gfxContext> context = new gfxContext(dt);
 
-  auto result = Draw(context, aSize, ImageRegion::Create(aSize),
+  auto result = Draw(context, size, ImageRegion::Create(size),
                      aWhichFrame, GraphicsFilter::FILTER_NEAREST,
                      Nothing(), aFlags);
 
   return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr;
 }
 
 NS_IMETHODIMP_(bool)
 DynamicImage::IsOpaque()
--- a/image/FrozenImage.cpp
+++ b/image/FrozenImage.cpp
@@ -39,24 +39,16 @@ FrozenImage::GetAnimated(bool* aAnimated
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 FrozenImage::GetFrame(uint32_t aWhichFrame,
                       uint32_t aFlags)
 {
   return InnerImage()->GetFrame(FRAME_FIRST, aFlags);
 }
 
-NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
-FrozenImage::GetFrameAtSize(const IntSize& aSize,
-                            uint32_t aWhichFrame,
-                            uint32_t aFlags)
-{
-  return InnerImage()->GetFrameAtSize(aSize, FRAME_FIRST, aFlags);
-}
-
 NS_IMETHODIMP_(bool)
 FrozenImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
 {
   return false;
 }
 
 NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
 FrozenImage::GetImageContainer(layers::LayerManager* aManager, uint32_t aFlags)
--- a/image/FrozenImage.h
+++ b/image/FrozenImage.h
@@ -32,20 +32,16 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual void IncrementAnimationConsumers() override;
   virtual void DecrementAnimationConsumers() override;
 
   NS_IMETHOD GetAnimated(bool* aAnimated) override;
   NS_IMETHOD_(already_AddRefed<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
-  NS_IMETHOD_(already_AddRefed<SourceSurface>)
-    GetFrameAtSize(const gfx::IntSize& aSize,
-                   uint32_t aWhichFrame,
-                   uint32_t aFlags) override;
   NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
                                               uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
--- a/image/ImageFactory.cpp
+++ b/image/ImageFactory.cpp
@@ -33,17 +33,16 @@ 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)
 {
@@ -138,23 +137,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/ImageWrapper.cpp
+++ b/image/ImageWrapper.cpp
@@ -169,24 +169,16 @@ ImageWrapper::GetAnimated(bool* aAnimate
 
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 ImageWrapper::GetFrame(uint32_t aWhichFrame,
                        uint32_t aFlags)
 {
   return mInnerImage->GetFrame(aWhichFrame, aFlags);
 }
 
-NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
-ImageWrapper::GetFrameAtSize(const IntSize& aSize,
-                             uint32_t aWhichFrame,
-                             uint32_t aFlags)
-{
-  return mInnerImage->GetFrameAtSize(aSize, aWhichFrame, aFlags);
-}
-
 NS_IMETHODIMP_(bool)
 ImageWrapper::IsOpaque()
 {
   return mInnerImage->IsOpaque();
 }
 
 NS_IMETHODIMP_(bool)
 ImageWrapper::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
--- a/image/OrientedImage.cpp
+++ b/image/OrientedImage.cpp
@@ -117,26 +117,16 @@ OrientedImage::GetFrame(uint32_t aWhichF
   ctx->Multiply(OrientationMatrix(size));
   gfxUtils::DrawPixelSnapped(ctx, drawable, size,
                              ImageRegion::Create(size),
                              surfaceFormat, GraphicsFilter::FILTER_FAST);
 
   return target->Snapshot();
 }
 
-NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
-OrientedImage::GetFrameAtSize(const IntSize& aSize,
-                              uint32_t aWhichFrame,
-                              uint32_t aFlags)
-{
-  // XXX(seth): It'd be nice to support downscale-during-decode for this case,
-  // but right now we just fall back to the intrinsic size.
-  return GetFrame(aWhichFrame, aFlags);
-}
-
 NS_IMETHODIMP_(bool)
 OrientedImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
 {
   if (mOrientation.IsIdentity()) {
     return InnerImage()->IsImageContainerAvailable(aManager, aFlags);
   }
   return false;
 }
--- a/image/OrientedImage.h
+++ b/image/OrientedImage.h
@@ -29,20 +29,16 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMETHOD GetWidth(int32_t* aWidth) override;
   NS_IMETHOD GetHeight(int32_t* aHeight) override;
   NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override;
   NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
   NS_IMETHOD_(already_AddRefed<SourceSurface>)
     GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
-  NS_IMETHOD_(already_AddRefed<SourceSurface>)
-    GetFrameAtSize(const gfx::IntSize& aSize,
-                   uint32_t aWhichFrame,
-                   uint32_t aFlags) override;
   NS_IMETHOD_(bool) IsImageContainerAvailable(layers::LayerManager* aManager,
                                               uint32_t aFlags) override;
   NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
     GetImageContainer(layers::LayerManager* aManager,
                       uint32_t aFlags) override;
   NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
                                const nsIntSize& aSize,
                                const ImageRegion& aRegion,
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -693,68 +693,54 @@ RasterImage::CopyFrame(uint32_t aWhichFr
 
 //******************************************************************************
 /* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
  *                                   in uint32_t aFlags); */
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
 RasterImage::GetFrame(uint32_t aWhichFrame,
                       uint32_t aFlags)
 {
-  return GetFrameInternal(mSize, aWhichFrame, aFlags).second().forget();
-}
-
-NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
-RasterImage::GetFrameAtSize(const IntSize& aSize,
-                            uint32_t aWhichFrame,
-                            uint32_t aFlags)
-{
-  return GetFrameInternal(aSize, aWhichFrame, aFlags).second().forget();
+  return GetFrameInternal(aWhichFrame, aFlags).second().forget();
 }
 
 Pair<DrawResult, RefPtr<SourceSurface>>
-RasterImage::GetFrameInternal(const IntSize& aSize,
-                              uint32_t aWhichFrame,
-                              uint32_t aFlags)
+RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
 {
   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
 
-  if (aSize.IsEmpty()) {
-    return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
-  }
-
   if (aWhichFrame > FRAME_MAX_VALUE) {
     return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
   }
 
   if (mError) {
     return MakePair(DrawResult::BAD_IMAGE, RefPtr<SourceSurface>());
   }
 
   // Get the frame. If it's not there, it's probably the caller's fault for
   // not waiting for the data to be loaded from the network or not passing
   // FLAG_SYNC_DECODE
   DrawableFrameRef frameRef =
-    LookupFrame(GetRequestedFrameIndex(aWhichFrame), aSize, aFlags);
+    LookupFrame(GetRequestedFrameIndex(aWhichFrame), mSize, aFlags);
   if (!frameRef) {
     // The OS threw this frame away and we couldn't redecode it.
     return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
   }
 
   // If this frame covers the entire image, we can just reuse its existing
   // surface.
   RefPtr<SourceSurface> frameSurf;
-  if (!frameRef->NeedsPadding() &&
-      frameRef->GetSize() == aSize) {
+  IntRect frameRect = frameRef->GetRect();
+  if (frameRect.x == 0 && frameRect.y == 0 &&
+      frameRect.width == mSize.width &&
+      frameRect.height == mSize.height) {
     frameSurf = frameRef->GetSurface();
   }
 
   // The image doesn't have a usable surface because it's been optimized away or
-  // because it's a partial update frame from an animation. Create one. (In this
-  // case we fall back to returning a surface at our intrinsic size, even if a
-  // different size was originally specified.)
+  // because it's a partial update frame from an animation. Create one.
   if (!frameSurf) {
     frameSurf = CopyFrame(aWhichFrame, aFlags);
   }
 
   if (!frameRef->IsImageComplete()) {
     return MakePair(DrawResult::INCOMPLETE, Move(frameSurf));
   }
 
@@ -765,17 +751,17 @@ Pair<DrawResult, nsRefPtr<layers::Image>
 RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aContainer);
 
   DrawResult drawResult;
   RefPtr<SourceSurface> surface;
   Tie(drawResult, surface) =
-    GetFrameInternal(mSize, FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
+    GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
   if (!surface) {
     // The OS threw out some or all of our buffer. We'll need to wait for the
     // redecode (which was automatically triggered by GetFrame) to complete.
     return MakePair(drawResult, nsRefPtr<layers::Image>());
   }
 
   CairoImage::Data cairoData;
   GetWidth(&cairoData.mSize.width);
--- a/image/RasterImage.h
+++ b/image/RasterImage.h
@@ -260,19 +260,17 @@ private:
                                           const ImageRegion& aRegion,
                                           GraphicsFilter aFilter,
                                           uint32_t aFlags);
 
   already_AddRefed<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
                                              uint32_t aFlags);
 
   Pair<DrawResult, RefPtr<gfx::SourceSurface>>
-    GetFrameInternal(const gfx::IntSize& aSize,
-                     uint32_t aWhichFrame,
-                     uint32_t aFlags);
+    GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags);
 
   LookupResult LookupFrameInternal(uint32_t aFrameNum,
                                    const gfx::IntSize& aSize,
                                    uint32_t aFlags);
   DrawableFrameRef LookupFrame(uint32_t aFrameNum,
                                const nsIntSize& aSize,
                                uint32_t aFlags);
   uint32_t GetCurrentFrameIndex() const;
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -663,67 +663,58 @@ VectorImage::IsOpaque()
 {
   return false; // In general, SVG content is not opaque.
 }
 
 //******************************************************************************
 /* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
  *                                   in uint32_t aFlags; */
 NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
-VectorImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags)
+VectorImage::GetFrame(uint32_t aWhichFrame,
+                      uint32_t aFlags)
 {
+  MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
+
+  if (aWhichFrame > FRAME_MAX_VALUE) {
+    return nullptr;
+  }
+
+  if (mError || !mIsFullyLoaded) {
+    return nullptr;
+  }
+
   // Look up height & width
   // ----------------------
   SVGSVGElement* svgElem = mSVGDocumentWrapper->GetRootSVGElem();
   MOZ_ASSERT(svgElem, "Should have a root SVG elem, since we finished "
                       "loading without errors");
   nsIntSize imageIntSize(svgElem->GetIntrinsicWidth(),
                          svgElem->GetIntrinsicHeight());
 
   if (imageIntSize.IsEmpty()) {
     // We'll get here if our SVG doc has a percent-valued or negative width or
     // height.
     return nullptr;
   }
 
-  return GetFrameAtSize(imageIntSize, aWhichFrame, aFlags);
-}
-
-NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
-VectorImage::GetFrameAtSize(const IntSize& aSize,
-                            uint32_t aWhichFrame,
-                            uint32_t aFlags)
-{
-  MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
-
-  if (aSize.IsEmpty()) {
-    return nullptr;
-  }
-
-  if (aWhichFrame > FRAME_MAX_VALUE) {
-    return nullptr;
-  }
-
-  if (mError || !mIsFullyLoaded) {
-    return nullptr;
-  }
-
   // Make our surface the size of what will ultimately be drawn to it.
   // (either the full image size, or the restricted region)
   RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
-    CreateOffscreenContentDrawTarget(aSize, SurfaceFormat::B8G8R8A8);
+    CreateOffscreenContentDrawTarget(IntSize(imageIntSize.width,
+                                             imageIntSize.height),
+                                     SurfaceFormat::B8G8R8A8);
   if (!dt) {
     NS_ERROR("Could not create a DrawTarget");
     return nullptr;
   }
 
   nsRefPtr<gfxContext> context = new gfxContext(dt);
 
-  auto result = Draw(context, aSize,
-                     ImageRegion::Create(aSize),
+  auto result = Draw(context, imageIntSize,
+                     ImageRegion::Create(imageIntSize),
                      aWhichFrame, GraphicsFilter::FILTER_NEAREST,
                      Nothing(), aFlags);
 
   return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr;
 }
 
 NS_IMETHODIMP_(bool)
 VectorImage::IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags)
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -9,24 +9,23 @@
 #include <stdlib.h>
 
 #include "mozilla/Endian.h"
 #include "mozilla/Move.h"
 #include "nsICODecoder.h"
 
 #include "RasterImage.h"
 
-using namespace mozilla::gfx;
-
 namespace mozilla {
 namespace image {
 
 // Constants.
 static const uint32_t ICOHEADERSIZE = 6;
 static const uint32_t BITMAPINFOSIZE = 40;
+static const uint32_t PREFICONSIZE = 16;
 
 // ----------------------------------------
 // Actual Data Processing
 // ----------------------------------------
 
 uint32_t
 nsICODecoder::CalcAlphaRowSize()
 {
@@ -56,40 +55,25 @@ nsICODecoder::GetNumColors()
     }
   }
   return numColors;
 }
 
 nsICODecoder::nsICODecoder(RasterImage* aImage)
   : Decoder(aImage)
   , mLexer(Transition::To(ICOState::HEADER, ICOHEADERSIZE))
-  , mBiggestResourceColorDepth(0)
   , mBestResourceDelta(INT_MIN)
   , mBestResourceColorDepth(0)
   , mNumIcons(0)
   , mCurrIcon(0)
   , mBPP(0)
   , mMaskRowSize(0)
   , mCurrMaskLine(0)
 { }
 
-nsresult
-nsICODecoder::SetTargetSize(const nsIntSize& aSize)
-{
-  // Make sure the size is reasonable.
-  if (MOZ_UNLIKELY(aSize.width <= 0 || aSize.height <= 0)) {
-    return NS_ERROR_FAILURE;
-  }
-
-  // Create a downscaler that we'll filter our output through.
-  mDownscaler.emplace(aSize);
-
-  return NS_OK;
-}
-
 void
 nsICODecoder::FinishInternal()
 {
   // We shouldn't be called in error cases
   MOZ_ASSERT(!HasError(), "Shouldn't call FinishInternal after error!");
 
   GetFinalStateFromContainedDecoder();
 }
@@ -233,39 +217,46 @@ nsICODecoder::ReadBIHSize(const char* aB
 {
   const int8_t* bih = reinterpret_cast<const int8_t*>(aBIH);
   int32_t headerSize;
   memcpy(&headerSize, bih, sizeof(headerSize));
   NativeEndian::swapFromLittleEndianInPlace(&headerSize, 1);
   return headerSize;
 }
 
+void
+nsICODecoder::SetHotSpotIfCursor()
+{
+  if (!mIsCursor) {
+    return;
+  }
+
+  mImageMetadata.SetHotspot(mDirEntry.mXHotspot, mDirEntry.mYHotspot);
+}
+
 LexerTransition<ICOState>
 nsICODecoder::ReadHeader(const char* aData)
 {
   // If the third byte is 1, this is an icon. If 2, a cursor.
   if ((aData[2] != 1) && (aData[2] != 2)) {
     return Transition::Terminate(ICOState::FAILURE);
   }
   mIsCursor = (aData[2] == 2);
 
   // The fifth and sixth bytes specify the number of resources in the file.
   mNumIcons =
     LittleEndian::readUint16(reinterpret_cast<const uint16_t*>(aData + 4));
   if (mNumIcons == 0) {
     return Transition::Terminate(ICOState::SUCCESS); // Nothing to do.
   }
 
-  // Downscale-during-decode can end up decoding different resources in the ICO
-  // file depending on the target size. Since the resources are not necessarily
-  // scaled versions of the same image, some may be transparent and some may not
-  // be. We could be precise about transparency if we decoded the metadata of
-  // every resource, but for now we don't and it's safest to assume that
-  // transparency could be present.
-  PostHasTransparency();
+  // If we didn't get a #-moz-resolution, default to PREFICONSIZE.
+  if (mResolution.width == 0 && mResolution.height == 0) {
+    mResolution.SizeTo(PREFICONSIZE, PREFICONSIZE);
+  }
 
   return Transition::To(ICOState::DIR_ENTRY, ICODIRENTRYSIZE);
 }
 
 size_t
 nsICODecoder::FirstResourceOffset() const
 {
   MOZ_ASSERT(mNumIcons > 0,
@@ -292,79 +283,40 @@ nsICODecoder::ReadDirEntry(const char* a
   e.mPlanes = LittleEndian::readUint16(&e.mPlanes);
   memcpy(&e.mBitCount, aData + 6, sizeof(e.mBitCount));
   e.mBitCount = LittleEndian::readUint16(&e.mBitCount);
   memcpy(&e.mBytesInRes, aData + 8, sizeof(e.mBytesInRes));
   e.mBytesInRes = LittleEndian::readUint32(&e.mBytesInRes);
   memcpy(&e.mImageOffset, aData + 12, sizeof(e.mImageOffset));
   e.mImageOffset = LittleEndian::readUint32(&e.mImageOffset);
 
-  // Determine if this is the biggest resource we've seen so far. We always use
-  // the biggest resource for the intrinsic size, and if we're not downscaling,
-  // we select it as the best resource as well.
-  IntSize entrySize(GetRealWidth(e), GetRealHeight(e));
-  if (e.mBitCount >= mBiggestResourceColorDepth &&
-      entrySize.width * entrySize.height >=
-        mBiggestResourceSize.width * mBiggestResourceSize.height) {
-    mBiggestResourceSize = entrySize;
-    mBiggestResourceColorDepth = e.mBitCount;
-    mBiggestResourceHotSpot = IntSize(e.mXHotspot, e.mYHotspot);
-
-    if (!mDownscaler) {
-      mDirEntry = e;
-    }
-  }
+  // Calculate the delta between this image's size and the desired size, so we
+  // can see if it is better than our current-best option.  In the case of
+  // several equally-good images, we use the last one. "Better" in this case is
+  // determined by |delta|, a measure of the difference in size between the
+  // entry we've found and the requested size. We will choose the smallest image
+  // that is >= requested size (i.e. we assume it's better to downscale a larger
+  // icon than to upscale a smaller one).
+  int32_t delta = GetRealWidth(e) - mResolution.width +
+                  GetRealHeight(e) - mResolution.height;
+  if (e.mBitCount >= mBestResourceColorDepth &&
+      ((mBestResourceDelta < 0 && delta >= mBestResourceDelta) ||
+       (delta >= 0 && delta <= mBestResourceDelta))) {
+    mBestResourceDelta = delta;
 
-  if (mDownscaler) {
-    // Calculate the delta between this resource's size and the desired size, so
-    // we can see if it is better than our current-best option.  In the case of
-    // several equally-good resources, we use the last one. "Better" in this
-    // case is determined by |delta|, a measure of the difference in size
-    // between the entry we've found and the downscaler's target size. We will
-    // choose the smallest resource that is >= the target size (i.e. we assume
-    // it's better to downscale a larger icon than to upscale a smaller one).
-    IntSize desiredSize = mDownscaler->TargetSize();
-    int32_t delta = entrySize.width - desiredSize.width +
-                    entrySize.height - desiredSize.height;
-    if (e.mBitCount >= mBestResourceColorDepth &&
-        ((mBestResourceDelta < 0 && delta >= mBestResourceDelta) ||
-         (delta >= 0 && delta <= mBestResourceDelta))) {
-      mBestResourceDelta = delta;
-      mBestResourceColorDepth = e.mBitCount;
-      mDirEntry = e;
+    // Ensure mImageOffset is >= size of the direntry headers (bug #245631).
+    if (e.mImageOffset < FirstResourceOffset()) {
+      return Transition::Terminate(ICOState::FAILURE);
     }
+
+    mBestResourceColorDepth = e.mBitCount;
+    mDirEntry = e;
   }
 
   if (mCurrIcon == mNumIcons) {
-    // Ensure the resource we selected has an offset past the ICO headers.
-    if (mDirEntry.mImageOffset < FirstResourceOffset()) {
-      return Transition::Terminate(ICOState::FAILURE);
-    }
-
-    // If this is a cursor, set the hotspot. We use the hotspot from the biggest
-    // resource since we also use that resource for the intrinsic size.
-    if (mIsCursor) {
-      mImageMetadata.SetHotspot(mBiggestResourceHotSpot.width,
-                                mBiggestResourceHotSpot.height);
-    }
-
-    // We always report the biggest resource's size as the intrinsic size; this
-    // is necessary for downscale-during-decode to work since we won't even
-    // attempt to *upscale* while decoding.
-    PostSize(mBiggestResourceSize.width, mBiggestResourceSize.height);
-    if (IsMetadataDecode()) {
-      return Transition::Terminate(ICOState::SUCCESS);
-    }
-
-    // If the resource we selected matches the downscaler's target size
-    // perfectly, we don't need to do any downscaling.
-    if (mDownscaler && GetRealSize() == mDownscaler->TargetSize()) {
-      mDownscaler.reset();
-    }
-
     size_t offsetToResource = mDirEntry.mImageOffset - FirstResourceOffset();
     return Transition::ToUnbuffered(ICOState::FOUND_RESOURCE,
                                     ICOState::SKIP_TO_RESOURCE,
                                     offsetToResource);
   }
 
   return Transition::To(ICOState::DIR_ENTRY, ICODIRENTRYSIZE);
 }
@@ -377,19 +329,16 @@ nsICODecoder::SniffResource(const char* 
   bool isPNG = !memcmp(aData, nsPNGDecoder::pngSignatureBytes,
                        PNGSIGNATURESIZE);
   if (isPNG) {
     // Create a PNG decoder which will do the rest of the work for us.
     mContainedDecoder = new nsPNGDecoder(mImage);
     mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
     mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
     mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
-    if (mDownscaler) {
-      mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
-    }
     mContainedDecoder->Init();
 
     if (!WriteToContainedDecoder(aData, PNGSIGNATURESIZE)) {
       return Transition::Terminate(ICOState::FAILURE);
     }
 
     if (mDirEntry.mBytesInRes <= PNGSIGNATURESIZE) {
       return Transition::Terminate(ICOState::FAILURE);
@@ -404,19 +353,16 @@ nsICODecoder::SniffResource(const char* 
     // Create a BMP decoder which will do most of the work for us; the exception
     // is the AND mask, which isn't present in standalone BMPs.
     nsBMPDecoder* bmpDecoder = new nsBMPDecoder(mImage);
     mContainedDecoder = bmpDecoder;
     bmpDecoder->SetUseAlphaData(true);
     mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
     mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
     mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
-    if (mDownscaler) {
-      mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
-    }
     mContainedDecoder->Init();
 
     // Make sure we have a sane size for the bitmap information header.
     int32_t bihSize = ReadBIHSize(aData);
     if (bihSize != static_cast<int32_t>(BITMAPINFOSIZE)) {
       return Transition::Terminate(ICOState::FAILURE);
     }
 
@@ -431,19 +377,29 @@ nsICODecoder::SniffResource(const char* 
 
 LexerTransition<ICOState>
 nsICODecoder::ReadPNG(const char* aData, uint32_t aLen)
 {
   if (!WriteToContainedDecoder(aData, aLen)) {
     return Transition::Terminate(ICOState::FAILURE);
   }
 
+  if (!HasSize() && mContainedDecoder->HasSize()) {
+    nsIntSize size = mContainedDecoder->GetSize();
+    PostSize(size.width, size.height);
+
+    if (IsMetadataDecode()) {
+      return Transition::Terminate(ICOState::SUCCESS);
+    }
+  }
+
   // Raymond Chen says that 32bpp only are valid PNG ICOs
   // http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
-  if (!static_cast<nsPNGDecoder*>(mContainedDecoder.get())->IsValidICO()) {
+  if (!IsMetadataDecode() &&
+      !static_cast<nsPNGDecoder*>(mContainedDecoder.get())->IsValidICO()) {
     return Transition::Terminate(ICOState::FAILURE);
   }
 
   return Transition::ContinueUnbuffered(ICOState::READ_PNG);
 }
 
 LexerTransition<ICOState>
 nsICODecoder::ReadBIH(const char* aData)
@@ -463,16 +419,19 @@ nsICODecoder::ReadBIH(const char* aData)
     return Transition::Terminate(ICOState::FAILURE);
   }
 
   if (!WriteToContainedDecoder(reinterpret_cast<const char*>(bfhBuffer),
                                sizeof(bfhBuffer))) {
     return Transition::Terminate(ICOState::FAILURE);
   }
 
+  // Set up the cursor hot spot if one is present.
+  SetHotSpotIfCursor();
+
   // Fix the ICO height from the BIH. It needs to be halved so our BMP decoder
   // will understand, because the BMP decoder doesn't expect the alpha mask that
   // follows the BMP data in an ICO.
   if (!FixBitmapHeight(reinterpret_cast<int8_t*>(mBIHraw))) {
     return Transition::Terminate(ICOState::FAILURE);
   }
 
   // Fix the ICO width from the BIH.
@@ -480,16 +439,24 @@ nsICODecoder::ReadBIH(const char* aData)
     return Transition::Terminate(ICOState::FAILURE);
   }
 
   // Write out the BMP's bitmap info header.
   if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw))) {
     return Transition::Terminate(ICOState::FAILURE);
   }
 
+  nsIntSize size = mContainedDecoder->GetSize();
+  PostSize(size.width, size.height);
+
+  // We have the size. If we're doing a metadata decode, we're done.
+  if (IsMetadataDecode()) {
+    return Transition::Terminate(ICOState::SUCCESS);
+  }
+
   // Sometimes the ICO BPP header field is not filled out so we should trust the
   // contained resource over our own information.
   // XXX(seth): Is this ever different than the value we obtained from
   // ReadBPP() above?
   nsRefPtr<nsBMPDecoder> bmpDecoder =
     static_cast<nsBMPDecoder*>(mContainedDecoder.get());
   mBPP = bmpDecoder->GetBitsPerPixel();
 
@@ -602,29 +569,16 @@ nsICODecoder::ReadMaskRow(const char* aD
 
   if (mCurrMaskLine == 0) {
     return Transition::To(ICOState::FINISHED_RESOURCE, 0);
   }
 
   return Transition::To(ICOState::READ_MASK_ROW, mMaskRowSize);
 }
 
-LexerTransition<ICOState>
-nsICODecoder::FinishResource()
-{
-  // Make sure the actual size of the resource matches the size in the directory
-  // entry. If not, we consider the image corrupt.
-  if (mContainedDecoder->HasSize() &&
-      mContainedDecoder->GetSize() != GetRealSize()) {
-    return Transition::Terminate(ICOState::FAILURE);
-  }
-
-  return Transition::Terminate(ICOState::SUCCESS);
-}
-
 void
 nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!");
   MOZ_ASSERT(aBuffer);
   MOZ_ASSERT(aCount > 0);
 
   Maybe<ICOState> terminalState =
@@ -649,17 +603,17 @@ nsICODecoder::WriteInternal(const char* 
           return ReadBMP(aData, aLength);
         case ICOState::PREPARE_FOR_MASK:
           return PrepareForMask();
         case ICOState::READ_MASK_ROW:
           return ReadMaskRow(aData);
         case ICOState::SKIP_MASK:
           return Transition::ContinueUnbuffered(ICOState::SKIP_MASK);
         case ICOState::FINISHED_RESOURCE:
-          return FinishResource();
+          return Transition::Terminate(ICOState::SUCCESS);
         default:
           MOZ_ASSERT_UNREACHABLE("Unknown ICOState");
           return Transition::Terminate(ICOState::FAILURE);
       }
     });
 
   if (!terminalState) {
     return;  // Need more data.
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -38,18 +38,16 @@ enum class ICOState
   FINISHED_RESOURCE
 };
 
 class nsICODecoder : public Decoder
 {
 public:
   virtual ~nsICODecoder() { }
 
-  nsresult SetTargetSize(const nsIntSize& aSize) override;
-
   /// @return the width of the icon directory entry @aEntry.
   static uint32_t GetRealWidth(const IconDirEntry& aEntry)
   {
     return aEntry.mWidth == 0 ? 256 : aEntry.mWidth;
   }
 
   /// @return the width of the selected directory entry (mDirEntry).
   uint32_t GetRealWidth() const { return GetRealWidth(mDirEntry); }
@@ -58,20 +56,19 @@ public:
   static uint32_t GetRealHeight(const IconDirEntry& aEntry)
   {
     return aEntry.mHeight == 0 ? 256 : aEntry.mHeight;
   }
 
   /// @return the height of the selected directory entry (mDirEntry).
   uint32_t GetRealHeight() const { return GetRealHeight(mDirEntry); }
 
-  /// @return the size of the selected directory entry (mDirEntry).
-  gfx::IntSize GetRealSize() const
+  virtual void SetResolution(const gfx::IntSize& aResolution) override
   {
-    return gfx::IntSize(GetRealWidth(), GetRealHeight());
+    mResolution = aResolution;
   }
 
   /// @return The offset from the beginning of the ICO to the first resource.
   size_t FirstResourceOffset() const;
 
   virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
   virtual void FinishInternal() override;
   virtual void FinishWithErrorInternal() override;
@@ -84,16 +81,18 @@ private:
 
   // Writes to the contained decoder and sets the appropriate errors
   // Returns true if there are no errors.
   bool WriteToContainedDecoder(const char* aBuffer, uint32_t aCount);
 
   // Gets decoder state from the contained decoder so it's visible externally.
   void GetFinalStateFromContainedDecoder();
 
+  // Sets the hotspot property of if we have a cursor
+  void SetHotSpotIfCursor();
   // Creates a bitmap file header buffer, returns true if successful
   bool FillBitmapFileHeaderBuffer(int8_t* bfh);
   // Fixes the ICO height to match that of the BIH.
   // and also fixes the BIH height to be /2 of what it was.
   // See definition for explanation.
   // Returns false if invalid information is contained within.
   bool FixBitmapHeight(int8_t* bih);
   // Fixes the ICO width to match that of the BIH.
@@ -111,26 +110,22 @@ private:
   LexerTransition<ICOState> ReadHeader(const char* aData);
   LexerTransition<ICOState> ReadDirEntry(const char* aData);
   LexerTransition<ICOState> SniffResource(const char* aData);
   LexerTransition<ICOState> ReadPNG(const char* aData, uint32_t aLen);
   LexerTransition<ICOState> ReadBIH(const char* aData);
   LexerTransition<ICOState> ReadBMP(const char* aData, uint32_t aLen);
   LexerTransition<ICOState> PrepareForMask();
   LexerTransition<ICOState> ReadMaskRow(const char* aData);
-  LexerTransition<ICOState> FinishResource();
 
   StreamingLexer<ICOState, 32> mLexer; // The lexer.
-  Maybe<Downscaler> mDownscaler;       // Our downscaler, if we're downscaling.
   nsRefPtr<Decoder> mContainedDecoder; // Either a BMP or PNG decoder.
+  gfx::IntSize mResolution;            // The requested -moz-resolution.
   char mBIHraw[40];                    // The bitmap information header.
   IconDirEntry mDirEntry;              // The dir entry for the selected resource.
-  IntSize mBiggestResourceSize;        // Used to select the intrinsic size.
-  IntSize mBiggestResourceHotSpot;     // Used to select the intrinsic size.
-  uint16_t mBiggestResourceColorDepth; // Used to select the intrinsic size.
   int32_t mBestResourceDelta;          // Used to select the best resource.
   uint16_t mBestResourceColorDepth;    // Used to select the best resource.
   uint16_t mNumIcons; // Stores the number of icons in the ICO file.
   uint16_t mCurrIcon; // Stores the current dir entry index we are processing.
   uint16_t mBPP;      // The BPP of the resource we're decoding.
   uint32_t mMaskRowSize;  // The size in bytes of each row in the BMP alpha mask.
   uint32_t mCurrMaskLine; // The line of the BMP alpha mask we're processing.
   bool mIsCursor;         // Is this ICO a cursor?
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -114,17 +114,17 @@ native nsIntSizeByVal(nsIntSize);
 
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces. It also allows drawing of images
  * onto Thebes contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, builtinclass, uuid(4e5a0547-6c54-4051-8b52-1f2fdd667696)]
+[scriptable, builtinclass, uuid(4880727a-5673-44f7-b248-f6c86e22a434)]
 interface imgIContainer : nsISupports
 {
   /**
    * The width of the container rectangle.  In the case of any error,
    * zero is returned, and an exception will be thrown.
    */
   readonly attribute int32_t width;
 
@@ -263,31 +263,16 @@ interface imgIContainer : nsISupports
    *
    * @param aWhichFrame Frame specifier of the FRAME_* variety.
    * @param aFlags Flags of the FLAG_* variety
    */
   [noscript, notxpcom] TempRefSourceSurface getFrame(in uint32_t aWhichFrame,
                                                      in uint32_t aFlags);
 
   /**
-   * Get a surface for the given frame at the specified size. Matching the
-   * requested size is best effort; it's not guaranteed that the surface you get
-   * will be a perfect match. (Some reasons you may get a surface of a different
-   * size include: if you requested upscaling, if downscale-during-decode is
-   * disabled, or if you didn't request the first frame.)
-   *
-   * @param aSize The desired size.
-   * @param aWhichFrame Frame specifier of the FRAME_* variety.
-   * @param aFlags Flags of the FLAG_* variety
-   */
-  [noscript, notxpcom] TempRefSourceSurface getFrameAtSize([const] in nsIntSize aSize,
-                                                           in uint32_t aWhichFrame,
-                                                           in uint32_t aFlags);
-
-  /**
    * Whether this image is opaque (i.e., needs a background painted behind it).
    */
   [notxpcom] boolean isOpaque();
 
   /**
    * @return true if getImageContainer() is expected to return a valid
    *         ImageContainer when passed the given @Manager and @Flags
    *         parameters.
--- a/image/imgTools.cpp
+++ b/image/imgTools.cpp
@@ -193,37 +193,36 @@ imgTools::EncodeScaledImage(imgIContaine
   NS_ENSURE_ARG(aScaledWidth >= 0 && aScaledHeight >= 0);
 
   // If no scaled size is specified, we'll just encode the image at its
   // original size (no scaling).
   if (aScaledWidth == 0 && aScaledHeight == 0) {
     return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
   }
 
-  // Retrieve the image's size.
-  int32_t imageWidth = 0;
-  int32_t imageHeight = 0;
-  aContainer->GetWidth(&imageWidth);
-  aContainer->GetHeight(&imageHeight);
+  // Use frame 0 from the image container.
+  RefPtr<SourceSurface> frame =
+    aContainer->GetFrame(imgIContainer::FRAME_FIRST,
+                         imgIContainer::FLAG_SYNC_DECODE);
+  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+
+  int32_t frameWidth = frame->GetSize().width;
+  int32_t frameHeight = frame->GetSize().height;
 
   // If the given width or height is zero we'll replace it with the image's
   // original dimensions.
-  IntSize scaledSize(aScaledWidth == 0 ? imageWidth : aScaledWidth,
-                     aScaledHeight == 0 ? imageHeight : aScaledHeight);
-
-  // Use frame 0 from the image container.
-  RefPtr<SourceSurface> frame =
-    aContainer->GetFrameAtSize(scaledSize,
-                               imgIContainer::FRAME_FIRST,
-                               imgIContainer::FLAG_HIGH_QUALITY_SCALING |
-                               imgIContainer::FLAG_SYNC_DECODE);
-  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
+  if (aScaledWidth == 0) {
+    aScaledWidth = frameWidth;
+  } else if (aScaledHeight == 0) {
+    aScaledHeight = frameHeight;
+  }
 
   RefPtr<DataSourceSurface> dataSurface =
-    Factory::CreateDataSourceSurface(scaledSize, SurfaceFormat::B8G8R8A8);
+    Factory::CreateDataSourceSurface(IntSize(aScaledWidth, aScaledHeight),
+                                     SurfaceFormat::B8G8R8A8);
   if (NS_WARN_IF(!dataSurface)) {
     return NS_ERROR_FAILURE;
   }
 
   DataSourceSurface::MappedSurface map;
   if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
     return NS_ERROR_FAILURE;
   }
@@ -234,20 +233,19 @@ imgTools::EncodeScaledImage(imgIContaine
                                      dataSurface->GetSize(),
                                      map.mStride,
                                      SurfaceFormat::B8G8R8A8);
   if (!dt) {
     gfxWarning() << "imgTools::EncodeImage failed in CreateDrawTargetForData";
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  IntSize frameSize = frame->GetSize();
   dt->DrawSurface(frame,
-                  Rect(0, 0, scaledSize.width, scaledSize.height),
-                  Rect(0, 0, frameSize.width, frameSize.height),
+                  Rect(0, 0, aScaledWidth, aScaledHeight),
+                  Rect(0, 0, frameWidth, frameHeight),
                   DrawSurfaceOptions(),
                   DrawOptions(1.0f, CompositionOp::OP_SOURCE));
 
   dataSurface->Unmap();
 
   return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
 }
 
--- a/image/test/crashtests/crashtests.list
+++ b/image/test/crashtests/crashtests.list
@@ -47,13 +47,8 @@ load multiple-png-hassize.ico
 load 856616.gif
 
 skip-if(AddressSanitizer) skip-if(B2G) load 944353.jpg
 
 # Bug 1160801: Ensure that we handle invalid disposal types.
 load invalid-disposal-method-1.gif
 load invalid-disposal-method-2.gif
 load invalid-disposal-method-3.gif
-
-# Ensure we handle ICO directory entries which specify the wrong size for the
-# contained resource.
-load invalid_ico_height.ico
-load invalid_ico_width.ico
--- a/image/test/mochitest/test_has_transparency.html
+++ b/image/test/mochitest/test_has_transparency.html
@@ -52,19 +52,18 @@ function testFiles() {
   yield ["damon.jpg", false];
 
   // Most BMPs are not transparent. (The TestMetadata GTest, which will
   // eventually replace this test totally, has coverage for the kinds that can be
   // transparent.)
   yield ["opaque.bmp", false];
 
   // ICO files which contain BMPs have an additional type of transparency - the
-  // AND mask - that warrants separate testing. (Although, after bug 1201796,
-  // all ICOs are considered transparent.)
-  yield ["ico-bmp-opaque.ico", true];
+  // AND mask - that warrants separate testing.
+  yield ["ico-bmp-opaque.ico", false];
   yield ["ico-bmp-transparent.ico", true];
 
   // SVGs are always transparent.
   yield ["lime100x100.svg", true];
 }
 
 function loadNext() {
   var currentFile = "";
index 025ebaed1ff12279d4e07cfcaf3bd1cbbeb0884b..d37f2f1cc0534d9aec717a087a13dd4eb5b83a8f
GIT binary patch
literal 13942
zc%1E;&1w@-6o7B6*n&b_N*8T5iaV<dBW~gg2;u{X(!H<H7f~1DPe2M?q$1K{ks|a*
zO9*Y!#x%{3F-DRmkd~CDIi52)S1#kEX%>?^BljzZQ|?T2zccB;<eUg`4u7Vmga`;B
zqF05uhB*`x7SYQ>e8aWt_&c5=9t%2;4;l;xgTY`h7z_r3!C?3=8NV=c7h@h{8snC3
zpFu(A51$qm;N|mY@O1hKJbL&5aP5X}ud{%j;~2@EogGM}Qjkn0VKy2i|F~{93A!v|
zlqN2Y-ElY;o1dG5OeO=e23o_oufx>|borS{r^%~{5mwg2bnSDw9AvXutA;Pj%XD5s
zr>`CIZ#J8d-rklq+~)Pz$M^G4C=@`};I(T{kpJP~A=qo6>s&6Ep;RhaHGExL_1v{5
z$iLNUfxU*=w{M_Qser5j*A~2X?FsTfIywTSh7Q%RzrPRFYV~goe4qCWo&Lwi$6%`g
z8jZ$3HOT)ZhkIJ9|H;V-3{pcrpSNmQTUn9sOSu0|?)i5*9T>ERjrDcy?$RHSL25|E
z<DPI={rlBWuh*>_lAD{JaVJ#&el_f7zI)1@u>1F_VQ)9%Id{UzU)IoWx2+oTdwZUA
zCwlqI8cM~YXWfa@{L7^uo^~gC`TN10aPs$yJ7M?tlRKgM`^}w@{(f{P$p3fcmoME3
z^7pGd!T!E<C%Sj84|0(6NH=#lPjJ38+Rf)Vi=ZuwNRK?jna>Mw=GPVW*PG-V;XK2c
zJp-IaIFE7;a-QTI;Y{Dt3Srz6=6hNOgTY|%4|2wZ@dD$fhW%romzE%rNYFFzx{LcP
z_L?!#T#Ovtoa@nZrZQg%^O`lEOLymAuFi&N|AT`Ab;d)rC#aXreQZ}}J918=I=p-R
zYG|_=Ij2w^YPFixPaeiRMV&K92kL7}2RT=eGX*#Hrzh6a9O4@ru6+(w`wUJFsjV$n
zKLgwQG^#^(2z_m*J{LI@@jV~L=V#r0Hr;(P-F+_IeJa{tXOB#GpGbF~$A0gfg?6MH
iS1`sfs8?Y{P>D$lc?|!C`WMu@puPq5EbuVkVfX_}Lb8$o
rename from image/test/crashtests/invalid_ico_height.ico
rename to image/test/reftest/ico/ico-bmp-corrupted/invalid_ico_height.ico
rename from image/test/crashtests/invalid_ico_width.ico
rename to image/test/reftest/ico/ico-bmp-corrupted/invalid_ico_width.ico
--- a/image/test/reftest/ico/ico-bmp-corrupted/reftest.list
+++ b/image/test/reftest/ico/ico-bmp-corrupted/reftest.list
@@ -3,8 +3,13 @@
 # Invalid value for bits per pixel (BPP) - detected when decoding the header.
 == wrapper.html?invalid-bpp.ico about:blank
 # Invalid BPP values for RLE4 - detected when decoding the image data.
 == wrapper.html?invalid-compression-RLE4.ico about:blank
 # Invalid BPP values for RLE8 - detected when decoding the image data.
 == wrapper.html?invalid-compression-RLE8.ico about:blank
 # Invalid compression value - detected when decoding the image data.
 == wrapper.html?invalid-compression.ico about:blank
+
+# Invalid ICO width and heigth should be ignored if the
+# contained BMP is correct.
+== invalid_ico_height.ico 16x16.png
+== invalid_ico_width.ico 16x16.png
--- a/image/test/reftest/ico/ico-mixed/reftest.list
+++ b/image/test/reftest/ico/ico-mixed/reftest.list
@@ -1,3 +1,14 @@
 # ICO BMP and PNG mixed tests
 
-== mixed-bmp-png.ico mixed-bmp-png48.png
+== mixed-bmp-png.ico mixed-bmp-png.png
+
+# Using media fragments to select different resolutions
+
+== mixed-bmp-png.ico#-moz-resolution=8,8 mixed-bmp-png.png
+== mixed-bmp-png.ico#test=true&-moz-resolution=8,8&other mixed-bmp-png.png
+== mixed-bmp-png.ico#-moz-resolution=32,32 mixed-bmp-png32.png
+== mixed-bmp-png.ico#-moz-resolution=39,39 mixed-bmp-png48.png
+== mixed-bmp-png.ico#-moz-resolution=40,40 mixed-bmp-png48.png
+== mixed-bmp-png.ico#-moz-resolution=48,48 mixed-bmp-png48.png
+== mixed-bmp-png.ico#-moz-resolution=64,64 mixed-bmp-png48.png
+== mixed-bmp-png.ico#-moz-resolution=64 mixed-bmp-png.png # Bad syntax will fall back to lowest resolution
index ecb88edf3ca8ff586d009cac9d2b1cb40aff8999..edbaf544349242589fc73db180b49af95c00f229
GIT binary patch
literal 5934
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
KWsEes6Z=1B(Q?E9
index cc8a4a31db973df11dd9c21b56d12eabab61cb62..df422207e7b9918f582896c7d7889c5103adf8f7
GIT binary patch
literal 3084
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
index ea14dbedede96973213586f1754a29c774e72993..645bc114c8de46cc0a4f6afb02c190f3aea9c7a3
GIT binary patch
literal 1078
zc%1ux<NpH&0WUXCHwH#V1_nkTWcYuZ!I^=X2?RhSGZ3(_v48*v8yhPdCkGc7CkH1d
z7Y{!V7dIa_Cnv8UFCV{vfS>>ukC3pCfH06P05XITq?4J21E^7eo0D6BWbpq0gCGZk
z0D}NCqaXv5AS1IN<NqTJ@<4a8GJ*jE6fiO|v#_$Ub8vET0~Kr)U|<5;&BVgY%F4n5
zl&uBIGq4D<3Mm>ovIz$!vMUve7&T5@$f4}C@t|nX#SbdRNkvVZTw>x9l2WQ_>Kd9_
zCZ=ZQ7M51dF0O9w9-dyoA)#U65s^{JDXD4c8JStdC8cHM6_r)ZEv;?s9i3g1CQq3<
zZTgIvvlcC0vUJ(<6)RV5+Pr1!w(UE1?mBe%$kAiRPn<k;>GGAU*RJ2VdF$b$$4{O<
zd;a3(tB;>PfBE|D`;VW$K>lK6U}l5?to{N90wWU(Fi6=!{$gY*2PqI_VO2C_6LJh>
zPb?HxGHT=yahkYr<3Ubk<Dd_sNktdA#8gZks(u7{4eT@GJk~^(&)^<I`0Ew}4>Kb$
z@|Xn~>={1CH`p`R@&2*Cv_&@i=s*6;rE}{ew``sDNVmkbR>Ww=#3g+aTyK>tpYBvv
zf5xT#WJi9l;fyyApO$PmRq%ZJe$n?UR)4xZ%ggYp_Fie<)#j)3mpxj?wXpfbe}=99
zwrUjz^zT-GXSusLev)3k_sy(zldFnF|Eblm{80V4?DHcXc|IG1UFqF6mW#bt-iprH
zuyhvZnn&d`c{d)i5w4u5w1LUtqZrT2-S(c3<n;FQooAhKY)z=-m5}A^qUGmyPIWa|
zf0mWgT)g6x?pu|~KlC_P1{=4==qc&XbUkOhyK1$o)7e{Rx30Q*d$-MhhKK5JxgW}w
zAF@hof7JbX>5tido1}88rc87-3uX9pXU+T?0lNgd{JobISAUMFbDx!RbI!({IZIZa
z+;&A(!`i;f=Hl&BzjF7^vS0Km=DgOUIm;|;Qda(sSTZMDWA{n5DUX(>YQMYIYrS^O
zeb4HT-4CZ9ly93aVCtPOr{8O*{KsKauF|z=g>7roma#YZD>>EdE^X5^TKqR<(_;&V
zA9Idb9+ydv@GAZAX=&qOQ~P_KXLqX2`o3i6E6<y&UrOl4-tvm)pYhP>pV;9m3tLx9
ZUSC<N&MGo#SEk0XkNx$h_tgKt2>>6_q)q?;
index 5722223c26fe0024d8c4d18f198114d5fde708bb..c3a4aee616675d212178f70a97d8ce73fc1813e2
GIT binary patch
literal 948
zc$@*W155mgP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV000AfNkl<ZIE_Wq
zZA{b!0LSrv8M=bR6`*jJ0!oI$G}1Y1KH(H^n&*TDN(PBSpuyeoq=3OvdO#V9B2%$2
zDo=>V4UD_Ey98Hw^3d_z0SAGilu96u$N#q%XukhFy!r@;Ac`UYA}|4121ocoXC$|(
zmhAFs@_()8{-eiC&%|c3PdfsLAWkBRQ*{45jN(!i!58%;Yg)+fe#rTTK4OcE_(y-i
z$&(q34D~;~c{U(UFxXPX_2L57Mw}+>yBnmHYDp>8aoIdTX7gQ?W%Wd!%An+eFYOh+
zJm@TfsS!X#VCo6YXF|{?$jJLDiqg!(XfynY&%Hv@4HE~-YB^GE=94SsZ1eTOQ0l{@
z`kfdnk`bpy5ttg`_Gg<gC%VyoWC^V?u4oUskd<|uV})fX4NZKiZy`$4#E#VO2|N}<
zWAQuOtMcJ~pAliW`zGekz37T{q&wOPi%Lq<p+(%v2qNkDQTF|)MV?cIb4WV=IeLQ6
zswvD|$I#7n^q4Lo+^I~%oV=8-=ml6*61r83Xh~kfmno4P%qc;hUCC^36;^8_SRa$i
zHbojW1zQ>Klw&OMN9f5@(wXRrB}PI=goL6^_M`@S6LBJwy;(mKa9)FFP&zNU@5N^M
z9@f9VhX(Zu#(R7)UEP9Em$DB_f*Tf<6zyhP)GJ>mHQ0}!_%j41T_7|i3-6Gxd11j;
zX21R(r%&u>pg_WKgDY*CaD?B_rqB`PMvqEDQ@}hLcUWNxf0Ih(Ms#tT`6YQLAN%?7
z;+&N@*n3fs9l*bpOBt#6rqPgwaL-tSK`y07A)#04h~<DS#t&X2-NS}>uZ66zb779)
z%-mTn#O+!|%TLRBXz*aPKa@Xe3lSK5Lb2Zlnm>~8m+B2H3Og(cCk&xW2w&~NMwczD
zneWc2?aOFSa-}cVnu-4H+}7>p@o*mk;xu=vbzFPfjyjnG?Lks3hn(nANa=`O#-E9+
z=}7RRGuD|_r4>WJEvCQjU21jbK%7KC1SThFxR^zr^E}EIzQT3sEQ}lMG07ci`_Pe&
zFni2#*8HP(pjY!2nyZJI7#n(qX~v;AK2BS{nr}Saxn@6?qWP~<BC)2z(+0iFmRpgI
zXj50A&rfB1^ucpX|5Fx4n4V^A;4XFFUZx^!KZSA`h5j<ikA_gAKF45hD@;F^2=E{F
WUdnCPA!Vxo0000<MNUMnLSTZj*T-Z4
--- a/image/test/unit/test_imgtools.js
+++ b/image/test/unit/test_imgtools.js
@@ -164,17 +164,17 @@ testdesc = "test encoding a scaled JPEG"
 // we'll reuse the container from the previous test
 istream = imgTools.encodeScaledImage(container, "image/jpeg", 16, 16);
 
 var encodedBytes = streamToArray(istream);
 // Get bytes for exected result
 var refName = "image1png16x16.jpg";
 var refFile = do_get_file(refName);
 istream = getFileInputStream(refFile);
-do_check_eq(istream.available(), 1051);
+do_check_eq(istream.available(), 1078);
 var referenceBytes = streamToArray(istream);
 
 // compare the encoder's output to the reference file.
 compareArrays(encodedBytes, referenceBytes);
 
 
 /* ========== 3 ========== */
 testnum++;
@@ -223,17 +223,17 @@ if (!isWindows) {
 // we'll reuse the container from the previous test
 istream = imgTools.encodeScaledImage(container, "image/png", 16, 16);
 
 encodedBytes = streamToArray(istream);
 // Get bytes for exected result
 refName = isWindows ? "image2jpg16x16-win.png" : "image2jpg16x16.png";
 refFile = do_get_file(refName);
 istream = getFileInputStream(refFile);
-do_check_eq(istream.available(), 950);
+do_check_eq(istream.available(), 948);
 referenceBytes = streamToArray(istream);
 
 // compare the encoder's output to the reference file.
 compareArrays(encodedBytes, referenceBytes);
 }
 
 
 /* ========== 6 ========== */
@@ -686,32 +686,30 @@ imgFile = do_get_file(imgName);
 
 istream = getFileInputStream(imgFile);
 do_check_eq(istream.available(), 17759);
 var errsrc = "none";
 
 try {
   container = imgTools.decodeImage(istream, inMimeType);
 
-  // We expect to hit an error during encoding because the ICO header of the
-  // image is fine, but the actual resources are corrupt. Since decodeImage()
-  // only performs a metadata decode, it doesn't decode far enough to realize
-  // this, but we'll find out when we do a full decode during encodeImage().
+  // We should never hit this - decodeImage throws an assertion because the
+  // image decoded doesn't have enough frames.
   try {
       istream = imgTools.encodeImage(container, "image/png");
   } catch (e) {
       err = e;
       errsrc = "encode";
   }
 } catch (e) {
   err = e;
   errsrc = "decode";
 }
 
-do_check_eq(errsrc, "encode");
+do_check_eq(errsrc, "decode");
 checkExpectedError(/NS_ERROR_FAILURE/, err);
 
 
 /* ========== bug 815359  ========== */
 testnum = 815359;
 testdesc = "test correct ico hotspots (bug 815359)";
 
 imgName = "bug815359.ico";
index 5722223c26fe0024d8c4d18f198114d5fde708bb..c3a4aee616675d212178f70a97d8ce73fc1813e2
GIT binary patch
literal 948
zc$@*W155mgP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV000AfNkl<ZIE_Wq
zZA{b!0LSrv8M=bR6`*jJ0!oI$G}1Y1KH(H^n&*TDN(PBSpuyeoq=3OvdO#V9B2%$2
zDo=>V4UD_Ey98Hw^3d_z0SAGilu96u$N#q%XukhFy!r@;Ac`UYA}|4121ocoXC$|(
zmhAFs@_()8{-eiC&%|c3PdfsLAWkBRQ*{45jN(!i!58%;Yg)+fe#rTTK4OcE_(y-i
z$&(q34D~;~c{U(UFxXPX_2L57Mw}+>yBnmHYDp>8aoIdTX7gQ?W%Wd!%An+eFYOh+
zJm@TfsS!X#VCo6YXF|{?$jJLDiqg!(XfynY&%Hv@4HE~-YB^GE=94SsZ1eTOQ0l{@
z`kfdnk`bpy5ttg`_Gg<gC%VyoWC^V?u4oUskd<|uV})fX4NZKiZy`$4#E#VO2|N}<
zWAQuOtMcJ~pAliW`zGekz37T{q&wOPi%Lq<p+(%v2qNkDQTF|)MV?cIb4WV=IeLQ6
zswvD|$I#7n^q4Lo+^I~%oV=8-=ml6*61r83Xh~kfmno4P%qc;hUCC^36;^8_SRa$i
zHbojW1zQ>Klw&OMN9f5@(wXRrB}PI=goL6^_M`@S6LBJwy;(mKa9)FFP&zNU@5N^M
z9@f9VhX(Zu#(R7)UEP9Em$DB_f*Tf<6zyhP)GJ>mHQ0}!_%j41T_7|i3-6Gxd11j;
zX21R(r%&u>pg_WKgDY*CaD?B_rqB`PMvqEDQ@}hLcUWNxf0Ih(Ms#tT`6YQLAN%?7
z;+&N@*n3fs9l*bpOBt#6rqPgwaL-tSK`y07A)#04h~<DS#t&X2-NS}>uZ66zb779)
z%-mTn#O+!|%TLRBXz*aPKa@Xe3lSK5Lb2Zlnm>~8m+B2H3Og(cCk&xW2w&~NMwczD
zneWc2?aOFSa-}cVnu-4H+}7>p@o*mk;xu=vbzFPfjyjnG?Lks3hn(nANa=`O#-E9+
z=}7RRGuD|_r4>WJEvCQjU21jbK%7KC1SThFxR^zr^E}EIzQT3sEQ}lMG07ci`_Pe&
zFni2#*8HP(pjY!2nyZJI7#n(qX~v;AK2BS{nr}Saxn@6?qWP~<BC)2z(+0iFmRpgI
zXj50A&rfB1^ucpX|5Fx4n4V^A;4XFFUZx^!KZSA`h5j<ikA_gAKF45hD@;F^2=E{F
WUdnCPA!Vxo0000<MNUMnLSTZj*T-Z4
index 238973189040030ed5071fb3f9ed8c141a802211..03a01c6de84a633c5a4a73a9b0187d92f4ba9125
GIT binary patch
literal 868
zc$@)b1DpJbP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0009kNkl<ZIE{Ui
zZ%ot$9LB%*&pYJKgB;y?N7{v(rijZTS#vDb_#?W}a%UqfDQ5)&Zuf&D=q}QF!A8#L
z&xrm^lAV?7x`A9GlMr*(;N0k7ID)(1Nh6K*qMFMi|9pB;xtZDX`uRN1o97X^gDm2C
z#IoTHZ%TGsU8?NOxs&fUEh+urn;pRkUON>dG&|3GV?VHeC`Q%`o#;}k0{;me@;vMo
zF=m<f2HA6bit4^e+WQCSRxi;NyGYHKQ|xa0n1*dDSr{~sze-%U1YD@i{B_QsOXRSh
z;g7uh+`gXL&{tH2qwEZxV_#$jZ-0dQ9(;=5VmfZj<<s{3vhJG!(Px)jPc+|ys@PE#
zJCnQ2RQC>3b1F*B@C18?#;G0{<56FLvbTD<9M*C*>_S8=A|l3wfBE0A6IF3CU2Er3
zYY|;<H&S^l!p@!%OvOGb0%ve{403pXKFMG@7QJkevyH1hO!zWy!m8rrLX(TaT0a#>
zzGlZ~XE7FdS(H~pfiJ*X_W_dMKfv{0UgUMR?zo&*)*e&6HdK!Twcg3m^^4h7RK$}l
z@8Iq@$@Y$uY^>`<e}4t~6_1ls>gDR74zAS^ee>>%()W;kJkk7Db7+H!o;6zB&(*WV
zA7bmi9!mTnN_}6TTULU`n$NqfySehdiEDFOdJpD~NUccKOic!=;vnj_Ftu4w6$deo
zlUc=1LU9so-;Nk_5p53P1BE1y8dw-~v3Z^L6%motkxi+@JvLOuNn)3o=}Ie|4m}66
z(=ad1Lv%TaHiu8EviT#TC3z$ZXhKBRiHJzIMt+<ux1u)Kh<mKWJxiHwaFVzBF<g!o
z78yzixL1&<cQD^6+*oMkyB_nri0J>Bg5!)!!@1%N#>&!B8*RirX{cU1iI?sr(X<k^
zK9l$}I+C+ylIQh^NbxOeTq9C;db!YN)NvwB&uBpg6Xh<>SK64Vvoqab<fpKn%cB~y
z9oiNV(cJcl6p@Xei(KiqnmBQng@FtUL#xevTez6<Y7=A4X}=qE^0bI(|L>4S5h*D*
u8$Nk8-8lBL-88zzVdxT(Cq%^hZ}Xqb0K7F1=KLuD0000<MNUMnLSTYT0jf3t