Bug 716140 - Set the size of images via ImageMetadata objects. r=seth
authorJoe Drew <joe@drew.ca>
Wed, 27 Feb 2013 14:23:08 -0500
changeset 125640 0a2fc100f05ffc7e8b6800c3c4aa69a52906d9c7
parent 125639 e0683dc77a1b9e798c46b62904e8de8bc096949d
child 125641 d1f978369c50ff398618c6ce04d1dc33d6883d81
push id24461
push useremorley@mozilla.com
push dateThu, 21 Mar 2013 11:51:51 +0000
treeherdermozilla-central@a73a2b5c423b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth
bugs716140
milestone22.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 716140 - Set the size of images via ImageMetadata objects. r=seth * * * imported patch jpeg-size-decode-more-writing
image/decoders/nsICODecoder.cpp
image/decoders/nsJPEGDecoder.cpp
image/src/Decoder.cpp
image/src/Decoder.h
image/src/ImageMetadata.h
image/src/RasterImage.cpp
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -208,16 +208,21 @@ nsICODecoder::SetHotSpotIfCursor() {
   mImageMetadata.SetHotspot(mDirEntry.mXHotspot, mDirEntry.mYHotspot);
 }
 
 void
 nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
 
+  if (IsSizeDecode() && HasSize()) {
+    // More data came in since we found the size. We have nothing to do here.
+    return;
+  }
+
   if (!aCount) // aCount=0 means EOF
     return;
 
   while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
     if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
       if ((*aBuffer != 1) && (*aBuffer != 2)) {
         PostDataError();
         return;
@@ -324,16 +329,22 @@ nsICODecoder::WriteInternal(const char* 
     }
   }
 
   // If we have a PNG, let the PNG decoder do all of the rest of the work
   if (mIsPNG && mContainedDecoder && mPos >= mImageOffset + PNGSIGNATURESIZE) {
     if (!WriteToContainedDecoder(aBuffer, aCount)) {
       return;
     }
+
+    if (mContainedDecoder->HasSize()) {
+      PostSize(mContainedDecoder->GetImageMetadata().GetWidth(),
+               mContainedDecoder->GetImageMetadata().GetHeight());
+    }
+
     mPos += aCount;
     aBuffer += aCount;
     aCount = 0;
 
     // Raymond Chen says that 32bpp only are valid PNG ICOs
     // http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
     if (!IsSizeDecode() &&
         !static_cast<nsPNGDecoder*>(mContainedDecoder.get())->IsValidICO()) {
@@ -418,16 +429,19 @@ nsICODecoder::WriteInternal(const char* 
       return;
     }
 
     // Write out the BMP's bitmap info header
     if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw))) {
       return;
     }
 
