flutter_flutter/flow/view_holder.cc
mikejurka ad8ccf47b1
[Fuchsia] Move physical shape layer compositing to Flutter (#17005)
* [fuchsia] Add labels to Scenic nodes.

* [fuchsia] Skip creating Scenic nodes for identity Transforms.

* [fuchsia] Assign elevation to Scenic nodes based on paint order.

* [fuchsia] Create Scenic OpacityNodes at leaf nodes.

* [fuchsia] Composite PhysicalShapeLayers using Skia, except when they need to float above child views.

In that case, they will still need to be pulled
into separate Scenic nodes to be composited on top
of the child view[s].

* [fuchsia] Add tests for Fuchsia-specific layer behavior.

Inspect commands going to Scenic and make sure
they match what is expected.

Also, restructure code to need less member variables,
and other cleanups based on review feedback.
2020-03-23 16:38:07 -07:00

156 lines
5.5 KiB
C++

// 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 GPU 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(ui_task_runner_);
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_);
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