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