1 // Copyright 2016 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/graphics/deferred_image_decoder.h"
6 
7 #include <memory>
8 #include "base/memory/scoped_refptr.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
11 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
12 #include "third_party/blink/renderer/platform/wtf/vector.h"
13 #include "third_party/skia/include/core/SkCanvas.h"
14 #include "third_party/skia/include/core/SkImage.h"
15 #include "third_party/skia/include/core/SkSurface.h"
16 
17 namespace blink {
18 namespace {
19 
CreateFrameAtIndex(DeferredImageDecoder * decoder,size_t index)20 sk_sp<SkImage> CreateFrameAtIndex(DeferredImageDecoder* decoder, size_t index) {
21   return SkImage::MakeFromGenerator(std::make_unique<SkiaPaintImageGenerator>(
22       decoder->CreateGenerator(), index,
23       cc::PaintImage::kDefaultGeneratorClientId));
24 }
25 
26 }  // namespace
27 
28 /**
29  *  Used to test decoding SkImages out of order.
30  *  e.g.
31  *  SkImage* imageA = decoder.createFrameAtIndex(0);
32  *  // supply more (but not all) data to the decoder
33  *  SkImage* imageB = decoder.createFrameAtIndex(laterFrame);
34  *  draw(imageB);
35  *  draw(imageA);
36  *
37  *  This results in using the same ImageDecoder (in the ImageDecodingStore) to
38  *  decode less data the second time. This test ensures that it is safe to do
39  *  so.
40  *
41  *  @param fileName File to decode
42  *  @param bytesForFirstFrame Number of bytes needed to return an SkImage
43  *  @param laterFrame Frame to decode with almost complete data. Can be 0.
44  */
MixImages(const char * file_name,size_t bytes_for_first_frame,size_t later_frame)45 static void MixImages(const char* file_name,
46                       size_t bytes_for_first_frame,
47                       size_t later_frame) {
48   const Vector<char> file = ReadFile(file_name)->CopyAs<Vector<char>>();
49 
50   scoped_refptr<SharedBuffer> partial_file =
51       SharedBuffer::Create(file.data(), bytes_for_first_frame);
52   std::unique_ptr<DeferredImageDecoder> decoder = DeferredImageDecoder::Create(
53       partial_file, false, ImageDecoder::kAlphaPremultiplied,
54       ColorBehavior::Ignore());
55   ASSERT_NE(decoder, nullptr);
56   sk_sp<SkImage> partial_image = CreateFrameAtIndex(decoder.get(), 0);
57 
58   scoped_refptr<SharedBuffer> almost_complete_file =
59       SharedBuffer::Create(file.data(), file.size() - 1);
60   decoder->SetData(almost_complete_file, false);
61   sk_sp<SkImage> image_with_more_data =
62       CreateFrameAtIndex(decoder.get(), later_frame);
63 
64   // we now want to ensure we don't crash if we access these in this order
65   SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
66   sk_sp<SkSurface> surf = SkSurface::MakeRaster(info);
67   surf->getCanvas()->drawImage(image_with_more_data, 0, 0);
68   surf->getCanvas()->drawImage(partial_image, 0, 0);
69 }
70 
TEST(DeferredImageDecoderTestWoPlatform,mixImagesGif)71 TEST(DeferredImageDecoderTestWoPlatform, mixImagesGif) {
72   MixImages("/images/resources/animated.gif", 818u, 1u);
73 }
74 
TEST(DeferredImageDecoderTestWoPlatform,mixImagesPng)75 TEST(DeferredImageDecoderTestWoPlatform, mixImagesPng) {
76   MixImages("/images/resources/mu.png", 910u, 0u);
77 }
78 
TEST(DeferredImageDecoderTestWoPlatform,mixImagesJpg)79 TEST(DeferredImageDecoderTestWoPlatform, mixImagesJpg) {
80   MixImages("/images/resources/2-dht.jpg", 177u, 0u);
81 }
82 
TEST(DeferredImageDecoderTestWoPlatform,mixImagesWebp)83 TEST(DeferredImageDecoderTestWoPlatform, mixImagesWebp) {
84   MixImages("/images/resources/webp-animated.webp", 142u, 1u);
85 }
86 
TEST(DeferredImageDecoderTestWoPlatform,mixImagesBmp)87 TEST(DeferredImageDecoderTestWoPlatform, mixImagesBmp) {
88   MixImages("/images/resources/lenna.bmp", 122u, 0u);
89 }
90 
TEST(DeferredImageDecoderTestWoPlatform,mixImagesIco)91 TEST(DeferredImageDecoderTestWoPlatform, mixImagesIco) {
92   MixImages("/images/resources/wrong-frame-dimensions.ico", 1376u, 1u);
93 }
94 
TEST(DeferredImageDecoderTestWoPlatform,fragmentedSignature)95 TEST(DeferredImageDecoderTestWoPlatform, fragmentedSignature) {
96   const char* test_files[] = {
97       "/images/resources/animated.gif",
98       "/images/resources/mu.png",
99       "/images/resources/2-dht.jpg",
100       "/images/resources/webp-animated.webp",
101       "/images/resources/lenna.bmp",
102       "/images/resources/wrong-frame-dimensions.ico",
103   };
104 
105   for (size_t i = 0; i < SK_ARRAY_COUNT(test_files); ++i) {
106     scoped_refptr<SharedBuffer> file_buffer = ReadFile(test_files[i]);
107     ASSERT_NE(file_buffer, nullptr);
108     // We need contiguous data, which SharedBuffer doesn't guarantee.
109     Vector<char> contiguous = file_buffer->CopyAs<Vector<char>>();
110     EXPECT_EQ(contiguous.size(), file_buffer->size());
111     const char* data = contiguous.data();
112 
113     // Truncated signature (only 1 byte).  Decoder instantiation should fail.
114     scoped_refptr<SharedBuffer> buffer = SharedBuffer::Create<size_t>(data, 1u);
115     EXPECT_FALSE(ImageDecoder::HasSufficientDataToSniffImageType(*buffer));
116     EXPECT_EQ(nullptr, DeferredImageDecoder::Create(
117                            buffer, false, ImageDecoder::kAlphaPremultiplied,
118                            ColorBehavior::Ignore()));
119 
120     // Append the rest of the data.  We should be able to sniff the signature
121     // now, even if segmented.
122     buffer->Append<size_t>(data + 1, contiguous.size() - 1);
123     EXPECT_TRUE(ImageDecoder::HasSufficientDataToSniffImageType(*buffer));
124     std::unique_ptr<DeferredImageDecoder> decoder =
125         DeferredImageDecoder::Create(buffer, false,
126                                      ImageDecoder::kAlphaPremultiplied,
127                                      ColorBehavior::Ignore());
128     ASSERT_NE(decoder, nullptr);
129     EXPECT_TRUE(String(test_files[i]).EndsWith(decoder->FilenameExtension()));
130   }
131 }
132 
133 }  // namespace blink
134