1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/test/image_decoder_test.h" 6 7 #include "base/file_util.h" 8 #include "base/files/file_enumerator.h" 9 #include "base/files/file_path.h" 10 #include "base/md5.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/path_service.h" 13 #include "base/strings/string_util.h" 14 #include "third_party/WebKit/public/platform/WebData.h" 15 #include "third_party/WebKit/public/platform/WebImage.h" 16 #include "third_party/WebKit/public/platform/WebSize.h" 17 #include "third_party/WebKit/public/web/WebImageDecoder.h" 18 19 using base::Time; 20 21 namespace { 22 23 const int kFirstFrameIndex = 0; 24 25 // Determine if we should test with file specified by |path| based 26 // on |file_selection| and the |threshold| for the file size. 27 bool ShouldSkipFile(const base::FilePath& path, 28 ImageDecoderTestFileSelection file_selection, 29 const int64 threshold) { 30 if (file_selection == TEST_ALL) 31 return false; 32 33 int64 image_size = 0; 34 base::GetFileSize(path, &image_size); 35 return (file_selection == TEST_SMALLER) == (image_size > threshold); 36 } 37 38 } // namespace 39 40 void ReadFileToVector(const base::FilePath& path, std::vector<char>* contents) { 41 std::string raw_image_data; 42 base::ReadFileToString(path, &raw_image_data); 43 contents->resize(raw_image_data.size()); 44 memcpy(&contents->at(0), raw_image_data.data(), raw_image_data.size()); 45 } 46 47 base::FilePath GetMD5SumPath(const base::FilePath& path) { 48 static const base::FilePath::StringType kDecodedDataExtension( 49 FILE_PATH_LITERAL(".md5sum")); 50 return base::FilePath(path.value() + kDecodedDataExtension); 51 } 52 53 #if defined(CALCULATE_MD5_SUMS) 54 void SaveMD5Sum(const base::FilePath& path, const blink::WebImage& web_image) { 55 // Calculate MD5 sum. 56 base::MD5Digest digest; 57 web_image.getSkBitmap().lockPixels(); 58 base::MD5Sum(web_image.getSkBitmap().getPixels(), 59 web_image.getSkBitmap().width() * web_image.getSkBitmap().height() * 60 sizeof(uint32_t), 61 &digest); 62 63 // Write sum to disk. 64 int bytes_written = file_util::WriteFile(path, 65 reinterpret_cast<const char*>(&digest), sizeof digest); 66 ASSERT_EQ(sizeof digest, bytes_written); 67 web_image.getSkBitmap().unlockPixels(); 68 } 69 #endif 70 71 #if !defined(CALCULATE_MD5_SUMS) 72 void VerifyImage(const blink::WebImageDecoder& decoder, 73 const base::FilePath& path, 74 const base::FilePath& md5_sum_path, 75 size_t frame_index) { 76 // Make sure decoding can complete successfully. 77 EXPECT_TRUE(decoder.isSizeAvailable()) << path.value(); 78 EXPECT_GE(decoder.frameCount(), frame_index) << path.value(); 79 EXPECT_TRUE(decoder.isFrameCompleteAtIndex(frame_index)) << path.value(); 80 EXPECT_FALSE(decoder.isFailed()); 81 82 // Calculate MD5 sum. 83 base::MD5Digest actual_digest; 84 blink::WebImage web_image = decoder.getFrameAtIndex(frame_index); 85 web_image.getSkBitmap().lockPixels(); 86 base::MD5Sum(web_image.getSkBitmap().getPixels(), 87 web_image.getSkBitmap().width() * web_image.getSkBitmap().height() * 88 sizeof(uint32_t), 89 &actual_digest); 90 91 // Read the MD5 sum off disk. 92 std::string file_bytes; 93 base::ReadFileToString(md5_sum_path, &file_bytes); 94 base::MD5Digest expected_digest; 95 ASSERT_EQ(sizeof expected_digest, file_bytes.size()) << path.value(); 96 memcpy(&expected_digest, file_bytes.data(), sizeof expected_digest); 97 98 // Verify that the sums are the same. 99 EXPECT_EQ(0, 100 memcmp(&expected_digest, &actual_digest, sizeof(base::MD5Digest))) 101 << path.value(); 102 web_image.getSkBitmap().unlockPixels(); 103 } 104 #endif 105 106 void ImageDecoderTest::SetUp() { 107 base::FilePath data_dir; 108 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &data_dir)); 109 data_dir_ = data_dir.AppendASCII("webkit"). 110 AppendASCII("data"). 111 AppendASCII(format_ + "_decoder"); 112 if (!base::PathExists(data_dir_)) { 113 const testing::TestInfo* const test_info = 114 testing::UnitTest::GetInstance()->current_test_info(); 115 VLOG(0) << test_info->name() << 116 " not running because test data wasn't found."; 117 data_dir_.clear(); 118 return; 119 } 120 } 121 122 std::vector<base::FilePath> ImageDecoderTest::GetImageFiles() const { 123 std::string pattern = "*." + format_; 124 125 base::FileEnumerator enumerator(data_dir_, 126 false, 127 base::FileEnumerator::FILES); 128 129 std::vector<base::FilePath> image_files; 130 base::FilePath next_file_name; 131 while (!(next_file_name = enumerator.Next()).empty()) { 132 base::FilePath base_name = next_file_name.BaseName(); 133 #if defined(OS_WIN) 134 std::string base_name_ascii = WideToASCII(base_name.value()); 135 #else 136 std::string base_name_ascii = base_name.value(); 137 #endif 138 if (!MatchPattern(base_name_ascii, pattern)) 139 continue; 140 image_files.push_back(next_file_name); 141 } 142 143 return image_files; 144 } 145 146 bool ImageDecoderTest::ShouldImageFail(const base::FilePath& path) const { 147 const base::FilePath::StringType kBadSuffix(FILE_PATH_LITERAL(".bad.")); 148 return (path.value().length() > (kBadSuffix.length() + format_.length()) && 149 !path.value().compare(path.value().length() - format_.length() - 150 kBadSuffix.length(), 151 kBadSuffix.length(), kBadSuffix)); 152 } 153 154 void ImageDecoderTest::TestDecoding( 155 ImageDecoderTestFileSelection file_selection, 156 const int64 threshold) { 157 if (data_dir_.empty()) 158 return; 159 const std::vector<base::FilePath> image_files(GetImageFiles()); 160 for (std::vector<base::FilePath>::const_iterator i = image_files.begin(); 161 i != image_files.end(); ++i) { 162 if (ShouldSkipFile(*i, file_selection, threshold)) 163 continue; 164 const base::FilePath md5_sum_path(GetMD5SumPath(*i)); 165 TestWebKitImageDecoder(*i, md5_sum_path, kFirstFrameIndex); 166 } 167 } 168 169 void ImageDecoderTest::TestWebKitImageDecoder(const base::FilePath& image_path, 170 const base::FilePath& md5_sum_path, int desired_frame_index) const { 171 bool should_test_chunking = true; 172 bool should_test_failed_images = true; 173 #ifdef CALCULATE_MD5_SUMS 174 // Do not test anything just get the md5 sums. 175 should_test_chunking = false; 176 should_test_failed_images = false; 177 #endif 178 179 std::vector<char> image_contents; 180 ReadFileToVector(image_path, &image_contents); 181 EXPECT_TRUE(image_contents.size()); 182 scoped_ptr<blink::WebImageDecoder> decoder(CreateWebKitImageDecoder()); 183 EXPECT_FALSE(decoder->isFailed()); 184 185 if (should_test_chunking) { 186 // Test chunking file into half. 187 const int partial_size = image_contents.size()/2; 188 189 blink::WebData partial_data( 190 reinterpret_cast<const char*>(&(image_contents.at(0))), partial_size); 191 192 // Make Sure the image decoder doesn't fail when we ask for the frame 193 // buffer for this partial image. 194 // NOTE: We can't check that frame 0 is non-NULL, because if this is an 195 // ICO and we haven't yet supplied enough data to read the directory, 196 // there is no framecount and thus no first frame. 197 decoder->setData(const_cast<blink::WebData&>(partial_data), false); 198 EXPECT_FALSE(decoder->isFailed()) << image_path.value(); 199 } 200 201 // Make sure passing the complete image results in successful decoding. 202 blink::WebData data(reinterpret_cast<const char*>(&(image_contents.at(0))), 203 image_contents.size()); 204 decoder->setData(const_cast<blink::WebData&>(data), true); 205 206 if (should_test_failed_images) { 207 if (ShouldImageFail(image_path)) { 208 EXPECT_FALSE(decoder->isFrameCompleteAtIndex(kFirstFrameIndex)); 209 EXPECT_TRUE(decoder->isFailed()); 210 return; 211 } 212 } 213 214 EXPECT_FALSE(decoder->isFailed()) << image_path.value(); 215 216 #ifdef CALCULATE_MD5_SUMS 217 // Since WebImage does not expose get data by frame, get the size 218 // through decoder and pass it to fromData so that the closest 219 // image dats to the size is returned. 220 blink::WebSize size(decoder->getImage(desired_frame_index).size()); 221 const blink::WebImage& image = blink::WebImage::fromData(data, size); 222 SaveMD5Sum(md5_sum_path, image); 223 #else 224 VerifyImage(*decoder, image_path, md5_sum_path, desired_frame_index); 225 #endif 226 } 227