TestDecodeToSurface.cpp (5772B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "gtest/gtest.h" 6 7 #include "Common.h" 8 #include "imgIContainer.h" 9 #include "ImageOps.h" 10 #include "mozilla/gfx/2D.h" 11 #include "nsComponentManagerUtils.h" 12 #include "nsCOMPtr.h" 13 #include "nsIInputStream.h" 14 #include "nsIRunnable.h" 15 #include "nsIThread.h" 16 #include "mozilla/RefPtr.h" 17 #include "nsString.h" 18 #include "nsThreadUtils.h" 19 20 using namespace mozilla; 21 using namespace mozilla::gfx; 22 using namespace mozilla::image; 23 24 class DecodeToSurfaceRunnable : public Runnable { 25 public: 26 DecodeToSurfaceRunnable(RefPtr<SourceSurface>& aSurface, 27 nsIInputStream* aInputStream, 28 ImageOps::ImageBuffer* aImageBuffer, 29 const ImageTestCase& aTestCase) 30 : mozilla::Runnable("DecodeToSurfaceRunnable"), 31 mSurface(aSurface), 32 mInputStream(aInputStream), 33 mImageBuffer(aImageBuffer), 34 mTestCase(aTestCase) {} 35 36 NS_IMETHOD Run() override { 37 Go(); 38 return NS_OK; 39 } 40 41 void Go() { 42 Maybe<IntSize> outputSize; 43 if (mTestCase.mOutputSize != mTestCase.mSize) { 44 outputSize.emplace(mTestCase.mOutputSize); 45 } 46 47 uint32_t flags = FromSurfaceFlags(mTestCase.mSurfaceFlags); 48 49 if (mImageBuffer) { 50 mSurface = ImageOps::DecodeToSurface( 51 mImageBuffer, nsDependentCString(mTestCase.mMimeType), flags, 52 outputSize); 53 } else { 54 mSurface = ImageOps::DecodeToSurface( 55 mInputStream.forget(), nsDependentCString(mTestCase.mMimeType), flags, 56 outputSize); 57 } 58 ASSERT_TRUE(mSurface != nullptr); 59 60 EXPECT_TRUE(mSurface->IsDataSourceSurface()); 61 EXPECT_TRUE(mSurface->GetFormat() == SurfaceFormat::OS_RGBX || 62 mSurface->GetFormat() == SurfaceFormat::OS_RGBA); 63 64 if (outputSize) { 65 EXPECT_EQ(*outputSize, mSurface->GetSize()); 66 } else { 67 EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); 68 } 69 70 EXPECT_TRUE(IsSolidColor(mSurface, mTestCase.Color(), mTestCase.Fuzz())); 71 } 72 73 private: 74 RefPtr<SourceSurface>& mSurface; 75 nsCOMPtr<nsIInputStream> mInputStream; 76 RefPtr<ImageOps::ImageBuffer> mImageBuffer; 77 ImageTestCase mTestCase; 78 }; 79 80 static void RunDecodeToSurface(const ImageTestCase& aTestCase, 81 ImageOps::ImageBuffer* aImageBuffer = nullptr) { 82 nsCOMPtr<nsIInputStream> inputStream; 83 if (!aImageBuffer) { 84 inputStream = LoadFile(aTestCase.mPath); 85 ASSERT_TRUE(inputStream != nullptr); 86 } 87 88 nsCOMPtr<nsIThread> thread; 89 nsresult rv = 90 NS_NewNamedThread("DecodeToSurface", getter_AddRefs(thread), nullptr); 91 ASSERT_NS_SUCCEEDED(rv); 92 93 // We run the DecodeToSurface tests off-main-thread to ensure that 94 // DecodeToSurface doesn't require any main-thread-only code. 95 RefPtr<SourceSurface> surface; 96 nsCOMPtr<nsIRunnable> runnable = new DecodeToSurfaceRunnable( 97 surface, inputStream, aImageBuffer, aTestCase); 98 NS_DispatchAndSpinEventLoopUntilComplete("RunDecodeToSurface"_ns, thread, 99 do_AddRef(runnable)); 100 101 thread->Shutdown(); 102 103 // Explicitly release the SourceSurface on the main thread. 104 surface = nullptr; 105 } 106 107 class ImageDecodeToSurface : public ::testing::Test { 108 protected: 109 AutoInitializeImageLib mInit; 110 }; 111 112 TEST_F(ImageDecodeToSurface, PNG) { RunDecodeToSurface(GreenPNGTestCase()); } 113 TEST_F(ImageDecodeToSurface, GIF) { RunDecodeToSurface(GreenGIFTestCase()); } 114 TEST_F(ImageDecodeToSurface, JPG) { RunDecodeToSurface(GreenJPGTestCase()); } 115 TEST_F(ImageDecodeToSurface, BMP) { RunDecodeToSurface(GreenBMPTestCase()); } 116 TEST_F(ImageDecodeToSurface, ICO) { RunDecodeToSurface(GreenICOTestCase()); } 117 TEST_F(ImageDecodeToSurface, Icon) { RunDecodeToSurface(GreenIconTestCase()); } 118 TEST_F(ImageDecodeToSurface, WebP) { RunDecodeToSurface(GreenWebPTestCase()); } 119 120 TEST_F(ImageDecodeToSurface, AnimatedGIF) { 121 RunDecodeToSurface(GreenFirstFrameAnimatedGIFTestCase()); 122 } 123 124 TEST_F(ImageDecodeToSurface, AnimatedPNG) { 125 RunDecodeToSurface(GreenFirstFrameAnimatedPNGTestCase()); 126 } 127 128 TEST_F(ImageDecodeToSurface, Corrupt) { 129 ImageTestCase testCase = CorruptTestCase(); 130 131 nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath); 132 ASSERT_TRUE(inputStream != nullptr); 133 134 RefPtr<SourceSurface> surface = ImageOps::DecodeToSurface( 135 inputStream.forget(), nsDependentCString(testCase.mMimeType), 136 imgIContainer::DECODE_FLAGS_DEFAULT); 137 EXPECT_TRUE(surface == nullptr); 138 } 139 140 TEST_F(ImageDecodeToSurface, ICOMultipleSizes) { 141 ImageTestCase testCase = GreenMultipleSizesICOTestCase(); 142 143 nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath); 144 ASSERT_TRUE(inputStream != nullptr); 145 146 RefPtr<ImageOps::ImageBuffer> buffer = 147 ImageOps::CreateImageBuffer(inputStream.forget()); 148 ASSERT_TRUE(buffer != nullptr); 149 150 ImageMetadata metadata; 151 nsresult rv = ImageOps::DecodeMetadata( 152 buffer, nsDependentCString(testCase.mMimeType), metadata); 153 EXPECT_NS_SUCCEEDED(rv); 154 ASSERT_TRUE(metadata.HasSize()); 155 EXPECT_EQ(testCase.mSize, metadata.GetSize().ToUnknownSize()); 156 157 const nsTArray<OrientedIntSize>& nativeSizes = metadata.GetNativeSizes(); 158 ASSERT_EQ(6u, nativeSizes.Length()); 159 160 OrientedIntSize expectedSizes[] = { 161 OrientedIntSize(16, 16), OrientedIntSize(32, 32), 162 OrientedIntSize(64, 64), OrientedIntSize(128, 128), 163 OrientedIntSize(256, 256), OrientedIntSize(256, 128), 164 }; 165 166 for (int i = 0; i < 6; ++i) { 167 EXPECT_EQ(expectedSizes[i], nativeSizes[i]); 168 169 // Request decoding at native size 170 testCase.mOutputSize = nativeSizes[i].ToUnknownSize(); 171 RunDecodeToSurface(testCase, buffer); 172 } 173 }