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 *
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 AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "third_party/blink/renderer/platform/graphics/decoding_image_generator.h"
27
28 #include <memory>
29 #include <utility>
30
31 #include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
32 #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
33 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
34 #include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
35 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
36 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
37 #include "third_party/skia/include/core/SkData.h"
38 #include "third_party/skia/include/core/SkImageInfo.h"
39
40 namespace blink {
41
42 // static
43 std::unique_ptr<SkImageGenerator>
CreateAsSkImageGenerator(sk_sp<SkData> data)44 DecodingImageGenerator::CreateAsSkImageGenerator(sk_sp<SkData> data) {
45 scoped_refptr<SegmentReader> segment_reader =
46 SegmentReader::CreateFromSkData(std::move(data));
47 // We just need the size of the image, so we have to temporarily create an
48 // ImageDecoder. Since we only need the size, the premul, high bit depth and
49 // gamma settings don't really matter.
50 const bool data_complete = true;
51 std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create(
52 segment_reader, data_complete, ImageDecoder::kAlphaPremultiplied,
53 ImageDecoder::kDefaultBitDepth, ColorBehavior::Ignore());
54 if (!decoder || !decoder->IsSizeAvailable())
55 return nullptr;
56
57 const IntSize size = decoder->Size();
58 const SkImageInfo info =
59 SkImageInfo::MakeN32(size.Width(), size.Height(), kPremul_SkAlphaType,
60 decoder->ColorSpaceForSkImages());
61
62 scoped_refptr<ImageFrameGenerator> frame = ImageFrameGenerator::Create(
63 SkISize::Make(size.Width(), size.Height()), false,
64 decoder->GetColorBehavior(), decoder->GetSupportedDecodeSizes());
65 if (!frame)
66 return nullptr;
67
68 WebVector<FrameMetadata> frames;
69 frames.emplace_back(FrameMetadata());
70 cc::ImageHeaderMetadata image_metadata =
71 decoder->MakeMetadataForDecodeAcceleration();
72 image_metadata.all_data_received_prior_to_decode = true;
73 sk_sp<DecodingImageGenerator> generator = DecodingImageGenerator::Create(
74 std::move(frame), info, std::move(segment_reader), std::move(frames),
75 PaintImage::GetNextContentId(), true /* all_data_received */,
76 false /* can_yuv_decode */, image_metadata);
77 return std::make_unique<SkiaPaintImageGenerator>(
78 std::move(generator), PaintImage::kDefaultFrameIndex,
79 PaintImage::kDefaultGeneratorClientId);
80 }
81
82 // static
Create(scoped_refptr<ImageFrameGenerator> frame_generator,const SkImageInfo & info,scoped_refptr<SegmentReader> data,WebVector<FrameMetadata> frames,PaintImage::ContentId content_id,bool all_data_received,bool can_yuv_decode,const cc::ImageHeaderMetadata & image_metadata)83 sk_sp<DecodingImageGenerator> DecodingImageGenerator::Create(
84 scoped_refptr<ImageFrameGenerator> frame_generator,
85 const SkImageInfo& info,
86 scoped_refptr<SegmentReader> data,
87 WebVector<FrameMetadata> frames,
88 PaintImage::ContentId content_id,
89 bool all_data_received,
90 bool can_yuv_decode,
91 const cc::ImageHeaderMetadata& image_metadata) {
92 return sk_sp<DecodingImageGenerator>(new DecodingImageGenerator(
93 std::move(frame_generator), info, std::move(data), std::move(frames),
94 content_id, all_data_received, can_yuv_decode, image_metadata));
95 }
96
DecodingImageGenerator(scoped_refptr<ImageFrameGenerator> frame_generator,const SkImageInfo & info,scoped_refptr<SegmentReader> data,WebVector<FrameMetadata> frames,PaintImage::ContentId complete_frame_content_id,bool all_data_received,bool can_yuv_decode,const cc::ImageHeaderMetadata & image_metadata)97 DecodingImageGenerator::DecodingImageGenerator(
98 scoped_refptr<ImageFrameGenerator> frame_generator,
99 const SkImageInfo& info,
100 scoped_refptr<SegmentReader> data,
101 WebVector<FrameMetadata> frames,
102 PaintImage::ContentId complete_frame_content_id,
103 bool all_data_received,
104 bool can_yuv_decode,
105 const cc::ImageHeaderMetadata& image_metadata)
106 : PaintImageGenerator(info, frames.ReleaseVector()),
107 frame_generator_(std::move(frame_generator)),
108 data_(std::move(data)),
109 all_data_received_(all_data_received),
110 can_yuv_decode_(can_yuv_decode),
111 complete_frame_content_id_(complete_frame_content_id),
112 image_metadata_(image_metadata) {}
113
114 DecodingImageGenerator::~DecodingImageGenerator() = default;
115
GetEncodedData() const116 sk_sp<SkData> DecodingImageGenerator::GetEncodedData() const {
117 TRACE_EVENT0("blink", "DecodingImageGenerator::refEncodedData");
118
119 // getAsSkData() may require copying, but the clients of this function are
120 // serializers, which want the data even if it requires copying, and even
121 // if the data is incomplete. (Otherwise they would potentially need to
122 // decode the partial image in order to re-encode it.)
123 return data_->GetAsSkData();
124 }
125
GetPixels(const SkImageInfo & dst_info,void * pixels,size_t row_bytes,size_t frame_index,PaintImage::GeneratorClientId client_id,uint32_t lazy_pixel_ref)126 bool DecodingImageGenerator::GetPixels(const SkImageInfo& dst_info,
127 void* pixels,
128 size_t row_bytes,
129 size_t frame_index,
130 PaintImage::GeneratorClientId client_id,
131 uint32_t lazy_pixel_ref) {
132 TRACE_EVENT2("blink", "DecodingImageGenerator::getPixels", "frame index",
133 static_cast<int>(frame_index), "client_id", client_id);
134
135 // Implementation only supports decoding to a supported size.
136 if (dst_info.dimensions() != GetSupportedDecodeSize(dst_info.dimensions())) {
137 return false;
138 }
139
140 // Color type can be N32 or F16. Otherwise, decode to N32 and convert to
141 // the requested color type from N32.
142 SkImageInfo target_info = dst_info;
143 char* memory = static_cast<char*>(pixels);
144 std::unique_ptr<char[]> memory_ref_ptr;
145 size_t adjusted_row_bytes = row_bytes;
146 if ((target_info.colorType() != kN32_SkColorType) &&
147 (target_info.colorType() != kRGBA_F16_SkColorType)) {
148 target_info = target_info.makeColorType(kN32_SkColorType);
149 // row_bytes is the size of scanline, so it should be >= info.minRowBytes().
150 DCHECK(row_bytes >= dst_info.minRowBytes());
151 // row_bytes must be a multiple of dst_info.bytesPerPixel().
152 DCHECK_EQ(0ul, row_bytes % dst_info.bytesPerPixel());
153 adjusted_row_bytes =
154 target_info.bytesPerPixel() * (row_bytes / dst_info.bytesPerPixel());
155 memory_ref_ptr.reset(new char[target_info.computeMinByteSize()]);
156 memory = memory_ref_ptr.get();
157 }
158
159 // Skip the check for alphaType. blink::ImageFrame may have changed the
160 // owning SkBitmap to kOpaque_SkAlphaType after fully decoding the image
161 // frame, so if we see a request for opaque, that is ok even if our initial
162 // alpha type was not opaque.
163
164 // Pass decodeColorSpace to the decoder. That is what we can expect the
165 // output to be.
166 sk_sp<SkColorSpace> decode_color_space = GetSkImageInfo().refColorSpace();
167 SkImageInfo decode_info = target_info.makeColorSpace(decode_color_space);
168
169 const bool needs_color_xform = !ApproximatelyEqualSkColorSpaces(
170 decode_color_space, target_info.refColorSpace());
171 ImageDecoder::AlphaOption alpha_option = ImageDecoder::kAlphaPremultiplied;
172 if (needs_color_xform && !decode_info.isOpaque()) {
173 alpha_option = ImageDecoder::kAlphaNotPremultiplied;
174 decode_info = decode_info.makeAlphaType(kUnpremul_SkAlphaType);
175 }
176
177 bool decoded = false;
178 {
179 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
180 "Decode LazyPixelRef", "LazyPixelRef", lazy_pixel_ref);
181 decoded = frame_generator_->DecodeAndScale(
182 data_.get(), all_data_received_, frame_index, decode_info, memory,
183 adjusted_row_bytes, alpha_option, client_id);
184 }
185
186 if (decoded && needs_color_xform) {
187 TRACE_EVENT0("blink", "DecodingImageGenerator::getPixels - apply xform");
188 SkPixmap src(decode_info, memory, adjusted_row_bytes);
189 decoded = src.readPixels(target_info, memory, adjusted_row_bytes);
190 DCHECK(decoded);
191 }
192
193 // Convert the color type to the requested one if necessary
194 if (decoded && target_info.colorType() != dst_info.colorType()) {
195 // Convert the color type by readPixels if dithering is not necessary
196 // (readPixels is potentially cheaper than a full-blown drawBitmap).
197 if (SkColorTypeBytesPerPixel(target_info.colorType()) <=
198 SkColorTypeBytesPerPixel(dst_info.colorType())) {
199 decoded = SkPixmap{target_info, memory, adjusted_row_bytes}.readPixels(
200 SkPixmap{dst_info, pixels, row_bytes});
201 DCHECK(decoded);
202 } else { // Do dithering by drawBitmap() if dithering is necessary
203 auto canvas = SkCanvas::MakeRasterDirect(dst_info, pixels, row_bytes);
204 DCHECK(canvas);
205
206 SkPaint paint;
207 paint.setDither(true);
208 paint.setBlendMode(SkBlendMode::kSrc);
209
210 SkBitmap bitmap;
211 decoded = bitmap.installPixels(target_info, memory, adjusted_row_bytes);
212 DCHECK(decoded);
213
214 canvas->drawBitmap(bitmap, 0, 0, &paint);
215 }
216 }
217 return decoded;
218 }
219
QueryYUVA8(SkYUVASizeInfo * size_info,SkYUVAIndex indices[SkYUVAIndex::kIndexCount],SkYUVColorSpace * color_space) const220 bool DecodingImageGenerator::QueryYUVA8(
221 SkYUVASizeInfo* size_info,
222 SkYUVAIndex indices[SkYUVAIndex::kIndexCount],
223 SkYUVColorSpace* color_space) const {
224 if (!can_yuv_decode_)
225 return false;
226
227 TRACE_EVENT0("blink", "DecodingImageGenerator::queryYUVA8");
228
229 // Indicate that we have three separate planes
230 indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
231 indices[SkYUVAIndex::kU_Index] = {1, SkColorChannel::kR};
232 indices[SkYUVAIndex::kV_Index] = {2, SkColorChannel::kR};
233 indices[SkYUVAIndex::kA_Index] = {-1, SkColorChannel::kR};
234
235 DCHECK(all_data_received_);
236 return frame_generator_->GetYUVComponentSizes(data_.get(), size_info,
237 color_space);
238 }
239
GetYUVA8Planes(const SkYUVASizeInfo & size_info,const SkYUVAIndex indices[4],void * planes[3],size_t frame_index,uint32_t lazy_pixel_ref)240 bool DecodingImageGenerator::GetYUVA8Planes(const SkYUVASizeInfo& size_info,
241 const SkYUVAIndex indices[4],
242 void* planes[3],
243 size_t frame_index,
244 uint32_t lazy_pixel_ref) {
245 // TODO(crbug.com/943519): YUV decoding does not currently support incremental
246 // decoding. See comment in image_frame_generator.h.
247 DCHECK(can_yuv_decode_);
248 DCHECK(all_data_received_);
249
250 TRACE_EVENT0("blink", "DecodingImageGenerator::getYUVA8Planes");
251 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
252 "Decode LazyPixelRef", "LazyPixelRef", lazy_pixel_ref);
253
254 // Verify sizes and indices
255 for (int i = 0; i < 3; ++i) {
256 if (size_info.fSizes[i].isEmpty() || !size_info.fWidthBytes[i]) {
257 return false;
258 }
259 }
260 if (!size_info.fSizes[3].isEmpty() || size_info.fWidthBytes[3]) {
261 return false;
262 }
263 int numPlanes;
264 if (!SkYUVAIndex::AreValidIndices(indices, &numPlanes) || numPlanes != 3) {
265 return false;
266 }
267
268 bool decoded =
269 frame_generator_->DecodeToYUV(data_.get(), frame_index, size_info.fSizes,
270 planes, size_info.fWidthBytes);
271 return decoded;
272 }
273
GetSupportedDecodeSize(const SkISize & requested_size) const274 SkISize DecodingImageGenerator::GetSupportedDecodeSize(
275 const SkISize& requested_size) const {
276 return frame_generator_->GetSupportedDecodeSize(requested_size);
277 }
278
GetContentIdForFrame(size_t frame_index) const279 PaintImage::ContentId DecodingImageGenerator::GetContentIdForFrame(
280 size_t frame_index) const {
281 DCHECK_LT(frame_index, GetFrameMetadata().size());
282
283 // If we have all the data for the image, or this particular frame, we can
284 // consider the decoded frame constant.
285 if (all_data_received_ || GetFrameMetadata().at(frame_index).complete)
286 return complete_frame_content_id_;
287
288 return PaintImageGenerator::GetContentIdForFrame(frame_index);
289 }
290
291 const cc::ImageHeaderMetadata*
GetMetadataForDecodeAcceleration() const292 DecodingImageGenerator::GetMetadataForDecodeAcceleration() const {
293 return &image_metadata_;
294 }
295
296 } // namespace blink
297