1 | // Copyright 2013 The Flutter 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 "flutter/lib/ui/painting/image_descriptor.h" |
6 | |
7 | #include "flutter/fml/build_config.h" |
8 | #include "flutter/fml/logging.h" |
9 | #include "flutter/fml/trace_event.h" |
10 | #include "flutter/lib/ui/painting/codec.h" |
11 | #include "flutter/lib/ui/painting/image_decoder.h" |
12 | #include "flutter/lib/ui/painting/multi_frame_codec.h" |
13 | #include "flutter/lib/ui/painting/single_frame_codec.h" |
14 | #include "flutter/lib/ui/ui_dart_state.h" |
15 | #include "third_party/tonic/dart_binding_macros.h" |
16 | #include "third_party/tonic/logging/dart_invoke.h" |
17 | |
18 | #ifdef OS_MACOSX |
19 | #include "third_party/skia/include/ports/SkImageGeneratorCG.h" |
20 | #define PLATFORM_IMAGE_GENERATOR(data) \ |
21 | SkImageGeneratorCG::MakeFromEncodedCG(data) |
22 | #elif OS_WIN |
23 | #include "third_party/skia/include/ports/SkImageGeneratorWIC.h" |
24 | #define PLATFORM_IMAGE_GENERATOR(data) \ |
25 | SkImageGeneratorWIC::MakeFromEncodedWIC(data) |
26 | #else |
27 | #define PLATFORM_IMAGE_GENERATOR(data) \ |
28 | std::unique_ptr<SkImageGenerator>(nullptr) |
29 | #endif |
30 | |
31 | namespace flutter { |
32 | |
33 | IMPLEMENT_WRAPPERTYPEINFO(ui, ImageDescriptor); |
34 | |
35 | #define FOR_EACH_BINDING(V) \ |
36 | V(ImageDescriptor, initRaw) \ |
37 | V(ImageDescriptor, instantiateCodec) \ |
38 | V(ImageDescriptor, width) \ |
39 | V(ImageDescriptor, height) \ |
40 | V(ImageDescriptor, bytesPerPixel) |
41 | |
42 | FOR_EACH_BINDING(DART_NATIVE_CALLBACK) |
43 | |
44 | void ImageDescriptor::RegisterNatives(tonic::DartLibraryNatives* natives) { |
45 | natives->Register( |
46 | {{"ImageDescriptor_initEncoded" , ImageDescriptor::initEncoded, 3, true}, |
47 | FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); |
48 | } |
49 | |
50 | const SkImageInfo ImageDescriptor::CreateImageInfo() const { |
51 | if (generator_) { |
52 | return generator_->getInfo(); |
53 | } |
54 | if (platform_image_generator_) { |
55 | return platform_image_generator_->getInfo(); |
56 | } |
57 | return SkImageInfo::MakeUnknown(); |
58 | } |
59 | |
60 | ImageDescriptor::ImageDescriptor(sk_sp<SkData> buffer, |
61 | const SkImageInfo& image_info, |
62 | std::optional<size_t> row_bytes) |
63 | : buffer_(std::move(buffer)), |
64 | generator_(nullptr), |
65 | platform_image_generator_(nullptr), |
66 | image_info_(std::move(image_info)), |
67 | row_bytes_(row_bytes) {} |
68 | |
69 | ImageDescriptor::ImageDescriptor(sk_sp<SkData> buffer, |
70 | std::unique_ptr<SkCodec> codec) |
71 | : buffer_(std::move(buffer)), |
72 | generator_(std::shared_ptr<SkCodecImageGenerator>( |
73 | static_cast<SkCodecImageGenerator*>( |
74 | SkCodecImageGenerator::MakeFromCodec(std::move(codec)) |
75 | .release()))), |
76 | platform_image_generator_(nullptr), |
77 | image_info_(CreateImageInfo()), |
78 | row_bytes_(std::nullopt) {} |
79 | |
80 | ImageDescriptor::ImageDescriptor(sk_sp<SkData> buffer, |
81 | std::unique_ptr<SkImageGenerator> generator) |
82 | : buffer_(std::move(buffer)), |
83 | generator_(nullptr), |
84 | platform_image_generator_(std::move(generator)), |
85 | image_info_(CreateImageInfo()), |
86 | row_bytes_(std::nullopt) {} |
87 | |
88 | void ImageDescriptor::initEncoded(Dart_NativeArguments args) { |
89 | Dart_Handle callback_handle = Dart_GetNativeArgument(args, 2); |
90 | if (!Dart_IsClosure(callback_handle)) { |
91 | Dart_SetReturnValue(args, tonic::ToDart("Callback must be a function" )); |
92 | return; |
93 | } |
94 | |
95 | Dart_Handle descriptor_handle = Dart_GetNativeArgument(args, 0); |
96 | ImmutableBuffer* immutable_buffer = |
97 | tonic::DartConverter<ImmutableBuffer*>::FromDart( |
98 | Dart_GetNativeArgument(args, 1)); |
99 | |
100 | if (!immutable_buffer) { |
101 | Dart_SetReturnValue(args, |
102 | tonic::ToDart("Buffer parameter must not be null" )); |
103 | return; |
104 | } |
105 | |
106 | // This call will succeed if Skia has a built-in codec for this. |
107 | // If it fails, we will check if the platform knows how to decode this image. |
108 | std::unique_ptr<SkCodec> codec = |
109 | SkCodec::MakeFromData(immutable_buffer->data()); |
110 | fml::RefPtr<ImageDescriptor> descriptor; |
111 | if (!codec) { |
112 | std::unique_ptr<SkImageGenerator> generator = |
113 | PLATFORM_IMAGE_GENERATOR(immutable_buffer->data()); |
114 | if (!generator) { |
115 | // We don't have a Skia codec for this image, and the platform doesn't |
116 | // know how to decode it. |
117 | Dart_SetReturnValue(args, tonic::ToDart("Invalid image data" )); |
118 | return; |
119 | } |
120 | descriptor = fml::MakeRefCounted<ImageDescriptor>(immutable_buffer->data(), |
121 | std::move(generator)); |
122 | } else { |
123 | descriptor = fml::MakeRefCounted<ImageDescriptor>(immutable_buffer->data(), |
124 | std::move(codec)); |
125 | } |
126 | |
127 | FML_DCHECK(descriptor); |
128 | |
129 | descriptor->AssociateWithDartWrapper(descriptor_handle); |
130 | tonic::DartInvoke(callback_handle, {Dart_TypeVoid()}); |
131 | } |
132 | |
133 | void ImageDescriptor::initRaw(Dart_Handle descriptor_handle, |
134 | fml::RefPtr<ImmutableBuffer> data, |
135 | int width, |
136 | int height, |
137 | int row_bytes, |
138 | PixelFormat pixel_format) { |
139 | SkColorType color_type = kUnknown_SkColorType; |
140 | switch (pixel_format) { |
141 | case PixelFormat::kRGBA8888: |
142 | color_type = kRGBA_8888_SkColorType; |
143 | break; |
144 | case PixelFormat::kBGRA8888: |
145 | color_type = kBGRA_8888_SkColorType; |
146 | break; |
147 | } |
148 | FML_DCHECK(color_type != kUnknown_SkColorType); |
149 | auto image_info = |
150 | SkImageInfo::Make(width, height, color_type, kPremul_SkAlphaType); |
151 | auto descriptor = fml::MakeRefCounted<ImageDescriptor>( |
152 | data->data(), std::move(image_info), |
153 | row_bytes == -1 ? std::nullopt : std::optional<size_t>(row_bytes)); |
154 | descriptor->AssociateWithDartWrapper(descriptor_handle); |
155 | } |
156 | |
157 | void ImageDescriptor::instantiateCodec(Dart_Handle codec_handle, |
158 | int target_width, |
159 | int target_height) { |
160 | fml::RefPtr<Codec> ui_codec; |
161 | if (!generator_ || generator_->getFrameCount() == 1) { |
162 | ui_codec = fml::MakeRefCounted<SingleFrameCodec>( |
163 | static_cast<fml::RefPtr<ImageDescriptor>>(this), target_width, |
164 | target_height); |
165 | } else { |
166 | ui_codec = fml::MakeRefCounted<MultiFrameCodec>(generator_); |
167 | } |
168 | ui_codec->AssociateWithDartWrapper(codec_handle); |
169 | } |
170 | |
171 | sk_sp<SkImage> ImageDescriptor::image() const { |
172 | SkBitmap bitmap; |
173 | if (!bitmap.tryAllocPixels(image_info_)) { |
174 | FML_LOG(ERROR) << "Failed to allocate memory for bitmap of size " |
175 | << image_info_.computeMinByteSize() << "B" ; |
176 | return nullptr; |
177 | } |
178 | |
179 | const auto& pixmap = bitmap.pixmap(); |
180 | if (!get_pixels(pixmap)) { |
181 | FML_LOG(ERROR) << "Failed to get pixels for image." ; |
182 | return nullptr; |
183 | } |
184 | bitmap.setImmutable(); |
185 | return SkImage::MakeFromBitmap(bitmap); |
186 | } |
187 | |
188 | bool ImageDescriptor::get_pixels(const SkPixmap& pixmap) const { |
189 | if (generator_) { |
190 | return generator_->getPixels(pixmap.info(), pixmap.writable_addr(), |
191 | pixmap.rowBytes()); |
192 | } |
193 | FML_DCHECK(platform_image_generator_); |
194 | return platform_image_generator_->getPixels(pixmap); |
195 | } |
196 | |
197 | } // namespace flutter |
198 | |