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