blob: 172494e8180ba02f726e24981760163a60763001 [file] [log] [blame] [edit]
// Copyright 2017 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/bin/ui/sketchy/canvas.h"
#include "garnet/bin/ui/sketchy/frame.h"
#include "garnet/bin/ui/sketchy/resources/import_node.h"
#include "garnet/bin/ui/sketchy/resources/stroke.h"
#include "lib/escher/util/fuchsia_utils.h"
#include "lib/fsl/tasks/message_loop.h"
namespace sketchy_service {
CanvasImpl::CanvasImpl(scenic_lib::Session* session, escher::Escher* escher)
: session_(session),
shared_buffer_pool_(session, escher),
stroke_manager_(escher) {}
void CanvasImpl::Init(fidl::InterfaceHandle<sketchy::CanvasListener> listener) {
// TODO(MZ-269): unimplemented.
FXL_LOG(ERROR) << "Init: unimplemented.";
}
void CanvasImpl::Enqueue(fidl::VectorPtr<sketchy::Command> commands) {
// TODO: Use `AddAll()` when fidl::VectorPtr supports it.
for (size_t i = 0; i < commands->size(); ++i) {
commands_.push_back(std::move(commands->at(i)));
}
}
void CanvasImpl::Present(uint64_t presentation_time, PresentCallback callback) {
// TODO(MZ-269): Present() should behave the same way as Scenic. Specifically,
// Commands shouldn't be applied immediately. Instead a frame-request should
// be triggered and the Commands enqueue; when the corresponding frame is
// processed all Commands that are scheduled for the current frame's
// presentation time are applied.
for (auto it = commands_->begin(); it != commands_->end(); ++it) {
if (!ApplyCommand(std::move(*it))) {
fsl::MessageLoop::GetCurrent()->QuitNow();
}
}
commands_.reset();
callbacks_.push_back(std::move(callback));
RequestScenicPresent(presentation_time);
}
void CanvasImpl::RequestScenicPresent(uint64_t presentation_time) {
if (is_scenic_present_requested_) {
return;
}
is_scenic_present_requested_ = true;
auto session_callback = [this, callbacks = std::move(callbacks_)](
images::PresentationInfo info) {
FXL_DCHECK(is_scenic_present_requested_);
is_scenic_present_requested_ = false;
for (auto& callback : callbacks) {
callback(info);
}
RequestScenicPresent(info.presentation_time + info.presentation_interval);
};
callbacks_.clear();
auto frame = Frame(&shared_buffer_pool_);
if (frame.init_failed()) {
session_->Present(presentation_time, std::move(session_callback));
return;
}
stroke_manager_.Update(&frame);
frame.RequestScenicPresent(session_, presentation_time,
std::move(session_callback));
}
bool CanvasImpl::ApplyCommand(sketchy::Command command) {
switch (command.Which()) {
case sketchy::Command::Tag::kCreateResource:
return ApplyCreateResourceCommand(std::move(command.create_resource()));
case sketchy::Command::Tag::kReleaseResource:
return ApplyReleaseResourceCommand(std::move(command.release_resource()));
case sketchy::Command::Tag::kSetPath:
return ApplySetPathCommand(std::move(command.set_path()));
case sketchy::Command::Tag::kAddStroke:
return ApplyAddStrokeCommand(std::move(command.add_stroke()));
case sketchy::Command::Tag::kRemoveStroke:
return ApplyRemoveStrokeCommand(std::move(command.remove_stroke()));
case sketchy::Command::Tag::kBeginStroke:
return ApplyBeginStrokeCommand(std::move(command.begin_stroke()));
case sketchy::Command::Tag::kExtendStroke:
return ApplyExtendStrokeCommand(std::move(command.extend_stroke()));
case sketchy::Command::Tag::kFinishStroke:
return ApplyFinishStrokeCommand(std::move(command.finish_stroke()));
case sketchy::Command::Tag::kClearGroup:
return ApplyClearGroupCommand(std::move(command.clear_group()));
case sketchy::Command::Tag::kScenicImportResource:
return ApplyScenicImportResourceCommand(
std::move(command.scenic_import_resource()));
case sketchy::Command::Tag::kScenicAddChild:
return ApplyScenicAddChildCommand(std::move(command.scenic_add_child()));
default:
FXL_DCHECK(false) << "Unsupported op: "
<< static_cast<uint32_t>(command.Which());
return false;
}
}
bool CanvasImpl::ApplyCreateResourceCommand(
sketchy::CreateResourceCommand create_resource) {
switch (create_resource.args.Which()) {
case sketchy::ResourceArgs::Tag::kStroke:
return CreateStroke(create_resource.id, create_resource.args.stroke());
case sketchy::ResourceArgs::Tag::kStrokeGroup:
return CreateStrokeGroup(create_resource.id,
create_resource.args.stroke_group());
default:
FXL_DCHECK(false) << "Unsupported resource: "
<< static_cast<uint32_t>(create_resource.args.Which());
return false;
}
}
bool CanvasImpl::CreateStroke(ResourceId id, sketchy::Stroke stroke) {
return resource_map_.AddResource(
id, fxl::MakeRefCounted<Stroke>(stroke_manager_.stroke_tessellator(),
shared_buffer_pool_.factory()));
}
bool CanvasImpl::CreateStrokeGroup(ResourceId id,
sketchy::StrokeGroup stroke_group) {
return resource_map_.AddResource(id,
fxl::MakeRefCounted<StrokeGroup>(session_));
}
bool CanvasImpl::ApplyReleaseResourceCommand(
sketchy::ReleaseResourceCommand command) {
return resource_map_.RemoveResource(command.id);
}
bool CanvasImpl::ApplySetPathCommand(sketchy::SetStrokePathCommand command) {
auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id);
if (!stroke) {
FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!";
return false;
}
return stroke_manager_.SetStrokePath(
stroke, std::make_unique<StrokePath>(std::move(command.path)));
}
bool CanvasImpl::ApplyAddStrokeCommand(sketchy::AddStrokeCommand command) {
auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id);
if (!stroke) {
FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!";
return false;
}
auto group = resource_map_.FindResource<StrokeGroup>(command.group_id);
if (!group) {
FXL_LOG(ERROR) << "No StrokeGroup of id " << command.group_id
<< " was found!";
return false;
}
return stroke_manager_.AddStrokeToGroup(stroke, group);
}
bool CanvasImpl::ApplyRemoveStrokeCommand(
sketchy::RemoveStrokeCommand command) {
auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id);
if (!stroke) {
FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!";
return false;
}
auto group = resource_map_.FindResource<StrokeGroup>(command.group_id);
if (!group) {
FXL_LOG(ERROR) << "No StrokeGroup of id " << command.group_id
<< " was found!";
return false;
}
return stroke_manager_.RemoveStrokeFromGroup(stroke, group);
}
bool CanvasImpl::ApplyBeginStrokeCommand(sketchy::BeginStrokeCommand command) {
auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id);
if (!stroke) {
FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!";
return false;
}
const auto& pos = command.touch.position;
return stroke_manager_.BeginStroke(stroke, {pos.x, pos.y});
}
bool CanvasImpl::ApplyExtendStrokeCommand(
sketchy::ExtendStrokeCommand command) {
auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id);
if (!stroke) {
FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!";
return false;
}
std::vector<glm::vec2> pts;
pts.reserve(command.touches->size());
for (const auto& touch : *command.touches) {
pts.push_back({touch.position.x, touch.position.y});
}
return stroke_manager_.ExtendStroke(stroke, std::move(pts));
}
bool CanvasImpl::ApplyFinishStrokeCommand(
sketchy::FinishStrokeCommand command) {
auto stroke = resource_map_.FindResource<Stroke>(command.stroke_id);
if (!stroke) {
FXL_LOG(ERROR) << "No Stroke of id " << command.stroke_id << " was found!";
return false;
}
return stroke_manager_.FinishStroke(stroke);
}
bool CanvasImpl::ApplyClearGroupCommand(sketchy::ClearGroupCommand command) {
auto group = resource_map_.FindResource<StrokeGroup>(command.group_id);
if (!group) {
FXL_LOG(ERROR) << "No Group of id " << command.group_id << " was found!";
return false;
}
return stroke_manager_.ClearGroup(group);
}
bool CanvasImpl::ApplyScenicImportResourceCommand(
gfx::ImportResourceCommand import_resource) {
switch (import_resource.spec) {
case gfx::ImportSpec::NODE:
return ScenicImportNode(import_resource.id,
std::move(import_resource.token));
}
}
bool CanvasImpl::ScenicImportNode(ResourceId id, zx::eventpair token) {
// As a client of Scenic, Canvas creates an ImportNode given token.
auto node = fxl::MakeRefCounted<ImportNode>(session_, std::move(token));
resource_map_.AddResource(id, std::move(node));
return true;
}
bool CanvasImpl::ApplyScenicAddChildCommand(gfx::AddChildCommand add_child) {
auto import_node = resource_map_.FindResource<ImportNode>(add_child.node_id);
auto stroke_group =
resource_map_.FindResource<StrokeGroup>(add_child.child_id);
if (!import_node || !stroke_group) {
return false;
}
import_node->AddChild(stroke_group);
return stroke_manager_.AddNewGroup(stroke_group);
}
} // namespace sketchy_service