| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "webkit/tools/test_shell/image_decoder_unittest.h" |
| |
| #include "base/file_util.h" |
| #include "base/files/file_path.h" |
| #include "base/md5.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/path_service.h" |
| #include "base/string_util.h" |
| #include "third_party/WebKit/Source/Platform/chromium/public/WebData.h" |
| #include "third_party/WebKit/Source/Platform/chromium/public/WebImage.h" |
| #include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebImageDecoder.h" |
| |
| using base::Time; |
| |
| namespace { |
| |
| const int kFirstFrameIndex = 0; |
| |
| // Determine if we should test with file specified by |path| based |
| // on |file_selection| and the |threshold| for the file size. |
| bool ShouldSkipFile(const base::FilePath& path, |
| ImageDecoderTestFileSelection file_selection, |
| const int64 threshold) { |
| if (file_selection == TEST_ALL) |
| return false; |
| |
| int64 image_size = 0; |
| file_util::GetFileSize(path, &image_size); |
| return (file_selection == TEST_SMALLER) == (image_size > threshold); |
| } |
| |
| } // namespace |
| |
| void ReadFileToVector(const base::FilePath& path, std::vector<char>* contents) { |
| std::string raw_image_data; |
| file_util::ReadFileToString(path, &raw_image_data); |
| contents->resize(raw_image_data.size()); |
| memcpy(&contents->at(0), raw_image_data.data(), raw_image_data.size()); |
| } |
| |
| base::FilePath GetMD5SumPath(const base::FilePath& path) { |
| static const base::FilePath::StringType kDecodedDataExtension( |
| FILE_PATH_LITERAL(".md5sum")); |
| return base::FilePath(path.value() + kDecodedDataExtension); |
| } |
| |
| #if defined(CALCULATE_MD5_SUMS) |
| void SaveMD5Sum(const base::FilePath& path, const WebKit::WebImage& web_image) { |
| // Calculate MD5 sum. |
| base::MD5Digest digest; |
| web_image.getSkBitmap().lockPixels(); |
| base::MD5Sum(web_image.getSkBitmap().getPixels(), |
| web_image.getSkBitmap().width() * web_image.getSkBitmap().height() * |
| sizeof(uint32_t), |
| &digest); |
| |
| // Write sum to disk. |
| int bytes_written = file_util::WriteFile(path, |
| reinterpret_cast<const char*>(&digest), sizeof digest); |
| ASSERT_EQ(sizeof digest, bytes_written); |
| web_image.getSkBitmap().unlockPixels(); |
| } |
| #endif |
| |
| #if !defined(CALCULATE_MD5_SUMS) |
| void VerifyImage(const WebKit::WebImageDecoder& decoder, |
| const base::FilePath& path, |
| const base::FilePath& md5_sum_path, |
| size_t frame_index) { |
| // Make sure decoding can complete successfully. |
| EXPECT_TRUE(decoder.isSizeAvailable()) << path.value(); |
| EXPECT_GE(decoder.frameCount(), frame_index) << path.value(); |
| EXPECT_TRUE(decoder.isFrameCompleteAtIndex(frame_index)) << path.value(); |
| EXPECT_FALSE(decoder.isFailed()); |
| |
| // Calculate MD5 sum. |
| base::MD5Digest actual_digest; |
| WebKit::WebImage web_image = decoder.getFrameAtIndex(frame_index); |
| web_image.getSkBitmap().lockPixels(); |
| base::MD5Sum(web_image.getSkBitmap().getPixels(), |
| web_image.getSkBitmap().width() * web_image.getSkBitmap().height() * |
| sizeof(uint32_t), |
| &actual_digest); |
| |
| // Read the MD5 sum off disk. |
| std::string file_bytes; |
| file_util::ReadFileToString(md5_sum_path, &file_bytes); |
| base::MD5Digest expected_digest; |
| ASSERT_EQ(sizeof expected_digest, file_bytes.size()) << path.value(); |
| memcpy(&expected_digest, file_bytes.data(), sizeof expected_digest); |
| |
| // Verify that the sums are the same. |
| EXPECT_EQ(0, |
| memcmp(&expected_digest, &actual_digest, sizeof(base::MD5Digest))) |
| << path.value(); |
| web_image.getSkBitmap().unlockPixels(); |
| } |
| #endif |
| |
| void ImageDecoderTest::SetUp() { |
| base::FilePath data_dir; |
| ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &data_dir)); |
| data_dir_ = data_dir.AppendASCII("webkit"). |
| AppendASCII("data"). |
| AppendASCII(format_ + "_decoder"); |
| ASSERT_TRUE(file_util::PathExists(data_dir_)) << data_dir_.value(); |
| } |
| |
| std::vector<base::FilePath> ImageDecoderTest::GetImageFiles() const { |
| std::string pattern = "*." + format_; |
| |
| file_util::FileEnumerator enumerator(data_dir_, |
| false, |
| file_util::FileEnumerator::FILES); |
| |
| std::vector<base::FilePath> image_files; |
| base::FilePath next_file_name; |
| while (!(next_file_name = enumerator.Next()).empty()) { |
| base::FilePath base_name = next_file_name.BaseName(); |
| #if defined(OS_WIN) |
| std::string base_name_ascii = WideToASCII(base_name.value()); |
| #else |
| std::string base_name_ascii = base_name.value(); |
| #endif |
| if (!MatchPattern(base_name_ascii, pattern)) |
| continue; |
| image_files.push_back(next_file_name); |
| } |
| |
| return image_files; |
| } |
| |
| bool ImageDecoderTest::ShouldImageFail(const base::FilePath& path) const { |
| static const base::FilePath::StringType kBadSuffix(FILE_PATH_LITERAL(".bad.")); |
| return (path.value().length() > (kBadSuffix.length() + format_.length()) && |
| !path.value().compare(path.value().length() - format_.length() - |
| kBadSuffix.length(), |
| kBadSuffix.length(), kBadSuffix)); |
| } |
| |
| void ImageDecoderTest::TestDecoding( |
| ImageDecoderTestFileSelection file_selection, |
| const int64 threshold) { |
| const std::vector<base::FilePath> image_files(GetImageFiles()); |
| for (std::vector<base::FilePath>::const_iterator i = image_files.begin(); |
| i != image_files.end(); ++i) { |
| if (ShouldSkipFile(*i, file_selection, threshold)) |
| continue; |
| const base::FilePath md5_sum_path(GetMD5SumPath(*i)); |
| TestWebKitImageDecoder(*i, md5_sum_path, kFirstFrameIndex); |
| } |
| } |
| |
| void ImageDecoderTest::TestWebKitImageDecoder(const base::FilePath& image_path, |
| const base::FilePath& md5_sum_path, int desired_frame_index) const { |
| bool should_test_chunking = true; |
| bool should_test_failed_images = true; |
| #ifdef CALCULATE_MD5_SUMS |
| // Do not test anything just get the md5 sums. |
| should_test_chunking = false; |
| should_test_failed_images = false; |
| #endif |
| |
| std::vector<char> image_contents; |
| ReadFileToVector(image_path, &image_contents); |
| EXPECT_TRUE(image_contents.size()); |
| scoped_ptr<WebKit::WebImageDecoder> decoder(CreateWebKitImageDecoder()); |
| EXPECT_FALSE(decoder->isFailed()); |
| |
| if (should_test_chunking) { |
| // Test chunking file into half. |
| const int partial_size = image_contents.size()/2; |
| |
| WebKit::WebData partial_data( |
| reinterpret_cast<const char*>(&(image_contents.at(0))), partial_size); |
| |
| // Make Sure the image decoder doesn't fail when we ask for the frame |
| // buffer for this partial image. |
| // NOTE: We can't check that frame 0 is non-NULL, because if this is an |
| // ICO and we haven't yet supplied enough data to read the directory, |
| // there is no framecount and thus no first frame. |
| decoder->setData(const_cast<WebKit::WebData&>(partial_data), false); |
| EXPECT_FALSE(decoder->isFailed()) << image_path.value(); |
| } |
| |
| // Make sure passing the complete image results in successful decoding. |
| WebKit::WebData data(reinterpret_cast<const char*>(&(image_contents.at(0))), |
| image_contents.size()); |
| decoder->setData(const_cast<WebKit::WebData&>(data), true); |
| |
| if (should_test_failed_images) { |
| if (ShouldImageFail(image_path)) { |
| EXPECT_FALSE(decoder->isFrameCompleteAtIndex(kFirstFrameIndex)); |
| EXPECT_TRUE(decoder->isFailed()); |
| return; |
| } |
| } |
| |
| EXPECT_FALSE(decoder->isFailed()) << image_path.value(); |
| |
| #ifdef CALCULATE_MD5_SUMS |
| // Since WebImage does not expose get data by frame, get the size |
| // through decoder and pass it to fromData so that the closest |
| // image dats to the size is returned. |
| WebKit::WebSize size(decoder->getImage(desired_frame_index).size()); |
| const WebKit::WebImage& image = WebKit::WebImage::fromData(data, size); |
| SaveMD5Sum(md5_sum_path, image); |
| #else |
| VerifyImage(*decoder, image_path, md5_sum_path, desired_frame_index); |
| #endif |
| } |