1 /*
2 * Copyright (c) 2013, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
32
33 #include "base/bind.h"
34 #include "base/test/simple_test_tick_clock.h"
35 #include "cc/paint/image_provider.h"
36 #include "cc/paint/skia_paint_canvas.h"
37 #include "cc/tiles/mipmap_util.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
40 #include "third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h"
41 #include "third_party/blink/renderer/platform/graphics/deferred_image_decoder.h"
42 #include "third_party/blink/renderer/platform/graphics/image_observer.h"
43 #include "third_party/blink/renderer/platform/graphics/test/mock_image_decoder.h"
44 #include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h"
45 #include "third_party/blink/renderer/platform/testing/histogram_tester.h"
46 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
47 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
48 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
49 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
50 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
51 #include "third_party/skia/include/core/SkColor.h"
52 #include "third_party/skia/include/core/SkImage.h"
53
54 namespace blink {
55 namespace {
56
57 class FrameSettingImageProvider : public cc::ImageProvider {
58 public:
FrameSettingImageProvider(size_t frame_index,cc::PaintImage::GeneratorClientId client_id)59 FrameSettingImageProvider(size_t frame_index,
60 cc::PaintImage::GeneratorClientId client_id)
61 : frame_index_(frame_index), client_id_(client_id) {}
62 ~FrameSettingImageProvider() override = default;
63
GetRasterContent(const cc::DrawImage & draw_image)64 ImageProvider::ScopedResult GetRasterContent(
65 const cc::DrawImage& draw_image) override {
66 DCHECK(!draw_image.paint_image().IsPaintWorklet());
67 auto sk_image =
68 draw_image.paint_image().GetSkImageForFrame(frame_index_, client_id_);
69 return ScopedResult(
70 cc::DecodedDrawImage(sk_image, SkSize::MakeEmpty(), SkSize::Make(1, 1),
71 draw_image.filter_quality(), true));
72 }
73
74 private:
75 size_t frame_index_;
76 cc::PaintImage::GeneratorClientId client_id_;
77 };
78
GenerateBitmapForPaintImage(cc::PaintImage paint_image,size_t frame_index,cc::PaintImage::GeneratorClientId client_id,SkBitmap * bitmap)79 void GenerateBitmapForPaintImage(cc::PaintImage paint_image,
80 size_t frame_index,
81 cc::PaintImage::GeneratorClientId client_id,
82 SkBitmap* bitmap) {
83 CHECK(paint_image);
84 CHECK_GE(paint_image.FrameCount(), frame_index);
85
86 SkImageInfo info =
87 SkImageInfo::MakeN32Premul(paint_image.width(), paint_image.height());
88 bitmap->allocPixels(info, paint_image.width() * 4);
89 bitmap->eraseColor(SK_AlphaTRANSPARENT);
90 FrameSettingImageProvider image_provider(frame_index, client_id);
91 cc::SkiaPaintCanvas canvas(*bitmap, &image_provider);
92 canvas.drawImage(paint_image, 0u, 0u, nullptr);
93 }
94
95 } // namespace
96
97 // Extends TestingPlatformSupportWithMockScheduler to add the ability to set the
98 // return value of MaxDecodedImageBytes().
99 class TestingPlatformSupportWithMaxDecodedBytes
100 : public TestingPlatformSupportWithMockScheduler {
101 public:
TestingPlatformSupportWithMaxDecodedBytes()102 TestingPlatformSupportWithMaxDecodedBytes() {}
~TestingPlatformSupportWithMaxDecodedBytes()103 ~TestingPlatformSupportWithMaxDecodedBytes() override {}
104
SetMaxDecodedImageBytes(size_t max_decoded_image_bytes)105 void SetMaxDecodedImageBytes(size_t max_decoded_image_bytes) {
106 max_decoded_image_bytes_ = max_decoded_image_bytes;
107 }
108
MaxDecodedImageBytes()109 size_t MaxDecodedImageBytes() override { return max_decoded_image_bytes_; }
110
111 private:
112 size_t max_decoded_image_bytes_ = Platform::kNoDecodedImageByteLimit;
113
114 DISALLOW_COPY_AND_ASSIGN(TestingPlatformSupportWithMaxDecodedBytes);
115 };
116
117 class BitmapImageTest : public testing::Test {
118 public:
119 class FakeImageObserver : public GarbageCollected<FakeImageObserver>,
120 public ImageObserver {
121 USING_GARBAGE_COLLECTED_MIXIN(FakeImageObserver);
122
123 public:
FakeImageObserver()124 FakeImageObserver()
125 : last_decoded_size_(0), last_decoded_size_changed_delta_(0) {}
126
DecodedSizeChangedTo(const Image *,size_t new_size)127 void DecodedSizeChangedTo(const Image*, size_t new_size) override {
128 last_decoded_size_changed_delta_ =
129 SafeCast<int>(new_size) - SafeCast<int>(last_decoded_size_);
130 last_decoded_size_ = new_size;
131 }
ShouldPauseAnimation(const Image *)132 bool ShouldPauseAnimation(const Image*) override { return false; }
AsyncLoadCompleted(const Image *)133 void AsyncLoadCompleted(const Image*) override { NOTREACHED(); }
134
Changed(const Image *)135 void Changed(const Image*) override {}
136
137 size_t last_decoded_size_;
138 int last_decoded_size_changed_delta_;
139 };
140
ReadFile(const char * file_name)141 static scoped_refptr<SharedBuffer> ReadFile(const char* file_name) {
142 String file_path = test::PlatformTestDataPath(file_name);
143 return test::ReadFromFile(file_path);
144 }
145
146 // Accessors to BitmapImage's protected methods.
DestroyDecodedData()147 void DestroyDecodedData() { image_->DestroyDecodedData(); }
FrameCount()148 size_t FrameCount() { return image_->FrameCount(); }
149
LoadImage(const char * file_name)150 void LoadImage(const char* file_name) {
151 scoped_refptr<SharedBuffer> image_data = ReadFile(file_name);
152 ASSERT_TRUE(image_data.get());
153
154 image_->SetData(image_data, true);
155 }
156
GenerateBitmap(size_t frame_index)157 SkBitmap GenerateBitmap(size_t frame_index) {
158 SkBitmap bitmap;
159 GenerateBitmapForPaintImage(image_->PaintImageForTesting(), frame_index,
160 cc::PaintImage::kDefaultGeneratorClientId,
161 &bitmap);
162 return bitmap;
163 }
164
GenerateBitmapForImage(const char * file_name)165 SkBitmap GenerateBitmapForImage(const char* file_name) {
166 scoped_refptr<SharedBuffer> image_data = ReadFile(file_name);
167 EXPECT_TRUE(image_data.get());
168 if (!image_data)
169 return SkBitmap();
170
171 auto image = BitmapImage::Create();
172 image->SetData(image_data, true);
173 auto paint_image = image->PaintImageForCurrentFrame();
174 CHECK(paint_image);
175
176 SkBitmap bitmap;
177 SkImageInfo info = SkImageInfo::MakeN32Premul(image->Size().Width(),
178 image->Size().Height());
179 bitmap.allocPixels(info, image->Size().Width() * 4);
180 bitmap.eraseColor(SK_AlphaTRANSPARENT);
181 cc::SkiaPaintCanvas canvas(bitmap);
182 canvas.drawImage(paint_image, 0u, 0u, nullptr);
183 return bitmap;
184 }
185
VerifyBitmap(const SkBitmap & bitmap,SkColor color)186 void VerifyBitmap(const SkBitmap& bitmap, SkColor color) {
187 ASSERT_GT(bitmap.width(), 0);
188 ASSERT_GT(bitmap.height(), 0);
189
190 for (int i = 0; i < bitmap.width(); ++i) {
191 for (int j = 0; j < bitmap.height(); ++j) {
192 auto bitmap_color = bitmap.getColor(i, j);
193 EXPECT_EQ(bitmap_color, color)
194 << "Bitmap: " << SkColorGetA(bitmap_color) << ","
195 << SkColorGetR(bitmap_color) << "," << SkColorGetG(bitmap_color)
196 << "," << SkColorGetB(bitmap_color)
197 << "Expected: " << SkColorGetA(color) << "," << SkColorGetR(color)
198 << "," << SkColorGetG(color) << "," << SkColorGetB(color);
199 }
200 }
201 }
202
VerifyBitmap(const SkBitmap & bitmap,const SkBitmap & expected)203 void VerifyBitmap(const SkBitmap& bitmap, const SkBitmap& expected) {
204 ASSERT_GT(bitmap.width(), 0);
205 ASSERT_GT(bitmap.height(), 0);
206 ASSERT_EQ(bitmap.info(), expected.info());
207
208 for (int i = 0; i < bitmap.width(); ++i) {
209 for (int j = 0; j < bitmap.height(); ++j) {
210 auto bitmap_color = bitmap.getColor(i, j);
211 auto expected_color = expected.getColor(i, j);
212 EXPECT_EQ(bitmap_color, expected_color)
213 << "Bitmap: " << SkColorGetA(bitmap_color) << ","
214 << SkColorGetR(bitmap_color) << "," << SkColorGetG(bitmap_color)
215 << "," << SkColorGetB(bitmap_color)
216 << "Expected: " << SkColorGetA(expected_color) << ","
217 << SkColorGetR(expected_color) << "," << SkColorGetG(expected_color)
218 << "," << SkColorGetB(expected_color);
219 }
220 }
221 }
222
DecodedSize()223 size_t DecodedSize() { return image_->TotalFrameBytes(); }
224
RepetitionCount()225 int RepetitionCount() { return image_->RepetitionCount(); }
226
ImageForDefaultFrame()227 scoped_refptr<Image> ImageForDefaultFrame() {
228 return image_->ImageForDefaultFrame();
229 }
230
LastDecodedSizeChange()231 int LastDecodedSizeChange() {
232 return image_observer_->last_decoded_size_changed_delta_;
233 }
234
Data()235 scoped_refptr<SharedBuffer> Data() { return image_->Data(); }
236
237 protected:
SetUp()238 void SetUp() override {
239 image_observer_ = MakeGarbageCollected<FakeImageObserver>();
240 image_ = BitmapImage::Create(image_observer_.Get());
241 }
242
243 Persistent<FakeImageObserver> image_observer_;
244 scoped_refptr<BitmapImage> image_;
245 ScopedTestingPlatformSupport<TestingPlatformSupportWithMaxDecodedBytes>
246 platform_;
247 };
248
TEST_F(BitmapImageTest,destroyDecodedData)249 TEST_F(BitmapImageTest, destroyDecodedData) {
250 LoadImage("animated-10color.gif");
251 image_->PaintImageForCurrentFrame();
252 size_t total_size = DecodedSize();
253 EXPECT_GT(total_size, 0u);
254 DestroyDecodedData();
255 EXPECT_EQ(-static_cast<int>(total_size), LastDecodedSizeChange());
256 EXPECT_EQ(0u, DecodedSize());
257 }
258
TEST_F(BitmapImageTest,maybeAnimated)259 TEST_F(BitmapImageTest, maybeAnimated) {
260 LoadImage("gif-loop-count.gif");
261 EXPECT_TRUE(image_->MaybeAnimated());
262 }
263
TEST_F(BitmapImageTest,isAllDataReceived)264 TEST_F(BitmapImageTest, isAllDataReceived) {
265 scoped_refptr<SharedBuffer> image_data = ReadFile("green.jpg");
266 ASSERT_TRUE(image_data.get());
267
268 scoped_refptr<BitmapImage> image = BitmapImage::Create();
269 EXPECT_FALSE(image->IsAllDataReceived());
270
271 image->SetData(image_data, false);
272 EXPECT_FALSE(image->IsAllDataReceived());
273
274 image->SetData(image_data, true);
275 EXPECT_TRUE(image->IsAllDataReceived());
276
277 image->SetData(SharedBuffer::Create("data", sizeof("data")), false);
278 EXPECT_FALSE(image->IsAllDataReceived());
279
280 image->SetData(image_data, true);
281 EXPECT_TRUE(image->IsAllDataReceived());
282 }
283
TEST_F(BitmapImageTest,noColorProfile)284 TEST_F(BitmapImageTest, noColorProfile) {
285 LoadImage("green.jpg");
286 image_->PaintImageForCurrentFrame();
287 EXPECT_EQ(1024u, DecodedSize());
288 EXPECT_FALSE(image_->HasColorProfile());
289 }
290
TEST_F(BitmapImageTest,jpegHasColorProfile)291 TEST_F(BitmapImageTest, jpegHasColorProfile) {
292 LoadImage("icc-v2-gbr.jpg");
293 image_->PaintImageForCurrentFrame();
294 EXPECT_EQ(227700u, DecodedSize());
295 EXPECT_TRUE(image_->HasColorProfile());
296 }
297
TEST_F(BitmapImageTest,pngHasColorProfile)298 TEST_F(BitmapImageTest, pngHasColorProfile) {
299 LoadImage("palatted-color-png-gamma-one-color-profile.png");
300 image_->PaintImageForCurrentFrame();
301 EXPECT_EQ(65536u, DecodedSize());
302 EXPECT_TRUE(image_->HasColorProfile());
303 }
304
TEST_F(BitmapImageTest,webpHasColorProfile)305 TEST_F(BitmapImageTest, webpHasColorProfile) {
306 LoadImage("webp-color-profile-lossy.webp");
307 image_->PaintImageForCurrentFrame();
308 EXPECT_EQ(2560000u, DecodedSize());
309 EXPECT_TRUE(image_->HasColorProfile());
310 }
311
TEST_F(BitmapImageTest,icoHasWrongFrameDimensions)312 TEST_F(BitmapImageTest, icoHasWrongFrameDimensions) {
313 LoadImage("wrong-frame-dimensions.ico");
314 // This call would cause crash without fix for 408026
315 ImageForDefaultFrame();
316 }
317
TEST_F(BitmapImageTest,correctDecodedDataSize)318 TEST_F(BitmapImageTest, correctDecodedDataSize) {
319 // Requesting any one frame shouldn't result in decoding any other frames.
320 LoadImage("anim_none.gif");
321 image_->PaintImageForCurrentFrame();
322 int frame_size =
323 static_cast<int>(image_->Size().Area() * sizeof(ImageFrame::PixelData));
324 EXPECT_EQ(frame_size, LastDecodedSizeChange());
325 }
326
TEST_F(BitmapImageTest,recachingFrameAfterDataChanged)327 TEST_F(BitmapImageTest, recachingFrameAfterDataChanged) {
328 LoadImage("green.jpg");
329 image_->PaintImageForCurrentFrame();
330 EXPECT_GT(LastDecodedSizeChange(), 0);
331 image_observer_->last_decoded_size_changed_delta_ = 0;
332
333 // Calling dataChanged causes the cache to flush, but doesn't affect the
334 // source's decoded frames. It shouldn't affect decoded size.
335 image_->DataChanged(true);
336 EXPECT_EQ(0, LastDecodedSizeChange());
337 // Recaching the first frame also shouldn't affect decoded size.
338 image_->PaintImageForCurrentFrame();
339 EXPECT_EQ(0, LastDecodedSizeChange());
340 }
341
TEST_F(BitmapImageTest,ConstantImageIdForPartiallyLoadedImages)342 TEST_F(BitmapImageTest, ConstantImageIdForPartiallyLoadedImages) {
343 scoped_refptr<SharedBuffer> image_data = ReadFile("green.jpg");
344 ASSERT_TRUE(image_data.get());
345
346 // Create a new buffer to partially supply the data.
347 scoped_refptr<SharedBuffer> partial_buffer = SharedBuffer::Create();
348 partial_buffer->Append(image_data->Data(), image_data->size() - 4);
349
350 // First partial load. Repeated calls for a PaintImage should have the same
351 // image until the data changes or the decoded data is destroyed.
352 ASSERT_EQ(image_->SetData(partial_buffer, false), Image::kSizeAvailable);
353 auto image1 = image_->PaintImageForCurrentFrame();
354 auto image2 = image_->PaintImageForCurrentFrame();
355 EXPECT_EQ(image1, image2);
356 auto sk_image1 = image1.GetSkImage();
357 auto sk_image2 = image2.GetSkImage();
358 EXPECT_EQ(sk_image1->uniqueID(), sk_image2->uniqueID());
359
360 // Frame keys should be the same for these PaintImages.
361 EXPECT_EQ(image1.GetKeyForFrame(PaintImage::kDefaultFrameIndex),
362 image2.GetKeyForFrame(PaintImage::kDefaultFrameIndex));
363
364 // Destroy the decoded data. This generates a new id since we don't cache
365 // image ids for partial decodes.
366 DestroyDecodedData();
367 auto image3 = image_->PaintImageForCurrentFrame();
368 auto sk_image3 = image3.GetSkImage();
369 EXPECT_NE(sk_image1, sk_image3);
370 EXPECT_NE(sk_image1->uniqueID(), sk_image3->uniqueID());
371
372 // Since the cached generator is discarded on destroying the cached decode,
373 // the new content id is generated resulting in an updated frame key.
374 EXPECT_NE(image1.GetKeyForFrame(PaintImage::kDefaultFrameIndex),
375 image3.GetKeyForFrame(PaintImage::kDefaultFrameIndex));
376
377 // Load complete. This should generate a new image id.
378 image_->SetData(image_data, true);
379 auto complete_image = image_->PaintImageForCurrentFrame();
380 auto complete_sk_image = complete_image.GetSkImage();
381 EXPECT_NE(sk_image3, complete_sk_image);
382 EXPECT_NE(sk_image3->uniqueID(), complete_sk_image->uniqueID());
383 EXPECT_NE(complete_image.GetKeyForFrame(PaintImage::kDefaultFrameIndex),
384 image3.GetKeyForFrame(PaintImage::kDefaultFrameIndex));
385
386 // Destroy the decoded data and re-create the PaintImage. The frame key
387 // remains constant but the SkImage id will change since we don't cache skia
388 // uniqueIDs.
389 DestroyDecodedData();
390 auto new_complete_image = image_->PaintImageForCurrentFrame();
391 auto new_complete_sk_image = new_complete_image.GetSkImage();
392 EXPECT_NE(new_complete_sk_image, complete_sk_image);
393 EXPECT_EQ(new_complete_image.GetKeyForFrame(PaintImage::kDefaultFrameIndex),
394 complete_image.GetKeyForFrame(PaintImage::kDefaultFrameIndex));
395 }
396
TEST_F(BitmapImageTest,ImageForDefaultFrame_MultiFrame)397 TEST_F(BitmapImageTest, ImageForDefaultFrame_MultiFrame) {
398 LoadImage("anim_none.gif");
399
400 // Multi-frame images create new StaticBitmapImages for each call.
401 auto default_image1 = image_->ImageForDefaultFrame();
402 auto default_image2 = image_->ImageForDefaultFrame();
403 EXPECT_NE(default_image1, default_image2);
404
405 // But the PaintImage should be the same.
406 auto paint_image1 = default_image1->PaintImageForCurrentFrame();
407 auto paint_image2 = default_image2->PaintImageForCurrentFrame();
408 EXPECT_EQ(paint_image1, paint_image2);
409 EXPECT_EQ(paint_image1.GetSkImage()->uniqueID(),
410 paint_image2.GetSkImage()->uniqueID());
411 }
412
TEST_F(BitmapImageTest,ImageForDefaultFrame_SingleFrame)413 TEST_F(BitmapImageTest, ImageForDefaultFrame_SingleFrame) {
414 LoadImage("green.jpg");
415
416 // Default frame images for single-frame cases is the image itself.
417 EXPECT_EQ(image_->ImageForDefaultFrame(), image_);
418 }
419
TEST_F(BitmapImageTest,GifDecoderFrame0)420 TEST_F(BitmapImageTest, GifDecoderFrame0) {
421 LoadImage("green-red-blue-yellow-animated.gif");
422 auto bitmap = GenerateBitmap(0u);
423 SkColor color = SkColorSetARGB(255, 0, 128, 0);
424 VerifyBitmap(bitmap, color);
425 }
426
TEST_F(BitmapImageTest,GifDecoderFrame1)427 TEST_F(BitmapImageTest, GifDecoderFrame1) {
428 LoadImage("green-red-blue-yellow-animated.gif");
429 auto bitmap = GenerateBitmap(1u);
430 VerifyBitmap(bitmap, SK_ColorRED);
431 }
432
TEST_F(BitmapImageTest,GifDecoderFrame2)433 TEST_F(BitmapImageTest, GifDecoderFrame2) {
434 LoadImage("green-red-blue-yellow-animated.gif");
435 auto bitmap = GenerateBitmap(2u);
436 VerifyBitmap(bitmap, SK_ColorBLUE);
437 }
438
TEST_F(BitmapImageTest,GifDecoderFrame3)439 TEST_F(BitmapImageTest, GifDecoderFrame3) {
440 LoadImage("green-red-blue-yellow-animated.gif");
441 auto bitmap = GenerateBitmap(3u);
442 VerifyBitmap(bitmap, SK_ColorYELLOW);
443 }
444
TEST_F(BitmapImageTest,GifDecoderMultiThreaded)445 TEST_F(BitmapImageTest, GifDecoderMultiThreaded) {
446 LoadImage("green-red-blue-yellow-animated.gif");
447 auto paint_image = image_->PaintImageForTesting();
448 ASSERT_EQ(paint_image.FrameCount(), 4u);
449
450 struct Decode {
451 SkBitmap bitmap;
452 std::unique_ptr<base::Thread> thread;
453 cc::PaintImage::GeneratorClientId client_id;
454 };
455
456 Decode decodes[4];
457 SkColor expected_color[4] = {SkColorSetARGB(255, 0, 128, 0), SK_ColorRED,
458 SK_ColorBLUE, SK_ColorYELLOW};
459 for (int i = 0; i < 4; ++i) {
460 decodes[i].thread =
461 std::make_unique<base::Thread>("Decode" + std::to_string(i));
462 decodes[i].client_id = cc::PaintImage::GetNextGeneratorClientId();
463
464 decodes[i].thread->StartAndWaitForTesting();
465 decodes[i].thread->task_runner()->PostTask(
466 FROM_HERE, base::BindOnce(&GenerateBitmapForPaintImage, paint_image, i,
467 decodes[i].client_id, &decodes[i].bitmap));
468 }
469
470 for (int i = 0; i < 4; ++i) {
471 decodes[i].thread->FlushForTesting();
472 VerifyBitmap(decodes[i].bitmap, expected_color[i]);
473 }
474 }
475
TEST_F(BitmapImageTest,APNGDecoder00)476 TEST_F(BitmapImageTest, APNGDecoder00) {
477 LoadImage("apng00.png");
478 auto actual_bitmap = GenerateBitmap(0u);
479 auto expected_bitmap = GenerateBitmapForImage("apng00-ref.png");
480 VerifyBitmap(actual_bitmap, expected_bitmap);
481 }
482
483 // Jump to the final frame of each image.
TEST_F(BitmapImageTest,APNGDecoder01)484 TEST_F(BitmapImageTest, APNGDecoder01) {
485 LoadImage("apng01.png");
486 auto actual_bitmap = GenerateBitmap(9u);
487 auto expected_bitmap = GenerateBitmapForImage("apng01-ref.png");
488 VerifyBitmap(actual_bitmap, expected_bitmap);
489 }
490
TEST_F(BitmapImageTest,APNGDecoder02)491 TEST_F(BitmapImageTest, APNGDecoder02) {
492 LoadImage("apng02.png");
493 auto actual_bitmap = GenerateBitmap(9u);
494 auto expected_bitmap = GenerateBitmapForImage("apng02-ref.png");
495 VerifyBitmap(actual_bitmap, expected_bitmap);
496 }
497
TEST_F(BitmapImageTest,APNGDecoder04)498 TEST_F(BitmapImageTest, APNGDecoder04) {
499 LoadImage("apng04.png");
500 auto actual_bitmap = GenerateBitmap(12u);
501 auto expected_bitmap = GenerateBitmapForImage("apng04-ref.png");
502 VerifyBitmap(actual_bitmap, expected_bitmap);
503 }
504
TEST_F(BitmapImageTest,APNGDecoder08)505 TEST_F(BitmapImageTest, APNGDecoder08) {
506 LoadImage("apng08.png");
507 auto actual_bitmap = GenerateBitmap(12u);
508 auto expected_bitmap = GenerateBitmapForImage("apng08-ref.png");
509 VerifyBitmap(actual_bitmap, expected_bitmap);
510 }
511
TEST_F(BitmapImageTest,APNGDecoder10)512 TEST_F(BitmapImageTest, APNGDecoder10) {
513 LoadImage("apng10.png");
514 auto actual_bitmap = GenerateBitmap(3u);
515 auto expected_bitmap = GenerateBitmapForImage("apng10-ref.png");
516 VerifyBitmap(actual_bitmap, expected_bitmap);
517 }
518
TEST_F(BitmapImageTest,APNGDecoder11)519 TEST_F(BitmapImageTest, APNGDecoder11) {
520 LoadImage("apng11.png");
521 auto actual_bitmap = GenerateBitmap(9u);
522 auto expected_bitmap = GenerateBitmapForImage("apng11-ref.png");
523 VerifyBitmap(actual_bitmap, expected_bitmap);
524 }
525
TEST_F(BitmapImageTest,APNGDecoder12)526 TEST_F(BitmapImageTest, APNGDecoder12) {
527 LoadImage("apng12.png");
528 auto actual_bitmap = GenerateBitmap(9u);
529 auto expected_bitmap = GenerateBitmapForImage("apng12-ref.png");
530 VerifyBitmap(actual_bitmap, expected_bitmap);
531 }
532
TEST_F(BitmapImageTest,APNGDecoder14)533 TEST_F(BitmapImageTest, APNGDecoder14) {
534 LoadImage("apng14.png");
535 auto actual_bitmap = GenerateBitmap(12u);
536 auto expected_bitmap = GenerateBitmapForImage("apng14-ref.png");
537 VerifyBitmap(actual_bitmap, expected_bitmap);
538 }
539
TEST_F(BitmapImageTest,APNGDecoder18)540 TEST_F(BitmapImageTest, APNGDecoder18) {
541 LoadImage("apng18.png");
542 auto actual_bitmap = GenerateBitmap(12u);
543 auto expected_bitmap = GenerateBitmapForImage("apng18-ref.png");
544 VerifyBitmap(actual_bitmap, expected_bitmap);
545 }
546
TEST_F(BitmapImageTest,APNGDecoder19)547 TEST_F(BitmapImageTest, APNGDecoder19) {
548 LoadImage("apng19.png");
549 auto actual_bitmap = GenerateBitmap(12u);
550 auto expected_bitmap = GenerateBitmapForImage("apng19-ref.png");
551 VerifyBitmap(actual_bitmap, expected_bitmap);
552 }
553
TEST_F(BitmapImageTest,APNGDecoderDisposePrevious)554 TEST_F(BitmapImageTest, APNGDecoderDisposePrevious) {
555 LoadImage("crbug722072.png");
556 auto actual_bitmap = GenerateBitmap(3u);
557 auto expected_bitmap = GenerateBitmapForImage("green.png");
558 VerifyBitmap(actual_bitmap, expected_bitmap);
559 }
560
TEST_F(BitmapImageTest,GIFRepetitionCount)561 TEST_F(BitmapImageTest, GIFRepetitionCount) {
562 LoadImage("three-frames_loop-three-times.gif");
563 auto paint_image = image_->PaintImageForCurrentFrame();
564 EXPECT_EQ(paint_image.repetition_count(), 3);
565 EXPECT_EQ(paint_image.FrameCount(), 3u);
566 }
567
TEST_F(BitmapImageTest,DecoderAndCacheMipLevels)568 TEST_F(BitmapImageTest, DecoderAndCacheMipLevels) {
569 // Here, we want to test that the mip level calculated by the cc matches
570 // exactly a size supported by the decoder. This is to make sure that the
571 // rounding used in cc matches the rounding in the decoder. The image in this
572 // test is 629x473 and uses 4:2:0 sampling. This means that the MCU is 16x16.
573 // Under no memory limits, this image would not be eligible for downscaling by
574 // the JPEG decoder because neither dimension is a multiple of 16 (see
575 // https://crbug.com/890745). However, we can force the JPEG decoder to
576 // support downscaling by limiting the maximum bytes allowed for decoding. If
577 // we limit to 315 * 237 * 4 bytes, we'll be forcing the maximum scale factor
578 // numerator to be 4 (assuming a denominator of 8).
579 platform_->SetMaxDecodedImageBytes(315 * 237 * 4);
580 LoadImage("original-cat-420-629x473.jpg");
581 auto paint_image = image_->PaintImageForCurrentFrame();
582
583 // The size of the PaintImage is based on the maximum bytes allowed for
584 // decoding.
585 ASSERT_EQ(315, paint_image.width());
586 ASSERT_EQ(237, paint_image.height());
587
588 // Level 0 should match the decoder supported size for scale factor 4/8.
589 // Level 1 should match the decoder supported size for scale factor 2/8.
590 // Level 2 should match the decoder supported size for scale factor 1/8.
591 // Higher levels (smaller sizes) are not supported by the JPEG decoder.
592 for (int mip_level = 0; mip_level < 3; ++mip_level) {
593 SCOPED_TRACE(mip_level);
594 SkISize scaled_size = gfx::SizeToSkISize(cc::MipMapUtil::GetSizeForLevel(
595 gfx::Size(paint_image.width(), paint_image.height()), mip_level));
596 SkISize supported_size = paint_image.GetSupportedDecodeSize(scaled_size);
597 EXPECT_EQ(gfx::SkISizeToSize(supported_size),
598 gfx::SkISizeToSize(scaled_size));
599 }
600 }
601
602 class BitmapImageTestWithMockDecoder : public BitmapImageTest,
603 public MockImageDecoderClient {
604 public:
SetUp()605 void SetUp() override {
606 BitmapImageTest::SetUp();
607
608 auto decoder = std::make_unique<MockImageDecoder>(this);
609 decoder->SetSize(10, 10);
610 image_->SetDecoderForTesting(
611 DeferredImageDecoder::CreateForTesting(std::move(decoder)));
612 }
613
DecoderBeingDestroyed()614 void DecoderBeingDestroyed() override {}
DecodeRequested()615 void DecodeRequested() override {}
GetStatus(size_t index)616 ImageFrame::Status GetStatus(size_t index) override {
617 if (index < frame_count_ - 1 || last_frame_complete_)
618 return ImageFrame::Status::kFrameComplete;
619 return ImageFrame::Status::kFramePartial;
620 }
FrameCount()621 size_t FrameCount() override { return frame_count_; }
RepetitionCount() const622 int RepetitionCount() const override { return repetition_count_; }
FrameDuration() const623 base::TimeDelta FrameDuration() const override { return duration_; }
624
625 protected:
626 base::TimeDelta duration_;
627 int repetition_count_;
628 size_t frame_count_;
629 bool last_frame_complete_;
630 };
631
TEST_F(BitmapImageTestWithMockDecoder,ImageMetadataTracking)632 TEST_F(BitmapImageTestWithMockDecoder, ImageMetadataTracking) {
633 // For a zero duration, we should make it non-zero when creating a PaintImage.
634 repetition_count_ = kAnimationLoopOnce;
635 frame_count_ = 4u;
636 last_frame_complete_ = false;
637 image_->SetData(SharedBuffer::Create("data", sizeof("data")), false);
638
639 PaintImage image = image_->PaintImageForCurrentFrame();
640 ASSERT_TRUE(image);
641 EXPECT_EQ(image.FrameCount(), frame_count_);
642 EXPECT_EQ(image.completion_state(),
643 PaintImage::CompletionState::PARTIALLY_DONE);
644 EXPECT_EQ(image.repetition_count(), repetition_count_);
645 for (size_t i = 0; i < image.GetFrameMetadata().size(); ++i) {
646 const auto& data = image.GetFrameMetadata()[i];
647 EXPECT_EQ(data.duration, base::TimeDelta::FromMilliseconds(100));
648 if (i == frame_count_ - 1 && !last_frame_complete_)
649 EXPECT_FALSE(data.complete);
650 else
651 EXPECT_TRUE(data.complete);
652 }
653
654 // Now the load is finished.
655 duration_ = base::TimeDelta::FromSeconds(1);
656 repetition_count_ = kAnimationLoopInfinite;
657 frame_count_ = 6u;
658 last_frame_complete_ = true;
659 image_->SetData(SharedBuffer::Create("data", sizeof("data")), true);
660
661 image = image_->PaintImageForCurrentFrame();
662 ASSERT_TRUE(image);
663 EXPECT_EQ(image.FrameCount(), frame_count_);
664 EXPECT_EQ(image.completion_state(), PaintImage::CompletionState::DONE);
665 EXPECT_EQ(image.repetition_count(), repetition_count_);
666 for (size_t i = 0; i < image.GetFrameMetadata().size(); ++i) {
667 const auto& data = image.GetFrameMetadata()[i];
668 if (i < 4u)
669 EXPECT_EQ(data.duration, base::TimeDelta::FromMilliseconds(100));
670 else
671 EXPECT_EQ(data.duration, base::TimeDelta::FromSeconds(1));
672 EXPECT_TRUE(data.complete);
673 }
674 }
675
TEST_F(BitmapImageTestWithMockDecoder,AnimationPolicyOverrideOriginalRepetitionNone)676 TEST_F(BitmapImageTestWithMockDecoder,
677 AnimationPolicyOverrideOriginalRepetitionNone) {
678 repetition_count_ = kAnimationNone;
679 frame_count_ = 4u;
680 last_frame_complete_ = true;
681 image_->SetData(SharedBuffer::Create("data", sizeof("data")), false);
682
683 PaintImage image = image_->PaintImageForCurrentFrame();
684 EXPECT_EQ(image.repetition_count(), repetition_count_);
685
686 // In all cases, the image shouldn't animate.
687
688 // Only one loop allowed.
689 image_->SetAnimationPolicy(kImageAnimationPolicyAnimateOnce);
690 image = image_->PaintImageForCurrentFrame();
691 EXPECT_EQ(image.repetition_count(), kAnimationNone);
692
693 // No animation allowed.
694 image_->SetAnimationPolicy(kImageAnimationPolicyNoAnimation);
695 image = image_->PaintImageForCurrentFrame();
696 EXPECT_EQ(image.repetition_count(), kAnimationNone);
697
698 // Default policy.
699 image_->SetAnimationPolicy(kImageAnimationPolicyAllowed);
700 image = image_->PaintImageForCurrentFrame();
701 EXPECT_EQ(image.repetition_count(), kAnimationNone);
702 }
703
TEST_F(BitmapImageTestWithMockDecoder,AnimationPolicyOverrideOriginalRepetitionOnce)704 TEST_F(BitmapImageTestWithMockDecoder,
705 AnimationPolicyOverrideOriginalRepetitionOnce) {
706 repetition_count_ = kAnimationLoopOnce;
707 frame_count_ = 4u;
708 last_frame_complete_ = true;
709 image_->SetData(SharedBuffer::Create("data", sizeof("data")), false);
710
711 PaintImage image = image_->PaintImageForCurrentFrame();
712 EXPECT_EQ(image.repetition_count(), repetition_count_);
713
714 // If the policy is no animation, then the repetition count is none. In all
715 // other cases, it remains loop once.
716
717 // Only one loop allowed.
718 image_->SetAnimationPolicy(kImageAnimationPolicyAnimateOnce);
719 image = image_->PaintImageForCurrentFrame();
720 EXPECT_EQ(image.repetition_count(), kAnimationLoopOnce);
721
722 // No animation allowed.
723 image_->SetAnimationPolicy(kImageAnimationPolicyNoAnimation);
724 image = image_->PaintImageForCurrentFrame();
725 EXPECT_EQ(image.repetition_count(), kAnimationNone);
726
727 // Default policy.
728 image_->SetAnimationPolicy(kImageAnimationPolicyAllowed);
729 image = image_->PaintImageForCurrentFrame();
730 EXPECT_EQ(image.repetition_count(), kAnimationLoopOnce);
731 }
732
TEST_F(BitmapImageTestWithMockDecoder,AnimationPolicyOverrideOriginalRepetitionInfinite)733 TEST_F(BitmapImageTestWithMockDecoder,
734 AnimationPolicyOverrideOriginalRepetitionInfinite) {
735 repetition_count_ = kAnimationLoopInfinite;
736 frame_count_ = 4u;
737 last_frame_complete_ = true;
738 image_->SetData(SharedBuffer::Create("data", sizeof("data")), false);
739
740 PaintImage image = image_->PaintImageForCurrentFrame();
741 EXPECT_EQ(image.repetition_count(), repetition_count_);
742
743 // The repetition count is determined by the animation policy.
744
745 // Only one loop allowed.
746 image_->SetAnimationPolicy(kImageAnimationPolicyAnimateOnce);
747 image = image_->PaintImageForCurrentFrame();
748 EXPECT_EQ(image.repetition_count(), kAnimationLoopOnce);
749
750 // No animation allowed.
751 image_->SetAnimationPolicy(kImageAnimationPolicyNoAnimation);
752 image = image_->PaintImageForCurrentFrame();
753 EXPECT_EQ(image.repetition_count(), kAnimationNone);
754
755 // Default policy.
756 image_->SetAnimationPolicy(kImageAnimationPolicyAllowed);
757 image = image_->PaintImageForCurrentFrame();
758 EXPECT_EQ(image.repetition_count(), repetition_count_);
759 }
760
TEST_F(BitmapImageTestWithMockDecoder,ResetAnimation)761 TEST_F(BitmapImageTestWithMockDecoder, ResetAnimation) {
762 repetition_count_ = kAnimationLoopInfinite;
763 frame_count_ = 4u;
764 last_frame_complete_ = true;
765 image_->SetData(SharedBuffer::Create("data", sizeof("data")), false);
766
767 PaintImage image = image_->PaintImageForCurrentFrame();
768 image_->ResetAnimation();
769 PaintImage image2 = image_->PaintImageForCurrentFrame();
770 EXPECT_GT(image2.reset_animation_sequence_id(),
771 image.reset_animation_sequence_id());
772 }
773
TEST_F(BitmapImageTestWithMockDecoder,PaintImageForStaticBitmapImage)774 TEST_F(BitmapImageTestWithMockDecoder, PaintImageForStaticBitmapImage) {
775 repetition_count_ = kAnimationLoopInfinite;
776 frame_count_ = 5;
777 last_frame_complete_ = true;
778 image_->SetData(SharedBuffer::Create("data", sizeof("data")), false);
779
780 // PaintImage for the original image is animated.
781 EXPECT_TRUE(image_->PaintImageForCurrentFrame().ShouldAnimate());
782
783 // But the StaticBitmapImage is not.
784 EXPECT_FALSE(image_->ImageForDefaultFrame()
785 ->PaintImageForCurrentFrame()
786 .ShouldAnimate());
787 }
788
789 template <typename HistogramEnumType>
790 struct HistogramTestParams {
HistogramTestParamsblink::HistogramTestParams791 HistogramTestParams(const char* filename, HistogramEnumType type, int count)
792 : filename(filename), type(type), count(count) {}
HistogramTestParamsblink::HistogramTestParams793 HistogramTestParams(const char* filename, HistogramEnumType type)
794 : HistogramTestParams(filename, type, 1) {}
795
796 const char* filename;
797 HistogramEnumType type;
798
799 // The number of events reported in the histogram when |type| is not
800 // kNoSamplesReported, otherwise is ignored.
801 int count;
802 };
803
804 template <typename HistogramEnumType>
805 class BitmapHistogramTest : public BitmapImageTest,
806 public testing::WithParamInterface<
807 HistogramTestParams<HistogramEnumType>> {
808 public:
809 // Flag to tell the test that no samples should have been reported in this
810 // case. Only useful when the parametric type is int.
811 static const int kNoSamplesReported = -1;
812
813 protected:
RunTest(const char * histogram_name)814 void RunTest(const char* histogram_name) {
815 HistogramTester histogram_tester;
816 LoadImage(this->GetParam().filename);
817 if (std::is_same<HistogramEnumType, int>::value &&
818 this->GetParam().type == kNoSamplesReported) {
819 histogram_tester.ExpectTotalCount(histogram_name, 0);
820 } else {
821 histogram_tester.ExpectUniqueSample(histogram_name, this->GetParam().type,
822 this->GetParam().count);
823 }
824 }
825 };
826
827 using DecodedImageTypeHistogramTest =
828 BitmapHistogramTest<BitmapImageMetrics::DecodedImageType>;
829
TEST_P(DecodedImageTypeHistogramTest,ImageType)830 TEST_P(DecodedImageTypeHistogramTest, ImageType) {
831 RunTest("Blink.DecodedImageType");
832 }
833
834 const DecodedImageTypeHistogramTest::ParamType
835 kDecodedImageTypeHistogramTestparams[] = {
836 {"green.jpg", BitmapImageMetrics::kImageJPEG},
837 {"palatted-color-png-gamma-one-color-profile.png",
838 BitmapImageMetrics::kImagePNG},
839 {"animated-10color.gif", BitmapImageMetrics::kImageGIF},
840 {"webp-color-profile-lossy.webp", BitmapImageMetrics::kImageWebP},
841 {"wrong-frame-dimensions.ico", BitmapImageMetrics::kImageICO},
842 {"lenna.bmp", BitmapImageMetrics::kImageBMP}};
843
844 INSTANTIATE_TEST_SUITE_P(
845 DecodedImageTypeHistogramTest,
846 DecodedImageTypeHistogramTest,
847 testing::ValuesIn(kDecodedImageTypeHistogramTestparams));
848
849 using DecodedImageOrientationHistogramTest =
850 BitmapHistogramTest<ImageOrientationEnum>;
851
TEST_P(DecodedImageOrientationHistogramTest,ImageOrientation)852 TEST_P(DecodedImageOrientationHistogramTest, ImageOrientation) {
853 RunTest("Blink.DecodedImage.Orientation");
854 }
855
856 const DecodedImageOrientationHistogramTest::ParamType
857 kDecodedImageOrientationHistogramTestParams[] = {
858 {"exif-orientation-1-ul.jpg", kOriginTopLeft},
859 {"exif-orientation-2-ur.jpg", kOriginTopRight},
860 {"exif-orientation-3-lr.jpg", kOriginBottomRight},
861 {"exif-orientation-4-lol.jpg", kOriginBottomLeft},
862 {"exif-orientation-5-lu.jpg", kOriginLeftTop},
863 {"exif-orientation-6-ru.jpg", kOriginRightTop},
864 {"exif-orientation-7-rl.jpg", kOriginRightBottom},
865 {"exif-orientation-8-llo.jpg", kOriginLeftBottom}};
866
867 INSTANTIATE_TEST_SUITE_P(
868 DecodedImageOrientationHistogramTest,
869 DecodedImageOrientationHistogramTest,
870 testing::ValuesIn(kDecodedImageOrientationHistogramTestParams));
871
872 using DecodedImageDensityHistogramTestKiBWeighted = BitmapHistogramTest<int>;
873
TEST_P(DecodedImageDensityHistogramTestKiBWeighted,JpegDensity)874 TEST_P(DecodedImageDensityHistogramTestKiBWeighted, JpegDensity) {
875 RunTest("Blink.DecodedImage.JpegDensity.KiBWeighted");
876 }
877
878 const DecodedImageDensityHistogramTestKiBWeighted::ParamType
879 kDecodedImageDensityHistogramTestKiBWeightedParams[] = {
880 // 64x64 too small to report any metric
881 {"rgb-jpeg-red.jpg",
882 DecodedImageDensityHistogramTestKiBWeighted::kNoSamplesReported},
883 // 439x154, 23220 bytes --> 2.74 bpp, 23 KiB (rounded up)
884 {"cropped_mandrill.jpg", 274, 23},
885 // 320x320, 74017 bytes --> 5.78, 72 KiB (rounded down)
886 {"blue-wheel-srgb-color-profile.jpg", 578, 72}};
887
888 INSTANTIATE_TEST_SUITE_P(
889 DecodedImageDensityHistogramTestKiBWeighted,
890 DecodedImageDensityHistogramTestKiBWeighted,
891 testing::ValuesIn(kDecodedImageDensityHistogramTestKiBWeightedParams));
892
893 } // namespace blink
894