| // 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> |
| #include <lib/ui/scenic/cpp/view_ref_pair.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, |
| fuchsia::ui::views::ViewRefControl control_ref, |
| fuchsia::ui::views::ViewRef view_ref, ResizeCallback resize_callback) { |
| if (!resize_callback) return nullptr; |
| |
| auto view = std::make_unique<ImagePipeView>(std::move(resize_callback)); |
| |
| if (!view->Init(context, std::move(view_token), std::move(control_ref), std::move(view_ref))) 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::views::ViewRefControl control_ref, fuchsia::ui::views::ViewRef view_ref) { |
| 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), std::move(control_ref), std::move(view_ref), |
| "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) { |
| auto [view_ref_control, view_ref] = scenic::ViewRefPair::New(); |
| CreateViewWithViewRef(std::move(view_token), std::move(view_ref_control), std::move(view_ref)); |
| } |
| |
| void ImagePipeViewProviderService::CreateViewWithViewRef(zx::eventpair view_token, |
| fuchsia::ui::views::ViewRefControl view_ref_control, |
| fuchsia::ui::views::ViewRef view_ref) { |
| create_view_callback_(scenic::ToViewToken(std::move(view_token)), std::move(view_ref_control), std::move(view_ref)); |
| } |
| |
| void ImagePipeViewProviderService::HandleViewProviderRequest(fidl::InterfaceRequest<fuchsia::ui::app::ViewProvider> request) { |
| bindings_.AddBinding(this, std::move(request)); |
| } |