mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
178 lines
6.2 KiB
C++
178 lines
6.2 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 <unordered_map>
|
|
|
|
#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;
|
|
|
|
// Rather than expend the effort to compute the proper amount of "airspace" to
|
|
// give to the child view, just pick an arbitrarily large number. This works
|
|
// fine in all current production cases, and the hack of using depth to order
|
|
// things in Z is going away with Flatland.
|
|
constexpr float kArbitraryLargeDepth = -1000.f;
|
|
|
|
} // namespace
|
|
|
|
namespace flutter {
|
|
|
|
void ViewHolder::Create(zx_koid_t id,
|
|
ViewIdCallback on_view_created,
|
|
fuchsia::ui::views::ViewHolderToken view_holder_token) {
|
|
// 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::unique_ptr<ViewHolder>(
|
|
new ViewHolder(std::move(view_holder_token), std::move(on_view_created)));
|
|
bindings->emplace(id, std::move(view_holder));
|
|
}
|
|
|
|
void ViewHolder::Destroy(zx_koid_t id, ViewIdCallback on_view_destroyed) {
|
|
auto* bindings = tls_view_holder_bindings.get();
|
|
FML_DCHECK(bindings);
|
|
auto binding = bindings->find(id);
|
|
FML_DCHECK(binding != bindings->end());
|
|
|
|
if (binding->second->view_holder_ && on_view_destroyed) {
|
|
on_view_destroyed(binding->second->view_holder_->id());
|
|
}
|
|
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(fuchsia::ui::views::ViewHolderToken view_holder_token,
|
|
ViewIdCallback on_view_created)
|
|
: pending_view_holder_token_(std::move(view_holder_token)),
|
|
on_view_created_(std::move(on_view_created)) {
|
|
FML_DCHECK(pending_view_holder_token_.value);
|
|
}
|
|
|
|
void ViewHolder::UpdateScene(scenic::Session* session,
|
|
scenic::ContainerNode& container_node,
|
|
const SkPoint& offset,
|
|
SkAlpha opacity) {
|
|
if (pending_view_holder_token_.value) {
|
|
entity_node_ = std::make_unique<scenic::EntityNode>(session);
|
|
opacity_node_ = std::make_unique<scenic::OpacityNodeHACK>(session);
|
|
view_holder_ = std::make_unique<scenic::ViewHolder>(
|
|
session, std::move(pending_view_holder_token_), "Flutter SceneHost");
|
|
opacity_node_->AddChild(*entity_node_);
|
|
opacity_node_->SetLabel("flutter::ViewHolder");
|
|
entity_node_->Attach(*view_holder_);
|
|
|
|
// Inform the rest of Flutter about the view being created.
|
|
// As long as we do this before calling `Present` on the session,
|
|
// View-related messages sent to the UI thread will never be processed
|
|
// before this internal message is delivered to the UI thread.
|
|
if (on_view_created_) {
|
|
on_view_created_(view_holder_->id());
|
|
}
|
|
}
|
|
FML_DCHECK(entity_node_);
|
|
FML_DCHECK(opacity_node_);
|
|
FML_DCHECK(view_holder_);
|
|
|
|
container_node.AddChild(*opacity_node_);
|
|
opacity_node_->SetOpacity(opacity / 255.0f);
|
|
entity_node_->SetTranslation(offset.x(), offset.y(), -0.1f);
|
|
entity_node_->SetHitTestBehavior(hit_test_behavior_);
|
|
if (view_properties_changed_) {
|
|
view_holder_->SetViewProperties(view_properties_);
|
|
view_properties_changed_ = false;
|
|
}
|
|
}
|
|
|
|
void ViewHolder::SetProperties(double width,
|
|
double height,
|
|
double insetTop,
|
|
double insetRight,
|
|
double insetBottom,
|
|
double insetLeft,
|
|
bool focusable) {
|
|
set_size(SkSize::Make(width, height));
|
|
set_occlusion_hint(
|
|
SkRect::MakeLTRB(insetLeft, insetTop, insetRight, insetBottom));
|
|
set_focusable(focusable);
|
|
}
|
|
|
|
void ViewHolder::set_hit_testable(bool value) {
|
|
hit_test_behavior_ = value ? fuchsia::ui::gfx::HitTestBehavior::kDefault
|
|
: fuchsia::ui::gfx::HitTestBehavior::kSuppress;
|
|
}
|
|
|
|
void ViewHolder::set_focusable(bool value) {
|
|
if (view_properties_.focus_change != value) {
|
|
view_properties_.focus_change = value;
|
|
view_properties_changed_ = true;
|
|
}
|
|
}
|
|
|
|
void ViewHolder::set_size(const SkSize& size) {
|
|
if (size.width() > 0.f && size.height() > 0.f) {
|
|
if (view_properties_.bounding_box.max.x != size.width()) {
|
|
view_properties_.bounding_box.max.x = size.width();
|
|
view_properties_changed_ = true;
|
|
}
|
|
if (view_properties_.bounding_box.max.y != size.height()) {
|
|
view_properties_.bounding_box.max.y = size.height();
|
|
view_properties_changed_ = true;
|
|
}
|
|
}
|
|
|
|
// TODO(dworsham): The Z-bound should be derived from elevation. We should be
|
|
// able to Z-limit the view's box but otherwise it uses all of the available
|
|
// airspace.
|
|
view_properties_.bounding_box.min.z = kArbitraryLargeDepth;
|
|
}
|
|
|
|
void ViewHolder::set_occlusion_hint(const SkRect& occlusion_hint) {
|
|
if (view_properties_.inset_from_min.x != occlusion_hint.fLeft) {
|
|
view_properties_.inset_from_min.x = occlusion_hint.fLeft;
|
|
view_properties_changed_ = true;
|
|
}
|
|
if (view_properties_.inset_from_min.y != occlusion_hint.fTop) {
|
|
view_properties_.inset_from_min.y = occlusion_hint.fTop;
|
|
view_properties_changed_ = true;
|
|
}
|
|
if (view_properties_.inset_from_max.x != occlusion_hint.fRight) {
|
|
view_properties_.inset_from_max.x = occlusion_hint.fRight;
|
|
view_properties_changed_ = true;
|
|
}
|
|
if (view_properties_.inset_from_max.y != occlusion_hint.fBottom) {
|
|
view_properties_.inset_from_max.y = occlusion_hint.fBottom;
|
|
view_properties_changed_ = true;
|
|
}
|
|
}
|
|
|
|
} // namespace flutter
|