Flutter Engine
image_descriptor.cc
Go to the documentation of this file.
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"
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 
43 
44 void ImageDescriptor::RegisterNatives(tonic::DartLibraryNatives* natives) {
45  natives->Register(
46  {{"ImageDescriptor_initEncoded", ImageDescriptor::initEncoded, 3, true},
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 =
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,
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
#define FOR_EACH_BINDING(V)
sk_sp< SkData > data() const
Callers should not modify the returned data. This is not exposed to Dart.
sk_sp< SkImage > image() const
#define FML_DCHECK(condition)
Definition: logging.h:86
uint32_t color_type
#define FML_LOG(severity)
Definition: logging.h:65
#define DART_NATIVE_CALLBACK(CLASS, METHOD)
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:20
static void initEncoded(Dart_NativeArguments args)
static void initRaw(Dart_Handle descriptor_handle, fml::RefPtr< ImmutableBuffer > data, int width, int height, int row_bytes, PixelFormat pixel_format)
IMPLEMENT_WRAPPERTYPEINFO(ui, Scene)
#define PLATFORM_IMAGE_GENERATOR(data)
sk_sp< SkData > data() const
The underlying buffer for this image.
const SkImageInfo & image_info() const
The orientation corrected image info for this image.
int height() const
The height of this image. EXIF oriented if applicable.
void instantiateCodec(Dart_Handle codec, int target_width, int target_height)
Associates a flutter::Codec object with the dart.ui Codec handle.
#define DART_REGISTER_NATIVE(CLASS, METHOD)
int width() const
The width of this image, EXIF oriented if applicable.
Dart_Handle ToDart(const T &object)
bool get_pixels(const SkPixmap &pixmap) const