blob: 14e6bf6dedeb99c0e9e22b09c872543f168a3ae2 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_FAKES_SCENIC_FAKE_SESSION_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_FAKES_SCENIC_FAKE_SESSION_H_
#include <fuchsia/images/cpp/fidl.h>
#include <fuchsia/scenic/scheduling/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl_test_base.h>
#include <lib/async/dispatcher.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/interface_handle.h>
#include <lib/fidl/cpp/interface_request.h>
#include <deque>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility> // For std::pair
#include <vector>
#include "flutter/fml/macros.h"
#include "fake_resources.h"
namespace flutter_runner::testing {
// A lightweight fake implementation of the scenic Session API, also called
// the "gfx API". The fake has no side effects besides mutating its own
// internal state.
//
// The fake allows tests to do a few things that would be difficult using either
// a mock implementation or the real implementation:
// + It allows the user to hook `Present` invocations and respond with
// stubbed-out `FuturePresentationTimes`, but more crucially it mimics the
// real scenic behavior of only processing commands when a `Present` is
// invoked.
// + It allows the user to inspect a snapshot of the session's local scene
// graph at any moment in time, via the `SceneGraph()` accessor.
// + The resources returned by `SceneGraph()` that the test uses for
// inspection are decoupled from the resources managed internally by the
// `FakeSession` itself -- they are a snapshot of the scene graph at that
// moment in time, with all snapshot state being cloned from the underlying
// scene graph state. This allows the `FakeSession` and test to naturally use
// `shared_ptr` for reference counting and mimic the real scenic behavior
// exactly, instead of an awkward index-based API.
// + It stores the various session resources generated by commands into a
// std::unordered_map, and also correctly manages the resource lifetimes via
// reference counting. This allows a resource to stay alive if its parent
// still holds a reference to it, in the same way the real scenic
// implementation would.
//
// Limitations:
// +Error handling / session disconnection is still WIP. FakeSession will
// likely generate a CHECK in any place where the real scenic would disconnect
// the session or send a ScenicError.
// +root_presenter-only commands e.g. CreateLayer are not handled.
// +Deprecated / obsolete commands are not handled.
// +Input is not handled.
// +Rendering is not handled.
// +Cross-session links are not handled; the FakeSession only stores the
// tokens provided to it in a FakeResourceState.
class FakeSession : public fuchsia::ui::scenic::testing::Session_TestBase {
public:
using PresentHandler =
std::function<fuchsia::images::PresentationInfo(uint64_t,
std::vector<zx::event>,
std::vector<zx::event>)>;
using Present2Handler =
std::function<fuchsia::scenic::scheduling::FuturePresentationTimes(
fuchsia::ui::scenic::Present2Args)>;
using RequestPresentationTimesHandler =
std::function<fuchsia::scenic::scheduling::FuturePresentationTimes(
int64_t)>;
using SessionAndListenerClientPair =
std::pair<fidl::InterfaceHandle<fuchsia::ui::scenic::Session>,
fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener>>;
FakeSession();
~FakeSession() override = default;
bool is_bound() const { return binding_.is_bound() && listener_.is_bound(); }
const std::string& debug_name() const { return debug_name_; }
const std::deque<fuchsia::ui::scenic::Command>& command_queue() const {
return command_queue_;
}
// Generate a snapshot of the underlying scene graph for test inspection.
FakeSceneGraph SceneGraph() const {
return SceneGraphFromState(scene_graph_);
}
// Bind this session's FIDL channels to the `dispatcher` and allow processing
// of incoming FIDL requests.
SessionAndListenerClientPair Bind(async_dispatcher_t* dispatcher = nullptr);
// Set a handler for `Present`-related FIDL calls' return values.
void SetPresentHandler(PresentHandler present_handler);
void SetPresent2Handler(Present2Handler present2_handler);
void SetRequestPresentationTimesHandler(
RequestPresentationTimesHandler request_presentation_times_handler);
// Call after a successful `Present` or `Present2` to fire an
// `OnFramePresented` event, which simulates the frame being displayed.
void FireOnFramePresentedEvent(
fuchsia::scenic::scheduling::FramePresentedInfo frame_presented_info);
// Disconnect the session with an error.
// TODO: Call this internally upon command error, instead of CHECK'ing.
void DisconnectSession();
private:
// |fuchsia::ui::scenic::testing::Session_TestBase|
void NotImplemented_(const std::string& name) override;
// |fuchsia::ui::scenic::Session|
void Enqueue(std::vector<fuchsia::ui::scenic::Command> cmds) override;
// |fuchsia::ui::scenic::Session|
void Present(uint64_t presentation_time,
std::vector<zx::event> acquire_fences,
std::vector<zx::event> release_fences,
PresentCallback callback) override;
// |fuchsia::ui::scenic::Session|
void Present2(fuchsia::ui::scenic::Present2Args args,
Present2Callback callback) override;
// |fuchsia::ui::scenic::Session|
void RequestPresentationTimes(
int64_t requested_prediction_span,
RequestPresentationTimesCallback callback) override;
// |fuchsia::ui::scenic::Session|
void RegisterBufferCollection(
uint32_t buffer_id,
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token)
override;
// |fuchsia::ui::scenic::Session|
void DeregisterBufferCollection(uint32_t buffer_id) override;
// |fuchsia::ui::scenic::Session|
void SetDebugName(std::string debug_name) override;
// Resource management.
std::shared_ptr<FakeResourceState> GetResource(FakeResourceId id);
void AddResource(FakeResourceState&& resource);
void DetachResourceFromParent(
std::shared_ptr<FakeResourceState> resource_ptr,
std::shared_ptr<FakeResourceState> new_parent_ptr = nullptr);
void PruneDeletedResourceRefs();
// Apply queued commands and mutate the resource map.
void ApplyCommands();
void ApplyCreateResourceCmd(fuchsia::ui::gfx::CreateResourceCmd command);
void ApplyReleaseResourceCmd(fuchsia::ui::gfx::ReleaseResourceCmd command);
void ApplyAddChildCmd(fuchsia::ui::gfx::AddChildCmd command);
void ApplyDetachCmd(fuchsia::ui::gfx::DetachCmd command);
void ApplyDetachChildrenCmd(fuchsia::ui::gfx::DetachChildrenCmd command);
void ApplySetTranslationCmd(fuchsia::ui::gfx::SetTranslationCmd command);
void ApplySetScaleCmd(fuchsia::ui::gfx::SetScaleCmd command);
void ApplySetRotationCmd(fuchsia::ui::gfx::SetRotationCmd command);
void ApplySetAnchorCmd(fuchsia::ui::gfx::SetAnchorCmd command);
void ApplySetOpacityCmd(fuchsia::ui::gfx::SetOpacityCmd command);
void ApplySetShapeCmd(fuchsia::ui::gfx::SetShapeCmd command);
void ApplySetMaterialCmd(fuchsia::ui::gfx::SetMaterialCmd command);
void ApplySetClipPlanesCmd(fuchsia::ui::gfx::SetClipPlanesCmd command);
void ApplySetViewPropertiesCmd(
fuchsia::ui::gfx::SetViewPropertiesCmd command);
void ApplySetHitTestBehaviorCmd(
fuchsia::ui::gfx::SetHitTestBehaviorCmd command);
void ApplySetSemanticVisibilityCmd(
fuchsia::ui::gfx::SetSemanticVisibilityCmd command);
void ApplySetTextureCmd(fuchsia::ui::gfx::SetTextureCmd command);
void ApplySetColorCmd(fuchsia::ui::gfx::SetColorCmd command);
void ApplySetEventMaskCmd(fuchsia::ui::gfx::SetEventMaskCmd command);
void ApplySetLabelCmd(fuchsia::ui::gfx::SetLabelCmd command);
void ApplySetEnableViewDebugBoundsCmd(
fuchsia::ui::gfx::SetEnableDebugViewBoundsCmd command);
void ApplySetViewHolderBoundsColorCmd(
fuchsia::ui::gfx::SetViewHolderBoundsColorCmd command);
void ApplyCreateMemory(FakeResourceId id, fuchsia::ui::gfx::MemoryArgs args);
void ApplyCreateImage(FakeResourceId id, fuchsia::ui::gfx::ImageArgs args);
void ApplyCreateImage2(FakeResourceId id, fuchsia::ui::gfx::ImageArgs2 args);
void ApplyCreateImage3(FakeResourceId id, fuchsia::ui::gfx::ImageArgs3 args);
void ApplyCreateImagePipe(FakeResourceId id,
fuchsia::ui::gfx::ImagePipeArgs args);
void ApplyCreateImagePipe2(FakeResourceId id,
fuchsia::ui::gfx::ImagePipe2Args args);
void ApplyCreateRectangle(FakeResourceId id,
fuchsia::ui::gfx::RectangleArgs args);
void ApplyCreateRoundedRectangle(FakeResourceId id,
fuchsia::ui::gfx::RoundedRectangleArgs args);
void ApplyCreateCircle(FakeResourceId id, fuchsia::ui::gfx::CircleArgs args);
void ApplyCreateMaterial(FakeResourceId id,
fuchsia::ui::gfx::MaterialArgs args);
void ApplyCreateView(FakeResourceId id, fuchsia::ui::gfx::ViewArgs args);
void ApplyCreateViewHolder(FakeResourceId id,
fuchsia::ui::gfx::ViewHolderArgs args);
void ApplyCreateView(FakeResourceId id, fuchsia::ui::gfx::ViewArgs3 args);
void ApplyCreateEntityNode(FakeResourceId id,
fuchsia::ui::gfx::EntityNodeArgs args);
void ApplyCreateOpacityNode(FakeResourceId id,
fuchsia::ui::gfx::OpacityNodeArgsHACK args);
void ApplyCreateShapeNode(FakeResourceId id,
fuchsia::ui::gfx::ShapeNodeArgs args);
fidl::Binding<fuchsia::ui::scenic::Session> binding_;
fuchsia::ui::scenic::SessionListenerPtr listener_;
std::string debug_name_;
FakeSceneGraphState scene_graph_;
std::deque<fuchsia::ui::scenic::Command> command_queue_;
// This map is used to cache parent refs for `AddChildCmd`.
//
// Ideally we would like to map weak(parent) -> weak(child), but std::weak_ptr
// cannot be the Key for an associative container. Instead we key on the raw
// parent pointer and store pair(weak(parent), weak(child)) in the map.
std::unordered_map<FakeResourceState*,
std::pair<std::weak_ptr<FakeResourceState>,
std::weak_ptr<FakeResourceState>>>
parents_map_;
PresentHandler present_handler_;
Present2Handler present2_handler_;
RequestPresentationTimesHandler request_presentation_times_handler_;
FML_DISALLOW_COPY_AND_ASSIGN(FakeSession);
};
} // namespace flutter_runner::testing
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_FLUTTER_TESTS_FAKES_SCENIC_FAKE_SESSION_H_