blob: f57bd2c871c3249fa4e766063d281d13416b1031 [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
vmpstr81a39a32017-05-16 19:30:217#include "base/atomic_sequence_num.h"
Khushalb41caaa2017-08-31 02:40:168#include "base/hash.h"
Khushal1b8abc012017-08-10 05:16:179#include "base/memory/ptr_util.h"
10#include "cc/paint/paint_image_generator.h"
Vladimir Levin4f2c08c2017-07-28 03:03:2811#include "cc/paint/paint_record.h"
Khushal1b8abc012017-08-10 05:16:1712#include "cc/paint/skia_paint_image_generator.h"
Vladimir Levin4f2c08c2017-07-28 03:03:2813#include "ui/gfx/skia_util.h"
vmpstr94cfa882017-04-14 01:19:3514
15namespace cc {
vmpstr81a39a32017-05-16 19:30:2116namespace {
tzik455b325fa2017-07-20 03:24:5717base::AtomicSequenceNumber s_next_id_;
Khushalb41caaa2017-08-31 02:40:1618base::AtomicSequenceNumber s_next_content_id_;
19} // namespace
vmpstr94cfa882017-04-14 01:19:3520
Khushal512439c2017-10-18 17:36:5321const PaintImage::Id PaintImage::kNonLazyStableId = -1;
Khushalfdacdc92017-09-22 22:40:5222const size_t PaintImage::kDefaultFrameIndex = 0u;
Khushal512439c2017-10-18 17:36:5323const PaintImage::Id PaintImage::kInvalidId = -2;
Khushalfdacdc92017-09-22 22:40:5224
vmpstr55c7657ca2017-04-29 00:46:4825PaintImage::PaintImage() = default;
vmpstr55c7657ca2017-04-29 00:46:4826PaintImage::PaintImage(const PaintImage& other) = default;
27PaintImage::PaintImage(PaintImage&& other) = default;
vmpstr94cfa882017-04-14 01:19:3528PaintImage::~PaintImage() = default;
29
vmpstr55c7657ca2017-04-29 00:46:4830PaintImage& PaintImage::operator=(const PaintImage& other) = default;
31PaintImage& PaintImage::operator=(PaintImage&& other) = default;
32
khushalsagard5e13bf2017-05-17 08:08:5033bool PaintImage::operator==(const PaintImage& other) const {
Khushalb481b282017-08-24 00:06:5334 return sk_image_ == other.sk_image_ && paint_record_ == other.paint_record_ &&
35 paint_record_rect_ == other.paint_record_rect_ &&
Khushalb41caaa2017-08-31 02:40:1636 paint_record_content_id_ == other.paint_record_content_id_ &&
Khushalb481b282017-08-24 00:06:5337 paint_image_generator_ == other.paint_image_generator_ &&
38 id_ == other.id_ && animation_type_ == other.animation_type_ &&
vmpstr05729e72017-06-06 03:07:1839 completion_state_ == other.completion_state_ &&
Khushalb481b282017-08-24 00:06:5340 subset_rect_ == other.subset_rect_ &&
Khushalb41caaa2017-08-31 02:40:1641 frame_index_ == other.frame_index_ &&
Khushal653954392017-09-25 22:20:0642 is_multipart_ == other.is_multipart_;
vmpstr55c7657ca2017-04-29 00:46:4843}
44
Vladimir Levin9167e1c2017-10-18 21:28:2445// static
46PaintImage::DecodingMode PaintImage::GetConservative(DecodingMode one,
47 DecodingMode two) {
48 if (one == two)
49 return one;
50 if (one == DecodingMode::kSync || two == DecodingMode::kSync)
51 return DecodingMode::kSync;
52 if (one == DecodingMode::kUnspecified || two == DecodingMode::kUnspecified)
53 return DecodingMode::kUnspecified;
54 DCHECK_EQ(one, DecodingMode::kAsync);
55 DCHECK_EQ(two, DecodingMode::kAsync);
56 return DecodingMode::kAsync;
57}
58
59// static
vmpstr81a39a32017-05-16 19:30:2160PaintImage::Id PaintImage::GetNextId() {
61 return s_next_id_.GetNext();
62}
63
Vladimir Levin9167e1c2017-10-18 21:28:2464// static
Khushalb41caaa2017-08-31 02:40:1665PaintImage::ContentId PaintImage::GetNextContentId() {
66 return s_next_content_id_.GetNext();
67}
68
Vladimir Levin4f2c08c2017-07-28 03:03:2869const sk_sp<SkImage>& PaintImage::GetSkImage() const {
Vladimir Levin4f2c08c2017-07-28 03:03:2870 return cached_sk_image_;
71}
72
Khushalb481b282017-08-24 00:06:5373PaintImage PaintImage::MakeSubset(const gfx::Rect& subset) const {
74 DCHECK(!subset.IsEmpty());
75
76 // If the subset is the same as the image bounds, we can return the same
77 // image.
78 gfx::Rect bounds(width(), height());
79 if (bounds == subset)
80 return *this;
81
82 DCHECK(bounds.Contains(subset))
83 << "Subset should not be greater than the image bounds";
84 PaintImage result(*this);
85 result.subset_rect_ = subset;
86 // Store the subset from the original image.
87 result.subset_rect_.Offset(subset_rect_.x(), subset_rect_.y());
88
Khushala866a802017-10-05 18:21:0089 // Creating the |cached_sk_image_| using the SkImage from the original
90 // PaintImage is an optimization to allow re-use of the original decode for
91 // image subsets in skia, for cases that rely on skia's image decode cache.
Khushalb481b282017-08-24 00:06:5392 result.cached_sk_image_ =
93 GetSkImage()->makeSubset(gfx::RectToSkIRect(subset));
94 return result;
95}
96
Khushala866a802017-10-05 18:21:0097void PaintImage::CreateSkImage() {
98 DCHECK(!cached_sk_image_);
99
100 if (sk_image_) {
101 cached_sk_image_ = sk_image_;
102 } else if (paint_record_) {
103 cached_sk_image_ = SkImage::MakeFromPicture(
104 ToSkPicture(paint_record_, gfx::RectToSkRect(paint_record_rect_)),
105 SkISize::Make(paint_record_rect_.width(), paint_record_rect_.height()),
106 nullptr, nullptr, SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
107 } else if (paint_image_generator_) {
108 cached_sk_image_ =
109 SkImage::MakeFromGenerator(base::MakeUnique<SkiaPaintImageGenerator>(
110 paint_image_generator_, frame_index_));
111 }
112
113 if (!subset_rect_.IsEmpty() && cached_sk_image_) {
114 cached_sk_image_ =
115 cached_sk_image_->makeSubset(gfx::RectToSkIRect(subset_rect_));
116 }
117}
118
Vladimir Levin772dc5f2017-08-25 01:54:29119SkISize PaintImage::GetSupportedDecodeSize(
120 const SkISize& requested_size) const {
Vladimir Levinc9aa97402017-09-07 21:24:57121 // TODO(vmpstr): If this image is using subset_rect, then we don't support
122 // decoding to any scale other than the original. See the comment in Decode()
123 // explaining this in more detail.
124 // TODO(vmpstr): For now, always decode to the original size. This can be
125 // enabled with the following code, and should be done as a follow-up.
126 // if (paint_image_generator_ && subset_rect_.IsEmpty())
127 // return paint_image_generator_->GetSupportedDecodeSize(requested_size);
Vladimir Levin772dc5f2017-08-25 01:54:29128 return SkISize::Make(width(), height());
129}
130
131SkImageInfo PaintImage::CreateDecodeImageInfo(const SkISize& size,
132 SkColorType color_type) const {
133 DCHECK(GetSupportedDecodeSize(size) == size);
134 return SkImageInfo::Make(size.width(), size.height(), color_type,
135 kPremul_SkAlphaType);
136}
137
138bool PaintImage::Decode(void* memory,
139 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52140 sk_sp<SkColorSpace> color_space,
141 size_t frame_index) const {
Vladimir Levinc9aa97402017-09-07 21:24:57142 // We only support decode to supported decode size.
143 DCHECK(info->dimensions() == GetSupportedDecodeSize(info->dimensions()));
144
145 // TODO(vmpstr): If we're using a subset_rect_ then the info specifies the
146 // requested size relative to the subset. However, the generator isn't aware
147 // of this subsetting and would need a size that is relative to the original
148 // image size. We could still implement this case, but we need to convert the
149 // requested size into the space of the original image. For now, fallback to
150 // DecodeFromSkImage().
151 if (paint_image_generator_ && subset_rect_.IsEmpty())
Khushalfdacdc92017-09-22 22:40:52152 return DecodeFromGenerator(memory, info, std::move(color_space),
153 frame_index);
154 return DecodeFromSkImage(memory, info, std::move(color_space), frame_index);
Vladimir Levinc9aa97402017-09-07 21:24:57155}
156
157bool PaintImage::DecodeFromGenerator(void* memory,
158 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52159 sk_sp<SkColorSpace> color_space,
160 size_t frame_index) const {
Vladimir Levinc9aa97402017-09-07 21:24:57161 DCHECK(subset_rect_.IsEmpty());
162
163 // First convert the info to have the requested color space, since the decoder
164 // will convert this for us.
165 *info = info->makeColorSpace(std::move(color_space));
166 if (info->colorType() != kN32_SkColorType) {
167 // Since the decoders only support N32 color types, make one of those and
168 // decode into temporary memory. Then read the bitmap which will convert it
169 // to the target color type.
170 SkImageInfo n32info = info->makeColorType(kN32_SkColorType);
171 std::unique_ptr<char[]> n32memory(
172 new char[n32info.minRowBytes() * n32info.height()]);
173
174 bool result = paint_image_generator_->GetPixels(n32info, n32memory.get(),
175 n32info.minRowBytes(),
Khushalfdacdc92017-09-22 22:40:52176 frame_index, unique_id());
Vladimir Levinc9aa97402017-09-07 21:24:57177 if (!result)
178 return false;
179
180 // The following block will use Skia to do the color type conversion from
181 // N32 to the destination color type. Since color space conversion was
182 // already done in GetPixels() above, remove the color space information
183 // first in case Skia tries to use it for something. In practice, n32info
184 // and *info color spaces match, so it should work without removing the
185 // color spaces, but better be safe.
186 SkImageInfo n32info_no_colorspace = n32info.makeColorSpace(nullptr);
187 SkImageInfo info_no_colorspace = info->makeColorSpace(nullptr);
188
189 SkBitmap bitmap;
190 bitmap.installPixels(n32info_no_colorspace, n32memory.get(),
191 n32info.minRowBytes());
192 return bitmap.readPixels(info_no_colorspace, memory, info->minRowBytes(), 0,
193 0);
194 }
195
196 return paint_image_generator_->GetPixels(*info, memory, info->minRowBytes(),
Khushalfdacdc92017-09-22 22:40:52197 frame_index, unique_id());
Vladimir Levinc9aa97402017-09-07 21:24:57198}
199
200bool PaintImage::DecodeFromSkImage(void* memory,
201 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52202 sk_sp<SkColorSpace> color_space,
203 size_t frame_index) const {
204 auto image = GetSkImageForFrame(frame_index);
Vladimir Levin772dc5f2017-08-25 01:54:29205 DCHECK(image);
206 if (color_space) {
207 image =
208 image->makeColorSpace(color_space, SkTransferFunctionBehavior::kIgnore);
209 if (!image)
210 return false;
211 }
212 // Note that the readPixels has to happen before converting the info to the
213 // given color space, since it can produce incorrect results.
214 bool result = image->readPixels(*info, memory, info->minRowBytes(), 0, 0,
215 SkImage::kDisallow_CachingHint);
Vladimir Levinc9aa97402017-09-07 21:24:57216 *info = info->makeColorSpace(std::move(color_space));
Vladimir Levin772dc5f2017-08-25 01:54:29217 return result;
218}
219
Khushalb42fb24d2017-09-14 19:15:15220bool PaintImage::ShouldAnimate() const {
221 return animation_type_ == AnimationType::ANIMATED &&
Khushalfdacdc92017-09-22 22:40:52222 repetition_count_ != kAnimationNone && FrameCount() > 1;
Khushalb42fb24d2017-09-14 19:15:15223}
224
Khushalb41caaa2017-08-31 02:40:16225PaintImage::FrameKey PaintImage::GetKeyForFrame(size_t frame_index) const {
226 DCHECK_LT(frame_index, FrameCount());
227 DCHECK(paint_image_generator_ || paint_record_);
228
229 // Query the content id that uniquely identifies the content for this frame
230 // from the content provider.
231 ContentId content_id = kInvalidContentId;
232 if (paint_image_generator_)
233 content_id = paint_image_generator_->GetContentIdForFrame(frame_index);
234 else
235 content_id = paint_record_content_id_;
236
237 DCHECK_NE(content_id, kInvalidContentId);
Khushal7ec0d58a2017-09-06 19:51:59238 return FrameKey(content_id, frame_index, subset_rect_);
Khushalb41caaa2017-08-31 02:40:16239}
240
241const std::vector<FrameMetadata>& PaintImage::GetFrameMetadata() const {
242 DCHECK_EQ(animation_type_, AnimationType::ANIMATED);
243 DCHECK(paint_image_generator_);
244
245 return paint_image_generator_->GetFrameMetadata();
246}
247
248size_t PaintImage::FrameCount() const {
249 if (!GetSkImage())
250 return 0u;
251 return paint_image_generator_
252 ? paint_image_generator_->GetFrameMetadata().size()
253 : 1u;
254}
255
Khushalfdacdc92017-09-22 22:40:52256sk_sp<SkImage> PaintImage::GetSkImageForFrame(size_t index) const {
257 DCHECK_LT(index, FrameCount());
258
259 if (index == frame_index_)
260 return GetSkImage();
261
262 sk_sp<SkImage> image = SkImage::MakeFromGenerator(
263 base::MakeUnique<SkiaPaintImageGenerator>(paint_image_generator_, index));
264 if (!subset_rect_.IsEmpty())
265 image = image->makeSubset(gfx::RectToSkIRect(subset_rect_));
266 return image;
267}
268
Khushalb41caaa2017-08-31 02:40:16269std::string PaintImage::ToString() const {
270 std::ostringstream str;
271 str << "sk_image_: " << sk_image_ << " paint_record_: " << paint_record_
272 << " paint_record_rect_: " << paint_record_rect_.ToString()
273 << " paint_image_generator_: " << paint_image_generator_
274 << " id_: " << id_
275 << " animation_type_: " << static_cast<int>(animation_type_)
276 << " completion_state_: " << static_cast<int>(completion_state_)
277 << " subset_rect_: " << subset_rect_.ToString()
278 << " frame_index_: " << frame_index_
Khushal653954392017-09-25 22:20:06279 << " is_multipart_: " << is_multipart_;
Khushalb41caaa2017-08-31 02:40:16280 return str.str();
281}
282
Khushal7ec0d58a2017-09-06 19:51:59283PaintImage::FrameKey::FrameKey(ContentId content_id,
Khushalb41caaa2017-08-31 02:40:16284 size_t frame_index,
285 gfx::Rect subset_rect)
Khushal7ec0d58a2017-09-06 19:51:59286 : content_id_(content_id),
Khushalb41caaa2017-08-31 02:40:16287 frame_index_(frame_index),
288 subset_rect_(subset_rect) {
Khushal7ec0d58a2017-09-06 19:51:59289 size_t original_hash = base::HashInts(static_cast<uint64_t>(content_id_),
290 static_cast<uint64_t>(frame_index_));
Khushalb41caaa2017-08-31 02:40:16291 if (subset_rect_.IsEmpty()) {
292 hash_ = original_hash;
293 } else {
294 size_t subset_hash =
295 base::HashInts(static_cast<uint64_t>(
296 base::HashInts(subset_rect_.x(), subset_rect_.y())),
297 static_cast<uint64_t>(base::HashInts(
298 subset_rect_.width(), subset_rect_.height())));
299 hash_ = base::HashInts(original_hash, subset_hash);
300 }
301}
302
303bool PaintImage::FrameKey::operator==(const FrameKey& other) const {
Khushal7ec0d58a2017-09-06 19:51:59304 return content_id_ == other.content_id_ &&
Khushalb41caaa2017-08-31 02:40:16305 frame_index_ == other.frame_index_ &&
306 subset_rect_ == other.subset_rect_;
307}
308
309bool PaintImage::FrameKey::operator!=(const FrameKey& other) const {
310 return !(*this == other);
311}
312
313std::string PaintImage::FrameKey::ToString() const {
314 std::ostringstream str;
Khushal7ec0d58a2017-09-06 19:51:59315 str << "content_id: " << content_id_ << ","
Khushalb41caaa2017-08-31 02:40:16316 << "frame_index: " << frame_index_ << ","
317 << "subset_rect: " << subset_rect_.ToString();
318 return str.str();
319}
320
vmpstr94cfa882017-04-14 01:19:35321} // namespace cc