Bug 1185799 (Part 1) - Use DecoderFactory to construct nsICODecoder's contained decoder. r=edwin
authorSeth Fowler <mark.seth.fowler@gmail.com>
Sat, 02 Jul 2016 21:20:55 -0600
changeset 346239 07a67db040dca1ae3722eed0cd36880dd66da73b
parent 346238 98eca6a35e1a96107aba99410afb256bdb2dd6cd
child 346240 090ab64054fd86f10f7f30c378c84bb57d112f62
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin
bugs1185799
milestone50.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 1185799 (Part 1) - Use DecoderFactory to construct nsICODecoder's contained decoder. r=edwin
image/Decoder.cpp
image/Decoder.h
image/DecoderFactory.cpp
image/DecoderFactory.h
image/decoders/nsICODecoder.cpp
image/decoders/nsICODecoder.h
--- a/image/Decoder.cpp
+++ b/image/Decoder.cpp
@@ -235,16 +235,22 @@ Decoder::SetTargetSize(const nsIntSize& 
   }
 
   // Create a downscaler that we'll filter our output through.
   mDownscaler.emplace(aSize);
 
   return NS_OK;
 }
 
+Maybe<IntSize>
+Decoder::GetTargetSize()
+{
+  return mDownscaler ? Some(mDownscaler->TargetSize()) : Nothing();
+}
+
 nsresult
 Decoder::AllocateFrame(uint32_t aFrameNum,
                        const nsIntSize& aTargetSize,
                        const nsIntRect& aFrameRect,
                        gfx::SurfaceFormat aFormat,
                        uint8_t aPaletteDepth)
 {
   mCurrentFrame = AllocateFrameInternal(aFrameNum, aTargetSize, aFrameRect,
--- a/image/Decoder.h
+++ b/image/Decoder.h
@@ -109,17 +109,24 @@ public:
    *
    * If the provided size is unacceptable, an error is returned.
    *
    * Returning NS_OK from this method is a promise that the decoder will decode
    * the image to the requested target size unless it encounters an error.
    *
    * This must be called before Init() is called.
    */
-  nsresult SetTargetSize(const nsIntSize& aSize);
+  nsresult SetTargetSize(const gfx::IntSize& aSize);
+
+  /**
+   * If this decoder supports downscale-during-decode and is configured to
+   * downscale, returns the target size that the output size will be decoded to.
+   * Otherwise, returns Nothing().
+   */
+  Maybe<gfx::IntSize> GetTargetSize();
 
   /**
    * Set the requested sample size for this decoder. Used to implement the
    * -moz-sample-size media fragment.
    *
    *  XXX(seth): Support for -moz-sample-size will be removed in bug 1120056.
    */
   virtual void SetSampleSize(int aSampleSize) { }
@@ -242,20 +249,28 @@ public:
     return mImageMetadata.GetSize();
   }
 
   virtual Telemetry::ID SpeedHistogram();
 
   ImageMetadata& GetImageMetadata() { return mImageMetadata; }
 
   /**
-   * Returns a weak pointer to the image associated with this decoder.
+   * @return a weak pointer to the image associated with this decoder. Illegal
+   * to call if this decoder is not associated with an image.
    */
   RasterImage* GetImage() const { MOZ_ASSERT(mImage); return mImage.get(); }
 
+  /**
+   * @return a possibly-null weak pointer to the image associated with this
+   * decoder. May be called even if this decoder is not associated with an
+   * image.
+   */
+  RasterImage* GetImageMaybeNull() const { return mImage.get(); }
+
   RawAccessFrameRef GetCurrentFrameRef()
   {
     return mCurrentFrame ? mCurrentFrame->RawAccessRef()
                          : RawAccessFrameRef();
   }
 
   /**
    * Writes data to the decoder. Only public for the benefit of nsICODecoder;
--- a/image/DecoderFactory.cpp
+++ b/image/DecoderFactory.cpp
@@ -223,16 +223,64 @@ DecoderFactory::CreateMetadataDecoder(De
     return nullptr;
   }
 
   RefPtr<IDecodingTask> task = new MetadataDecodingTask(WrapNotNull(decoder));
   return task.forget();
 }
 
 /* static */ already_AddRefed<Decoder>
+DecoderFactory::CreateDecoderForICOResource(DecoderType aType,
+                                            NotNull<SourceBuffer*> aSourceBuffer,
+                                            NotNull<nsICODecoder*> aICODecoder,
+                                            const Maybe<uint32_t>& aDataOffset
+                                              /* = Nothing() */)
+{
+  // Create the decoder.
+  RefPtr<Decoder> decoder;
+  switch (aType) {
+    case DecoderType::BMP:
+      MOZ_ASSERT(aDataOffset);
+      decoder = new nsBMPDecoder(aICODecoder->GetImageMaybeNull(), *aDataOffset);
+      break;
+
+    case DecoderType::PNG:
+      MOZ_ASSERT(!aDataOffset);
+      decoder = new nsPNGDecoder(aICODecoder->GetImageMaybeNull());
+      break;
+
+    default:
+      MOZ_ASSERT_UNREACHABLE("Invalid ICO resource decoder type");
+      return nullptr;
+  }
+
+  MOZ_ASSERT(decoder);
+
+  // Initialize the decoder, copying settings from @aICODecoder.
+  decoder->SetMetadataDecode(aICODecoder->IsMetadataDecode());
+  decoder->SetIterator(aSourceBuffer->Iterator());
+  decoder->SetDecoderFlags(aICODecoder->GetDecoderFlags());
+  decoder->SetSurfaceFlags(aICODecoder->GetSurfaceFlags());
+
+  // Set a target size for downscale-during-decode if applicable.
+  const Maybe<IntSize> targetSize = aICODecoder->GetTargetSize();
+  if (targetSize) {
+    DebugOnly<nsresult> rv = decoder->SetTargetSize(*targetSize);
+    MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
+  }
+
+  decoder->Init();
+  if (NS_FAILED(decoder->GetDecoderError())) {
+    return nullptr;
+  }
+
+  return decoder.forget();
+}
+
+/* static */ already_AddRefed<Decoder>
 DecoderFactory::CreateAnonymousDecoder(DecoderType aType,
                                        NotNull<SourceBuffer*> aSourceBuffer,
                                        const Maybe<IntSize>& aTargetSize,
                                        SurfaceFlags aSurfaceFlags)
 {
   if (aType == DecoderType::UNKNOWN) {
     return nullptr;
   }
--- a/image/DecoderFactory.h
+++ b/image/DecoderFactory.h
@@ -15,16 +15,17 @@
 #include "nsCOMPtr.h"
 #include "SurfaceFlags.h"
 
 namespace mozilla {
 namespace image {
 
 class Decoder;
 class IDecodingTask;
+class nsICODecoder;
 class RasterImage;
 class SourceBuffer;
 
 /**
  * The type of decoder; this is usually determined from a MIME type using
  * DecoderFactory::GetDecoderType().
  */
 enum class DecoderType
@@ -115,16 +116,39 @@ public:
    */
   static already_AddRefed<IDecodingTask>
   CreateMetadataDecoder(DecoderType aType,
                         NotNull<RasterImage*> aImage,
                         NotNull<SourceBuffer*> aSourceBuffer,
                         int aSampleSize);
 
   /**
+   * Creates and initializes a decoder for an ICO resource, which may be either
+   * a BMP or PNG image.
+   *
+   * @param aType Which type of decoder to create. This must be either BMP or
+   *              PNG.
+   * @param aSourceBuffer The SourceBuffer which the decoder will read its data
+   *                      from.
+   * @param aICODecoder The ICO decoder which is controlling this resource
+   *                    decoder. @aICODecoder's settings will be copied to the
+   *                    resource decoder, so the two decoders will have the
+   *                    same decoder flags, surface flags, target size, and
+   *                    other parameters.
+   * @param aDataOffset If @aType is BMP, specifies the offset at which data
+   *                    begins in the BMP resource. Must be Some() if and only
+   *                    if @aType is BMP.
+   */
+  static already_AddRefed<Decoder>
+  CreateDecoderForICOResource(DecoderType aType,
+                              NotNull<SourceBuffer*> aSourceBuffer,
+                              NotNull<nsICODecoder*> aICODecoder,
+                              const Maybe<uint32_t>& aDataOffset = Nothing());
+
+  /**
    * Creates and initializes an anonymous decoder (one which isn't associated
    * with an Image object). Only the first frame of the image will be decoded.
    *
    * @param aType Which type of decoder to create - JPEG, PNG, etc.
    * @param aSourceBuffer The SourceBuffer which the decoder will read its data
    *                      from.
    * @param aTargetSize If not Nothing(), the target size which the image should
    *                    be scaled to during decoding. It's an error to specify
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -286,24 +286,21 @@ LexerTransition<ICOState>
 nsICODecoder::SniffResource(const char* aData)
 {
   // We use the first PNGSIGNATURESIZE bytes to determine whether this resource
   // is a PNG or a BMP.
   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();
+    mContainedSourceBuffer = new SourceBuffer();
+    mContainedDecoder =
+      DecoderFactory::CreateDecoderForICOResource(DecoderType::PNG,
+                                                  WrapNotNull(mContainedSourceBuffer),
+                                                  WrapNotNull(this));
 
     if (!WriteToContainedDecoder(aData, PNGSIGNATURESIZE)) {
       return Transition::TerminateFailure();
     }
 
     if (mDirEntry.mBytesInRes <= PNGSIGNATURESIZE) {
       return Transition::TerminateFailure();
     }
@@ -366,25 +363,24 @@ nsICODecoder::ReadBIH(const char* aData)
     if (numColors == (uint16_t)-1) {
       return Transition::TerminateFailure();
     }
     dataOffset += 4 * numColors;
   }
 
   // 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.
-  RefPtr<nsBMPDecoder> bmpDecoder = new nsBMPDecoder(mImage, dataOffset);
-  mContainedDecoder = bmpDecoder;
-  mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
-  mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
-  mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
-  if (mDownscaler) {
-    mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
-  }
-  mContainedDecoder->Init();
+  mContainedSourceBuffer = new SourceBuffer();
+  mContainedDecoder =
+    DecoderFactory::CreateDecoderForICOResource(DecoderType::BMP,
+                                                WrapNotNull(mContainedSourceBuffer),
+                                                WrapNotNull(this),
+                                                Some(dataOffset));
+  RefPtr<nsBMPDecoder> bmpDecoder =
+    static_cast<nsBMPDecoder*>(mContainedDecoder.get());
 
   // Verify that the BIH width and height values match the ICO directory entry,
   // and fix the BIH height value to compensate for the fact that the underlying
   // BMP decoder doesn't know about AND masks.
   if (!CheckAndFixBitmapSize(reinterpret_cast<int8_t*>(mBIHraw))) {
     return Transition::TerminateFailure();
   }
 
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -107,16 +107,17 @@ private:
   LexerTransition<ICOState> ReadBMP(const char* aData, uint32_t aLen);
   LexerTransition<ICOState> PrepareForMask();
   LexerTransition<ICOState> ReadMaskRow(const char* aData);
   LexerTransition<ICOState> FinishMask();
   LexerTransition<ICOState> FinishResource();
 
   StreamingLexer<ICOState, 32> mLexer; // The lexer.
   RefPtr<Decoder> mContainedDecoder; // Either a BMP or PNG decoder.
+  RefPtr<SourceBuffer> mContainedSourceBuffer;  // SourceBuffer for mContainedDecoder.
   UniquePtr<uint8_t[]> mMaskBuffer;    // A temporary buffer for the alpha mask.
   char mBIHraw[bmp::InfoHeaderLength::WIN_ICO]; // The bitmap information header.
   IconDirEntry mDirEntry;              // The dir entry for the selected resource.
   gfx::IntSize mBiggestResourceSize;   // Used to select the intrinsic size.
   gfx::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.