未验证 提交 7a7804b6 编写于 作者: M mikaelpessa 提交者: GitHub

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

上级 bb32446c
......@@ -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);
......@@ -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() {
......
......@@ -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_; }
......@@ -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,
......@@ -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);
};
......
......@@ -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.";
......@@ -143,7 +144,8 @@ 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
{
......@@ -151,7 +153,7 @@ Engine::Engine(Delegate& delegate,
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();
}));
......
......@@ -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_;
......
......@@ -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(),
......@@ -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();
}
......@@ -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(
......@@ -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;
......@@ -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());
......@@ -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);
......@@ -437,6 +466,8 @@ void FuchsiaExternalViewEmbedder::Reset() {
for (auto& layer : scenic_layers_) {
layer.material.SetTexture(0);
}
input_interceptor_.reset();
}
} // namespace flutter_runner
......@@ -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|
......@@ -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{};
......@@ -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);
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册