| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "flutter/flow/view_holder.h" | |
| #include "flutter/fml/thread_local.h" | |
| namespace { | |
| using ViewHolderBindings = | |
| std::unordered_map<zx_koid_t, std::unique_ptr<flutter::ViewHolder>>; | |
| FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<ViewHolderBindings> | |
| tls_view_holder_bindings; | |
| fuchsia::ui::gfx::ViewProperties ToViewProperties(float width, | |
| float height, | |
| float insetTop, | |
| float insetRight, | |
| float insetBottom, | |
| float insetLeft, | |
| bool focusable) { | |
| return fuchsia::ui::gfx::ViewProperties({ | |
| .bounding_box = fuchsia::ui::gfx::BoundingBox({ | |
| .min = fuchsia::ui::gfx::vec3({ | |
| .x = 0.f, | |
| .y = 0.f, | |
| .z = -1000.f, | |
| }), | |
| .max = fuchsia::ui::gfx::vec3({.x = width, .y = height, .z = 0.f}), | |
| }), | |
| .inset_from_min = fuchsia::ui::gfx::vec3({ | |
| .x = insetLeft, | |
| .y = insetTop, | |
| .z = 0.f, | |
| }), | |
| .inset_from_max = fuchsia::ui::gfx::vec3({ | |
| .x = insetRight, | |
| .y = insetBottom, | |
| .z = 0.f, | |
| }), | |
| .focus_change = focusable, | |
| }); | |
| } | |
| } // namespace | |
| namespace flutter { | |
| void ViewHolder::Create(zx_koid_t id, | |
| fml::RefPtr<fml::TaskRunner> ui_task_runner, | |
| fuchsia::ui::views::ViewHolderToken view_holder_token, | |
| const BindCallback& on_bind_callback) { | |
| // This raster thread contains at least 1 ViewHolder. Initialize the | |
| // per-thread bindings. | |
| if (tls_view_holder_bindings.get() == nullptr) { | |
| tls_view_holder_bindings.reset(new ViewHolderBindings()); | |
| } | |
| auto* bindings = tls_view_holder_bindings.get(); | |
| FML_DCHECK(bindings); | |
| FML_DCHECK(bindings->find(id) == bindings->end()); | |
| auto view_holder = std::make_unique<ViewHolder>(std::move(ui_task_runner), | |
| std::move(view_holder_token), | |
| on_bind_callback); | |
| bindings->emplace(id, std::move(view_holder)); | |
| } | |
| void ViewHolder::Destroy(zx_koid_t id) { | |
| auto* bindings = tls_view_holder_bindings.get(); | |
| FML_DCHECK(bindings); | |
| bindings->erase(id); | |
| } | |
| ViewHolder* ViewHolder::FromId(zx_koid_t id) { | |
| auto* bindings = tls_view_holder_bindings.get(); | |
| if (!bindings) { | |
| return nullptr; | |
| } | |
| auto binding = bindings->find(id); | |
| if (binding == bindings->end()) { | |
| return nullptr; | |
| } | |
| return binding->second.get(); | |
| } | |
| ViewHolder::ViewHolder(fml::RefPtr<fml::TaskRunner> ui_task_runner, | |
| fuchsia::ui::views::ViewHolderToken view_holder_token, | |
| const BindCallback& on_bind_callback) | |
| : ui_task_runner_(std::move(ui_task_runner)), | |
| pending_view_holder_token_(std::move(view_holder_token)), | |
| pending_bind_callback_(on_bind_callback) { | |
| FML_DCHECK(pending_view_holder_token_.value); | |
| } | |
| void ViewHolder::UpdateScene(SceneUpdateContext& context, | |
| const SkPoint& offset, | |
| const SkSize& size, | |
| SkAlpha opacity, | |
| bool hit_testable) { | |
| if (pending_view_holder_token_.value) { | |
| entity_node_ = std::make_unique<scenic::EntityNode>(context.session()); | |
| opacity_node_ = | |
| std::make_unique<scenic::OpacityNodeHACK>(context.session()); | |
| view_holder_ = std::make_unique<scenic::ViewHolder>( | |
| context.session(), std::move(pending_view_holder_token_), | |
| "Flutter SceneHost"); | |
| opacity_node_->AddChild(*entity_node_); | |
| opacity_node_->SetLabel("flutter::ViewHolder"); | |
| entity_node_->Attach(*view_holder_); | |
| if (ui_task_runner_ && pending_view_holder_token_.value) { | |
| ui_task_runner_->PostTask( | |
| [bind_callback = std::move(pending_bind_callback_), | |
| view_holder_id = view_holder_->id()]() { | |
| bind_callback(view_holder_id); | |
| }); | |
| } | |
| } | |
| FML_DCHECK(entity_node_); | |
| FML_DCHECK(opacity_node_); | |
| FML_DCHECK(view_holder_); | |
| context.top_entity()->embedder_node().AddChild(*opacity_node_); | |
| opacity_node_->SetOpacity(opacity / 255.0f); | |
| entity_node_->SetTranslation(offset.x(), offset.y(), -0.1f); | |
| entity_node_->SetHitTestBehavior( | |
| hit_testable ? fuchsia::ui::gfx::HitTestBehavior::kDefault | |
| : fuchsia::ui::gfx::HitTestBehavior::kSuppress); | |
| if (has_pending_properties_) { | |
| // TODO(dworsham): This should be derived from size and elevation. We | |
| // should be able to Z-limit the view's box but otherwise it uses all of the | |
| // available airspace. | |
| view_holder_->SetViewProperties(std::move(pending_properties_)); | |
| has_pending_properties_ = false; | |
| } | |
| } | |
| void ViewHolder::SetProperties(double width, | |
| double height, | |
| double insetTop, | |
| double insetRight, | |
| double insetBottom, | |
| double insetLeft, | |
| bool focusable) { | |
| pending_properties_ = ToViewProperties(width, height, insetTop, insetRight, | |
| insetBottom, insetLeft, focusable); | |
| has_pending_properties_ = true; | |
| } | |
| } // namespace flutter |