+    PostSize(mContainedDecoder->GetImageMetadata().GetWidth(),
+             mContainedDecoder->GetImageMetadata().GetHeight());
+
     // We have the size. If we're doing a size decode, we got what
     // we came for.
     if (IsSizeDecode())
       return;
 
     // Sometimes the ICO BPP header field is not filled out
     // so we should trust the contained resource over our own
     // information.
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -189,16 +189,21 @@ nsJPEGDecoder::FinishInternal()
 void
 nsJPEGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
 {
   mSegment = (const JOCTET *)aBuffer;
   mSegmentLen = aCount;
 
   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
 
+  if (IsSizeDecode() && HasSize()) {
+    // More data came in since we found the size. We have nothing to do here.
+    return;
+  }
+
   /* Return here if there is a fatal error within libjpeg. */
   nsresult error_code;
   // This cast to nsresult makes sense because setjmp() returns whatever we
   // passed to longjmp(), which was actually an nsresult.
   if ((error_code = (nsresult)setjmp(mErr.setjmp_buffer)) != NS_OK) {
     if (error_code == NS_ERROR_FAILURE) {
       PostDataError();
       /* Error due to corrupt stream - return NS_OK and consume silently
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -232,33 +232,36 @@ Decoder::FlushInvalidations()
   if (mInvalidRect.IsEmpty())
     return;
 
   if (mObserver) {
 #ifdef XP_MACOSX
     // Bug 703231
     // Because of high quality down sampling on mac we show scan lines while decoding.
     // Bypass this problem by redrawing the border.
-    int32_t width;
-    int32_t height;
+    if (mImageMetadata.HasSize()) {
+      nsIntRect mImageBound(0, 0, mImageMetadata.GetWidth(), mImageMetadata.GetHeight());
 
-    mImage.GetWidth(&width);
-    mImage.GetHeight(&height);
-    nsIntRect mImageBound(0, 0, width, height);
-
-    mInvalidRect.Inflate(1);
-    mInvalidRect = mInvalidRect.Intersect(mImageBound);
+      mInvalidRect.Inflate(1);
+      mInvalidRect = mInvalidRect.Intersect(mImageBound);
+    }
 #endif
     mObserver->FrameChanged(&mInvalidRect);
   }
 
   // Clear the invalidation rectangle
   mInvalidRect.SetEmpty();
 }
 
+void
+Decoder::SetSizeOnImage()
+{
+  mImage.SetSize(mImageMetadata.GetWidth(), mImageMetadata.GetHeight());
+}
+
 /*
  * Hook stubs. Override these as necessary in decoder implementations.
  */
 
 void Decoder::InitInternal() { }
 void Decoder::WriteInternal(const char* aBuffer, uint32_t aCount) { }
 void Decoder::FinishInternal() { }
 
@@ -269,17 +272,17 @@ void Decoder::FinishInternal() { }
 void
 Decoder::PostSize(int32_t aWidth, int32_t aHeight)
 {
   // Validate
   NS_ABORT_IF_FALSE(aWidth >= 0, "Width can't be negative!");
   NS_ABORT_IF_FALSE(aHeight >= 0, "Height can't be negative!");
 
   // Tell the image
-  mImage.SetSize(aWidth, aHeight);
+  mImageMetadata.SetSize(aWidth, aHeight);
 
   // Notify the observer
   if (mObserver)
     mObserver->OnStartContainer();
 }
 
 void
 Decoder::PostFrameStart()
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -126,16 +126,19 @@ public:
   enum DecodeStyle {
       PROGRESSIVE, // produce intermediate frames representing the partial state of the image
       SEQUENTIAL // decode to final image immediately
   };
 
   void SetDecodeFlags(uint32_t aFlags) { mDecodeFlags = aFlags; }
   uint32_t GetDecodeFlags() { return mDecodeFlags; }
 
+  bool HasSize() const { return mImageMetadata.HasSize(); }
+  void SetSizeOnImage();
+
   // Use HistogramCount as an invalid Histogram ID
   virtual Telemetry::ID SpeedHistogram() { return Telemetry::HistogramCount; }
 
   ImageMetadata& GetImageMetadata() { return mImageMetadata; }
 
   // Tell the decoder infrastructure to allocate a frame. By default, frame 0
   // is created as an ARGB frame with no offset and with size width * height.
   // If decoders need something different, they must ask for it.
--- a/image/src/ImageMetadata.h
+++ b/image/src/ImageMetadata.h
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/StandardInteger.h"
+#include "mozilla/Util.h"
+#include "nsSize.h"
 
 namespace mozilla {
 namespace image {
 
 class RasterImage;
 
 // The metadata about an image that decoders accumulate as they decode.
 class ImageMetadata
@@ -35,21 +37,33 @@ public:
     mLoopCount = loopcount;
   }
 
   void SetIsNonPremultiplied(bool nonPremult)
   {
     mIsNonPremultiplied = nonPremult;
   }
 
+  void SetSize(int32_t width, int32_t height)
+  {
+    mSize.construct(nsIntSize(width, height));
+  }
+
+  bool HasSize() const { return !mSize.empty(); }
+
+  int32_t GetWidth() const { return mSize.ref().width; }
+  int32_t GetHeight() const { return mSize.ref().height; }
+
 private:
   // The hotspot found on cursors, or -1 if none was found.
   int32_t mHotspotX;
   int32_t mHotspotY;
 
   // The loop count for animated images, or -1 for infinite loop.
   int32_t mLoopCount;
 
+  Maybe<nsIntSize> mSize;
+
   bool mIsNonPremultiplied;
 };
 
 } // namespace image
 } // namespace mozilla
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -3211,17 +3211,16 @@ RasterImage::DecodeSomeData(uint32_t aMa
 {
   // We should have a decoder if we get here
   NS_ABORT_IF_FALSE(mDecoder, "trying to decode without decoder!");
 
   // If we have nothing to decode, return
   if (mBytesDecoded == mSourceData.Length())
     return NS_OK;
 
-
   // write the proper amount of data
   uint32_t bytesToDecode = std::min(aMaxBytes,
                                   mSourceData.Length() - mBytesDecoded);
   nsresult rv = WriteToDecoder(mSourceData.Elements() + mBytesDecoded,
                                bytesToDecode);
 
   return rv;
 }
@@ -3357,16 +3356,20 @@ RasterImage::FinishedSomeDecoding(eShutd
   bool wasSize = false;
   nsresult rv = NS_OK;
 
   if (image->mDecoder) {
     if (request && request->mChunkCount && !image->mDecoder->IsSizeDecode()) {
       Telemetry::Accumulate(Telemetry::IMAGE_DECODE_CHUNKS, request->mChunkCount);
     }
 
+    if (!image->mHasSize && image->mDecoder->HasSize()) {
+      image->mDecoder->SetSizeOnImage();
+    }
+
     // If the decode finished, or we're specifically being told to shut down,
     // tell the image and shut down the decoder.
     if (image->mDecoder->GetDecodeDone() || image->IsDecodeFinished() ||
         aIntent != eShutdownIntent_Done) {
       done = true;
 
       // Hold on to a reference to the decoder until we're done with it
       nsRefPtr<Decoder> decoder = image->mDecoder;