Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Add "input shield" to capture pointer input for reinjection #22067

Merged
merged 7 commits into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions flow/scene_update_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,16 @@ void SetMaterialColor(scenic::Material& material,
SceneUpdateContext::SceneUpdateContext(std::string debug_label,
fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair,
SessionWrapper& session)
SessionWrapper& session,
bool intercept_all_input)
: session_(session),
root_view_(session_.get(),
std::move(view_token),
std::move(view_ref_pair.control_ref),
std::move(view_ref_pair.view_ref),
debug_label),
root_node_(session_.get()) {
root_node_(session_.get()),
intercept_all_input_(intercept_all_input) {
root_view_.AddChild(root_node_);
root_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);

Expand Down Expand Up @@ -317,6 +319,14 @@ SceneUpdateContext::Frame::Frame(std::shared_ptr<SceneUpdateContext> context,
// with opacity != 1. For now, clamp to a infinitesimally smaller value than
// 1, which does not cause visual problems in practice.
opacity_node_.SetOpacity(std::min(kOneMinusEpsilon, opacity_ / 255.0f));

if (context->intercept_all_input_) {
context->input_interceptor_.emplace(context->session_.get());
context->input_interceptor_->UpdateDimensions(
context->session_.get(), rrect.width(), rrect.height(),
-(local_elevation + kScenicZElevationBetweenLayers * 0.5f));
entity_node().AddChild(context->input_interceptor_->node());
}
}

SceneUpdateContext::Frame::~Frame() {
Expand Down
40 changes: 39 additions & 1 deletion flow/scene_update_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ class SceneUpdateContext : public flutter::ExternalViewEmbedder {
SceneUpdateContext(std::string debug_label,
fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair,
SessionWrapper& session);
SessionWrapper& session,
bool intercept_all_input = false);
~SceneUpdateContext() = default;

scenic::ContainerNode& root_node() { return root_node_; }
Expand Down Expand Up @@ -177,6 +178,40 @@ class SceneUpdateContext : public flutter::ExternalViewEmbedder {
std::optional<bool> override_hit_testable = std::nullopt);

private:
// Helper class for setting up an invisible rectangle to catch all input.
// Rejected input will then be re-injected into a suitable platform view
// controlled by this Engine instance.
class InputInterceptor {
public:
InputInterceptor(scenic::Session* session)
: opacity_node_(session), shape_node_(session) {
opacity_node_.SetLabel("Flutter::InputInterceptor");
opacity_node_.SetOpacity(0.f);

// Set the shape node to capture all input. Any unwanted input will be
// reinjected.
shape_node_.SetHitTestBehavior(
fuchsia::ui::gfx::HitTestBehavior::kDefault);
shape_node_.SetSemanticVisibility(false);

opacity_node_.AddChild(shape_node_);
}

void UpdateDimensions(scenic::Session* session,
float width,
float height,
float elevation) {
opacity_node_.SetTranslation(width * 0.5f, height * 0.5f, elevation);
shape_node_.SetShape(scenic::Rectangle(session, width, height));
}

const scenic::Node& node() { return opacity_node_; }

private:
scenic::OpacityNodeHACK opacity_node_;
scenic::ShapeNode shape_node_;
};

void CreateFrame(scenic::EntityNode& entity_node,
const SkRRect& rrect,
SkColor color,
Expand All @@ -199,6 +234,9 @@ class SceneUpdateContext : public flutter::ExternalViewEmbedder {
float next_elevation_ = 0.f;
float alpha_ = 1.f;

std::optional<InputInterceptor> input_interceptor_;
bool intercept_all_input_ = false;

FML_DISALLOW_COPY_AND_ASSIGN(SceneUpdateContext);
};

Expand Down
6 changes: 4 additions & 2 deletions shell/platform/fuchsia/flutter/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Engine::Engine(Delegate& delegate,
#if defined(LEGACY_FUCHSIA_EMBEDDER)
use_legacy_renderer_(product_config.use_legacy_renderer()),
#endif
intercept_all_input_(product_config.get_intercept_all_input()),
weak_factory_(this) {
if (zx::event::create(0, &vsync_event_) != ZX_OK) {
FML_DLOG(ERROR) << "Could not create the vsync event.";
Expand Down Expand Up @@ -143,15 +144,16 @@ Engine::Engine(Delegate& delegate,
legacy_external_view_embedder_ =
std::make_shared<flutter::SceneUpdateContext>(
thread_label_, std::move(view_token),
std::move(view_ref_pair), session_connection_.value());
std::move(view_ref_pair), session_connection_.value(),
intercept_all_input_);
} else
#endif
{
external_view_embedder_ =
std::make_shared<FuchsiaExternalViewEmbedder>(
thread_label_, std::move(view_token),
std::move(view_ref_pair), session_connection_.value(),
surface_producer_.value());
surface_producer_.value(), intercept_all_input_);
}
view_embedder_latch.Signal();
}));
Expand Down
1 change: 1 addition & 0 deletions shell/platform/fuchsia/flutter/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class Engine final {
#if defined(LEGACY_FUCHSIA_EMBEDDER)
bool use_legacy_renderer_ = true;
#endif
bool intercept_all_input_ = false;

fml::WeakPtrFactory<Engine> weak_factory_;

Expand Down
37 changes: 34 additions & 3 deletions shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ FuchsiaExternalViewEmbedder::FuchsiaExternalViewEmbedder(
fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair,
SessionConnection& session,
VulkanSurfaceProducer& surface_producer)
VulkanSurfaceProducer& surface_producer,
bool intercept_all_input)
: session_(session),
surface_producer_(surface_producer),
root_view_(session_.get(),
Expand All @@ -38,13 +39,20 @@ FuchsiaExternalViewEmbedder::FuchsiaExternalViewEmbedder(
std::move(view_ref_pair.view_ref),
debug_label),
metrics_node_(session_.get()),
root_node_(session_.get()) {
root_node_(session_.get()),
intercept_all_input_(intercept_all_input) {
root_view_.AddChild(metrics_node_);
metrics_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
metrics_node_.SetLabel("Flutter::MetricsWatcher");
metrics_node_.AddChild(root_node_);
root_node_.SetLabel("Flutter::LayerTree");

// Set up the input interceptor at the top of the scene, if applicable.
if (intercept_all_input_) {
input_interceptor_.emplace(session_.get());
metrics_node_.AddChild(input_interceptor_->node());
}

session_.Present();
}

Expand Down Expand Up @@ -114,6 +122,15 @@ void FuchsiaExternalViewEmbedder::BeginFrame(
frame_layers_.emplace(
std::make_pair(kRootLayerId, EmbedderLayer(frame_size, std::nullopt)));
frame_composition_order_.push_back(kRootLayerId);

// Set up the input interceptor at the top of the scene, if applicable.
if (input_interceptor_.has_value()) {
// TODO: Don't hardcode elevation.
const float kMaximumElevation = -100.f;
input_interceptor_->UpdateDimensions(session_.get(), frame_size.width(),
frame_size.height(),
kMaximumElevation);
}
}

void FuchsiaExternalViewEmbedder::EndFrame(
Expand All @@ -126,7 +143,6 @@ void FuchsiaExternalViewEmbedder::SubmitFrame(
GrDirectContext* context,
std::unique_ptr<flutter::SurfaceFrame> frame) {
TRACE_EVENT0("flutter", "FuchsiaExternalViewEmbedder::SubmitFrame");

std::vector<std::unique_ptr<SurfaceProducerSurface>> frame_surfaces;
std::unordered_map<EmbedderLayerId, size_t> frame_surface_indices;

Expand Down Expand Up @@ -164,6 +180,7 @@ void FuchsiaExternalViewEmbedder::SubmitFrame(
const float inv_dpr = 1.0f / frame_dpr_;
root_node_.SetScale(inv_dpr, inv_dpr, 1.0f);

bool first_layer = true;
for (const auto& layer_id : frame_composition_order_) {
const auto& layer = frame_layers_.find(layer_id);
FML_DCHECK(layer != frame_layers_.end());
Expand Down Expand Up @@ -324,6 +341,18 @@ void FuchsiaExternalViewEmbedder::SubmitFrame(
SK_AlphaOPAQUE, SK_AlphaOPAQUE - 1);
scenic_layer.material.SetTexture(*surface_image);

// Only the first (i.e. the bottom-most) layer should receive input.
// TODO: Workaround for invisible overlays stealing input. Remove when
// the underlying bug is fixed.
if (first_layer) {
scenic_layer.shape_node.SetHitTestBehavior(
fuchsia::ui::gfx::HitTestBehavior::kDefault);
} else {
scenic_layer.shape_node.SetHitTestBehavior(
fuchsia::ui::gfx::HitTestBehavior::kSuppress);
}
first_layer = false;

// Attach the ScenicLayer to the main scene graph.
root_node_.AddChild(scenic_layer.shape_node);

Expand Down Expand Up @@ -437,6 +466,8 @@ void FuchsiaExternalViewEmbedder::Reset() {
for (auto& layer : scenic_layers_) {
layer.material.SetTexture(0);
}

input_interceptor_.reset();
}

} // namespace flutter_runner
41 changes: 40 additions & 1 deletion shell/platform/fuchsia/flutter/fuchsia_external_view_embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class FuchsiaExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
fuchsia::ui::views::ViewToken view_token,
scenic::ViewRefPair view_ref_pair,
SessionConnection& session,
VulkanSurfaceProducer& surface_producer);
VulkanSurfaceProducer& surface_producer,
bool intercept_all_input = false);
~FuchsiaExternalViewEmbedder();

// |ExternalViewEmbedder|
Expand Down Expand Up @@ -131,6 +132,40 @@ class FuchsiaExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
scenic::Material material;
};

// Helper class for setting up an invisible rectangle to catch all input.
// Rejected input will then be re-injected into a suitable platform view
// controlled by this Engine instance.
class InputInterceptor {
public:
InputInterceptor(scenic::Session* session)
: opacity_node_(session), shape_node_(session) {
opacity_node_.SetLabel("Flutter::InputInterceptor");
opacity_node_.SetOpacity(0.5f);

// Set the shape node to capture all input. Any unwanted input will be
// reinjected.
shape_node_.SetHitTestBehavior(
fuchsia::ui::gfx::HitTestBehavior::kDefault);
shape_node_.SetSemanticVisibility(false);

opacity_node_.AddChild(shape_node_);
}

void UpdateDimensions(scenic::Session* session,
float width,
float height,
float elevation) {
opacity_node_.SetTranslation(width * 0.5f, height * 0.5f, elevation);
shape_node_.SetShape(scenic::Rectangle(session, width, height));
}

const scenic::Node& node() { return opacity_node_; }

private:
scenic::OpacityNodeHACK opacity_node_;
scenic::ShapeNode shape_node_;
};

using EmbedderLayerId = std::optional<uint32_t>;
constexpr static EmbedderLayerId kRootLayerId = EmbedderLayerId{};

Expand All @@ -145,11 +180,15 @@ class FuchsiaExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
std::unordered_map<int64_t, ScenicView> scenic_views_;
std::vector<ScenicLayer> scenic_layers_;

std::optional<InputInterceptor> input_interceptor_;

std::unordered_map<EmbedderLayerId, EmbedderLayer> frame_layers_;
std::vector<EmbedderLayerId> frame_composition_order_;
SkISize frame_size_ = SkISize::Make(0, 0);
float frame_dpr_ = 1.f;

bool intercept_all_input_ = false;

FML_DISALLOW_COPY_AND_ASSIGN(FuchsiaExternalViewEmbedder);
};

Expand Down