Bug 1527951 - Ignore WebP image's alpha channel when a frame is marked as opaque. r=tnikkel a=lizzard
authorAndrew Osmond <aosmond@mozilla.com>
Fri, 15 Feb 2019 15:46:08 -0500
changeset 516170 aecc839fd41caf60a010626eb209deccdbf859ef
parent 516169 7bd928c859a554df57f30f2f7525c06fa6402fb1
child 516171 20cd9dd27bfc31a54f8451837f941891374d3363
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel, lizzard
bugs1527951
milestone66.0
Bug 1527951 - Ignore WebP image's alpha channel when a frame is marked as opaque. r=tnikkel a=lizzard Differential Revision: https://phabricator.services.mozilla.com/D19994
image/decoders/nsWebPDecoder.cpp
image/test/gtest/Common.cpp
image/test/gtest/Common.h
image/test/gtest/TestDecoders.cpp
image/test/gtest/moz.build
image/test/gtest/transparent-no-alpha-header.webp
image/test/gtest/transparent.webp
--- a/image/decoders/nsWebPDecoder.cpp
+++ b/image/decoders/nsWebPDecoder.cpp
@@ -474,28 +474,39 @@ LexerResult nsWebPDecoder::ReadSingle(co
 
     for (int row = mLastRow; row < lastRow; row++) {
       uint8_t* src = rowStart + row * stride;
       if (mTransform) {
         qcms_transform_data(mTransform, src, src, width);
       }
 
       WriteState result;
-      if (noPremultiply) {
+      if (mFormat == SurfaceFormat::B8G8R8A8) {
+        if (noPremultiply) {
+          result =
+              mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
+                const uint32_t pixel =
+                    gfxPackedPixelNoPreMultiply(src[3], src[0], src[1], src[2]);
+                src += 4;
+                return AsVariant(pixel);
+              });
+        } else {
+          result =
+              mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
+                const uint32_t pixel =
+                    gfxPackedPixel(src[3], src[0], src[1], src[2]);
+                src += 4;
+                return AsVariant(pixel);
+              });
+        }
+      } else {
+        // We are producing a surface without transparency. Ignore the alpha
+        // channel provided to us by the library.
         result = mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
-          MOZ_ASSERT(mFormat == SurfaceFormat::B8G8R8A8 || src[3] == 0xFF);
-          const uint32_t pixel =
-              gfxPackedPixelNoPreMultiply(src[3], src[0], src[1], src[2]);
-          src += 4;
-          return AsVariant(pixel);
-        });
-      } else {
-        result = mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
-          MOZ_ASSERT(mFormat == SurfaceFormat::B8G8R8A8 || src[3] == 0xFF);
-          const uint32_t pixel = gfxPackedPixel(src[3], src[0], src[1], src[2]);
+          const uint32_t pixel = gfxPackedPixel(0xFF, src[0], src[1], src[2]);
           src += 4;
           return AsVariant(pixel);
         });
       }
 
       Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
       if (invalidRect) {
         PostInvalidation(invalidRect->mInputSpaceRect,
--- a/image/test/gtest/Common.cpp
+++ b/image/test/gtest/Common.cpp
@@ -608,16 +608,30 @@ ImageTestCase TransparentPNGTestCase() {
                        TEST_CASE_IS_TRANSPARENT);
 }
 
 ImageTestCase TransparentGIFTestCase() {
   return ImageTestCase("transparent.gif", "image/gif", IntSize(16, 16),
                        TEST_CASE_IS_TRANSPARENT);
 }
 
+ImageTestCase TransparentWebPTestCase() {
+  ImageTestCase test("transparent.webp", "image/webp", IntSize(100, 100),
+                     TEST_CASE_IS_TRANSPARENT);
+  test.mColor = BGRAColor::Transparent();
+  return test;
+}
+
+ImageTestCase TransparentNoAlphaHeaderWebPTestCase() {
+  ImageTestCase test("transparent-no-alpha-header.webp", "image/webp",
+                     IntSize(100, 100), TEST_CASE_IS_FUZZY);
+  test.mColor = BGRAColor(0x00, 0x00, 0x00, 0xFF);  // black
+  return test;
+}
+
 ImageTestCase FirstFramePaddingGIFTestCase() {
   return ImageTestCase("transparent.gif", "image/gif", IntSize(16, 16),
                        TEST_CASE_IS_TRANSPARENT);
 }
 
 ImageTestCase TransparentIfWithinICOBMPTestCase(TestCaseFlags aFlags) {
   // This is a BMP that is only transparent when decoded as if it is within an
   // ICO file. (Note: aFlags needs to be set to TEST_CASE_DEFAULT_FLAGS or
--- a/image/test/gtest/Common.h
+++ b/image/test/gtest/Common.h
@@ -25,50 +25,16 @@ class nsIInputStream;
 
 namespace mozilla {
 namespace image {
 
 ///////////////////////////////////////////////////////////////////////////////
 // Types
 ///////////////////////////////////////////////////////////////////////////////
 
-enum TestCaseFlags {
-  TEST_CASE_DEFAULT_FLAGS = 0,
-  TEST_CASE_IS_FUZZY = 1 << 0,
-  TEST_CASE_HAS_ERROR = 1 << 1,
-  TEST_CASE_IS_TRANSPARENT = 1 << 2,
-  TEST_CASE_IS_ANIMATED = 1 << 3,
-  TEST_CASE_IGNORE_OUTPUT = 1 << 4,
-};
-
-struct ImageTestCase {
-  ImageTestCase(const char* aPath, const char* aMimeType, gfx::IntSize aSize,
-                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
-      : mPath(aPath),
-        mMimeType(aMimeType),
-        mSize(aSize),
-        mOutputSize(aSize),
-        mFlags(aFlags) {}
-
-  ImageTestCase(const char* aPath, const char* aMimeType, gfx::IntSize aSize,
-                gfx::IntSize aOutputSize,
-                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
-      : mPath(aPath),
-        mMimeType(aMimeType),
-        mSize(aSize),
-        mOutputSize(aOutputSize),
-        mFlags(aFlags) {}
-
-  const char* mPath;
-  const char* mMimeType;
-  gfx::IntSize mSize;
-  gfx::IntSize mOutputSize;
-  uint32_t mFlags;
-};
-
 struct BGRAColor {
   BGRAColor() : BGRAColor(0, 0, 0, 0) {}
 
   BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha,
             bool aPremultiplied = false)
       : mBlue(aBlue),
         mGreen(aGreen),
         mRed(aRed),
@@ -98,16 +64,53 @@ struct BGRAColor {
 
   uint8_t mBlue;
   uint8_t mGreen;
   uint8_t mRed;
   uint8_t mAlpha;
   bool mPremultiplied;
 };
 
+enum TestCaseFlags {
+  TEST_CASE_DEFAULT_FLAGS = 0,
+  TEST_CASE_IS_FUZZY = 1 << 0,
+  TEST_CASE_HAS_ERROR = 1 << 1,
+  TEST_CASE_IS_TRANSPARENT = 1 << 2,
+  TEST_CASE_IS_ANIMATED = 1 << 3,
+  TEST_CASE_IGNORE_OUTPUT = 1 << 4,
+};
+
+struct ImageTestCase {
+  ImageTestCase(const char* aPath, const char* aMimeType, gfx::IntSize aSize,
+                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
+      : mPath(aPath),
+        mMimeType(aMimeType),
+        mSize(aSize),
+        mOutputSize(aSize),
+        mFlags(aFlags),
+        mColor(BGRAColor::Green()) {}
+
+  ImageTestCase(const char* aPath, const char* aMimeType, gfx::IntSize aSize,
+                gfx::IntSize aOutputSize,
+                uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
+      : mPath(aPath),
+        mMimeType(aMimeType),
+        mSize(aSize),
+        mOutputSize(aOutputSize),
+        mFlags(aFlags),
+        mColor(BGRAColor::Green()) {}
+
+  const char* mPath;
+  const char* mMimeType;
+  gfx::IntSize mSize;
+  gfx::IntSize mOutputSize;
+  uint32_t mFlags;
+  BGRAColor mColor;
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 // General Helpers
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
  * A RAII class that ensure that ImageLib services are available. Any tests that
  * require ImageLib to be initialized (for example, any test that uses the
  * SurfaceCache; see image::EnsureModuleInitialized() for the full list) can
@@ -431,16 +434,18 @@ ImageTestCase BlendAnimatedWebPTestCase(
 ImageTestCase CorruptTestCase();
 ImageTestCase CorruptBMPWithTruncatedHeader();
 ImageTestCase CorruptICOWithBadBMPWidthTestCase();
 ImageTestCase CorruptICOWithBadBMPHeightTestCase();
 ImageTestCase CorruptICOWithBadBppTestCase();
 
 ImageTestCase TransparentPNGTestCase();
 ImageTestCase TransparentGIFTestCase();
+ImageTestCase TransparentWebPTestCase();
+ImageTestCase TransparentNoAlphaHeaderWebPTestCase();
 ImageTestCase FirstFramePaddingGIFTestCase();
 ImageTestCase TransparentIfWithinICOBMPTestCase(TestCaseFlags aFlags);
 ImageTestCase NoFrameDelayGIFTestCase();
 ImageTestCase ExtraImageSubBlocksAnimatedGIFTestCase();
 
 ImageTestCase TransparentBMPWhenBMPAlphaEnabledTestCase();
 ImageTestCase RLE4BMPTestCase();
 ImageTestCase RLE8BMPTestCase();
--- a/image/test/gtest/TestDecoders.cpp
+++ b/image/test/gtest/TestDecoders.cpp
@@ -84,17 +84,17 @@ static void CheckDecoderResults(const Im
     return;
   }
 
   if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
     return;
   }
 
   // Check the output.
-  EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green(),
+  EXPECT_TRUE(IsSolidColor(surface, aTestCase.mColor,
                            aTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0));
 }
 
 template <typename Func>
 void WithSingleChunkDecode(const ImageTestCase& aTestCase,
                            const Maybe<IntSize>& aOutputSize,
                            Func aResultChecker) {
   nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
@@ -720,16 +720,24 @@ TEST_F(ImageDecoders, WebPLargeMultiChun
 TEST_F(ImageDecoders, WebPDownscaleDuringDecode) {
   CheckDownscaleDuringDecode(DownscaledWebPTestCase());
 }
 
 TEST_F(ImageDecoders, WebPIccSrgbMultiChunk) {
   CheckDecoderMultiChunk(GreenWebPIccSrgbTestCase());
 }
 
+TEST_F(ImageDecoders, WebPTransparentSingleChunk) {
+  CheckDecoderSingleChunk(TransparentWebPTestCase());
+}
+
+TEST_F(ImageDecoders, WebPTransparentNoAlphaHeaderSingleChunk) {
+  CheckDecoderSingleChunk(TransparentNoAlphaHeaderWebPTestCase());
+}
+
 TEST_F(ImageDecoders, AnimatedGIFSingleChunk) {
   CheckDecoderSingleChunk(GreenFirstFrameAnimatedGIFTestCase());
 }
 
 TEST_F(ImageDecoders, AnimatedGIFMultiChunk) {
   CheckDecoderMultiChunk(GreenFirstFrameAnimatedGIFTestCase());
 }
 
--- a/image/test/gtest/moz.build
+++ b/image/test/gtest/moz.build
@@ -71,18 +71,20 @@ TEST_HARNESS_FILES.gtest += [
     'green.webp',
     'invalid-truncated-metadata.bmp',
     'large.webp',
     'no-frame-delay.gif',
     'rle4.bmp',
     'rle8.bmp',
     'transparent-ico-with-and-mask.ico',
     'transparent-if-within-ico.bmp',
+    'transparent-no-alpha-header.webp',
     'transparent.gif',
     'transparent.png',
+    'transparent.webp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/dom/base',
     '/gfx/2d',
     '/image',
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8ddd73ac7a2a23ae9e1d1aa3d807715d5202bd82
GIT binary patch
literal 120
zc$^FJbaN|UU|<M$bqWXzu!!JdfPiE$a`XxC-~{p**#!gzJ39WcGXT{nH~>X9urkbL
z)JkDUVX&L%vCwDf5@jWY6$~4MI5YDe7C&G}&R)6qNL&QluGx27pEf`_^B5TZ{Wr}F
H2bm85hhQRX
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..87b9520521a3dc90dcd8020a40791904820118d9
GIT binary patch
literal 120
zc$^FJbaN|UU|<M$bqWXzu!!ISvIT%R8H^l#0z5c@JVtf_LBWoWf9woEH3|+ukqxX2
za~ZW#7*ZJQCVDLNS-M17Nnr)U1|iPOyobdP7?QJB?mZG0!M1Dm9oMG~P|iFChJXJ}
JGsA(}832u-B76V<