blob: 0331bfc1ca30354ffbdd1e0918086102a22498e3 [file] [log] [blame]
vmpstr94cfa882017-04-14 01:19:351// Copyright 2017 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 "cc/paint/paint_image.h"
Khushal1b8abc012017-08-10 05:16:176
Gyuyoung Kime83664012017-12-02 00:12:497#include <memory>
8
vmpstr81a39a32017-05-16 19:30:219#include "base/atomic_sequence_num.h"
Daniel Chengc0581992019-03-29 04:52:5610#include "base/hash/hash.h"
Khushal01e86782018-06-26 21:10:5311#include "cc/paint/paint_image_builder.h"
Khushal1b8abc012017-08-10 05:16:1712#include "cc/paint/paint_image_generator.h"
Vladimir Levin4f2c08c2017-07-28 03:03:2813#include "cc/paint/paint_record.h"
Xida Chenc5cb8562019-08-14 22:41:5614#include "cc/paint/paint_worklet_input.h"
Khushal1b8abc012017-08-10 05:16:1715#include "cc/paint/skia_paint_image_generator.h"
Vladimir Levin4f2c08c2017-07-28 03:03:2816#include "ui/gfx/skia_util.h"
vmpstr94cfa882017-04-14 01:19:3517
18namespace cc {
vmpstr81a39a32017-05-16 19:30:2119namespace {
Lei Zhang868717c2018-05-09 04:33:5620base::AtomicSequenceNumber g_next_image_id;
21base::AtomicSequenceNumber g_next_image_content_id;
Khushal123f71d2018-08-24 08:21:1622base::AtomicSequenceNumber g_next_generator_client_id;
Khushalb41caaa2017-08-31 02:40:1623} // namespace
vmpstr94cfa882017-04-14 01:19:3524
Khushal512439c2017-10-18 17:36:5325const PaintImage::Id PaintImage::kNonLazyStableId = -1;
Khushalfdacdc92017-09-22 22:40:5226const size_t PaintImage::kDefaultFrameIndex = 0u;
Khushal512439c2017-10-18 17:36:5327const PaintImage::Id PaintImage::kInvalidId = -2;
Khushalcace4d42018-02-26 22:06:2528const PaintImage::ContentId PaintImage::kInvalidContentId = -1;
Khushal123f71d2018-08-24 08:21:1629const PaintImage::GeneratorClientId PaintImage::kDefaultGeneratorClientId = 0;
Khushalfdacdc92017-09-22 22:40:5230
vmpstr55c7657ca2017-04-29 00:46:4831PaintImage::PaintImage() = default;
vmpstr55c7657ca2017-04-29 00:46:4832PaintImage::PaintImage(const PaintImage& other) = default;
33PaintImage::PaintImage(PaintImage&& other) = default;
vmpstr94cfa882017-04-14 01:19:3534PaintImage::~PaintImage() = default;
35
vmpstr55c7657ca2017-04-29 00:46:4836PaintImage& PaintImage::operator=(const PaintImage& other) = default;
37PaintImage& PaintImage::operator=(PaintImage&& other) = default;
38
khushalsagard5e13bf2017-05-17 08:08:5039bool PaintImage::operator==(const PaintImage& other) const {
Adrienne Walker6ac30632017-11-18 01:52:0740 if (sk_image_ != other.sk_image_)
41 return false;
42 if (paint_record_ != other.paint_record_)
43 return false;
44 if (paint_record_rect_ != other.paint_record_rect_)
45 return false;
Khushal73760a32018-02-16 19:29:5146 if (content_id_ != other.content_id_)
Adrienne Walker6ac30632017-11-18 01:52:0747 return false;
48 if (paint_image_generator_ != other.paint_image_generator_)
49 return false;
50 if (id_ != other.id_)
51 return false;
52 if (animation_type_ != other.animation_type_)
53 return false;
54 if (completion_state_ != other.completion_state_)
55 return false;
56 if (subset_rect_ != other.subset_rect_)
57 return false;
Adrienne Walker6ac30632017-11-18 01:52:0758 if (is_multipart_ != other.is_multipart_)
59 return false;
60 return true;
vmpstr55c7657ca2017-04-29 00:46:4861}
62
Vladimir Levin9167e1c2017-10-18 21:28:2463// static
64PaintImage::DecodingMode PaintImage::GetConservative(DecodingMode one,
65 DecodingMode two) {
66 if (one == two)
67 return one;
68 if (one == DecodingMode::kSync || two == DecodingMode::kSync)
69 return DecodingMode::kSync;
70 if (one == DecodingMode::kUnspecified || two == DecodingMode::kUnspecified)
71 return DecodingMode::kUnspecified;
72 DCHECK_EQ(one, DecodingMode::kAsync);
73 DCHECK_EQ(two, DecodingMode::kAsync);
74 return DecodingMode::kAsync;
75}
76
77// static
vmpstr81a39a32017-05-16 19:30:2178PaintImage::Id PaintImage::GetNextId() {
Lei Zhang868717c2018-05-09 04:33:5679 return g_next_image_id.GetNext();
vmpstr81a39a32017-05-16 19:30:2180}
81
Vladimir Levin9167e1c2017-10-18 21:28:2482// static
Khushalb41caaa2017-08-31 02:40:1683PaintImage::ContentId PaintImage::GetNextContentId() {
Lei Zhang868717c2018-05-09 04:33:5684 return g_next_image_content_id.GetNext();
Khushalb41caaa2017-08-31 02:40:1685}
86
Khushal01e86782018-06-26 21:10:5387// static
Khushal123f71d2018-08-24 08:21:1688PaintImage::GeneratorClientId PaintImage::GetNextGeneratorClientId() {
89 // These IDs must start from 1, since 0 is the kDefaultGeneratorClientId.
90 return g_next_generator_client_id.GetNext() + 1;
91}
92
93// static
Khushal01e86782018-06-26 21:10:5394PaintImage PaintImage::CreateFromBitmap(SkBitmap bitmap) {
95 if (bitmap.drawsNothing())
96 return PaintImage();
97
98 return PaintImageBuilder::WithDefault()
99 .set_id(PaintImage::GetNextId())
100 .set_image(SkImage::MakeFromBitmap(bitmap),
101 PaintImage::GetNextContentId())
102 .TakePaintImage();
103}
104
Vladimir Levin4f2c08c2017-07-28 03:03:28105const sk_sp<SkImage>& PaintImage::GetSkImage() const {
Vladimir Levin4f2c08c2017-07-28 03:03:28106 return cached_sk_image_;
107}
108
Khushalb481b282017-08-24 00:06:53109PaintImage PaintImage::MakeSubset(const gfx::Rect& subset) const {
110 DCHECK(!subset.IsEmpty());
111
112 // If the subset is the same as the image bounds, we can return the same
113 // image.
114 gfx::Rect bounds(width(), height());
115 if (bounds == subset)
116 return *this;
117
118 DCHECK(bounds.Contains(subset))
119 << "Subset should not be greater than the image bounds";
120 PaintImage result(*this);
121 result.subset_rect_ = subset;
122 // Store the subset from the original image.
123 result.subset_rect_.Offset(subset_rect_.x(), subset_rect_.y());
124
Khushala866a802017-10-05 18:21:00125 // Creating the |cached_sk_image_| using the SkImage from the original
126 // PaintImage is an optimization to allow re-use of the original decode for
127 // image subsets in skia, for cases that rely on skia's image decode cache.
Khushalb481b282017-08-24 00:06:53128 result.cached_sk_image_ =
129 GetSkImage()->makeSubset(gfx::RectToSkIRect(subset));
130 return result;
131}
132
Khushala866a802017-10-05 18:21:00133void PaintImage::CreateSkImage() {
134 DCHECK(!cached_sk_image_);
135
136 if (sk_image_) {
137 cached_sk_image_ = sk_image_;
138 } else if (paint_record_) {
139 cached_sk_image_ = SkImage::MakeFromPicture(
140 ToSkPicture(paint_record_, gfx::RectToSkRect(paint_record_rect_)),
141 SkISize::Make(paint_record_rect_.width(), paint_record_rect_.height()),
142 nullptr, nullptr, SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
143 } else if (paint_image_generator_) {
144 cached_sk_image_ =
Gyuyoung Kime83664012017-12-02 00:12:49145 SkImage::MakeFromGenerator(std::make_unique<SkiaPaintImageGenerator>(
Khushal123f71d2018-08-24 08:21:16146 paint_image_generator_, kDefaultFrameIndex,
147 kDefaultGeneratorClientId));
Khushala866a802017-10-05 18:21:00148 }
149
150 if (!subset_rect_.IsEmpty() && cached_sk_image_) {
151 cached_sk_image_ =
152 cached_sk_image_->makeSubset(gfx::RectToSkIRect(subset_rect_));
153 }
154}
155
Andres Calderon Jaramilloae8e59d2019-04-01 18:21:34156bool PaintImage::IsEligibleForAcceleratedDecoding() const {
157 if (!CanDecodeFromGenerator())
158 return false;
159 DCHECK(paint_image_generator_);
160 return paint_image_generator_->IsEligibleForAcceleratedDecoding();
161}
162
Vladimir Levin772dc5f2017-08-25 01:54:29163SkISize PaintImage::GetSupportedDecodeSize(
164 const SkISize& requested_size) const {
Madeleine Barowsky1052a402019-01-29 18:46:02165 // TODO(vmpstr): In some cases we do not support decoding to any other
166 // size than the original. See the comment in CanDecodeFromGenerator()
167 // for more detail.
168 if (CanDecodeFromGenerator())
Khushalf9e3faed2018-06-20 21:31:13169 return paint_image_generator_->GetSupportedDecodeSize(requested_size);
Vladimir Levin772dc5f2017-08-25 01:54:29170 return SkISize::Make(width(), height());
171}
172
Vladimir Levin772dc5f2017-08-25 01:54:29173bool PaintImage::Decode(void* memory,
174 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52175 sk_sp<SkColorSpace> color_space,
Khushal123f71d2018-08-24 08:21:16176 size_t frame_index,
177 GeneratorClientId client_id) const {
Eric Karl79c29462018-01-27 07:19:28178 // We don't support SkImageInfo's with color spaces on them. Color spaces
179 // should always be passed via the |color_space| arg.
180 DCHECK(!info->colorSpace());
181
Madeleine Barowsky1052a402019-01-29 18:46:02182 // We only support decode to supported decode size.
183 DCHECK(info->dimensions() == GetSupportedDecodeSize(info->dimensions()));
184
185 // TODO(vmpstr): In some cases we do not support decoding to any other
186 // size than the original. See the comment in CanDecodeFromGenerator()
187 // for more detail. For now, fallback to DecodeFromSkImage().
188 if (CanDecodeFromGenerator()) {
Khushalfdacdc92017-09-22 22:40:52189 return DecodeFromGenerator(memory, info, std::move(color_space),
Khushal123f71d2018-08-24 08:21:16190 frame_index, client_id);
Madeleine Barowsky1052a402019-01-29 18:46:02191 }
Khushal123f71d2018-08-24 08:21:16192 return DecodeFromSkImage(memory, info, std::move(color_space), frame_index,
193 client_id);
Vladimir Levinc9aa97402017-09-07 21:24:57194}
195
Madeleine Barowsky1052a402019-01-29 18:46:02196bool PaintImage::DecodeYuv(void* planes[SkYUVASizeInfo::kMaxCount],
197 size_t frame_index,
198 GeneratorClientId client_id,
199 const SkYUVASizeInfo& yuva_size_info) const {
200 SkYUVAIndex indices[SkYUVAIndex::kIndexCount];
201 // Passing nullptr for the SkYUVASizeInfo forces IsYuv to create and fill out
202 // a temporary object instead because |yuva_size_info| is const.
203 bool is_yuv = IsYuv(nullptr, indices);
204 DCHECK(is_yuv);
205 DCHECK(CanDecodeFromGenerator());
206 const uint32_t lazy_pixel_ref = unique_id();
207 return paint_image_generator_->GetYUVA8Planes(yuva_size_info, indices, planes,
208 frame_index, lazy_pixel_ref);
209}
210
Vladimir Levinc9aa97402017-09-07 21:24:57211bool PaintImage::DecodeFromGenerator(void* memory,
212 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52213 sk_sp<SkColorSpace> color_space,
Khushal123f71d2018-08-24 08:21:16214 size_t frame_index,
215 GeneratorClientId client_id) const {
Madeleine Barowsky1052a402019-01-29 18:46:02216 DCHECK(CanDecodeFromGenerator());
Vladimir Levinc9aa97402017-09-07 21:24:57217 // First convert the info to have the requested color space, since the decoder
218 // will convert this for us.
219 *info = info->makeColorSpace(std::move(color_space));
Madeleine Barowsky1052a402019-01-29 18:46:02220 const uint32_t lazy_pixel_ref = unique_id();
Vladimir Levinc9aa97402017-09-07 21:24:57221 return paint_image_generator_->GetPixels(*info, memory, info->minRowBytes(),
Madeleine Barowsky1052a402019-01-29 18:46:02222 frame_index, client_id,
223 lazy_pixel_ref);
224}
225
226// TODO(vmpstr): If we're using a subset_rect_ then the info specifies the
227// requested size relative to the subset. However, the generator isn't aware
228// of this subsetting and would need a size that is relative to the original
229// image size. We could still implement this case, but we need to convert the
230// requested size into the space of the original image.
231bool PaintImage::CanDecodeFromGenerator() const {
232 return paint_image_generator_ && subset_rect_.IsEmpty();
Vladimir Levinc9aa97402017-09-07 21:24:57233}
234
235bool PaintImage::DecodeFromSkImage(void* memory,
236 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52237 sk_sp<SkColorSpace> color_space,
Khushal123f71d2018-08-24 08:21:16238 size_t frame_index,
239 GeneratorClientId client_id) const {
240 auto image = GetSkImageForFrame(frame_index, client_id);
Vladimir Levin772dc5f2017-08-25 01:54:29241 DCHECK(image);
242 if (color_space) {
Brian Osman5459bae12018-07-17 12:32:26243 image = image->makeColorSpace(color_space);
Vladimir Levin772dc5f2017-08-25 01:54:29244 if (!image)
245 return false;
246 }
247 // Note that the readPixels has to happen before converting the info to the
248 // given color space, since it can produce incorrect results.
249 bool result = image->readPixels(*info, memory, info->minRowBytes(), 0, 0,
250 SkImage::kDisallow_CachingHint);
Vladimir Levinc9aa97402017-09-07 21:24:57251 *info = info->makeColorSpace(std::move(color_space));
Vladimir Levin772dc5f2017-08-25 01:54:29252 return result;
253}
254
Khushalb42fb24d2017-09-14 19:15:15255bool PaintImage::ShouldAnimate() const {
256 return animation_type_ == AnimationType::ANIMATED &&
Khushalfdacdc92017-09-22 22:40:52257 repetition_count_ != kAnimationNone && FrameCount() > 1;
Khushalb42fb24d2017-09-14 19:15:15258}
259
Khushalb41caaa2017-08-31 02:40:16260PaintImage::FrameKey PaintImage::GetKeyForFrame(size_t frame_index) const {
261 DCHECK_LT(frame_index, FrameCount());
Khushalb41caaa2017-08-31 02:40:16262
263 // Query the content id that uniquely identifies the content for this frame
264 // from the content provider.
265 ContentId content_id = kInvalidContentId;
266 if (paint_image_generator_)
267 content_id = paint_image_generator_->GetContentIdForFrame(frame_index);
Khushal73760a32018-02-16 19:29:51268 else if (paint_record_ || sk_image_)
269 content_id = content_id_;
Khushalb41caaa2017-08-31 02:40:16270
271 DCHECK_NE(content_id, kInvalidContentId);
Khushal7ec0d58a2017-09-06 19:51:59272 return FrameKey(content_id, frame_index, subset_rect_);
Khushalb41caaa2017-08-31 02:40:16273}
274
Reza.Zakerinasab9afecdf2018-09-25 11:26:26275SkColorType PaintImage::GetColorType() const {
276 if (paint_image_generator_)
277 return paint_image_generator_->GetSkImageInfo().colorType();
278 if (GetSkImage())
279 return GetSkImage()->colorType();
280 return kUnknown_SkColorType;
281}
282
Xida Chenc5cb8562019-08-14 22:41:56283int PaintImage::width() const {
284 return paint_worklet_input_
285 ? static_cast<int>(paint_worklet_input_->GetSize().width())
286 : GetSkImage()->width();
287}
288
289int PaintImage::height() const {
290 return paint_worklet_input_
291 ? static_cast<int>(paint_worklet_input_->GetSize().height())
292 : GetSkImage()->height();
293}
294
Madeleine Barowsky5521e0b2019-08-08 19:38:10295PaintImage::ImageType PaintImage::GetImageType() const {
296 if (paint_image_generator_)
297 return paint_image_generator_->GetImageType();
298 return PaintImage::ImageType::kInvalid;
299}
300
Madeleine Barowsky1052a402019-01-29 18:46:02301bool PaintImage::IsYuv(SkYUVASizeInfo* yuva_size_info,
Madeleine Barowsky0c1ac182019-08-09 23:08:35302 SkYUVAIndex* plane_indices,
303 SkYUVColorSpace* yuv_color_space) const {
Madeleine Barowsky1052a402019-01-29 18:46:02304 SkYUVASizeInfo temp_yuva_size_info;
305 SkYUVAIndex temp_plane_indices[SkYUVAIndex::kIndexCount];
Madeleine Barowsky0c1ac182019-08-09 23:08:35306 SkYUVColorSpace temp_yuv_color_space;
Madeleine Barowsky1052a402019-01-29 18:46:02307 if (!yuva_size_info) {
308 yuva_size_info = &temp_yuva_size_info;
309 }
310 if (!plane_indices) {
311 plane_indices = temp_plane_indices;
312 }
Madeleine Barowsky0c1ac182019-08-09 23:08:35313 if (!yuv_color_space) {
314 yuv_color_space = &temp_yuv_color_space;
315 }
316 // ImageDecoder will fill out the value of |yuv_color_space| depending on
317 // the codec's specification.
Madeleine Barowsky1052a402019-01-29 18:46:02318 return CanDecodeFromGenerator() &&
319 paint_image_generator_->QueryYUVA8(yuva_size_info, plane_indices,
Madeleine Barowsky0c1ac182019-08-09 23:08:35320 yuv_color_space);
Madeleine Barowsky1052a402019-01-29 18:46:02321}
322
Khushalb41caaa2017-08-31 02:40:16323const std::vector<FrameMetadata>& PaintImage::GetFrameMetadata() const {
324 DCHECK_EQ(animation_type_, AnimationType::ANIMATED);
325 DCHECK(paint_image_generator_);
326
327 return paint_image_generator_->GetFrameMetadata();
328}
329
330size_t PaintImage::FrameCount() const {
331 if (!GetSkImage())
332 return 0u;
333 return paint_image_generator_
334 ? paint_image_generator_->GetFrameMetadata().size()
335 : 1u;
336}
337
Khushal123f71d2018-08-24 08:21:16338sk_sp<SkImage> PaintImage::GetSkImageForFrame(
339 size_t index,
340 GeneratorClientId client_id) const {
Khushalfdacdc92017-09-22 22:40:52341 DCHECK_LT(index, FrameCount());
342
Khushal123f71d2018-08-24 08:21:16343 // |client_id| and |index| are only relevant for generator backed images which
344 // perform lazy decoding and can be multi-frame.
345 if (!paint_image_generator_) {
346 DCHECK_EQ(index, kDefaultFrameIndex);
347 return GetSkImage();
348 }
349
350 // The internally cached SkImage is constructed using the default frame index
351 // and GeneratorClientId. Avoid creating a new SkImage.
352 if (index == kDefaultFrameIndex && client_id == kDefaultGeneratorClientId)
Khushalfdacdc92017-09-22 22:40:52353 return GetSkImage();
354
Khushal123f71d2018-08-24 08:21:16355 sk_sp<SkImage> image =
356 SkImage::MakeFromGenerator(std::make_unique<SkiaPaintImageGenerator>(
357 paint_image_generator_, index, client_id));
Khushalfdacdc92017-09-22 22:40:52358 if (!subset_rect_.IsEmpty())
359 image = image->makeSubset(gfx::RectToSkIRect(subset_rect_));
360 return image;
361}
362
Khushalb41caaa2017-08-31 02:40:16363std::string PaintImage::ToString() const {
364 std::ostringstream str;
365 str << "sk_image_: " << sk_image_ << " paint_record_: " << paint_record_
366 << " paint_record_rect_: " << paint_record_rect_.ToString()
367 << " paint_image_generator_: " << paint_image_generator_
368 << " id_: " << id_
369 << " animation_type_: " << static_cast<int>(animation_type_)
370 << " completion_state_: " << static_cast<int>(completion_state_)
371 << " subset_rect_: " << subset_rect_.ToString()
Madeleine Barowsky1052a402019-01-29 18:46:02372 << " is_multipart_: " << is_multipart_ << " is YUV: " << IsYuv();
Khushalb41caaa2017-08-31 02:40:16373 return str.str();
374}
375
Khushal7ec0d58a2017-09-06 19:51:59376PaintImage::FrameKey::FrameKey(ContentId content_id,
Khushalb41caaa2017-08-31 02:40:16377 size_t frame_index,
378 gfx::Rect subset_rect)
Khushal7ec0d58a2017-09-06 19:51:59379 : content_id_(content_id),
Khushalb41caaa2017-08-31 02:40:16380 frame_index_(frame_index),
381 subset_rect_(subset_rect) {
Khushal7ec0d58a2017-09-06 19:51:59382 size_t original_hash = base::HashInts(static_cast<uint64_t>(content_id_),
383 static_cast<uint64_t>(frame_index_));
Khushalb41caaa2017-08-31 02:40:16384 if (subset_rect_.IsEmpty()) {
385 hash_ = original_hash;
386 } else {
387 size_t subset_hash =
388 base::HashInts(static_cast<uint64_t>(
389 base::HashInts(subset_rect_.x(), subset_rect_.y())),
390 static_cast<uint64_t>(base::HashInts(
391 subset_rect_.width(), subset_rect_.height())));
392 hash_ = base::HashInts(original_hash, subset_hash);
393 }
394}
395
396bool PaintImage::FrameKey::operator==(const FrameKey& other) const {
Khushal7ec0d58a2017-09-06 19:51:59397 return content_id_ == other.content_id_ &&
Khushalb41caaa2017-08-31 02:40:16398 frame_index_ == other.frame_index_ &&
399 subset_rect_ == other.subset_rect_;
400}
401
402bool PaintImage::FrameKey::operator!=(const FrameKey& other) const {
403 return !(*this == other);
404}
405
406std::string PaintImage::FrameKey::ToString() const {
407 std::ostringstream str;
Khushal7ec0d58a2017-09-06 19:51:59408 str << "content_id: " << content_id_ << ","
Khushalb41caaa2017-08-31 02:40:16409 << "frame_index: " << frame_index_ << ","
410 << "subset_rect: " << subset_rect_.ToString();
411 return str.str();
412}
413
vmpstr94cfa882017-04-14 01:19:35414} // namespace cc