blob: 696b879755c1e968ced3bc6c88844496ead226bd [file] [log] [blame]
// Copyright 2018 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 "garnet/public/lib/ui/base_view/cpp/v1_base_view.h"
#include <lib/component/cpp/connect.h>
#include <lib/fxl/logging.h>
#include <lib/fxl/time/time_point.h>
#include <lib/ui/geometry/cpp/geometry_util.h>
#include <trace/event.h>
namespace scenic {
V1BaseView::V1BaseView(scenic::ViewContext context,
const std::string& debug_name)
: startup_context_(context.startup_context),
view_manager_(startup_context_->ConnectToEnvironmentService<
::fuchsia::ui::viewsv1::ViewManager>()),
view_listener_binding_(this),
view_container_listener_binding_(this),
incoming_services_(context.outgoing_services.Bind()),
outgoing_services_(std::move(context.incoming_services)),
session_(std::move(context.session_and_listener_request)),
parent_node_(&session_) {
FXL_DCHECK(context.view_token);
session_.SetDebugName(debug_name);
zx::eventpair parent_export_token;
parent_node_.BindAsRequest(&parent_export_token);
view_manager_->CreateView2(view_.NewRequest(), std::move(context.view_token),
view_listener_binding_.NewBinding(),
std::move(parent_export_token), debug_name);
session_.set_event_handler(
std::bind(&V1BaseView::HandleSessionEvents, this, std::placeholders::_1));
parent_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
}
V1BaseView::~V1BaseView() = default;
fuchsia::sys::ServiceProvider* V1BaseView::GetViewServiceProvider() {
if (!view_service_provider_)
view_->GetServiceProvider(view_service_provider_.NewRequest());
return view_service_provider_.get();
}
::fuchsia::ui::viewsv1::ViewContainer* V1BaseView::GetViewContainer() {
if (!view_container_) {
view_->GetContainer(view_container_.NewRequest());
view_container_->SetListener(view_container_listener_binding_.NewBinding());
}
return view_container_.get();
}
void V1BaseView::SetReleaseHandler(
fit::function<void(zx_status_t status)> callback) {
view_listener_binding_.set_error_handler(std::move(callback));
}
void V1BaseView::InvalidateScene() {
if (invalidate_pending_)
return;
invalidate_pending_ = true;
// Present the scene ASAP. Pass in the last presentation time; otherwise, if
// presentation_time argument is less than the previous time passed to
// PresentScene, the Session will be closed.
// (We cannot use the current time because the last requested presentation
// time, |last_presentation_time_|, could still be in the future. This is
// because Session.Present() returns after it _begins_ preparing the given
// frame, not after it is presented.)
if (!present_pending_)
PresentScene(last_presentation_time_);
}
void V1BaseView::PresentScene(zx_time_t presentation_time) {
FXL_DCHECK(!present_pending_);
present_pending_ = true;
// Keep track of the most recent presentation time we've passed to
// Session.Present(), for use in InvalidateScene().
last_presentation_time_ = presentation_time;
session()->Present(presentation_time,
[this](fuchsia::images::PresentationInfo info) {
FXL_DCHECK(present_pending_);
zx_time_t next_presentation_time =
info.presentation_time + info.presentation_interval;
bool present_needed = false;
if (invalidate_pending_) {
invalidate_pending_ = false;
OnSceneInvalidated(std::move(info));
present_needed = true;
}
present_pending_ = false;
if (present_needed)
PresentScene(next_presentation_time);
});
}
void V1BaseView::HandleSessionEvents(
std::vector<fuchsia::ui::scenic::Event> events) {
const fuchsia::ui::gfx::Metrics* new_metrics = nullptr;
for (size_t i = 0; i < events.size(); ++i) {
const auto& event = events[i];
if (event.is_gfx()) {
const fuchsia::ui::gfx::Event& scenic_event = event.gfx();
if (scenic_event.is_metrics() &&
scenic_event.metrics().node_id == parent_node_.id()) {
new_metrics = &scenic_event.metrics().metrics;
}
} else if (event.is_input()) {
// Act on input event just once.
OnInputEvent(std::move(events[i].input()));
// Create a dummy event to safely take its place.
fuchsia::ui::scenic::Command unhandled;
fuchsia::ui::scenic::Event unhandled_event;
unhandled_event.set_unhandled(std::move(unhandled));
events[i] = std::move(unhandled_event);
}
}
if (new_metrics && original_metrics_ != *new_metrics) {
original_metrics_ = *new_metrics;
AdjustMetricsAndPhysicalSize();
}
OnScenicEvent(std::move(events));
}
void V1BaseView::SetNeedSquareMetrics(bool enable) {
if (need_square_metrics_ == enable)
return;
need_square_metrics_ = true;
AdjustMetricsAndPhysicalSize();
}
void V1BaseView::AdjustMetricsAndPhysicalSize() {
adjusted_metrics_ = original_metrics_;
if (need_square_metrics_) {
adjusted_metrics_.scale_x = adjusted_metrics_.scale_y =
std::max(original_metrics_.scale_x, original_metrics_.scale_y);
}
physical_size_.width = logical_size_.width * adjusted_metrics_.scale_x;
physical_size_.height = logical_size_.height * adjusted_metrics_.scale_y;
InvalidateScene();
}
void V1BaseView::OnPropertiesChanged(
::fuchsia::ui::viewsv1::ViewProperties old_properties) {}
void V1BaseView::OnSceneInvalidated(
fuchsia::images::PresentationInfo presentation_info) {}
void V1BaseView::OnScenicEvent(std::vector<fuchsia::ui::scenic::Event> events) {
}
bool V1BaseView::OnInputEvent(fuchsia::ui::input::InputEvent event) {
return false;
}
void V1BaseView::OnChildAttached(
uint32_t child_key, ::fuchsia::ui::viewsv1::ViewInfo child_view_info) {}
void V1BaseView::OnChildUnavailable(uint32_t child_key) {}
void V1BaseView::OnPropertiesChanged(
::fuchsia::ui::viewsv1::ViewProperties properties,
OnPropertiesChangedCallback callback) {
TRACE_DURATION("view", "OnPropertiesChanged");
::fuchsia::ui::viewsv1::ViewProperties old_properties =
std::move(properties_);
properties_ = std::move(properties);
if (logical_size_ != properties_.view_layout->size) {
logical_size_ = properties_.view_layout->size;
AdjustMetricsAndPhysicalSize();
}
OnPropertiesChanged(std::move(old_properties));
callback();
}
void V1BaseView::OnChildAttached(
uint32_t child_key, ::fuchsia::ui::viewsv1::ViewInfo child_view_info,
OnChildUnavailableCallback callback) {
TRACE_DURATION("view", "OnChildAttached", "child_key", child_key);
OnChildAttached(child_key, std::move(child_view_info));
callback();
}
void V1BaseView::OnChildUnavailable(uint32_t child_key,
OnChildUnavailableCallback callback) {
TRACE_DURATION("view", "OnChildUnavailable", "child_key", child_key);
OnChildUnavailable(child_key);
callback();
}
} // namespace scenic