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