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

Commit 30aa3cc

Browse files
authored
[fuchsia][a11y] Set explicit hit regions in flatland embedder (#37338)
1 parent 54232a4 commit 30aa3cc

6 files changed

Lines changed: 458 additions & 78 deletions

File tree

shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ void FlatlandExternalViewEmbedder::PrerollCompositeEmbeddedView(
9393
zx_handle_t handle = static_cast<zx_handle_t>(view_id);
9494
FML_CHECK(frame_layers_.count(handle) == 0);
9595

96-
frame_layers_.emplace(std::make_pair(EmbedderLayerId{handle},
97-
EmbedderLayer(frame_size_, *params)));
96+
frame_layers_.emplace(std::make_pair(
97+
EmbedderLayerId{handle},
98+
EmbedderLayer(frame_size_, *params, flutter::RTreeFactory())));
9899
frame_composition_order_.push_back(handle);
99100
}
100101

@@ -125,8 +126,9 @@ void FlatlandExternalViewEmbedder::BeginFrame(
125126
frame_dpr_ = device_pixel_ratio;
126127

127128
// Create the root layer.
128-
frame_layers_.emplace(
129-
std::make_pair(kRootLayerId, EmbedderLayer(frame_size, std::nullopt)));
129+
frame_layers_.emplace(std::make_pair(
130+
kRootLayerId,
131+
EmbedderLayer(frame_size, std::nullopt, flutter::RTreeFactory())));
130132
frame_composition_order_.push_back(kRootLayerId);
131133
}
132134

@@ -193,6 +195,19 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
193195
}
194196
}
195197

198+
// Finish recording SkPictures.
199+
{
200+
TRACE_EVENT0("flutter", "FinishRecordingPictures");
201+
202+
for (const auto& surface_index : frame_surface_indices) {
203+
const auto& layer = frame_layers_.find(surface_index.first);
204+
FML_CHECK(layer != frame_layers_.end());
205+
layer->second.picture =
206+
layer->second.recorder->finishRecordingAsPicture();
207+
FML_CHECK(layer->second.picture != nullptr);
208+
}
209+
}
210+
196211
// Submit layers and platform views to Scenic in composition order.
197212
{
198213
TRACE_EVENT0("flutter", "SubmitLayers");
@@ -334,30 +349,43 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
334349
? fuchsia::ui::composition::BlendMode::SRC
335350
: fuchsia::ui::composition::BlendMode::SRC_OVER);
336351

352+
// Set hit regions for this layer; these hit regions correspond to the
353+
// portions of the layer on which skia drew content.
354+
{
355+
FML_CHECK(layer->second.rtree);
356+
std::list<SkRect> intersection_rects =
357+
layer->second.rtree->searchNonOverlappingDrawnRects(
358+
SkRect::Make(layer->second.surface_size));
359+
360+
std::vector<fuchsia::ui::composition::HitRegion> hit_regions;
361+
for (const SkRect& rect : intersection_rects) {
362+
hit_regions.emplace_back();
363+
auto& new_hit_region = hit_regions.back();
364+
new_hit_region.region.x = rect.x();
365+
new_hit_region.region.y = rect.y();
366+
new_hit_region.region.width = rect.width();
367+
new_hit_region.region.height = rect.height();
368+
new_hit_region.hit_test =
369+
fuchsia::ui::composition::HitTestInteraction::DEFAULT;
370+
}
371+
372+
flatland_->flatland()->SetHitRegions(
373+
flatland_layers_[flatland_layer_index].transform_id,
374+
std::move(hit_regions));
375+
}
376+
337377
// Attach the FlatlandLayer to the main scene graph.
338378
flatland_->flatland()->AddChild(
339379
root_transform_id_,
340380
flatland_layers_[flatland_layer_index].transform_id);
341381
child_transforms_.emplace_back(
342382
flatland_layers_[flatland_layer_index].transform_id);
343-
344-
// Attach full-screen hit testing shield. Note that since the hit-region
345-
// may be transformed (translated, rotated), we do not want to set
346-
// width/height to FLT_MAX. This will cause a numeric overflow.
347-
flatland_->flatland()->SetHitRegions(
348-
flatland_layers_[flatland_layer_index].transform_id,
349-
{{{0, 0, kMaxHitRegionSize, kMaxHitRegionSize},
350-
fuchsia::ui::composition::HitTestInteraction::
351-
SEMANTICALLY_INVISIBLE}});
352383
}
353384

354385
// Reset for the next pass:
355386
flatland_layer_index++;
356387
}
357388

358-
// TODO(fxbug.dev/104956): Setting per-layer overlay hit region for Flatland
359-
// external view embedder should match with what is being done in GFX
360-
// external view embedder.
361389
// Set up the input interceptor at the top of the
362390
// scene, if applicable. It will capture all input, and any unwanted input
363391
// will be reinjected into embedded views.
@@ -396,13 +424,10 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
396424

397425
const auto& layer = frame_layers_.find(surface_index.first);
398426
FML_CHECK(layer != frame_layers_.end());
399-
sk_sp<SkPicture> picture =
400-
layer->second.recorder->finishRecordingAsPicture();
401-
FML_CHECK(picture != nullptr);
402427

