blob: 76bd970a1d334630f47278fc446d5dce31bee7c6 [file] [log] [blame]
// Copyright 2019 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 "imagepipe_view.h"
#include <lib/syslog/global.h>
enum {
kViewId = 1,
kRootNodeId = 2,
kMaterialId = 3,
kShapeNodeId = 4,
kImagePipeId = 5,
kFirstNewResourceId = 6,
};
std::unique_ptr<ImagePipeView> ImagePipeView::Create(sys::ComponentContext* context,
fuchsia::ui::views::ViewToken view_token,
ResizeCallback resize_callback) {
auto view = std::make_unique<ImagePipeView>(std::move(resize_callback));
if (!view)
return nullptr;
if (!view->Init(context, std::move(view_token)))
return nullptr;
return view;
}
ImagePipeView::ImagePipeView(ResizeCallback resize_callback)
: session_listener_binding_(this),
resize_callback_(std::move(resize_callback)),
new_resource_id_(kFirstNewResourceId) {}
static void PushCommand(std::vector<fuchsia::ui::scenic::Command>* cmds,
fuchsia::ui::gfx::Command cmd) {
// Wrap the gfx::Command in a scenic::Command, then push it.
cmds->push_back(scenic::NewCommand(std::move(cmd)));
}
bool ImagePipeView::Init(sys::ComponentContext* context, fuchsia::ui::views::ViewToken view_token) {
fuchsia::ui::scenic::ScenicPtr scenic = context->svc()->Connect<fuchsia::ui::scenic::Scenic>();
scenic->CreateSession(session_.NewRequest(), session_listener_binding_.NewBinding());
zx::channel remote_endpoint;
zx_status_t status = zx::channel::create(0, &image_pipe_endpoint_, &remote_endpoint);
if (status != ZX_OK) {
FX_LOGF(ERROR, "ImagePipeView", "Init: failed to create channel (%d)", status);
return false;
}
std::vector<fuchsia::ui::scenic::Command> cmds;
PushCommand(&cmds, scenic::NewCreateViewCmd(kViewId, std::move(view_token), "imagepipe_view"));
PushCommand(&cmds, scenic::NewCreateEntityNodeCmd(kRootNodeId));
PushCommand(&cmds, scenic::NewAddChildCmd(kViewId, kRootNodeId));
PushCommand(&cmds, scenic::NewCreateMaterialCmd(kMaterialId));
PushCommand(&cmds, scenic::NewCreateImagePipe2Cmd(
kImagePipeId, fidl::InterfaceRequest<fuchsia::images::ImagePipe2>(
std::move(remote_endpoint))));
PushCommand(&cmds, scenic::NewSetTextureCmd(kMaterialId, kImagePipeId));
PushCommand(&cmds, scenic::NewCreateShapeNodeCmd(kShapeNodeId));
PushCommand(&cmds, scenic::NewSetMaterialCmd(kShapeNodeId, kMaterialId));
PushCommand(&cmds, scenic::NewAddChildCmd(kRootNodeId, kShapeNodeId));
session_->Enqueue(std::move(cmds));
session_->Present(0, // presentation time
{}, // acquire fences
{}, // release fences
[](fuchsia::images::PresentationInfo info) {} // presentation callback
);
return true;
}
static bool IsViewPropertiesChangedEvent(const fuchsia::ui::scenic::Event& event) {
return (event.Which() == fuchsia::ui::scenic::Event::Tag::kGfx) &&
(event.gfx().Which() == fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged);
}
// |fuchsia::ui::scenic::SessionListener|
void ImagePipeView::OnScenicEvent(std::vector<fuchsia::ui::scenic::Event> events) {
for (auto& event : events) {
if (IsViewPropertiesChangedEvent(event)) {
OnViewPropertiesChanged(event.gfx().view_properties_changed().properties);
}
}
}
void ImagePipeView::OnViewPropertiesChanged(fuchsia::ui::gfx::ViewProperties vp) {
view_width_ =
(vp.bounding_box.max.x - vp.inset_from_max.x) - (vp.bounding_box.min.x + vp.inset_from_min.x);
view_height_ =
(vp.bounding_box.max.y - vp.inset_from_max.y) - (vp.bounding_box.min.y + vp.inset_from_min.y);
if (view_width_ == 0 || view_height_ == 0)
return;
std::vector<fuchsia::ui::scenic::Command> cmds;
int shape_id = new_resource_id_++;
PushCommand(&cmds, scenic::NewCreateRectangleCmd(shape_id, view_width_, view_height_));
PushCommand(&cmds, scenic::NewSetShapeCmd(kShapeNodeId, shape_id));
PushCommand(&cmds, scenic::NewReleaseResourceCmd(shape_id));
// Position is relative to the View's origin system.
const float center_x = view_width_ * .5f;
const float center_y = view_height_ * .5f;
constexpr float kBackgroundElevation = 0.f;
PushCommand(&cmds, scenic::NewSetTranslationCmd(kShapeNodeId,
{center_x, center_y, -kBackgroundElevation}));
session_->Enqueue(std::move(cmds));
session_->Present(0, // presentation time
{}, // acquire fences
{}, // release fences
[](fuchsia::images::PresentationInfo info) {} // presentation callback
);
resize_callback_(view_width_, view_height_);
}
// |fuchsia::ui::scenic::SessionListener|
void ImagePipeView::OnScenicError(std::string error) {
FX_LOGF(ERROR, "ImagePipeView", "OnScenicError: %s", error.c_str());
}
ImagePipeViewProviderService::ImagePipeViewProviderService(sys::ComponentContext* context,
CreateViewCallback create_view_callback)
: create_view_callback_(std::move(create_view_callback)) {
context->outgoing()->AddPublicService<fuchsia::ui::app::ViewProvider>(
[this](fidl::InterfaceRequest<fuchsia::ui::app::ViewProvider> request) {
this->HandleViewProviderRequest(std::move(request));
});
}
void ImagePipeViewProviderService::CreateView(
zx::eventpair view_token,
fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> incoming_services,
fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> outgoing_services) {
create_view_callback_(scenic::ToViewToken(std::move(view_token)));
}
void ImagePipeViewProviderService::HandleViewProviderRequest(
fidl::InterfaceRequest<fuchsia::ui::app::ViewProvider> request) {
bindings_.AddBinding(this, std::move(request));
}