1 // Copyright 2015 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 "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
6
7 #include <memory>
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "third_party/blink/renderer/platform/image-decoders/image_frame.h"
10 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
11 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
12 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
13 #include "third_party/blink/renderer/platform/wtf/text/string_hasher.h"
14
15 namespace blink {
16
ReadFile(StringView file_name)17 scoped_refptr<SharedBuffer> ReadFile(StringView file_name) {
18 StringBuilder file_path;
19 file_path.Append(test::BlinkWebTestsDir());
20 file_path.Append(file_name);
21 return test::ReadFromFile(file_path.ToString());
22 }
23
ReadFile(const char * dir,const char * file_name)24 scoped_refptr<SharedBuffer> ReadFile(const char* dir, const char* file_name) {
25 StringBuilder file_path;
26 if (strncmp(dir, "web_tests/", 10) == 0) {
27 file_path.Append(test::BlinkWebTestsDir());
28 file_path.Append('/');
29 file_path.Append(dir + 10);
30 } else {
31 file_path.Append(test::BlinkRootDir());
32 file_path.Append('/');
33 file_path.Append(dir);
34 }
35 file_path.Append('/');
36 file_path.Append(file_name);
37 return test::ReadFromFile(file_path.ToString());
38 }
39
HashBitmap(const SkBitmap & bitmap)40 unsigned HashBitmap(const SkBitmap& bitmap) {
41 return StringHasher::HashMemory(bitmap.getPixels(), bitmap.computeByteSize());
42 }
43
CreateDecodingBaseline(DecoderCreator create_decoder,SharedBuffer * data)44 static unsigned CreateDecodingBaseline(DecoderCreator create_decoder,
45 SharedBuffer* data) {
46 std::unique_ptr<ImageDecoder> decoder = create_decoder();
47 decoder->SetData(data, true);
48 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
49 return HashBitmap(frame->Bitmap());
50 }
51
CreateDecodingBaseline(DecoderCreator create_decoder,SharedBuffer * data,Vector<unsigned> * baseline_hashes)52 void CreateDecodingBaseline(DecoderCreator create_decoder,
53 SharedBuffer* data,
54 Vector<unsigned>* baseline_hashes) {
55 std::unique_ptr<ImageDecoder> decoder = create_decoder();
56 decoder->SetData(data, true);
57 size_t frame_count = decoder->FrameCount();
58 for (size_t i = 0; i < frame_count; ++i) {
59 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(i);
60 baseline_hashes->push_back(HashBitmap(frame->Bitmap()));
61 }
62 }
63
TestByteByByteDecode(DecoderCreator create_decoder,SharedBuffer * shared_data,size_t expected_frame_count,int expected_repetition_count)64 void TestByteByByteDecode(DecoderCreator create_decoder,
65 SharedBuffer* shared_data,
66 size_t expected_frame_count,
67 int expected_repetition_count) {
68 const Vector<char> data = shared_data->CopyAs<Vector<char>>();
69
70 Vector<unsigned> baseline_hashes;
71 CreateDecodingBaseline(create_decoder, shared_data, &baseline_hashes);
72
73 std::unique_ptr<ImageDecoder> decoder = create_decoder();
74
75 size_t frame_count = 0;
76 size_t frames_decoded = 0;
77
78 // Pass data to decoder byte by byte.
79 scoped_refptr<SharedBuffer> source_data[2] = {SharedBuffer::Create(),
80 SharedBuffer::Create()};
81 const char* source = data.data();
82
83 for (size_t length = 1; length <= data.size() && !decoder->Failed();
84 ++length) {
85 source_data[0]->Append(source, 1u);
86 source_data[1]->Append(source++, 1u);
87 // Alternate the buffers to cover the JPEGImageDecoder::OnSetData restart
88 // code.
89 decoder->SetData(source_data[length & 1].get(), length == data.size());
90
91 EXPECT_LE(frame_count, decoder->FrameCount());
92 frame_count = decoder->FrameCount();
93
94 if (!decoder->IsSizeAvailable())
95 continue;
96
97 for (size_t i = frames_decoded; i < frame_count; ++i) {
98 // In ICOImageDecoder memory layout could differ from frame order.
99 // E.g. memory layout could be |<frame1><frame0>| and frame_count
100 // would return 1 until receiving full file.
101 // When file is completely received frame_count would return 2 and
102 // only then both frames could be completely decoded.
103 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(i);
104 if (frame && frame->GetStatus() == ImageFrame::kFrameComplete)
105 ++frames_decoded;
106 }
107 }
108
109 EXPECT_FALSE(decoder->Failed());
110 EXPECT_EQ(expected_frame_count, decoder->FrameCount());
111 EXPECT_EQ(expected_frame_count, frames_decoded);
112 EXPECT_EQ(expected_repetition_count, decoder->RepetitionCount());
113
114 ASSERT_EQ(expected_frame_count, baseline_hashes.size());
115 for (size_t i = 0; i < decoder->FrameCount(); i++) {
116 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(i);
117 EXPECT_EQ(baseline_hashes[i], HashBitmap(frame->Bitmap()));
118 }
119 }
120
121 // This test verifies that calling SharedBuffer::MergeSegmentsIntoBuffer() does
122 // not break decoding at a critical point: in between a call to decode the size
123 // (when the decoder stops while it may still have input data to read) and a
124 // call to do a full decode.
TestMergeBuffer(DecoderCreator create_decoder,SharedBuffer * shared_data)125 static void TestMergeBuffer(DecoderCreator create_decoder,
126 SharedBuffer* shared_data) {
127 const unsigned hash = CreateDecodingBaseline(create_decoder, shared_data);
128 const Vector<char> data = shared_data->CopyAs<Vector<char>>();
129
130 // In order to do any verification, this test needs to move the data owned
131 // by the SharedBuffer. A way to guarantee that is to create a new one, and
132 // then append a string of characters greater than kSegmentSize. This
133 // results in writing the data into a segment, skipping the internal
134 // contiguous buffer.
135 scoped_refptr<SharedBuffer> segmented_data = SharedBuffer::Create();
136 segmented_data->Append(data.data(), data.size());
137
138 std::unique_ptr<ImageDecoder> decoder = create_decoder();
139 decoder->SetData(segmented_data.get(), true);
140
141 ASSERT_TRUE(decoder->IsSizeAvailable());
142
143 // This will call SharedBuffer::MergeSegmentsIntoBuffer, copying all
144 // segments into the contiguous buffer. If the ImageDecoder was pointing to
145 // data in a segment, its pointer would no longer be valid.
146 segmented_data->Data();
147
148 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
149 ASSERT_FALSE(decoder->Failed());
150 EXPECT_EQ(frame->GetStatus(), ImageFrame::kFrameComplete);
151 EXPECT_EQ(HashBitmap(frame->Bitmap()), hash);
152 }
153
TestRandomFrameDecode(DecoderCreator create_decoder,SharedBuffer * full_data,size_t skipping_step)154 static void TestRandomFrameDecode(DecoderCreator create_decoder,
155 SharedBuffer* full_data,
156 size_t skipping_step) {
157 Vector<unsigned> baseline_hashes;
158 CreateDecodingBaseline(create_decoder, full_data, &baseline_hashes);
159 size_t frame_count = baseline_hashes.size();
160
161 // Random decoding should get the same results as sequential decoding.
162 std::unique_ptr<ImageDecoder> decoder = create_decoder();
163 decoder->SetData(full_data, true);
164 for (size_t i = 0; i < skipping_step; ++i) {
165 for (size_t j = i; j < frame_count; j += skipping_step) {
166 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
167 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(j);
168 EXPECT_EQ(baseline_hashes[j], HashBitmap(frame->Bitmap()));
169 }
170 }
171
172 // Decoding in reverse order.
173 decoder = create_decoder();
174 decoder->SetData(full_data, true);
175 for (size_t i = frame_count; i; --i) {
176 SCOPED_TRACE(testing::Message() << "Reverse i:" << i);
177 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(i - 1);
178 EXPECT_EQ(baseline_hashes[i - 1], HashBitmap(frame->Bitmap()));
179 }
180 }
181
TestRandomDecodeAfterClearFrameBufferCache(DecoderCreator create_decoder,SharedBuffer * data,size_t skipping_step)182 static void TestRandomDecodeAfterClearFrameBufferCache(
183 DecoderCreator create_decoder,
184 SharedBuffer* data,
185 size_t skipping_step) {
186 Vector<unsigned> baseline_hashes;
187 CreateDecodingBaseline(create_decoder, data, &baseline_hashes);
188 size_t frame_count = baseline_hashes.size();
189
190 std::unique_ptr<ImageDecoder> decoder = create_decoder();
191 decoder->SetData(data, true);
192 for (size_t clear_except_frame = 0; clear_except_frame < frame_count;
193 ++clear_except_frame) {
194 decoder->ClearCacheExceptFrame(clear_except_frame);
195 for (size_t i = 0; i < skipping_step; ++i) {
196 for (size_t j = 0; j < frame_count; j += skipping_step) {
197 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
198 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(j);
199 EXPECT_EQ(baseline_hashes[j], HashBitmap(frame->Bitmap()));
200 }
201 }
202 }
203 }
204
TestDecodeAfterReallocatingData(DecoderCreator create_decoder,SharedBuffer * data)205 static void TestDecodeAfterReallocatingData(DecoderCreator create_decoder,
206 SharedBuffer* data) {
207 std::unique_ptr<ImageDecoder> decoder = create_decoder();
208
209 // Parse from 'data'.
210 decoder->SetData(data, true);
211 size_t frame_count = decoder->FrameCount();
212
213 // ... and then decode frames from 'reallocated_data'.
214 Vector<char> copy = data->CopyAs<Vector<char>>();
215 scoped_refptr<SharedBuffer> reallocated_data =
216 SharedBuffer::AdoptVector(copy);
217 ASSERT_TRUE(reallocated_data.get());
218 data->Clear();
219 decoder->SetData(reallocated_data.get(), true);
220
221 for (size_t i = 0; i < frame_count; ++i) {
222 const ImageFrame* const frame = decoder->DecodeFrameBufferAtIndex(i);
223 EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
224 }
225 }
226
TestByteByByteSizeAvailable(DecoderCreator create_decoder,SharedBuffer * data,size_t frame_offset,bool has_color_space,int expected_repetition_count)227 static void TestByteByByteSizeAvailable(DecoderCreator create_decoder,
228 SharedBuffer* data,
229 size_t frame_offset,
230 bool has_color_space,
231 int expected_repetition_count) {
232 std::unique_ptr<ImageDecoder> decoder = create_decoder();
233 EXPECT_LT(frame_offset, data->size());
234
235 // Send data to the decoder byte-by-byte and use the provided frame offset in
236 // the data to check that IsSizeAvailable() changes state only when that
237 // offset is reached. Also check other decoder state.
238 scoped_refptr<SharedBuffer> temp_data = SharedBuffer::Create();
239 const Vector<char> source_buffer = data->CopyAs<Vector<char>>();
240 const char* source = source_buffer.data();
241 for (size_t length = 1; length <= frame_offset; ++length) {
242 temp_data->Append(source++, 1u);
243 decoder->SetData(temp_data.get(), false);
244
245 if (length < frame_offset) {
246 EXPECT_FALSE(decoder->IsSizeAvailable());
247 EXPECT_TRUE(decoder->Size().IsEmpty());
248 EXPECT_FALSE(decoder->HasEmbeddedColorProfile());
249 EXPECT_EQ(0u, decoder->FrameCount());
250 EXPECT_EQ(kAnimationLoopOnce, decoder->RepetitionCount());
251 EXPECT_FALSE(decoder->DecodeFrameBufferAtIndex(0));
252 } else {
253 EXPECT_TRUE(decoder->IsSizeAvailable());
254 EXPECT_FALSE(decoder->Size().IsEmpty());
255 EXPECT_EQ(decoder->HasEmbeddedColorProfile(), has_color_space);
256 EXPECT_EQ(1u, decoder->FrameCount());
257 EXPECT_EQ(expected_repetition_count, decoder->RepetitionCount());
258 }
259
260 ASSERT_FALSE(decoder->Failed());
261 }
262 }
263
TestProgressiveDecoding(DecoderCreator create_decoder,SharedBuffer * full_buffer,size_t increment)264 static void TestProgressiveDecoding(DecoderCreator create_decoder,
265 SharedBuffer* full_buffer,
266 size_t increment) {
267 const Vector<char> full_data = full_buffer->CopyAs<Vector<char>>();
268 const size_t full_length = full_data.size();
269
270 std::unique_ptr<ImageDecoder> decoder;
271
272 Vector<unsigned> truncated_hashes;
273 Vector<unsigned> progressive_hashes;
274
275 // Compute hashes when the file is truncated.
276 scoped_refptr<SharedBuffer> data = SharedBuffer::Create();
277 const char* source = full_data.data();
278 for (size_t i = 1; i <= full_length; i += increment) {
279 decoder = create_decoder();
280 data->Append(source++, 1u);
281 decoder->SetData(data.get(), i == full_length);
282 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
283 if (!frame) {
284 truncated_hashes.push_back(0);
285 continue;
286 }
287 truncated_hashes.push_back(HashBitmap(frame->Bitmap()));
288 }
289
290 // Compute hashes when the file is progressively decoded.
291 decoder = create_decoder();
292 data = SharedBuffer::Create();
293 source = full_data.data();
294 for (size_t i = 1; i <= full_length; i += increment) {
295 data->Append(source++, 1u);
296 decoder->SetData(data.get(), i == full_length);
297 ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
298 if (!frame) {
299 progressive_hashes.push_back(0);
300 continue;
301 }
302 progressive_hashes.push_back(HashBitmap(frame->Bitmap()));
303 }
304
305 for (size_t i = 0; i < truncated_hashes.size(); ++i)
306 ASSERT_EQ(truncated_hashes[i], progressive_hashes[i]);
307 }
308
TestUpdateRequiredPreviousFrameAfterFirstDecode(DecoderCreator create_decoder,SharedBuffer * full_buffer)309 void TestUpdateRequiredPreviousFrameAfterFirstDecode(
310 DecoderCreator create_decoder,
311 SharedBuffer* full_buffer) {
312 const Vector<char> full_data = full_buffer->CopyAs<Vector<char>>();
313 std::unique_ptr<ImageDecoder> decoder = create_decoder();
314
315 // Give it data that is enough to parse but not decode in order to check the
316 // status of RequiredPreviousFrameIndex before decoding.
317 scoped_refptr<SharedBuffer> data = SharedBuffer::Create();
318 const char* source = full_data.data();
319 do {
320 data->Append(source++, 1u);
321 decoder->SetData(data.get(), false);
322 } while (!decoder->FrameCount() ||
323 decoder->DecodeFrameBufferAtIndex(0)->GetStatus() ==
324 ImageFrame::kFrameEmpty);
325
326 EXPECT_EQ(kNotFound,
327 decoder->DecodeFrameBufferAtIndex(0)->RequiredPreviousFrameIndex());
328 unsigned frame_count = decoder->FrameCount();
329 for (size_t i = 1; i < frame_count; ++i) {
330 EXPECT_EQ(
331 i - 1,
332 decoder->DecodeFrameBufferAtIndex(i)->RequiredPreviousFrameIndex());
333 }
334
335 decoder->SetData(full_buffer, true);
336 for (size_t i = 0; i < frame_count; ++i) {
337 EXPECT_EQ(
338 kNotFound,
339 decoder->DecodeFrameBufferAtIndex(i)->RequiredPreviousFrameIndex());
340 }
341 }
342
TestResumePartialDecodeAfterClearFrameBufferCache(DecoderCreator create_decoder,SharedBuffer * full_buffer)343 void TestResumePartialDecodeAfterClearFrameBufferCache(
344 DecoderCreator create_decoder,
345 SharedBuffer* full_buffer) {
346 const Vector<char> full_data = full_buffer->CopyAs<Vector<char>>();
347 Vector<unsigned> baseline_hashes;
348 CreateDecodingBaseline(create_decoder, full_buffer, &baseline_hashes);
349 size_t frame_count = baseline_hashes.size();
350
351 std::unique_ptr<ImageDecoder> decoder = create_decoder();
352
353 // Let frame 0 be partially decoded.
354 scoped_refptr<SharedBuffer> data = SharedBuffer::Create();
355 const char* source = full_data.data();
356 do {
357 data->Append(source++, 1u);
358 decoder->SetData(data.get(), false);
359 } while (!decoder->FrameCount() ||
360 decoder->DecodeFrameBufferAtIndex(0)->GetStatus() ==
361 ImageFrame::kFrameEmpty);
362
363 // Skip to the last frame and clear.
364 decoder->SetData(full_buffer, true);
365 EXPECT_EQ(frame_count, decoder->FrameCount());
366 ImageFrame* last_frame = decoder->DecodeFrameBufferAtIndex(frame_count - 1);
367 EXPECT_EQ(baseline_hashes[frame_count - 1], HashBitmap(last_frame->Bitmap()));
368 decoder->ClearCacheExceptFrame(kNotFound);
369
370 // Resume decoding of the first frame.
371 ImageFrame* first_frame = decoder->DecodeFrameBufferAtIndex(0);
372 EXPECT_EQ(ImageFrame::kFrameComplete, first_frame->GetStatus());
373 EXPECT_EQ(baseline_hashes[0], HashBitmap(first_frame->Bitmap()));
374 }
375
TestByteByByteDecode(DecoderCreator create_decoder,const char * file,size_t expected_frame_count,int expected_repetition_count)376 void TestByteByByteDecode(DecoderCreator create_decoder,
377 const char* file,
378 size_t expected_frame_count,
379 int expected_repetition_count) {
380 SCOPED_TRACE(file);
381 scoped_refptr<SharedBuffer> data = ReadFile(file);
382 ASSERT_TRUE(data.get());
383 TestByteByByteDecode(create_decoder, data.get(), expected_frame_count,
384 expected_repetition_count);
385 }
TestByteByByteDecode(DecoderCreator create_decoder,const char * dir,const char * file,size_t expected_frame_count,int expected_repetition_count)386 void TestByteByByteDecode(DecoderCreator create_decoder,
387 const char* dir,
388 const char* file,
389 size_t expected_frame_count,
390 int expected_repetition_count) {
391 SCOPED_TRACE(file);
392 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
393 ASSERT_TRUE(data.get());
394 TestByteByByteDecode(create_decoder, data.get(), expected_frame_count,
395 expected_repetition_count);
396 }
397
TestMergeBuffer(DecoderCreator create_decoder,const char * file)398 void TestMergeBuffer(DecoderCreator create_decoder, const char* file) {
399 scoped_refptr<SharedBuffer> data = ReadFile(file);
400 ASSERT_TRUE(data.get());
401 TestMergeBuffer(create_decoder, data.get());
402 }
403
TestMergeBuffer(DecoderCreator create_decoder,const char * dir,const char * file)404 void TestMergeBuffer(DecoderCreator create_decoder,
405 const char* dir,
406 const char* file) {
407 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
408 ASSERT_TRUE(data.get());
409 TestMergeBuffer(create_decoder, data.get());
410 }
411
TestRandomFrameDecode(DecoderCreator create_decoder,const char * file,size_t skipping_step)412 void TestRandomFrameDecode(DecoderCreator create_decoder,
413 const char* file,
414 size_t skipping_step) {
415 scoped_refptr<SharedBuffer> data = ReadFile(file);
416 ASSERT_TRUE(data.get());
417 SCOPED_TRACE(file);
418 TestRandomFrameDecode(create_decoder, data.get(), skipping_step);
419 }
TestRandomFrameDecode(DecoderCreator create_decoder,const char * dir,const char * file,size_t skipping_step)420 void TestRandomFrameDecode(DecoderCreator create_decoder,
421 const char* dir,
422 const char* file,
423 size_t skipping_step) {
424 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
425 ASSERT_TRUE(data.get());
426 SCOPED_TRACE(file);
427 TestRandomFrameDecode(create_decoder, data.get(), skipping_step);
428 }
429
TestRandomDecodeAfterClearFrameBufferCache(DecoderCreator create_decoder,const char * file,size_t skipping_step)430 void TestRandomDecodeAfterClearFrameBufferCache(DecoderCreator create_decoder,
431 const char* file,
432 size_t skipping_step) {
433 scoped_refptr<SharedBuffer> data = ReadFile(file);
434 ASSERT_TRUE(data.get());
435 SCOPED_TRACE(file);
436 TestRandomDecodeAfterClearFrameBufferCache(create_decoder, data.get(),
437 skipping_step);
438 }
439
TestRandomDecodeAfterClearFrameBufferCache(DecoderCreator create_decoder,const char * dir,const char * file,size_t skipping_step)440 void TestRandomDecodeAfterClearFrameBufferCache(DecoderCreator create_decoder,
441 const char* dir,
442 const char* file,
443 size_t skipping_step) {
444 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
445 ASSERT_TRUE(data.get());
446 SCOPED_TRACE(file);
447 TestRandomDecodeAfterClearFrameBufferCache(create_decoder, data.get(),
448 skipping_step);
449 }
450
TestDecodeAfterReallocatingData(DecoderCreator create_decoder,const char * file)451 void TestDecodeAfterReallocatingData(DecoderCreator create_decoder,
452 const char* file) {
453 scoped_refptr<SharedBuffer> data = ReadFile(file);
454 ASSERT_TRUE(data.get());
455 TestDecodeAfterReallocatingData(create_decoder, data.get());
456 }
457
TestDecodeAfterReallocatingData(DecoderCreator create_decoder,const char * dir,const char * file)458 void TestDecodeAfterReallocatingData(DecoderCreator create_decoder,
459 const char* dir,
460 const char* file) {
461 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
462 ASSERT_TRUE(data.get());
463 TestDecodeAfterReallocatingData(create_decoder, data.get());
464 }
465
TestByteByByteSizeAvailable(DecoderCreator create_decoder,const char * file,size_t frame_offset,bool has_color_space,int expected_repetition_count)466 void TestByteByByteSizeAvailable(DecoderCreator create_decoder,
467 const char* file,
468 size_t frame_offset,
469 bool has_color_space,
470 int expected_repetition_count) {
471 scoped_refptr<SharedBuffer> data = ReadFile(file);
472 ASSERT_TRUE(data.get());
473 TestByteByByteSizeAvailable(create_decoder, data.get(), frame_offset,
474 has_color_space, expected_repetition_count);
475 }
476
TestByteByByteSizeAvailable(DecoderCreator create_decoder,const char * dir,const char * file,size_t frame_offset,bool has_color_space,int expected_repetition_count)477 void TestByteByByteSizeAvailable(DecoderCreator create_decoder,
478 const char* dir,
479 const char* file,
480 size_t frame_offset,
481 bool has_color_space,
482 int expected_repetition_count) {
483 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
484 ASSERT_TRUE(data.get());
485 TestByteByByteSizeAvailable(create_decoder, data.get(), frame_offset,
486 has_color_space, expected_repetition_count);
487 }
488
TestProgressiveDecoding(DecoderCreator create_decoder,const char * file,size_t increment)489 void TestProgressiveDecoding(DecoderCreator create_decoder,
490 const char* file,
491 size_t increment) {
492 scoped_refptr<SharedBuffer> data = ReadFile(file);
493 ASSERT_TRUE(data.get());
494 TestProgressiveDecoding(create_decoder, data.get(), increment);
495 }
496
TestProgressiveDecoding(DecoderCreator create_decoder,const char * dir,const char * file,size_t increment)497 void TestProgressiveDecoding(DecoderCreator create_decoder,
498 const char* dir,
499 const char* file,
500 size_t increment) {
501 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
502 ASSERT_TRUE(data.get());
503 TestProgressiveDecoding(create_decoder, data.get(), increment);
504 }
505
TestUpdateRequiredPreviousFrameAfterFirstDecode(DecoderCreator create_decoder,const char * dir,const char * file)506 void TestUpdateRequiredPreviousFrameAfterFirstDecode(
507 DecoderCreator create_decoder,
508 const char* dir,
509 const char* file) {
510 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
511 ASSERT_TRUE(data.get());
512 TestUpdateRequiredPreviousFrameAfterFirstDecode(create_decoder, data.get());
513 }
514
TestUpdateRequiredPreviousFrameAfterFirstDecode(DecoderCreator create_decoder,const char * file)515 void TestUpdateRequiredPreviousFrameAfterFirstDecode(
516 DecoderCreator create_decoder,
517 const char* file) {
518 scoped_refptr<SharedBuffer> data = ReadFile(file);
519 ASSERT_TRUE(data.get());
520 TestUpdateRequiredPreviousFrameAfterFirstDecode(create_decoder, data.get());
521 }
522
TestResumePartialDecodeAfterClearFrameBufferCache(DecoderCreator create_decoder,const char * dir,const char * file)523 void TestResumePartialDecodeAfterClearFrameBufferCache(
524 DecoderCreator create_decoder,
525 const char* dir,
526 const char* file) {
527 scoped_refptr<SharedBuffer> data = ReadFile(dir, file);
528 ASSERT_TRUE(data.get());
529 TestResumePartialDecodeAfterClearFrameBufferCache(create_decoder, data.get());
530 }
531
TestResumePartialDecodeAfterClearFrameBufferCache(DecoderCreator create_decoder,const char * file)532 void TestResumePartialDecodeAfterClearFrameBufferCache(
533 DecoderCreator create_decoder,
534 const char* file) {
535 scoped_refptr<SharedBuffer> data = ReadFile(file);
536 ASSERT_TRUE(data.get());
537 TestResumePartialDecodeAfterClearFrameBufferCache(create_decoder, data.get());
538 }
539
PremultiplyColor(uint32_t c)540 static uint32_t PremultiplyColor(uint32_t c) {
541 return SkPremultiplyARGBInline(SkGetPackedA32(c), SkGetPackedR32(c),
542 SkGetPackedG32(c), SkGetPackedB32(c));
543 }
544
VerifyFramesMatch(const char * file,const ImageFrame * const a,const ImageFrame * const b)545 static void VerifyFramesMatch(const char* file,
546 const ImageFrame* const a,
547 const ImageFrame* const b) {
548 const SkBitmap& bitmap_a = a->Bitmap();
549 const SkBitmap& bitmap_b = b->Bitmap();
550 ASSERT_EQ(bitmap_a.width(), bitmap_b.width());
551 ASSERT_EQ(bitmap_a.height(), bitmap_b.height());
552
553 int max_difference = 0;
554 for (int y = 0; y < bitmap_a.height(); ++y) {
555 for (int x = 0; x < bitmap_a.width(); ++x) {
556 uint32_t color_a = *bitmap_a.getAddr32(x, y);
557 if (!a->PremultiplyAlpha())
558 color_a = PremultiplyColor(color_a);
559 uint32_t color_b = *bitmap_b.getAddr32(x, y);
560 if (!b->PremultiplyAlpha())
561 color_b = PremultiplyColor(color_b);
562 uint8_t* pixel_a = reinterpret_cast<uint8_t*>(&color_a);
563 uint8_t* pixel_b = reinterpret_cast<uint8_t*>(&color_b);
564 for (int channel = 0; channel < 4; ++channel) {
565 const int difference = abs(pixel_a[channel] - pixel_b[channel]);
566 if (difference > max_difference)
567 max_difference = difference;
568 }
569 }
570 }
571
572 // Pre-multiplication could round the RGBA channel values. So, we declare
573 // that the frames match if the RGBA channel values differ by at most 2.
574 EXPECT_GE(2, max_difference) << file;
575 }
576
577 // Verifies that result of alpha blending is similar for AlphaPremultiplied and
578 // AlphaNotPremultiplied cases.
TestAlphaBlending(DecoderCreatorWithAlpha create_decoder,const char * file)579 void TestAlphaBlending(DecoderCreatorWithAlpha create_decoder,
580 const char* file) {
581 scoped_refptr<SharedBuffer> data = ReadFile(file);
582 ASSERT_TRUE(data.get());
583
584 std::unique_ptr<ImageDecoder> decoder_a =
585 create_decoder(ImageDecoder::kAlphaPremultiplied);
586 decoder_a->SetData(data.get(), true);
587
588 std::unique_ptr<ImageDecoder> decoder_b =
589 create_decoder(ImageDecoder::kAlphaNotPremultiplied);
590 decoder_b->SetData(data.get(), true);
591
592 size_t frame_count = decoder_a->FrameCount();
593 ASSERT_EQ(frame_count, decoder_b->FrameCount());
594
595 for (size_t i = 0; i < frame_count; ++i) {
596 VerifyFramesMatch(file, decoder_a->DecodeFrameBufferAtIndex(i),
597 decoder_b->DecodeFrameBufferAtIndex(i));
598 }
599 }
600
601 } // namespace blink
602