blob: 5a59453d1afab3d6300866083d584f729b0e44ea [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"
Khushalb41caaa2017-08-31 02:40:1610#include "base/hash.h"
Khushal1b8abc012017-08-10 05:16:1711#include "cc/paint/paint_image_generator.h"
Vladimir Levin4f2c08c2017-07-28 03:03:2812#include "cc/paint/paint_record.h"
Khushal1b8abc012017-08-10 05:16:1713#include "cc/paint/skia_paint_image_generator.h"
Vladimir Levin4f2c08c2017-07-28 03:03:2814#include "ui/gfx/skia_util.h"
vmpstr94cfa882017-04-14 01:19:3515
16namespace cc {
vmpstr81a39a32017-05-16 19:30:2117namespace {
Vladimir Levin5d3f4ab2017-12-12 19:43:3818base::AtomicSequenceNumber g_next_id_;
19base::AtomicSequenceNumber g_next_content_id_;
Khushalb41caaa2017-08-31 02:40:1620} // namespace
vmpstr94cfa882017-04-14 01:19:3521
Khushal512439c2017-10-18 17:36:5322const PaintImage::Id PaintImage::kNonLazyStableId = -1;
Khushalfdacdc92017-09-22 22:40:5223const size_t PaintImage::kDefaultFrameIndex = 0u;
Khushal512439c2017-10-18 17:36:5324const PaintImage::Id PaintImage::kInvalidId = -2;
Khushalfdacdc92017-09-22 22:40:5225
vmpstr55c7657ca2017-04-29 00:46:4826PaintImage::PaintImage() = default;
vmpstr55c7657ca2017-04-29 00:46:4827PaintImage::PaintImage(const PaintImage& other) = default;
28PaintImage::PaintImage(PaintImage&& other) = default;
vmpstr94cfa882017-04-14 01:19:3529PaintImage::~PaintImage() = default;
30
vmpstr55c7657ca2017-04-29 00:46:4831PaintImage& PaintImage::operator=(const PaintImage& other) = default;
32PaintImage& PaintImage::operator=(PaintImage&& other) = default;
33
khushalsagard5e13bf2017-05-17 08:08:5034bool PaintImage::operator==(const PaintImage& other) const {
Adrienne Walker6ac30632017-11-18 01:52:0735 if (sk_image_ != other.sk_image_)
36 return false;
37 if (paint_record_ != other.paint_record_)
38 return false;
39 if (paint_record_rect_ != other.paint_record_rect_)
40 return false;
41 if (paint_record_content_id_ != other.paint_record_content_id_)
42 return false;
43 if (paint_image_generator_ != other.paint_image_generator_)
44 return false;
45 if (id_ != other.id_)
46 return false;
47 if (animation_type_ != other.animation_type_)
48 return false;
49 if (completion_state_ != other.completion_state_)
50 return false;
51 if (subset_rect_ != other.subset_rect_)
52 return false;
53 if (frame_index_ != other.frame_index_)
54 return false;
55 if (is_multipart_ != other.is_multipart_)
56 return false;
57 return true;
vmpstr55c7657ca2017-04-29 00:46:4858}
59
Vladimir Levin9167e1c2017-10-18 21:28:2460// static
61PaintImage::DecodingMode PaintImage::GetConservative(DecodingMode one,
62 DecodingMode two) {
63 if (one == two)
64 return one;
65 if (one == DecodingMode::kSync || two == DecodingMode::kSync)
66 return DecodingMode::kSync;
67 if (one == DecodingMode::kUnspecified || two == DecodingMode::kUnspecified)
68 return DecodingMode::kUnspecified;
69 DCHECK_EQ(one, DecodingMode::kAsync);
70 DCHECK_EQ(two, DecodingMode::kAsync);
71 return DecodingMode::kAsync;
72}
73
74// static
vmpstr81a39a32017-05-16 19:30:2175PaintImage::Id PaintImage::GetNextId() {
Vladimir Levin5d3f4ab2017-12-12 19:43:3876 return g_next_id_.GetNext();
vmpstr81a39a32017-05-16 19:30:2177}
78
Vladimir Levin9167e1c2017-10-18 21:28:2479// static
Khushalb41caaa2017-08-31 02:40:1680PaintImage::ContentId PaintImage::GetNextContentId() {
Vladimir Levin5d3f4ab2017-12-12 19:43:3881 return g_next_content_id_.GetNext();
Khushalb41caaa2017-08-31 02:40:1682}
83
Vladimir Levin4f2c08c2017-07-28 03:03:2884const sk_sp<SkImage>& PaintImage::GetSkImage() const {
Vladimir Levin4f2c08c2017-07-28 03:03:2885 return cached_sk_image_;
86}
87
Khushalb481b282017-08-24 00:06:5388PaintImage PaintImage::MakeSubset(const gfx::Rect& subset) const {
89 DCHECK(!subset.IsEmpty());
90
91 // If the subset is the same as the image bounds, we can return the same
92 // image.
93 gfx::Rect bounds(width(), height());
94 if (bounds == subset)
95 return *this;
96
97 DCHECK(bounds.Contains(subset))
98 << "Subset should not be greater than the image bounds";
99 PaintImage result(*this);
100 result.subset_rect_ = subset;
101 // Store the subset from the original image.
102 result.subset_rect_.Offset(subset_rect_.x(), subset_rect_.y());
103
Khushala866a802017-10-05 18:21:00104 // Creating the |cached_sk_image_| using the SkImage from the original
105 // PaintImage is an optimization to allow re-use of the original decode for
106 // image subsets in skia, for cases that rely on skia's image decode cache.
Khushalb481b282017-08-24 00:06:53107 result.cached_sk_image_ =
108 GetSkImage()->makeSubset(gfx::RectToSkIRect(subset));
109 return result;
110}
111
Khushala866a802017-10-05 18:21:00112void PaintImage::CreateSkImage() {
113 DCHECK(!cached_sk_image_);
114
115 if (sk_image_) {
116 cached_sk_image_ = sk_image_;
117 } else if (paint_record_) {
118 cached_sk_image_ = SkImage::MakeFromPicture(
119 ToSkPicture(paint_record_, gfx::RectToSkRect(paint_record_rect_)),
120 SkISize::Make(paint_record_rect_.width(), paint_record_rect_.height()),
121 nullptr, nullptr, SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
122 } else if (paint_image_generator_) {
123 cached_sk_image_ =
Gyuyoung Kime83664012017-12-02 00:12:49124 SkImage::MakeFromGenerator(std::make_unique<SkiaPaintImageGenerator>(
Khushala866a802017-10-05 18:21:00125 paint_image_generator_, frame_index_));
126 }
127
128 if (!subset_rect_.IsEmpty() && cached_sk_image_) {
129 cached_sk_image_ =
130 cached_sk_image_->makeSubset(gfx::RectToSkIRect(subset_rect_));
131 }
132}
133
Vladimir Levin772dc5f2017-08-25 01:54:29134SkISize PaintImage::GetSupportedDecodeSize(
135 const SkISize& requested_size) const {
Vladimir Levinc9aa97402017-09-07 21:24:57136 // TODO(vmpstr): If this image is using subset_rect, then we don't support
137 // decoding to any scale other than the original. See the comment in Decode()
138 // explaining this in more detail.
139 // TODO(vmpstr): For now, always decode to the original size. This can be
140 // enabled with the following code, and should be done as a follow-up.
141 // if (paint_image_generator_ && subset_rect_.IsEmpty())
142 // return paint_image_generator_->GetSupportedDecodeSize(requested_size);
Vladimir Levin772dc5f2017-08-25 01:54:29143 return SkISize::Make(width(), height());
144}
145
Vladimir Levin772dc5f2017-08-25 01:54:29146bool PaintImage::Decode(void* memory,
147 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52148 sk_sp<SkColorSpace> color_space,
149 size_t frame_index) const {
Vladimir Levinc9aa97402017-09-07 21:24:57150 // We only support decode to supported decode size.
151 DCHECK(info->dimensions() == GetSupportedDecodeSize(info->dimensions()));
152
Eric Karl79c29462018-01-27 07:19:28153 // We don't support SkImageInfo's with color spaces on them. Color spaces
154 // should always be passed via the |color_space| arg.
155 DCHECK(!info->colorSpace());
156
Vladimir Levinc9aa97402017-09-07 21:24:57157 // TODO(vmpstr): If we're using a subset_rect_ then the info specifies the
158 // requested size relative to the subset. However, the generator isn't aware
159 // of this subsetting and would need a size that is relative to the original
160 // image size. We could still implement this case, but we need to convert the
161 // requested size into the space of the original image. For now, fallback to
162 // DecodeFromSkImage().
163 if (paint_image_generator_ && subset_rect_.IsEmpty())
Khushalfdacdc92017-09-22 22:40:52164 return DecodeFromGenerator(memory, info, std::move(color_space),
165 frame_index);
166 return DecodeFromSkImage(memory, info, std::move(color_space), frame_index);
Vladimir Levinc9aa97402017-09-07 21:24:57167}
168
169bool PaintImage::DecodeFromGenerator(void* memory,
170 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52171 sk_sp<SkColorSpace> color_space,
172 size_t frame_index) const {
Vladimir Levinc9aa97402017-09-07 21:24:57173 DCHECK(subset_rect_.IsEmpty());
174
175 // First convert the info to have the requested color space, since the decoder
176 // will convert this for us.
177 *info = info->makeColorSpace(std::move(color_space));
178 if (info->colorType() != kN32_SkColorType) {
179 // Since the decoders only support N32 color types, make one of those and
180 // decode into temporary memory. Then read the bitmap which will convert it
181 // to the target color type.
182 SkImageInfo n32info = info->makeColorType(kN32_SkColorType);
183 std::unique_ptr<char[]> n32memory(
184 new char[n32info.minRowBytes() * n32info.height()]);
185
186 bool result = paint_image_generator_->GetPixels(n32info, n32memory.get(),
187 n32info.minRowBytes(),
Khushalfdacdc92017-09-22 22:40:52188 frame_index, unique_id());
Vladimir Levinc9aa97402017-09-07 21:24:57189 if (!result)
190 return false;
191
192 // The following block will use Skia to do the color type conversion from
193 // N32 to the destination color type. Since color space conversion was
194 // already done in GetPixels() above, remove the color space information
195 // first in case Skia tries to use it for something. In practice, n32info
196 // and *info color spaces match, so it should work without removing the
197 // color spaces, but better be safe.
198 SkImageInfo n32info_no_colorspace = n32info.makeColorSpace(nullptr);
199 SkImageInfo info_no_colorspace = info->makeColorSpace(nullptr);
200
201 SkBitmap bitmap;
202 bitmap.installPixels(n32info_no_colorspace, n32memory.get(),
203 n32info.minRowBytes());
204 return bitmap.readPixels(info_no_colorspace, memory, info->minRowBytes(), 0,
205 0);
206 }
207
208 return paint_image_generator_->GetPixels(*info, memory, info->minRowBytes(),
Khushalfdacdc92017-09-22 22:40:52209 frame_index, unique_id());
Vladimir Levinc9aa97402017-09-07 21:24:57210}
211
212bool PaintImage::DecodeFromSkImage(void* memory,
213 SkImageInfo* info,
Khushalfdacdc92017-09-22 22:40:52214 sk_sp<SkColorSpace> color_space,
215 size_t frame_index) const {
216 auto image = GetSkImageForFrame(frame_index);
Vladimir Levin772dc5f2017-08-25 01:54:29217 DCHECK(image);
218 if (color_space) {
219 image =
220 image->makeColorSpace(color_space, SkTransferFunctionBehavior::kIgnore);
221 if (!image)
222 return false;
223 }
224 // Note that the readPixels has to happen before converting the info to the
225 // given color space, since it can produce incorrect results.
226 bool result = image->readPixels(*info, memory, info->minRowBytes(), 0, 0,
227 SkImage::kDisallow_CachingHint);
Vladimir Levinc9aa97402017-09-07 21:24:57228 *info = info->makeColorSpace(std::move(color_space));
Vladimir Levin772dc5f2017-08-25 01:54:29229 return result;
230}
231
Khushalb42fb24d2017-09-14 19:15:15232bool PaintImage::ShouldAnimate() const {
233 return animation_type_ == AnimationType::ANIMATED &&
Khushalfdacdc92017-09-22 22:40:52234 repetition_count_ != kAnimationNone && FrameCount() > 1;
Khushalb42fb24d2017-09-14 19:15:15235}
236
Khushalb41caaa2017-08-31 02:40:16237PaintImage::FrameKey PaintImage::GetKeyForFrame(size_t frame_index) const {
238 DCHECK_LT(frame_index, FrameCount());
239 DCHECK(paint_image_generator_ || paint_record_);
240
241 // Query the content id that uniquely identifies the content for this frame
242 // from the content provider.
243 ContentId content_id = kInvalidContentId;
244 if (paint_image_generator_)
245 content_id = paint_image_generator_->GetContentIdForFrame(frame_index);
246 else
247 content_id = paint_record_content_id_;
248
249 DCHECK_NE(content_id, kInvalidContentId);
Khushal7ec0d58a2017-09-06 19:51:59250 return FrameKey(content_id, frame_index, subset_rect_);
Khushalb41caaa2017-08-31 02:40:16251}
252
253const std::vector<FrameMetadata>& PaintImage::GetFrameMetadata() const {
254 DCHECK_EQ(animation_type_, AnimationType::ANIMATED);
255 DCHECK(paint_image_generator_);
256
257 return paint_image_generator_->GetFrameMetadata();
258}
259
260size_t PaintImage::FrameCount() const {
261 if (!GetSkImage())
262 return 0u;
263 return paint_image_generator_
264 ? paint_image_generator_->GetFrameMetadata().size()
265 : 1u;
266}
267
Khushalfdacdc92017-09-22 22:40:52268sk_sp<SkImage> PaintImage::GetSkImageForFrame(size_t index) const {
269 DCHECK_LT(index, FrameCount());
270
271 if (index == frame_index_)
272 return GetSkImage();
273
274 sk_sp<SkImage> image = SkImage::MakeFromGenerator(
Gyuyoung Kime83664012017-12-02 00:12:49275 std::make_unique<SkiaPaintImageGenerator>(paint_image_generator_, index));
Khushalfdacdc92017-09-22 22:40:52276 if (!subset_rect_.IsEmpty())
277 image = image->makeSubset(gfx::RectToSkIRect(subset_rect_));
278 return image;
279}
280
Khushalb41caaa2017-08-31 02:40:16281std::string PaintImage::ToString() const {
282 std::ostringstream str;
283 str << "sk_image_: " << sk_image_ << " paint_record_: " << paint_record_
284 << " paint_record_rect_: " << paint_record_rect_.ToString()
285 << " paint_image_generator_: " << paint_image_generator_
286 << " id_: " << id_
287 << " animation_type_: " << static_cast<int>(animation_type_)
288 << " completion_state_: " << static_cast<int>(completion_state_)
289 << " subset_rect_: " << subset_rect_.ToString()
290 << " frame_index_: " << frame_index_
Khushal653954392017-09-25 22:20:06291 << " is_multipart_: " << is_multipart_;
Khushalb41caaa2017-08-31 02:40:16292 return str.str();
293}
294
Khushal7ec0d58a2017-09-06 19:51:59295PaintImage::FrameKey::FrameKey(ContentId content_id,
Khushalb41caaa2017-08-31 02:40:16296 size_t frame_index,
297 gfx::Rect subset_rect)
Khushal7ec0d58a2017-09-06 19:51:59298 : content_id_(content_id),
Khushalb41caaa2017-08-31 02:40:16299 frame_index_(frame_index),
300 subset_rect_(subset_rect) {
Khushal7ec0d58a2017-09-06 19:51:59301 size_t original_hash = base::HashInts(static_cast<uint64_t>(content_id_),
302 static_cast<uint64_t>(frame_index_));
Khushalb41caaa2017-08-31 02:40:16303 if (subset_rect_.IsEmpty()) {
304 hash_ = original_hash;
305 } else {
306 size_t subset_hash =
307 base::HashInts(static_cast<uint64_t>(
308 base::HashInts(subset_rect_.x(), subset_rect_.y())),
309 static_cast<uint64_t>(base::HashInts(
310 subset_rect_.width(), subset_rect_.height())));
311 hash_ = base::HashInts(original_hash, subset_hash);
312 }
313}
314
315bool PaintImage::FrameKey::operator==(const FrameKey& other) const {
Khushal7ec0d58a2017-09-06 19:51:59316 return content_id_ == other.content_id_ &&
Khushalb41caaa2017-08-31 02:40:16317 frame_index_ == other.frame_index_ &&
318 subset_rect_ == other.subset_rect_;
319}
320
321bool PaintImage::FrameKey::operator!=(const FrameKey& other) const {
322 return !(*this == other);
323}
324
325std::string PaintImage::FrameKey::ToString() const {
326 std::ostringstream str;
Khushal7ec0d58a2017-09-06 19:51:59327 str << "content_id: " << content_id_ << ","
Khushalb41caaa2017-08-31 02:40:16328 << "frame_index: " << frame_index_ << ","
329 << "subset_rect: " << subset_rect_.ToString();
330 return str.str();
331}
332
vmpstr94cfa882017-04-14 01:19:35333} // namespace cc