blob: 4e6b32f03f671ce1d18fdad030744e979462ab86 [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 "annotation_manager.h"
#include "src/ui/scenic/lib/gfx/engine/object_linker.h"
#include "src/ui/scenic/lib/gfx/engine/session.h"
#include "src/ui/scenic/lib/gfx/engine/view_tree.h"
#include "src/ui/scenic/lib/gfx/resources/view.h"
#include "src/ui/scenic/lib/gfx/resources/view_holder.h"
namespace scenic_impl {
namespace gfx {
using fuchsia::ui::views::ViewHolderToken;
using fuchsia::ui::views::ViewRef;
AnnotationManager::AnnotationManager(SceneGraphWeakPtr scene_graph, ViewLinker* view_linker,
std::unique_ptr<Session> session)
: scene_graph_(scene_graph),
view_linker_(view_linker),
session_(std::move(session)),
weak_factory_(this) {
FXL_DCHECK(scene_graph_);
FXL_DCHECK(view_linker_);
FXL_DCHECK(session_);
}
ViewHolderPtr AnnotationManager::NewAnnotationViewHolder(ViewHolderToken view_holder_token) {
std::ostringstream annotation_debug_name;
annotation_debug_name << "Annotation ViewHolder: Token " << view_holder_token.value.get();
ViewHolderPtr annotation_view_holder = fxl::MakeRefCounted<ViewHolder>(
session_.get(), session_->id(), /* node_id */ 0U, /* suppress_events */ true,
annotation_debug_name.str(), session_->shared_error_reporter(),
session_->view_tree_updater());
// Set hit test behavior to kSuppress so it will suppress all hit testings.
annotation_view_holder->SetHitTestBehavior(fuchsia::ui::gfx::HitTestBehavior::kSuppress);
// Set up link with annotation View.
ViewLinker::ExportLink link = view_linker_->CreateExport(
annotation_view_holder.get(), std::move(view_holder_token.value), session_->error_reporter());
FXL_CHECK(link.valid()) << "Cannot setup link with annotation View!";
annotation_view_holder->Connect(std::move(link));
return annotation_view_holder;
}
bool AnnotationManager::HasHandler(AnnotationHandlerId handler_id) const {
return handlers_state_.find(handler_id) != handlers_state_.end();
}
bool AnnotationManager::RegisterHandler(AnnotationHandlerId handler_id,
fit::function<void(zx_status_t)> on_handler_removed) {
if (HasHandler(handler_id)) {
return false;
}
handlers_state_[handler_id] =
HandlerState{.requests = {}, .on_handler_removed = std::move(on_handler_removed)};
return true;
}
bool AnnotationManager::RemoveHandlerWithEpitaph(AnnotationHandlerId handler_id,
zx_status_t epitaph) {
if (!HasHandler(handler_id)) {
return false;
}
handlers_state_[handler_id].on_handler_removed(epitaph);
handlers_state_.erase(handler_id);
return true;
}
void AnnotationManager::RequestCreate(AnnotationHandlerId handler_id, ViewRef main_view,
ViewHolderToken view_holder_token,
OnAnnotationViewHolderCreatedCallback callback) {
FXL_CHECK(HasHandler(handler_id)) << "Handler ID " << handler_id << " invalid!";
handlers_state_[handler_id].requests.push_back(CreationRequest{
.fulfilled = false,
.main_view = std::move(main_view),
.annotation_view_holder = NewAnnotationViewHolder(std::move(view_holder_token)),
.callback = std::move(callback),
});
}
void AnnotationManager::CleanupInvalidHandlerState(
const std::vector<std::pair<AnnotationHandlerId, zx_status_t>>& invalid_handlers_info) {
// Clean up invalid handlers.
for (const auto [handler_id, epitaph] : invalid_handlers_info) {
auto result = RemoveHandlerWithEpitaph(handler_id, epitaph);
FXL_DCHECK(result) << "Remove annotation handler #" << handler_id
<< " failed: Handler doesn't exist.";
}
}
void AnnotationManager::CleanupFulfilledRequests() {
for (auto& kv : handlers_state_) {
HandlerState& state = kv.second;
state.requests.remove_if([](const CreationRequest& request) { return request.fulfilled; });
}
}
void AnnotationManager::FulfillCreateRequests() {
std::vector<std::pair<AnnotationHandlerId, zx_status_t>> invalid_handlers_info;
for (auto& kv : handlers_state_) {
AnnotationHandlerId handler_id = kv.first;
HandlerState& state = kv.second;
for (auto& request : state.requests) {
zx_koid_t main_view_koid = ExtractKoid(request.main_view);
zx_status_t status = scene_graph_->view_tree().AddAnnotationViewHolder(
main_view_koid, std::move(request.annotation_view_holder));
if (status == ZX_OK) {
request.fulfilled = true;
request.callback();
} else if (status != ZX_ERR_NOT_FOUND) {
invalid_handlers_info.emplace_back(handler_id, status);
break;
}
}
}
CleanupInvalidHandlerState(invalid_handlers_info);
CleanupFulfilledRequests();
}
} // namespace gfx
} // namespace scenic_impl