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/flow/view_holder.h"
6
7 #include "flutter/fml/thread_local.h"
8
9 namespace {
10
11 using ViewHolderBindings =
12 std::unordered_map<zx_koid_t, std::unique_ptr<flutter::ViewHolder>>;
13
14 FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<ViewHolderBindings>
15 tls_view_holder_bindings;
16
ToViewProperties(float width,float height,float insetTop,float insetRight,float insetBottom,float insetLeft,bool focusable)17 fuchsia::ui::gfx::ViewProperties ToViewProperties(float width,
18 float height,
19 float insetTop,
20 float insetRight,
21 float insetBottom,
22 float insetLeft,
23 bool focusable) {
24 return fuchsia::ui::gfx::ViewProperties({
25 .bounding_box = fuchsia::ui::gfx::BoundingBox({
26 .min = fuchsia::ui::gfx::vec3({
27 .x = 0.f,
28 .y = 0.f,
29 .z = -1000.f,
30 }),
31 .max = fuchsia::ui::gfx::vec3({.x = width, .y = height, .z = 0.f}),
32 }),
33 .inset_from_min = fuchsia::ui::gfx::vec3({
34 .x = insetLeft,
35 .y = insetTop,
36 .z = 0.f,
37 }),
38 .inset_from_max = fuchsia::ui::gfx::vec3({
39 .x = insetRight,
40 .y = insetBottom,
41 .z = 0.f,
42 }),
43 .focus_change = focusable,
44 });
45 }
46
47 } // namespace
48
49 namespace flutter {
50
Create(zx_koid_t id,fml::RefPtr<fml::TaskRunner> ui_task_runner,fuchsia::ui::views::ViewHolderToken view_holder_token,BindCallback on_bind_callback)51 void ViewHolder::Create(zx_koid_t id,
52 fml::RefPtr<fml::TaskRunner> ui_task_runner,
53 fuchsia::ui::views::ViewHolderToken view_holder_token,
54 BindCallback on_bind_callback) {
55 // This GPU thread contains at least 1 ViewHolder. Initialize the per-thread
56 // bindings.
57 if (tls_view_holder_bindings.get() == nullptr) {
58 tls_view_holder_bindings.reset(new ViewHolderBindings());
59 }
60
61 auto* bindings = tls_view_holder_bindings.get();
62 FML_DCHECK(bindings);
63 FML_DCHECK(bindings->find(id) == bindings->end());
64
65 auto view_holder = std::make_unique<ViewHolder>(std::move(ui_task_runner),
66 std::move(view_holder_token),
67 std::move(on_bind_callback));
68 bindings->emplace(id, std::move(view_holder));
69 }
70
Destroy(zx_koid_t id)71 void ViewHolder::Destroy(zx_koid_t id) {
72 auto* bindings = tls_view_holder_bindings.get();
73 FML_DCHECK(bindings);
74
75 bindings->erase(id);
76 }
77
FromId(zx_koid_t id)78 ViewHolder* ViewHolder::FromId(zx_koid_t id) {
79 auto* bindings = tls_view_holder_bindings.get();
80 if (!bindings) {
81 return nullptr;
82 }
83
84 auto binding = bindings->find(id);
85 if (binding == bindings->end()) {
86 return nullptr;
87 }
88
89 return binding->second.get();
90 }
91
ViewHolder(fml::RefPtr<fml::TaskRunner> ui_task_runner,fuchsia::ui::views::ViewHolderToken view_holder_token,BindCallback on_bind_callback)92 ViewHolder::ViewHolder(fml::RefPtr<fml::TaskRunner> ui_task_runner,
93 fuchsia::ui::views::ViewHolderToken view_holder_token,
94 BindCallback on_bind_callback)
95 : ui_task_runner_(std::move(ui_task_runner)),
96 pending_view_holder_token_(std::move(view_holder_token)),
97 pending_bind_callback_(std::move(on_bind_callback)) {
98 FML_DCHECK(ui_task_runner_);
99 FML_DCHECK(pending_view_holder_token_.value);
100 }
101
UpdateScene(SceneUpdateContext & context,const SkPoint & offset,const SkSize & size,bool hit_testable)102 void ViewHolder::UpdateScene(SceneUpdateContext& context,
103 const SkPoint& offset,
104 const SkSize& size,
105 bool hit_testable) {
106 if (pending_view_holder_token_.value) {
107 opacity_node_ =
108 std::make_unique<scenic::OpacityNodeHACK>(context.session());
109 entity_node_ = std::make_unique<scenic::EntityNode>(context.session());
110 view_holder_ = std::make_unique<scenic::ViewHolder>(
111 context.session(), std::move(pending_view_holder_token_),
112 "Flutter SceneHost");
113
114 opacity_node_->AddChild(*entity_node_);
115 entity_node_->Attach(*view_holder_);
116 ui_task_runner_->PostTask(
117 [bind_callback = std::move(pending_bind_callback_),
118 view_holder_id = view_holder_->id()]() {
119 bind_callback(view_holder_id);
120 });
121 }
122 FML_DCHECK(opacity_node_);
123 FML_DCHECK(view_holder_);
124
125 context.top_entity()->entity_node().AddChild(*opacity_node_);
126 entity_node_->SetTranslation(offset.x(), offset.y(), -0.1f);
127 entity_node_->SetHitTestBehavior(
128 hit_testable ? fuchsia::ui::gfx::HitTestBehavior::kDefault
129 : fuchsia::ui::gfx::HitTestBehavior::kSuppress);
130 if (has_pending_opacity_) {
131 opacity_node_->SetOpacity(pending_opacity_);
132
133 has_pending_opacity_ = false;
134 }
135 if (has_pending_properties_) {
136 view_holder_->SetViewProperties(std::move(pending_properties_));
137
138 has_pending_properties_ = false;
139 }
140 }
141
SetProperties(double width,double height,double insetTop,double insetRight,double insetBottom,double insetLeft,bool focusable)142 void ViewHolder::SetProperties(double width,
143 double height,
144 double insetTop,
145 double insetRight,
146 double insetBottom,
147 double insetLeft,
148 bool focusable) {
149 pending_properties_ = ToViewProperties(width, height, insetTop, insetRight,
150 insetBottom, insetLeft, focusable);
151 has_pending_properties_ = true;
152 }
153
SetOpacity(double opacity)154 void ViewHolder::SetOpacity(double opacity) {
155 pending_opacity_ = std::clamp(opacity, 0.0, 1.0);
156 has_pending_opacity_ = true;
157 }
158
159 } // namespace flutter
160