Bug 1527951 - Ignore WebP image's alpha channel when a frame is marked as opaque. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Fri, 15 Feb 2019 15:46:08 -0500
changeset 517546 1c887a569595636763f17265af1e7c8cced30d50
parent 517545 b4ab57f9c0cb57f93a6ec6fd8a5bf45d54ebfffa
child 517547 d9b2f663c85b6edede78d4ff1257375fbc60b042
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1527951
milestone67.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 1527951 - Ignore WebP image's alpha channel when a frame is marked as opaque. r=tnikkel 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<