403428
canvas->setMatrix(SkMatrix::I());
404429
canvas->clear(SK_ColorTRANSPARENT);
405-
canvas->drawPicture(picture);
430+
canvas->drawPicture(layer->second.picture);
406431
canvas->flush();
407432
}
408433
}

shell/platform/fuchsia/flutter/flatland_external_view_embedder.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <vector>
1818

1919
#include "flutter/flow/embedded_views.h"
20+
#include "flutter/flow/rtree.h"
2021
#include "flutter/fml/logging.h"
2122
#include "flutter/fml/macros.h"
2223
#include "flutter/shell/common/canvas_spy.h"
@@ -144,18 +145,29 @@ class FlatlandExternalViewEmbedder final
144145

145146
struct EmbedderLayer {
146147
EmbedderLayer(const SkISize& frame_size,
147-
std::optional<flutter::EmbeddedViewParams> view_params)
148-
: embedded_view_params(std::move(view_params)),
148+
std::optional<flutter::EmbeddedViewParams> view_params,
149+
flutter::RTreeFactory rtree_factory)
150+
: rtree(rtree_factory.getInstance()),
151+
embedded_view_params(std::move(view_params)),
149152
recorder(std::make_unique<SkPictureRecorder>()),
150153
canvas_spy(std::make_unique<flutter::CanvasSpy>(
151-
recorder->beginRecording(frame_size.width(),
152-
frame_size.height()))),
153-
surface_size(frame_size) {}
154+
recorder->beginRecording(SkRect::Make(frame_size),
155+
&rtree_factory))),
156+
surface_size(frame_size),
157+
picture(nullptr) {}
158+
159+
// Records paint operations applied to this layer's `SkCanvas`.
160+
// These records are used to determine which portions of this layer
161+
// contain content. The embedder propagates this information to scenic, so
162+
// that scenic can accurately decide which portions of this layer may
163+
// interact with input.
164+
sk_sp<flutter::RTree> rtree;
154165

155166
std::optional<flutter::EmbeddedViewParams> embedded_view_params;
156167
std::unique_ptr<SkPictureRecorder> recorder;
157168
std::unique_ptr<flutter::CanvasSpy> canvas_spy;
158169
SkISize surface_size;
170+
sk_sp<SkPicture> picture;
159171
};
160172
using EmbedderLayerId = std::optional<uint32_t>;
161173
constexpr static EmbedderLayerId kRootLayerId = EmbedderLayerId{};

shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ void FakeFlatland::SetHitRegions(
850850

851851
auto& transform = found_transform->second;
852852
FML_CHECK(transform);
853-
transform->num_hit_regions = regions.size();
853+
transform->hit_regions = std::move(regions);
854854
}
855855

856856
void FakeFlatland::Clear() {

shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ std::shared_ptr<FakeTransform> CloneFakeTransform(
7272
.children = CloneFakeTransformVector(
7373
transform->children, transform_cache),
7474
.content = CloneFakeContent(transform->content),
75-
.num_hit_regions = transform->num_hit_regions,
75+
.hit_regions = transform->hit_regions,
7676
}));
7777
FML_CHECK(success);
7878

@@ -136,7 +136,7 @@ bool FakeTransform::operator==(const FakeTransform& other) const {
136136
return id == other.id && translation == other.translation &&
137137
*clip_bounds == *other.clip_bounds &&
138138
orientation == other.orientation && children == other.children &&
139-
content == other.content && num_hit_regions == other.num_hit_regions;
139+
content == other.content && hit_regions == other.hit_regions;
140140
}
141141

142142
bool FakeGraph::operator==(const FakeGraph& other) const {

shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <lib/fidl/cpp/interface_request.h>
1616
#include <zircon/types.h>
1717

18+
#include <algorithm>
1819
#include <cstdint>
1920
#include <optional>
2021
#include <unordered_map>
@@ -98,6 +99,31 @@ inline bool operator==(const fuchsia::ui::composition::ImageProperties& a,
9899
return size_equal;
99100
}
100101

102+
inline bool operator==(const fuchsia::ui::composition::HitRegion& a,
103+
const fuchsia::ui::composition::HitRegion& b) {
104+
return a.region == b.region && a.hit_test == b.hit_test;
105+
}
106+
107+
inline bool operator!=(const fuchsia::ui::composition::HitRegion& a,
108+
const fuchsia::ui::composition::HitRegion& b) {
109+
return !(a == b);
110+
}
111+
112+
inline bool operator==(
113+
const std::vector<fuchsia::ui::composition::HitRegion>& a,
114+
const std::vector<fuchsia::ui::composition::HitRegion>& b) {
115+
if (a.size() != b.size())
116+
return false;
117+
118+
for (size_t i = 0; i < a.size(); ++i) {
119+
if (a[i] != b[i]) {
120+
return false;
121+
}
122+
}
123+
124+
return true;
125+
}
126+
101127
namespace flutter_runner::testing {
102128

103129
constexpr static fuchsia::ui::composition::TransformId kInvalidTransformId{0};
@@ -194,7 +220,7 @@ struct FakeTransform {
194220

195221
std::vector<std::shared_ptr<FakeTransform>> children;
196222
std::shared_ptr<FakeContent> content;
197-
size_t num_hit_regions;
223+
std::vector<fuchsia::ui::composition::HitRegion> hit_regions;
198224
};
199225

200226
struct FakeGraph {

0 commit comments

Comments
 (0)