blob: 4f03bb75ad32418e688575fec1e2649f0370d150 [file] [log] [blame]
// Copyright 2015 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 "lib/ui/view_framework/base_view.h"
#include <trace/event.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"
namespace mozart {
namespace {
fuchsia::ui::scenic::ScenicPtr GetScenic(
::fuchsia::ui::viewsv1::ViewManager* view_manager) {
fuchsia::ui::scenic::ScenicPtr scenic;
view_manager->GetScenic(scenic.NewRequest());
return scenic;
}
} // namespace
BaseView::BaseView(
::fuchsia::ui::viewsv1::ViewManagerPtr view_manager,
fidl::InterfaceRequest<::fuchsia::ui::viewsv1token::ViewOwner>
view_owner_request,
const std::string& label)
: view_manager_(std::move(view_manager)),
view_listener_binding_(this),
view_container_listener_binding_(this),
session_(GetScenic(view_manager_.get()).get()),
parent_node_(&session_) {
FXL_DCHECK(view_manager_);
FXL_DCHECK(view_owner_request);
zx::eventpair parent_export_token;
parent_node_.BindAsRequest(&parent_export_token);
view_manager_->CreateView2(
view_.NewRequest(),
zx::eventpair(view_owner_request.TakeChannel().release()),
view_listener_binding_.NewBinding(), std::move(parent_export_token),
label);
session_.set_event_handler(
std::bind(&BaseView::HandleSessionEvents, this, std::placeholders::_1));
parent_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
}
BaseView::~BaseView() = default;
fuchsia::sys::ServiceProvider* BaseView::GetViewServiceProvider() {
if (!view_service_provider_)
view_->GetServiceProvider(view_service_provider_.NewRequest());
return view_service_provider_.get();
}
::fuchsia::ui::viewsv1::ViewContainer* BaseView::GetViewContainer() {
if (!view_container_) {
view_->GetContainer(view_container_.NewRequest());
view_container_->SetListener(view_container_listener_binding_.NewBinding());
}
return view_container_.get();
}
void BaseView::SetReleaseHandler(fit::function<void(zx_status_t)> callback) {
view_listener_binding_.set_error_handler(std::move(callback));
}
void BaseView::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 BaseView::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 BaseView::HandleSessionEvents(
fidl::VectorPtr<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 BaseView::SetNeedSquareMetrics(bool enable) {
if (need_square_metrics_ == enable)
return;
need_square_metrics_ = true;
AdjustMetricsAndPhysicalSize();
}
void BaseView::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 BaseView::OnPropertiesChanged(
::fuchsia::ui::viewsv1::ViewProperties old_properties) {}
void BaseView::OnSceneInvalidated(
fuchsia::images::PresentationInfo presentation_info) {}
void BaseView::OnScenicEvent(
fidl::VectorPtr<fuchsia::ui::scenic::Event> events) {}
bool BaseView::OnInputEvent(fuchsia::ui::input::InputEvent event) {
return false;
}
void BaseView::OnChildAttached(
uint32_t child_key, ::fuchsia::ui::viewsv1::ViewInfo child_view_info) {}
void BaseView::OnChildUnavailable(uint32_t child_key) {}
void BaseView::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 BaseView::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 BaseView::OnChildUnavailable(uint32_t child_key,
OnChildUnavailableCallback callback) {
TRACE_DURATION("view", "OnChildUnavailable", "child_key", child_key);
OnChildUnavailable(child_key);
callback();
}
} // namespace mozart