1 /*
2  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
3  * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
28 
29 #include <algorithm>
30 #include <memory>
31 #include <utility>
32 
33 #include "base/memory/scoped_refptr.h"
34 #include "base/metrics/histogram_macros.h"
35 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
36 #include "third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h"
37 #include "third_party/blink/renderer/platform/graphics/dark_mode_image_classifier.h"
38 #include "third_party/blink/renderer/platform/graphics/deferred_image_decoder.h"
39 #include "third_party/blink/renderer/platform/graphics/image_observer.h"
40 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
41 #include "third_party/blink/renderer/platform/graphics/paint/paint_flags.h"
42 #include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
43 #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
44 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
45 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
46 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
47 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
48 #include "third_party/blink/renderer/platform/timer.h"
49 #include "third_party/blink/renderer/platform/wtf/assertions.h"
50 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
51 
52 namespace blink {
53 namespace {
54 
55 const int kMinImageSizeForClassification1D = 24;
56 const int kMaxImageSizeForClassification1D = 100;
57 
58 }  // namespace
59 
GetRepetitionCountWithPolicyOverride(int actual_count,ImageAnimationPolicy policy)60 int GetRepetitionCountWithPolicyOverride(int actual_count,
61                                          ImageAnimationPolicy policy) {
62   if (actual_count == kAnimationNone ||
63       policy == kImageAnimationPolicyNoAnimation) {
64     return kAnimationNone;
65   }
66 
67   if (actual_count == kAnimationLoopOnce ||
68       policy == kImageAnimationPolicyAnimateOnce) {
69     return kAnimationLoopOnce;
70   }
71 
72   return actual_count;
73 }
74 
BitmapImage(ImageObserver * observer,bool is_multipart)75 BitmapImage::BitmapImage(ImageObserver* observer, bool is_multipart)
76     : Image(observer, is_multipart),
77       animation_policy_(kImageAnimationPolicyAllowed),
78       all_data_received_(false),
79       have_size_(false),
80       size_available_(false),
81       have_frame_count_(false),
82       repetition_count_status_(kUnknown),
83       repetition_count_(kAnimationNone),
84       frame_count_(0) {}
85 
~BitmapImage()86 BitmapImage::~BitmapImage() {}
87 
CurrentFrameHasSingleSecurityOrigin() const88 bool BitmapImage::CurrentFrameHasSingleSecurityOrigin() const {
89   return true;
90 }
91 
DestroyDecodedData()92 void BitmapImage::DestroyDecodedData() {
93   cached_frame_ = PaintImage();
94   NotifyMemoryChanged();
95 }
96 
Data()97 scoped_refptr<SharedBuffer> BitmapImage::Data() {
98   return decoder_ ? decoder_->Data() : nullptr;
99 }
100 
NotifyMemoryChanged()101 void BitmapImage::NotifyMemoryChanged() {
102   if (GetImageObserver())
103     GetImageObserver()->DecodedSizeChangedTo(this, TotalFrameBytes());
104 }
105 
TotalFrameBytes()106 size_t BitmapImage::TotalFrameBytes() {
107   if (cached_frame_)
108     return static_cast<size_t>(Size().Area()) * sizeof(ImageFrame::PixelData);
109   return 0u;
110 }
111 
PaintImageForTesting()112 PaintImage BitmapImage::PaintImageForTesting() {
113   return CreatePaintImage();
114 }
115 
CreatePaintImage()116 PaintImage BitmapImage::CreatePaintImage() {
117   sk_sp<PaintImageGenerator> generator =
118       decoder_ ? decoder_->CreateGenerator() : nullptr;
119   if (!generator)
120     return PaintImage();
121 
122   auto completion_state = all_data_received_
123                               ? PaintImage::CompletionState::DONE
124                               : PaintImage::CompletionState::PARTIALLY_DONE;
125   auto builder =
126       CreatePaintImageBuilder()
127           .set_paint_image_generator(std::move(generator))
128           .set_repetition_count(GetRepetitionCountWithPolicyOverride(
129               RepetitionCount(), animation_policy_))
130           .set_is_high_bit_depth(decoder_->ImageIsHighBitDepth())
131           .set_completion_state(completion_state)
132           .set_reset_animation_sequence_id(reset_animation_sequence_id_);
133 
134   return builder.TakePaintImage();
135 }
136 
UpdateSize() const137 void BitmapImage::UpdateSize() const {
138   if (!size_available_ || have_size_ || !decoder_)
139     return;
140 
141   size_ = decoder_->FrameSizeAtIndex(0);
142   if (decoder_->OrientationAtIndex(0).UsesWidthAsHeight())
143     size_respecting_orientation_ = size_.TransposedSize();
144   else
145     size_respecting_orientation_ = size_;
146   have_size_ = true;
147 }
148 
Size() const149 IntSize BitmapImage::Size() const {
150   UpdateSize();
151   return size_;
152 }
153 
SizeRespectingOrientation() const154 IntSize BitmapImage::SizeRespectingOrientation() const {
155   UpdateSize();
156   return size_respecting_orientation_;
157 }
158 
HasDefaultOrientation() const159 bool BitmapImage::HasDefaultOrientation() const {
160   ImageOrientation orientation = CurrentFrameOrientation();
161   return orientation == kDefaultImageOrientation;
162 }
163 
GetHotSpot(IntPoint & hot_spot) const164 bool BitmapImage::GetHotSpot(IntPoint& hot_spot) const {
165   return decoder_ && decoder_->HotSpot(hot_spot);
166 }
167 
168 // We likely don't need to confirm that this is the first time all data has
169 // been received as a way to avoid reporting the UMA multiple times for the
170 // same image. However, we err on the side of caution.
ShouldReportByteSizeUMAs(bool data_now_completely_received)171 bool BitmapImage::ShouldReportByteSizeUMAs(bool data_now_completely_received) {
172   if (!decoder_)
173     return false;
174   // Ensures that refactoring to check truthiness of ByteSize() method is
175   // equivalent to the previous use of Data() and does not mess up UMAs.
176   DCHECK_EQ(!decoder_->ByteSize(), !decoder_->Data());
177   return !all_data_received_ && data_now_completely_received &&
178          decoder_->ByteSize() && IsSizeAvailable();
179 }
180 
SetData(scoped_refptr<SharedBuffer> data,bool all_data_received)181 Image::SizeAvailability BitmapImage::SetData(scoped_refptr<SharedBuffer> data,
182                                              bool all_data_received) {
183   if (!data)
184     return kSizeAvailable;
185 
186   int length = data->size();
187   if (!length)
188     return kSizeAvailable;
189 
190   if (decoder_) {
191     decoder_->SetData(std::move(data), all_data_received);
192     return DataChanged(all_data_received);
193   }
194 
195   bool has_enough_data = ImageDecoder::HasSufficientDataToSniffImageType(*data);
196   decoder_ = DeferredImageDecoder::Create(std::move(data), all_data_received,
197                                           ImageDecoder::kAlphaPremultiplied,
198                                           ColorBehavior::Tag());
199   // If we had enough data but couldn't create a decoder, it implies a decode
200   // failure.
201   if (has_enough_data && !decoder_)
202     return kSizeAvailable;
203   return DataChanged(all_data_received);
204 }
205 
206 // Return the image density in 0.01 "bits per pixel" rounded to the nearest
207 // integer.
ImageDensityInCentiBpp(IntSize size,size_t image_size_bytes)208 static inline uint64_t ImageDensityInCentiBpp(IntSize size,
209                                               size_t image_size_bytes) {
210   uint64_t image_area = static_cast<uint64_t>(size.Width()) * size.Height();
211   return (static_cast<uint64_t>(image_size_bytes) * 100 * 8 + image_area / 2) /
212          image_area;
213 }
214 
DataChanged(bool all_data_received)215 Image::SizeAvailability BitmapImage::DataChanged(bool all_data_received) {
216   TRACE_EVENT0("blink", "BitmapImage::dataChanged");
217 
218   // If the data was updated, clear the |cached_frame_| to push it to the
219   // compositor thread. Its necessary to clear the frame since more data
220   // requires a new PaintImageGenerator instance.
221   cached_frame_ = PaintImage();
222 
223   // Report the image density metric right after we received all the data. The
224   // SetData() call on the decoder_ (if there is one) should have decoded the
225   // images and we should know the image size at this point.
226   if (ShouldReportByteSizeUMAs(all_data_received) &&
227       decoder_->FilenameExtension() == "jpg") {
228     BitmapImageMetrics::CountImageJpegDensity(
229         std::min(Size().Width(), Size().Height()),
230         ImageDensityInCentiBpp(Size(), decoder_->ByteSize()),
231         decoder_->ByteSize());
232   }
233 
234   // Feed all the data we've seen so far to the image decoder.
235   all_data_received_ = all_data_received;
236   have_frame_count_ = false;
237 
238   return IsSizeAvailable() ? kSizeAvailable : kSizeUnavailable;
239 }
240 
HasColorProfile() const241 bool BitmapImage::HasColorProfile() const {
242   return decoder_ && decoder_->HasEmbeddedColorProfile();
243 }
244 
FilenameExtension() const245 String BitmapImage::FilenameExtension() const {
246   return decoder_ ? decoder_->FilenameExtension() : String();
247 }
248 
Draw(cc::PaintCanvas * canvas,const PaintFlags & flags,const FloatRect & dst_rect,const FloatRect & src_rect,RespectImageOrientationEnum should_respect_image_orientation,ImageClampingMode clamp_mode,ImageDecodingMode decode_mode)249 void BitmapImage::Draw(
250     cc::PaintCanvas* canvas,
251     const PaintFlags& flags,
252     const FloatRect& dst_rect,
253     const FloatRect& src_rect,
254     RespectImageOrientationEnum should_respect_image_orientation,
255     ImageClampingMode clamp_mode,
256     ImageDecodingMode decode_mode) {
257   TRACE_EVENT0("skia", "BitmapImage::draw");
258 
259   PaintImage image = PaintImageForCurrentFrame();
260   if (!image)
261     return;  // It's too early and we don't have an image yet.
262 
263   auto paint_image_decoding_mode = ToPaintImageDecodingMode(decode_mode);
264   if (image.decoding_mode() != paint_image_decoding_mode) {
265     image = PaintImageBuilder::WithCopy(std::move(image))
266                 .set_decoding_mode(paint_image_decoding_mode)
267                 .TakePaintImage();
268   }
269 
270   FloatRect adjusted_src_rect = src_rect;
271   adjusted_src_rect.Intersect(SkRect::MakeWH(image.width(), image.height()));
272 
273   if (adjusted_src_rect.IsEmpty() || dst_rect.IsEmpty())
274     return;  // Nothing to draw.
275 
276   ImageOrientation orientation = kDefaultImageOrientation;
277   if (should_respect_image_orientation == kRespectImageOrientation)
278     orientation = CurrentFrameOrientation();
279 
280   PaintCanvasAutoRestore auto_restore(canvas, false);
281   FloatRect adjusted_dst_rect = dst_rect;
282   if (orientation != kDefaultImageOrientation) {
283     canvas->save();
284 
285     // ImageOrientation expects the origin to be at (0, 0)
286     canvas->translate(adjusted_dst_rect.X(), adjusted_dst_rect.Y());
287     adjusted_dst_rect.SetLocation(FloatPoint());
288 
289     canvas->concat(AffineTransformToSkMatrix(
290         orientation.TransformFromDefault(adjusted_dst_rect.Size())));
291 
292     if (orientation.UsesWidthAsHeight()) {
293       // The destination rect will have its width and height already reversed
294       // for the orientation of the image, as it was needed for page layout, so
295       // we need to reverse it back here.
296       adjusted_dst_rect =
297           FloatRect(adjusted_dst_rect.X(), adjusted_dst_rect.Y(),
298                     adjusted_dst_rect.Height(), adjusted_dst_rect.Width());
299     }
300   }
301 
302   uint32_t unique_id = image.GetSkImage()->uniqueID();
303   bool is_lazy_generated = image.IsLazyGenerated();
304   canvas->drawImageRect(std::move(image), adjusted_src_rect, adjusted_dst_rect,
305                         &flags,
306                         WebCoreClampingModeToSkiaRectConstraint(clamp_mode));
307 
308   if (is_lazy_generated) {
309     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
310                          "Draw LazyPixelRef", TRACE_EVENT_SCOPE_THREAD,
311                          "LazyPixelRef", unique_id);
312   }
313 
314   StartAnimation();
315 }
316 
FrameCount()317 size_t BitmapImage::FrameCount() {
318   if (!have_frame_count_) {
319     frame_count_ = decoder_ ? decoder_->FrameCount() : 0;
320     have_frame_count_ = frame_count_ > 0;
321   }
322   return frame_count_;
323 }
324 
HasVisibleImageSize(IntSize size)325 static inline bool HasVisibleImageSize(IntSize size) {
326   return (size.Width() > 1 || size.Height() > 1);
327 }
328 
IsSizeAvailable()329 bool BitmapImage::IsSizeAvailable() {
330   if (size_available_)
331     return true;
332 
333   size_available_ = decoder_ && decoder_->IsSizeAvailable();
334   if (size_available_ && HasVisibleImageSize(Size())) {
335     BitmapImageMetrics::CountDecodedImageType(decoder_->FilenameExtension());
336     if (decoder_->FilenameExtension() == "jpg") {
337       BitmapImageMetrics::CountImageOrientation(
338           decoder_->OrientationAtIndex(0).Orientation());
339     }
340   }
341 
342   return size_available_;
343 }
344 
PaintImageForCurrentFrame()345 PaintImage BitmapImage::PaintImageForCurrentFrame() {
346   if (cached_frame_)
347     return cached_frame_;
348 
349   cached_frame_ = CreatePaintImage();
350 
351   // Create the SkImage backing for this PaintImage here to ensure that copies
352   // of the PaintImage share the same SkImage. Skia's caching of the decoded
353   // output of this image is tied to the lifetime of the SkImage. So we create
354   // the SkImage here and cache the PaintImage to keep the decode alive in
355   // skia's cache.
356   cached_frame_.GetSkImage();
357   NotifyMemoryChanged();
358 
359   return cached_frame_;
360 }
361 
ImageForDefaultFrame()362 scoped_refptr<Image> BitmapImage::ImageForDefaultFrame() {
363   if (FrameCount() > 1) {
364     PaintImage paint_image = PaintImageForCurrentFrame();
365     if (!paint_image)
366       return nullptr;
367 
368     if (paint_image.ShouldAnimate()) {
369       // To prevent the compositor from animating this image, we set the
370       // animation count to kAnimationNone. This makes the image essentially
371       // static.
372       paint_image = PaintImageBuilder::WithCopy(std::move(paint_image))
373                         .set_repetition_count(kAnimationNone)
374                         .TakePaintImage();
375     }
376     return StaticBitmapImage::Create(std::move(paint_image));
377   }
378 
379   return Image::ImageForDefaultFrame();
380 }
381 
CurrentFrameKnownToBeOpaque()382 bool BitmapImage::CurrentFrameKnownToBeOpaque() {
383   // If the image is animated, it is being animated by the compositor and we
384   // don't know what the current frame is.
385   // TODO(khushalsagar): We could say the image is opaque if none of the frames
386   // have alpha.
387   if (MaybeAnimated())
388     return false;
389 
390   // We ask the decoder whether the image has alpha because in some cases the
391   // the correct value is known after decoding. The DeferredImageDecoder caches
392   // the accurate value from the decoded result.
393   const bool frame_has_alpha =
394       decoder_ ? decoder_->FrameHasAlphaAtIndex(PaintImage::kDefaultFrameIndex)
395                : true;
396   return !frame_has_alpha;
397 }
398 
CurrentFrameIsComplete()399 bool BitmapImage::CurrentFrameIsComplete() {
400   return decoder_
401              ? decoder_->FrameIsReceivedAtIndex(PaintImage::kDefaultFrameIndex)
402              : false;
403 }
404 
CurrentFrameIsLazyDecoded()405 bool BitmapImage::CurrentFrameIsLazyDecoded() {
406   // BitmapImage supports only lazy generated images.
407   return true;
408 }
409 
CurrentFrameOrientation() const410 ImageOrientation BitmapImage::CurrentFrameOrientation() const {
411   return decoder_ ? decoder_->OrientationAtIndex(PaintImage::kDefaultFrameIndex)
412                   : kDefaultImageOrientation;
413 }
414 
RepetitionCount()415 int BitmapImage::RepetitionCount() {
416   if ((repetition_count_status_ == kUnknown) ||
417       ((repetition_count_status_ == kUncertain) && all_data_received_)) {
418     // Snag the repetition count.  If |imageKnownToBeComplete| is false, the
419     // repetition count may not be accurate yet for GIFs; in this case the
420     // decoder will default to cAnimationLoopOnce, and we'll try and read
421     // the count again once the whole image is decoded.
422     repetition_count_ = decoder_ ? decoder_->RepetitionCount() : kAnimationNone;
423 
424     // When requesting more than a single loop, repetition count is one less
425     // than the actual number of loops.
426     if (repetition_count_ > 0)
427       repetition_count_++;
428 
429     repetition_count_status_ =
430         (all_data_received_ || repetition_count_ == kAnimationNone)
431             ? kCertain
432             : kUncertain;
433   }
434   return repetition_count_;
435 }
436 
ResetAnimation()437 void BitmapImage::ResetAnimation() {
438   cached_frame_ = PaintImage();
439   reset_animation_sequence_id_++;
440 }
441 
MaybeAnimated()442 bool BitmapImage::MaybeAnimated() {
443   if (FrameCount() > 1)
444     return true;
445 
446   return decoder_ && decoder_->RepetitionCount() != kAnimationNone;
447 }
448 
SetAnimationPolicy(ImageAnimationPolicy policy)449 void BitmapImage::SetAnimationPolicy(ImageAnimationPolicy policy) {
450   if (animation_policy_ == policy)
451     return;
452 
453   animation_policy_ = policy;
454   ResetAnimation();
455 }
456 
CheckTypeSpecificConditionsForDarkMode(const FloatRect & dest_rect,DarkModeImageClassifier * classifier)457 DarkModeClassification BitmapImage::CheckTypeSpecificConditionsForDarkMode(
458     const FloatRect& dest_rect,
459     DarkModeImageClassifier* classifier) {
460   if (dest_rect.Width() < kMinImageSizeForClassification1D ||
461       dest_rect.Height() < kMinImageSizeForClassification1D)
462     return DarkModeClassification::kApplyFilter;
463 
464   if (dest_rect.Width() > kMaxImageSizeForClassification1D ||
465       dest_rect.Height() > kMaxImageSizeForClassification1D) {
466     return DarkModeClassification::kDoNotApplyFilter;
467   }
468 
469   classifier->SetImageType(DarkModeImageClassifier::ImageType::kBitmap);
470 
471   return DarkModeClassification::kNotClassified;
472 }
473 
474 }  // namespace blink
475