1 /*
2 * Copyright (C) 2012 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "third_party/blink/renderer/platform/graphics/deferred_image_decoder.h"
27
28 #include <memory>
29 #include <utility>
30
31 #include "base/macros.h"
32 #include "base/memory/ptr_util.h"
33 #include "third_party/blink/renderer/platform/graphics/decoding_image_generator.h"
34 #include "third_party/blink/renderer/platform/graphics/image_decoding_store.h"
35 #include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
36 #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
37 #include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
38 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
39 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
40 #include "third_party/skia/include/core/SkImage.h"
41
42 namespace blink {
43
44 namespace {
45
46 // Do not rename entries or reuse numeric values to ensure the histogram is
47 // consistent over time.
48 enum IncrementalDecodePerImageType {
49 kJpegIncrementalNeeded = 0,
50 kJpegAllDataReceivedInitially = 1,
51 kWebPIncrementalNeeded = 2,
52 kWebPAllDataReceivedInitially = 3,
53 kBoundaryValue
54 };
55
ReportIncrementalDecodeNeeded(bool all_data_received,const String & image_type)56 void ReportIncrementalDecodeNeeded(bool all_data_received,
57 const String& image_type) {
58 DCHECK(IsMainThread());
59 DEFINE_STATIC_LOCAL(EnumerationHistogram, incremental_decode_needed_histogram,
60 ("Blink.ImageDecoders.IncrementalDecodeNeeded",
61 IncrementalDecodePerImageType::kBoundaryValue));
62 if (image_type == "jpg") {
63 incremental_decode_needed_histogram.Count(
64 all_data_received
65 ? IncrementalDecodePerImageType::kJpegAllDataReceivedInitially
66 : IncrementalDecodePerImageType::kJpegIncrementalNeeded);
67 } else if (image_type == "webp") {
68 incremental_decode_needed_histogram.Count(
69 all_data_received
70 ? IncrementalDecodePerImageType::kWebPAllDataReceivedInitially
71 : IncrementalDecodePerImageType::kWebPIncrementalNeeded);
72 }
73 }
74
RecordByteSizeAndWhetherIncrementalDecode(const String & image_type,bool incrementally_decoded,size_t bytes)75 void RecordByteSizeAndWhetherIncrementalDecode(const String& image_type,
76 bool incrementally_decoded,
77 size_t bytes) {
78 DCHECK(IsMainThread());
79 // A base::HistogramBase::Sample may not fit the number of bytes of the image.
80 base::HistogramBase::Sample sample_bytes =
81 base::saturated_cast<base::HistogramBase::Sample>(bytes);
82 if (image_type == "jpg") {
83 if (incrementally_decoded) {
84 DEFINE_STATIC_LOCAL(
85 CustomCountHistogram, jpeg_byte_size_incrementally_decoded_histogram,
86 ("Blink.ImageDecoders.IncrementallyDecodedByteSize.Jpeg",
87 125 /* min */, 15000000 /* 15 MB */, 100 /* bucket count */));
88 jpeg_byte_size_incrementally_decoded_histogram.Count(sample_bytes);
89 } else {
90 DEFINE_STATIC_LOCAL(
91 CustomCountHistogram,
92 jpeg_byte_size_initially_fully_decoded_histogram,
93 ("Blink.ImageDecoders.InitiallyFullyDecodedByteSize.Jpeg",
94 125 /* min */, 15000000 /* 15 MB */, 100 /* bucket count */));
95 jpeg_byte_size_initially_fully_decoded_histogram.Count(sample_bytes);
96 }
97 } else {
98 DCHECK_EQ(image_type, "webp");
99 if (incrementally_decoded) {
100 DEFINE_STATIC_LOCAL(
101 CustomCountHistogram, webp_byte_size_incrementally_decoded_histogram,
102 ("Blink.ImageDecoders.IncrementallyDecodedByteSize.WebP",
103 125 /* min */, 15000000 /* 15 MB */, 100 /* bucket count */));
104 webp_byte_size_incrementally_decoded_histogram.Count(sample_bytes);
105 } else {
106 DEFINE_STATIC_LOCAL(
107 CustomCountHistogram,
108 webp_byte_size_initially_fully_decoded_histogram,
109 ("Blink.ImageDecoders.InitiallyFullyDecodedByteSize.WebP",
110 125 /* min */, 15000000 /* 15 MB */, 100 /* bucket count */));
111 webp_byte_size_initially_fully_decoded_histogram.Count(sample_bytes);
112 }
113 }
114 }
115
116 } // namespace
117
118 struct DeferredFrameData {
119 DISALLOW_NEW();
120
121 public:
DeferredFrameDatablink::DeferredFrameData122 DeferredFrameData()
123 : orientation_(kDefaultImageOrientation), is_received_(false) {}
124
125 ImageOrientation orientation_;
126 base::TimeDelta duration_;
127 bool is_received_;
128
129 private:
130 DISALLOW_COPY_AND_ASSIGN(DeferredFrameData);
131 };
132
Create(scoped_refptr<SharedBuffer> data,bool data_complete,ImageDecoder::AlphaOption alpha_option,const ColorBehavior & color_behavior)133 std::unique_ptr<DeferredImageDecoder> DeferredImageDecoder::Create(
134 scoped_refptr<SharedBuffer> data,
135 bool data_complete,
136 ImageDecoder::AlphaOption alpha_option,
137 const ColorBehavior& color_behavior) {
138 std::unique_ptr<ImageDecoder> metadata_decoder =
139 ImageDecoder::Create(data, data_complete, alpha_option,
140 ImageDecoder::kDefaultBitDepth, color_behavior);
141 if (!metadata_decoder)
142 return nullptr;
143
144 std::unique_ptr<DeferredImageDecoder> decoder(
145 new DeferredImageDecoder(std::move(metadata_decoder)));
146
147 // Since we've just instantiated a fresh decoder, there's no need to reset its
148 // data.
149 decoder->SetDataInternal(std::move(data), data_complete, false);
150
151 return decoder;
152 }
153
CreateForTesting(std::unique_ptr<ImageDecoder> metadata_decoder)154 std::unique_ptr<DeferredImageDecoder> DeferredImageDecoder::CreateForTesting(
155 std::unique_ptr<ImageDecoder> metadata_decoder) {
156 return base::WrapUnique(
157 new DeferredImageDecoder(std::move(metadata_decoder)));
158 }
159
DeferredImageDecoder(std::unique_ptr<ImageDecoder> metadata_decoder)160 DeferredImageDecoder::DeferredImageDecoder(
161 std::unique_ptr<ImageDecoder> metadata_decoder)
162 : metadata_decoder_(std::move(metadata_decoder)),
163 repetition_count_(kAnimationNone),
164 all_data_received_(false),
165 first_decoding_generator_created_(false),
166 can_yuv_decode_(false),
167 has_hot_spot_(false),
168 image_is_high_bit_depth_(false),
169 complete_frame_content_id_(PaintImage::GetNextContentId()) {}
170
171 DeferredImageDecoder::~DeferredImageDecoder() = default;
172
FilenameExtension() const173 String DeferredImageDecoder::FilenameExtension() const {
174 return metadata_decoder_ ? metadata_decoder_->FilenameExtension()
175 : filename_extension_;
176 }
177
CreateGenerator()178 sk_sp<PaintImageGenerator> DeferredImageDecoder::CreateGenerator() {
179 if (frame_generator_ && frame_generator_->DecodeFailed())
180 return nullptr;
181
182 if (invalid_image_ || frame_data_.IsEmpty())
183 return nullptr;
184
185 DCHECK(frame_generator_);
186 const SkISize& decoded_size = frame_generator_->GetFullSize();
187 DCHECK_GT(decoded_size.width(), 0);
188 DCHECK_GT(decoded_size.height(), 0);
189
190 sk_sp<SkROBuffer> ro_buffer(rw_buffer_->makeROBufferSnapshot());
191 scoped_refptr<SegmentReader> segment_reader =
192 SegmentReader::CreateFromSkROBuffer(std::move(ro_buffer));
193
194 // ImageFrameGenerator has the latest known alpha state. There will be a
195 // performance boost if the image is opaque since we can avoid painting
196 // the background in this case.
197 // For multi-frame images, these maybe animated on the compositor thread.
198 // So we can not mark them as opaque unless all frames are opaque.
199 // TODO(khushalsagar): Check whether all frames being added to the
200 // generator are opaque when populating FrameMetadata below.
201 SkAlphaType alpha_type = kPremul_SkAlphaType;
202 if (frame_data_.size() == 1u && !frame_generator_->HasAlpha(0u))
203 alpha_type = kOpaque_SkAlphaType;
204
205 SkImageInfo info =
206 SkImageInfo::MakeN32(decoded_size.width(), decoded_size.height(),
207 alpha_type, color_space_for_sk_images_);
208 if (image_is_high_bit_depth_)
209 info = info.makeColorType(kRGBA_F16_SkColorType);
210
211 WebVector<FrameMetadata> frames(frame_data_.size());
212 for (size_t i = 0; i < frame_data_.size(); ++i) {
213 frames[i].complete = frame_data_[i].is_received_;
214 frames[i].duration = FrameDurationAtIndex(i);
215 }
216
217 // Report UMA about whether incremental decoding is done for JPEG/WebP images.
218 const String image_type = FilenameExtension();
219 if (!first_decoding_generator_created_) {
220 DCHECK(!incremental_decode_needed_.has_value());
221 incremental_decode_needed_ = !all_data_received_;
222 if (image_type == "jpg" || image_type == "webp") {
223 ReportIncrementalDecodeNeeded(all_data_received_, image_type);
224 }
225 }
226 DCHECK(incremental_decode_needed_.has_value());
227
228 // TODO(crbug.com/943519):
229 // If we haven't received all data, we might veto YUV and begin doing
230 // incremental RGB decoding until all data were received. Then the final
231 // decode would be in YUV (but from the beginning of the image).
232 //
233 // The memory/speed tradeoffs of mixing RGB and YUV decoding are unclear due
234 // to caching at various levels. Additionally, incremental decoding is less
235 // common, so we avoid worrying about this with the line below.
236 can_yuv_decode_ &= !incremental_decode_needed_.value();
237
238 DCHECK(image_metadata_);
239 image_metadata_->all_data_received_prior_to_decode =
240 !incremental_decode_needed_.value();
241
242 auto generator = DecodingImageGenerator::Create(
243 frame_generator_, info, std::move(segment_reader), std::move(frames),
244 complete_frame_content_id_, all_data_received_, can_yuv_decode_,
245 *image_metadata_);
246 first_decoding_generator_created_ = true;
247
248 size_t image_byte_size = ByteSize();
249 if (all_data_received_ && (image_type == "jpg" || image_type == "webp")) {
250 DCHECK(incremental_decode_needed_.has_value());
251 DCHECK(image_byte_size);
252 RecordByteSizeAndWhetherIncrementalDecode(
253 image_type, incremental_decode_needed_.value(), image_byte_size);
254 }
255
256 return generator;
257 }
258
Data()259 scoped_refptr<SharedBuffer> DeferredImageDecoder::Data() {
260 if (!rw_buffer_)
261 return nullptr;
262 sk_sp<SkROBuffer> ro_buffer(rw_buffer_->makeROBufferSnapshot());
263 scoped_refptr<SharedBuffer> shared_buffer = SharedBuffer::Create();
264 SkROBuffer::Iter it(ro_buffer.get());
265 do {
266 shared_buffer->Append(static_cast<const char*>(it.data()), it.size());
267 } while (it.next());
268 return shared_buffer;
269 }
270
SetData(scoped_refptr<SharedBuffer> data,bool all_data_received)271 void DeferredImageDecoder::SetData(scoped_refptr<SharedBuffer> data,
272 bool all_data_received) {
273 SetDataInternal(std::move(data), all_data_received, true);
274 }
275
SetDataInternal(scoped_refptr<SharedBuffer> data,bool all_data_received,bool push_data_to_decoder)276 void DeferredImageDecoder::SetDataInternal(scoped_refptr<SharedBuffer> data,
277 bool all_data_received,
278 bool push_data_to_decoder) {
279 if (metadata_decoder_) {
280 all_data_received_ = all_data_received;
281 if (push_data_to_decoder)
282 metadata_decoder_->SetData(data, all_data_received);
283 PrepareLazyDecodedFrames();
284 }
285
286 if (frame_generator_) {
287 if (!rw_buffer_)
288 rw_buffer_ = std::make_unique<SkRWBuffer>(data->size());
289
290 for (auto it = data->GetIteratorAt(rw_buffer_->size()); it != data->cend();
291 ++it) {
292 DCHECK_GE(data->size(), rw_buffer_->size() + it->size());
293 const size_t remaining = data->size() - rw_buffer_->size() - it->size();
294 rw_buffer_->append(it->data(), it->size(), remaining);
295 }
296 }
297 }
298
IsSizeAvailable()299 bool DeferredImageDecoder::IsSizeAvailable() {
300 // m_actualDecoder is 0 only if image decoding is deferred and that means
301 // the image header decoded successfully and the size is available.
302 return metadata_decoder_ ? metadata_decoder_->IsSizeAvailable() : true;
303 }
304
HasEmbeddedColorProfile() const305 bool DeferredImageDecoder::HasEmbeddedColorProfile() const {
306 return metadata_decoder_ ? metadata_decoder_->HasEmbeddedColorProfile()
307 : has_embedded_color_profile_;
308 }
309
Size() const310 IntSize DeferredImageDecoder::Size() const {
311 return metadata_decoder_ ? metadata_decoder_->Size() : size_;
312 }
313
FrameSizeAtIndex(size_t index) const314 IntSize DeferredImageDecoder::FrameSizeAtIndex(size_t index) const {
315 // FIXME: LocalFrame size is assumed to be uniform. This might not be true for
316 // future supported codecs.
317 return metadata_decoder_ ? metadata_decoder_->FrameSizeAtIndex(index) : size_;
318 }
319
FrameCount()320 size_t DeferredImageDecoder::FrameCount() {
321 return metadata_decoder_ ? metadata_decoder_->FrameCount()
322 : frame_data_.size();
323 }
324
RepetitionCount() const325 int DeferredImageDecoder::RepetitionCount() const {
326 return metadata_decoder_ ? metadata_decoder_->RepetitionCount()
327 : repetition_count_;
328 }
329
FrameHasAlphaAtIndex(size_t index) const330 bool DeferredImageDecoder::FrameHasAlphaAtIndex(size_t index) const {
331 if (metadata_decoder_)
332 return metadata_decoder_->FrameHasAlphaAtIndex(index);
333 if (!frame_generator_->IsMultiFrame())
334 return frame_generator_->HasAlpha(index);
335 return true;
336 }
337
FrameIsReceivedAtIndex(size_t index) const338 bool DeferredImageDecoder::FrameIsReceivedAtIndex(size_t index) const {
339 if (metadata_decoder_)
340 return metadata_decoder_->FrameIsReceivedAtIndex(index);
341 if (index < frame_data_.size())
342 return frame_data_[index].is_received_;
343 return false;
344 }
345
FrameDurationAtIndex(size_t index) const346 base::TimeDelta DeferredImageDecoder::FrameDurationAtIndex(size_t index) const {
347 base::TimeDelta duration;
348 if (metadata_decoder_)
349 duration = metadata_decoder_->FrameDurationAtIndex(index);
350 if (index < frame_data_.size())
351 duration = frame_data_[index].duration_;
352
353 // Many annoying ads specify a 0 duration to make an image flash as quickly as
354 // possible. We follow Firefox's behavior and use a duration of 100 ms for any
355 // frames that specify a duration of <= 10 ms. See <rdar://problem/7689300>
356 // and <http://webkit.org/b/36082> for more information.
357 if (duration <= base::TimeDelta::FromMilliseconds(10))
358 duration = base::TimeDelta::FromMilliseconds(100);
359
360 return duration;
361 }
362
OrientationAtIndex(size_t index) const363 ImageOrientation DeferredImageDecoder::OrientationAtIndex(size_t index) const {
364 if (metadata_decoder_)
365 return metadata_decoder_->Orientation();
366 if (index < frame_data_.size())
367 return frame_data_[index].orientation_;
368 return kDefaultImageOrientation;
369 }
370
ByteSize() const371 size_t DeferredImageDecoder::ByteSize() const {
372 return rw_buffer_ ? rw_buffer_->size() : 0u;
373 }
374
ActivateLazyDecoding()375 void DeferredImageDecoder::ActivateLazyDecoding() {
376 if (frame_generator_)
377 return;
378
379 size_ = metadata_decoder_->Size();
380 image_is_high_bit_depth_ = metadata_decoder_->ImageIsHighBitDepth();
381 has_hot_spot_ = metadata_decoder_->HotSpot(hot_spot_);
382 filename_extension_ = metadata_decoder_->FilenameExtension();
383 has_embedded_color_profile_ = metadata_decoder_->HasEmbeddedColorProfile();
384 color_space_for_sk_images_ = metadata_decoder_->ColorSpaceForSkImages();
385
386 const bool is_single_frame =
387 metadata_decoder_->RepetitionCount() == kAnimationNone ||
388 (all_data_received_ && metadata_decoder_->FrameCount() == 1u);
389 const SkISize decoded_size =
390 SkISize::Make(metadata_decoder_->DecodedSize().Width(),
391 metadata_decoder_->DecodedSize().Height());
392 frame_generator_ = ImageFrameGenerator::Create(
393 decoded_size, !is_single_frame, metadata_decoder_->GetColorBehavior(),
394 metadata_decoder_->GetSupportedDecodeSizes());
395 }
396
PrepareLazyDecodedFrames()397 void DeferredImageDecoder::PrepareLazyDecodedFrames() {
398 if (!metadata_decoder_ || !metadata_decoder_->IsSizeAvailable())
399 return;
400
401 if (invalid_image_)
402 return;
403
404 if (!image_metadata_)
405 image_metadata_ = metadata_decoder_->MakeMetadataForDecodeAcceleration();
406
407 // If the image contains a coded size with zero in either or both size
408 // dimensions, the image is invalid.
409 if (image_metadata_->coded_size.has_value() &&
410 image_metadata_->coded_size.value().IsEmpty()) {
411 invalid_image_ = true;
412 return;
413 }
414
415 ActivateLazyDecoding();
416
417 const size_t previous_size = frame_data_.size();
418 frame_data_.resize(metadata_decoder_->FrameCount());
419
420 // The decoder may be invalidated during a FrameCount(). Simply bail if so.
421 if (metadata_decoder_->Failed()) {
422 invalid_image_ = true;
423 return;
424 }
425
426 // We have encountered a broken image file. Simply bail.
427 if (frame_data_.size() < previous_size) {
428 invalid_image_ = true;
429 return;
430 }
431
432 for (size_t i = previous_size; i < frame_data_.size(); ++i) {
433 frame_data_[i].duration_ = metadata_decoder_->FrameDurationAtIndex(i);
434 frame_data_[i].orientation_ = metadata_decoder_->Orientation();
435 frame_data_[i].is_received_ = metadata_decoder_->FrameIsReceivedAtIndex(i);
436 }
437
438 // The last lazy decoded frame created from previous call might be
439 // incomplete so update its state.
440 if (previous_size) {
441 const size_t last_frame = previous_size - 1;
442 frame_data_[last_frame].is_received_ =
443 metadata_decoder_->FrameIsReceivedAtIndex(last_frame);
444 }
445
446 can_yuv_decode_ =
447 metadata_decoder_->CanDecodeToYUV() && all_data_received_ &&
448 !frame_generator_->IsMultiFrame();
449
450 // If we've received all of the data, then we can reset the metadata decoder,
451 // since everything we care about should now be stored in |frame_data_|.
452 if (all_data_received_) {
453 repetition_count_ = metadata_decoder_->RepetitionCount();
454 metadata_decoder_.reset();
455 // Hold on to m_rwBuffer, which is still needed by createFrameAtIndex.
456 }
457 }
458
HotSpot(IntPoint & hot_spot) const459 bool DeferredImageDecoder::HotSpot(IntPoint& hot_spot) const {
460 if (metadata_decoder_)
461 return metadata_decoder_->HotSpot(hot_spot);
462 if (has_hot_spot_)
463 hot_spot = hot_spot_;
464 return has_hot_spot_;
465 }
466
467 } // namespace blink
468
469 namespace WTF {
470 template <>
471 struct VectorTraits<blink::DeferredFrameData>
472 : public SimpleClassVectorTraits<blink::DeferredFrameData> {
473 STATIC_ONLY(VectorTraits);
474 static const bool kCanInitializeWithMemset =
475 false; // Not all DeferredFrameData members initialize to 0.
476 };
477 } // namespace WTF
478