• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/compositing/scene_host.h"
6 
7 #include <lib/ui/scenic/cpp/view_token_pair.h>
8 #include <lib/zx/eventpair.h>
9 
10 #include "flutter/flow/view_holder.h"
11 #include "flutter/fml/thread_local.h"
12 #include "flutter/lib/ui/ui_dart_state.h"
13 
14 namespace {
15 
16 using SceneHostBindings = std::unordered_map<zx_koid_t, flutter::SceneHost*>;
17 
18 FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<SceneHostBindings>
19     tls_scene_host_bindings;
20 
SceneHost_constructor(Dart_NativeArguments args)21 void SceneHost_constructor(Dart_NativeArguments args) {
22   // This UI thread / Isolate contains at least 1 SceneHost.  Initialize the
23   // per-Isolate bindings.
24   if (tls_scene_host_bindings.get() == nullptr) {
25     tls_scene_host_bindings.reset(new SceneHostBindings());
26   }
27 
28   tonic::DartCallConstructor(&flutter::SceneHost::Create, args);
29 }
30 
GetSceneHost(scenic::ResourceId id)31 flutter::SceneHost* GetSceneHost(scenic::ResourceId id) {
32   auto* bindings = tls_scene_host_bindings.get();
33   FML_DCHECK(bindings);
34 
35   auto binding = bindings->find(id);
36   if (binding != bindings->end()) {
37     return binding->second;
38   }
39 
40   return nullptr;
41 }
42 
InvokeDartClosure(const tonic::DartPersistentValue & closure)43 void InvokeDartClosure(const tonic::DartPersistentValue& closure) {
44   auto dart_state = closure.dart_state().lock();
45   if (!dart_state) {
46     return;
47   }
48 
49   tonic::DartState::Scope scope(dart_state);
50   auto dart_handle = closure.value();
51 
52   FML_DCHECK(dart_handle && !Dart_IsNull(dart_handle) &&
53              Dart_IsClosure(dart_handle));
54   tonic::DartInvoke(dart_handle, {});
55 }
56 
57 template <typename T>
InvokeDartFunction(const tonic::DartPersistentValue & function,T & arg)58 void InvokeDartFunction(const tonic::DartPersistentValue& function, T& arg) {
59   auto dart_state = function.dart_state().lock();
60   if (!dart_state) {
61     return;
62   }
63 
64   tonic::DartState::Scope scope(dart_state);
65   auto dart_handle = function.value();
66 
67   FML_DCHECK(dart_handle && !Dart_IsNull(dart_handle) &&
68              Dart_IsClosure(dart_handle));
69   tonic::DartInvoke(dart_handle, {tonic::ToDart(arg)});
70 }
71 
GetKoid(zx_handle_t handle)72 zx_koid_t GetKoid(zx_handle_t handle) {
73   zx_info_handle_basic_t info;
74   zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info,
75                                           sizeof(info), nullptr, nullptr);
76   return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
77 }
78 
79 }  // namespace
80 
81 namespace flutter {
82 
83 IMPLEMENT_WRAPPERTYPEINFO(ui, SceneHost);
84 
85 #define FOR_EACH_BINDING(V)   \
86   V(SceneHost, dispose)       \
87   V(SceneHost, setProperties) \
88   V(SceneHost, setOpacity)
89 
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)90 FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
91 
92 void SceneHost::RegisterNatives(tonic::DartLibraryNatives* natives) {
93   natives->Register({{"SceneHost_constructor", SceneHost_constructor, 5, true},
94                      FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
95 }
96 
Create(fml::RefPtr<zircon::dart::Handle> viewHolderToken,Dart_Handle viewConnectedCallback,Dart_Handle viewDisconnectedCallback,Dart_Handle viewStateChangedCallback)97 fml::RefPtr<SceneHost> SceneHost::Create(
98     fml::RefPtr<zircon::dart::Handle> viewHolderToken,
99     Dart_Handle viewConnectedCallback,
100     Dart_Handle viewDisconnectedCallback,
101     Dart_Handle viewStateChangedCallback) {
102   return fml::MakeRefCounted<SceneHost>(viewHolderToken, viewConnectedCallback,
103                                         viewDisconnectedCallback,
104                                         viewStateChangedCallback);
105 }
106 
OnViewConnected(scenic::ResourceId id)107 void SceneHost::OnViewConnected(scenic::ResourceId id) {
108   auto* scene_host = GetSceneHost(id);
109 
110   if (scene_host && !scene_host->view_connected_callback_.is_empty()) {
111     InvokeDartClosure(scene_host->view_connected_callback_);
112   }
113 }
114 
OnViewDisconnected(scenic::ResourceId id)115 void SceneHost::OnViewDisconnected(scenic::ResourceId id) {
116   auto* scene_host = GetSceneHost(id);
117 
118   if (scene_host && !scene_host->view_disconnected_callback_.is_empty()) {
119     InvokeDartClosure(scene_host->view_disconnected_callback_);
120   }
121 }
122 
OnViewStateChanged(scenic::ResourceId id,bool state)123 void SceneHost::OnViewStateChanged(scenic::ResourceId id, bool state) {
124   auto* scene_host = GetSceneHost(id);
125 
126   if (scene_host && !scene_host->view_state_changed_callback_.is_empty()) {
127     InvokeDartFunction(scene_host->view_state_changed_callback_, state);
128   }
129 }
130 
SceneHost(fml::RefPtr<zircon::dart::Handle> viewHolderToken,Dart_Handle viewConnectedCallback,Dart_Handle viewDisconnectedCallback,Dart_Handle viewStateChangedCallback)131 SceneHost::SceneHost(fml::RefPtr<zircon::dart::Handle> viewHolderToken,
132                      Dart_Handle viewConnectedCallback,
133                      Dart_Handle viewDisconnectedCallback,
134                      Dart_Handle viewStateChangedCallback)
135     : gpu_task_runner_(
136           UIDartState::Current()->GetTaskRunners().GetGPUTaskRunner()),
137       koid_(GetKoid(viewHolderToken->handle())) {
138   auto dart_state = UIDartState::Current();
139 
140   // Initialize callbacks it they are non-null in Dart.
141   if (!Dart_IsNull(viewConnectedCallback)) {
142     view_connected_callback_.Set(dart_state, viewConnectedCallback);
143   }
144   if (!Dart_IsNull(viewDisconnectedCallback)) {
145     view_disconnected_callback_.Set(dart_state, viewDisconnectedCallback);
146   }
147   if (!Dart_IsNull(viewStateChangedCallback)) {
148     view_state_changed_callback_.Set(dart_state, viewStateChangedCallback);
149   }
150 
151   // This callback will be posted as a task  when the |scenic::ViewHolder|
152   // resource is created and given an id by the GPU thread.
153   auto bind_callback = [scene_host = this](scenic::ResourceId id) {
154     auto* bindings = tls_scene_host_bindings.get();
155     FML_DCHECK(bindings);
156     FML_DCHECK(bindings->find(id) == bindings->end());
157 
158     bindings->emplace(std::make_pair(id, scene_host));
159   };
160 
161   // Pass the raw handle to the GPU thead; destroying a |zircon::dart::Handle|
162   // on that thread can cause a race condition.
163   gpu_task_runner_->PostTask(
164       [id = koid_,
165        ui_task_runner =
166            UIDartState::Current()->GetTaskRunners().GetUITaskRunner(),
167        raw_handle = viewHolderToken->ReleaseHandle(), bind_callback]() {
168         flutter::ViewHolder::Create(
169             id, std::move(ui_task_runner),
170             scenic::ToViewHolderToken(zx::eventpair(raw_handle)),
171             std::move(bind_callback));
172       });
173 }
174 
~SceneHost()175 SceneHost::~SceneHost() {
176   auto* bindings = tls_scene_host_bindings.get();
177   FML_DCHECK(bindings);
178   bindings->erase(koid_);
179 
180   gpu_task_runner_->PostTask(
181       [id = koid_]() { flutter::ViewHolder::Destroy(id); });
182 }
183 
dispose()184 void SceneHost::dispose() {
185   ClearDartWrapper();
186 }
187 
setProperties(double width,double height,double insetTop,double insetRight,double insetBottom,double insetLeft,bool focusable)188 void SceneHost::setProperties(double width,
189                               double height,
190                               double insetTop,
191                               double insetRight,
192                               double insetBottom,
193                               double insetLeft,
194                               bool focusable) {
195   gpu_task_runner_->PostTask([id = koid_, width, height, insetTop, insetRight,
196                               insetBottom, insetLeft, focusable]() {
197     auto* view_holder = flutter::ViewHolder::FromId(id);
198     FML_DCHECK(view_holder);
199 
200     view_holder->SetProperties(width, height, insetTop, insetRight, insetBottom,
201                                insetLeft, focusable);
202   });
203 }
204 
setOpacity(double opacity)205 void SceneHost::setOpacity(double opacity) {
206   gpu_task_runner_->PostTask([id = koid_, opacity]() {
207     auto* view_holder = flutter::ViewHolder::FromId(id);
208     FML_DCHECK(view_holder);
209 
210     view_holder->SetOpacity(opacity);
211   });
212 }
213 
214 }  // namespace flutter
215