Flutter Engine
single_frame_codec.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/single_frame_codec.h"
6 
7 #include "flutter/lib/ui/ui_dart_state.h"
9 
10 namespace flutter {
11 
13  uint32_t target_width,
14  uint32_t target_height)
15  : status_(Status::kNew),
16  descriptor_(std::move(descriptor)),
17  target_width_(target_width),
18  target_height_(target_height) {}
19 
21 
23  return 1;
24 }
25 
27  return 0;
28 }
29 
30 Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle callback_handle) {
31  if (!Dart_IsClosure(callback_handle)) {
32  return tonic::ToDart("Callback must be a function");
33  }
34 
35  if (status_ == Status::kComplete) {
36  tonic::DartInvoke(callback_handle,
37  {tonic::ToDart(cached_image_), tonic::ToDart(0)});
38  return Dart_Null();
39  }
40 
41  // This has to be valid because this method is called from Dart.
42  auto dart_state = UIDartState::Current();
43 
44  pending_callbacks_.emplace_back(dart_state, callback_handle);
45 
46  if (status_ == Status::kInProgress) {
47  // Another call to getNextFrame is in progress and will invoke the
48  // pending callbacks when decoding completes.
49  return Dart_Null();
50  }
51 
52  auto decoder = dart_state->GetImageDecoder();
53 
54  if (!decoder) {
55  return tonic::ToDart("Image decoder not available.");
56  }
57 
58  // The SingleFrameCodec must be deleted on the UI thread. Allocate a RefPtr
59  // on the heap to ensure that the SingleFrameCodec remains alive until the
60  // decoder callback is invoked on the UI thread. The callback can then
61  // drop the reference.
62  fml::RefPtr<SingleFrameCodec>* raw_codec_ref =
64 
65  decoder->Decode(
66  descriptor_, target_width_, target_height_, [raw_codec_ref](auto image) {
67  std::unique_ptr<fml::RefPtr<SingleFrameCodec>> codec_ref(raw_codec_ref);
68  fml::RefPtr<SingleFrameCodec> codec(std::move(*codec_ref));
69 
70  auto state = codec->pending_callbacks_.front().dart_state().lock();
71 
72  if (!state) {
73  // This is probably because the isolate has been terminated before the
74  // image could be decoded.
75 
76  return;
77  }
78 
79  tonic::DartState::Scope scope(state.get());
80 
81  if (image.get()) {
82  auto canvas_image = fml::MakeRefCounted<CanvasImage>();
83  canvas_image->set_image(std::move(image));
84 
85  codec->cached_image_ = std::move(canvas_image);
86  }
87 
88  // The cached frame is now available and should be returned to any
89  // future callers.
90  codec->status_ = Status::kComplete;
91 
92  // Invoke any callbacks that were provided before the frame was decoded.
93  for (const DartPersistentValue& callback : codec->pending_callbacks_) {
95  callback.value(),
96  {tonic::ToDart(codec->cached_image_), tonic::ToDart(0)});
97  }
98  codec->pending_callbacks_.clear();
99  });
100 
101  // The encoded data is no longer needed now that it has been handed off
102  // to the decoder.
103  descriptor_ = nullptr;
104 
105  status_ = Status::kInProgress;
106 
107  return Dart_Null();
108 }
109 
111  const auto& data_size = descriptor_->GetAllocationSize();
112  const auto frame_byte_size =
113  cached_image_ ? cached_image_->GetAllocationSize() : 0;
114  return data_size + frame_byte_size + sizeof(this);
115 }
116 
117 } // namespace flutter
size_t GetAllocationSize() const override
Definition: ref_ptr.h:252
Dart_Handle getNextFrame(Dart_Handle args) override
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:20
SingleFrameCodec(fml::RefPtr< ImageDescriptor > descriptor, uint32_t target_width, uint32_t target_height)
int repetitionCount() const override
int frameCount() const override
Dart_Handle ToDart(const T &object)
static UIDartState * Current()