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.
5 #include "content/test/image_decoder_test.h"
7 #include "base/file_util.h"
8 #include "base/files/file_enumerator.h"
9 #include "base/files/file_path.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"
23 const int kFirstFrameIndex
= 0;
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
)
34 base::GetFileSize(path
, &image_size
);
35 return (file_selection
== TEST_SMALLER
) == (image_size
> threshold
);
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());
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
);
53 #if defined(CALCULATE_MD5_SUMS)
54 void SaveMD5Sum(const base::FilePath
& path
, const blink::WebImage
& web_image
) {
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() *
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();
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
,
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());
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() *
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
);
98 // Verify that the sums are the same.
100 memcmp(&expected_digest
, &actual_digest
, sizeof(base::MD5Digest
)))
102 web_image
.getSkBitmap().unlockPixels();
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").
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.";
122 std::vector
<base::FilePath
> ImageDecoderTest::GetImageFiles() const {
123 std::string pattern
= "*." + format_
;
125 base::FileEnumerator
enumerator(data_dir_
,
127 base::FileEnumerator::FILES
);
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();
134 std::string base_name_ascii
= WideToASCII(base_name
.value());
136 std::string base_name_ascii
= base_name
.value();
138 if (!MatchPattern(base_name_ascii
, pattern
))
140 image_files
.push_back(next_file_name
);
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() -
151 kBadSuffix
.length(), kBadSuffix
));
154 void ImageDecoderTest::TestDecoding(
155 ImageDecoderTestFileSelection file_selection
,
156 const int64 threshold
) {
157 if (data_dir_
.empty())
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
))
164 const base::FilePath
md5_sum_path(GetMD5SumPath(*i
));
165 TestWebKitImageDecoder(*i
, md5_sum_path
, kFirstFrameIndex
);
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;
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());
185 if (should_test_chunking
) {
186 // Test chunking file into half.
187 const int partial_size
= image_contents
.size()/2;
189 blink::WebData
partial_data(
190 reinterpret_cast<const char*>(&(image_contents
.at(0))), partial_size
);
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();
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);
206 if (should_test_failed_images
) {
207 if (ShouldImageFail(image_path
)) {
208 EXPECT_FALSE(decoder
->isFrameCompleteAtIndex(kFirstFrameIndex
));
209 EXPECT_TRUE(decoder
->isFailed());
214 EXPECT_FALSE(decoder
->isFailed()) << image_path
.value();
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
);
224 VerifyImage(*decoder
, image_path
, md5_sum_path
, desired_frame_index
);