[fuchsia][a11y] Set explicit hit regions in flatland embedder (flutter/engine#37338)
This commit is contained in:
committed by
GitHub
parent
6710befd88
commit
42fb1ed9d7
@@ -93,8 +93,9 @@ void FlatlandExternalViewEmbedder::PrerollCompositeEmbeddedView(
|
||||
zx_handle_t handle = static_cast<zx_handle_t>(view_id);
|
||||
FML_CHECK(frame_layers_.count(handle) == 0);
|
||||
|
||||
frame_layers_.emplace(std::make_pair(EmbedderLayerId{handle},
|
||||
EmbedderLayer(frame_size_, *params)));
|
||||
frame_layers_.emplace(std::make_pair(
|
||||
EmbedderLayerId{handle},
|
||||
EmbedderLayer(frame_size_, *params, flutter::RTreeFactory())));
|
||||
frame_composition_order_.push_back(handle);
|
||||
}
|
||||
|
||||
@@ -125,8 +126,9 @@ void FlatlandExternalViewEmbedder::BeginFrame(
|
||||
frame_dpr_ = device_pixel_ratio;
|
||||
|
||||
// Create the root layer.
|
||||
frame_layers_.emplace(
|
||||
std::make_pair(kRootLayerId, EmbedderLayer(frame_size, std::nullopt)));
|
||||
frame_layers_.emplace(std::make_pair(
|
||||
kRootLayerId,
|
||||
EmbedderLayer(frame_size, std::nullopt, flutter::RTreeFactory())));
|
||||
frame_composition_order_.push_back(kRootLayerId);
|
||||
}
|
||||
|
||||
@@ -193,6 +195,19 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
|
||||
}
|
||||
}
|
||||
|
||||
// Finish recording SkPictures.
|
||||
{
|
||||
TRACE_EVENT0("flutter", "FinishRecordingPictures");
|
||||
|
||||
for (const auto& surface_index : frame_surface_indices) {
|
||||
const auto& layer = frame_layers_.find(surface_index.first);
|
||||
FML_CHECK(layer != frame_layers_.end());
|
||||
layer->second.picture =
|
||||
layer->second.recorder->finishRecordingAsPicture();
|
||||
FML_CHECK(layer->second.picture != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Submit layers and platform views to Scenic in composition order.
|
||||
{
|
||||
TRACE_EVENT0("flutter", "SubmitLayers");
|
||||
@@ -334,30 +349,43 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
|
||||
? fuchsia::ui::composition::BlendMode::SRC
|
||||
: fuchsia::ui::composition::BlendMode::SRC_OVER);
|
||||
|
||||
// Set hit regions for this layer; these hit regions correspond to the
|
||||
// portions of the layer on which skia drew content.
|
||||
{
|
||||
FML_CHECK(layer->second.rtree);
|
||||
std::list<SkRect> intersection_rects =
|
||||
layer->second.rtree->searchNonOverlappingDrawnRects(
|
||||
SkRect::Make(layer->second.surface_size));
|
||||
|
||||
std::vector<fuchsia::ui::composition::HitRegion> hit_regions;
|
||||
for (const SkRect& rect : intersection_rects) {
|
||||
hit_regions.emplace_back();
|
||||
auto& new_hit_region = hit_regions.back();
|
||||
new_hit_region.region.x = rect.x();
|
||||
new_hit_region.region.y = rect.y();
|
||||
new_hit_region.region.width = rect.width();
|
||||
new_hit_region.region.height = rect.height();
|
||||
new_hit_region.hit_test =
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT;
|
||||
}
|
||||
|
||||
flatland_->flatland()->SetHitRegions(
|
||||
flatland_layers_[flatland_layer_index].transform_id,
|
||||
std::move(hit_regions));
|
||||
}
|
||||
|
||||
// Attach the FlatlandLayer to the main scene graph.
|
||||
flatland_->flatland()->AddChild(
|
||||
root_transform_id_,
|
||||
flatland_layers_[flatland_layer_index].transform_id);
|
||||
child_transforms_.emplace_back(
|
||||
flatland_layers_[flatland_layer_index].transform_id);
|
||||
|
||||
// Attach full-screen hit testing shield. Note that since the hit-region
|
||||
// may be transformed (translated, rotated), we do not want to set
|
||||
// width/height to FLT_MAX. This will cause a numeric overflow.
|
||||
flatland_->flatland()->SetHitRegions(
|
||||
flatland_layers_[flatland_layer_index].transform_id,
|
||||
{{{0, 0, kMaxHitRegionSize, kMaxHitRegionSize},
|
||||
fuchsia::ui::composition::HitTestInteraction::
|
||||
SEMANTICALLY_INVISIBLE}});
|
||||
}
|
||||
|
||||
// Reset for the next pass:
|
||||
flatland_layer_index++;
|
||||
}
|
||||
|
||||
// TODO(fxbug.dev/104956): Setting per-layer overlay hit region for Flatland
|
||||
// external view embedder should match with what is being done in GFX
|
||||
// external view embedder.
|
||||
// Set up the input interceptor at the top of the
|
||||
// scene, if applicable. It will capture all input, and any unwanted input
|
||||
// will be reinjected into embedded views.
|
||||
@@ -396,13 +424,10 @@ void FlatlandExternalViewEmbedder::SubmitFrame(
|
||||
|
||||
const auto& layer = frame_layers_.find(surface_index.first);
|
||||
FML_CHECK(layer != frame_layers_.end());
|
||||
sk_sp<SkPicture> picture =
|
||||
layer->second.recorder->finishRecordingAsPicture();
|
||||
FML_CHECK(picture != nullptr);
|
||||
|
||||
canvas->setMatrix(SkMatrix::I());
|
||||
canvas->clear(SK_ColorTRANSPARENT);
|
||||
canvas->drawPicture(picture);
|
||||
canvas->drawPicture(layer->second.picture);
|
||||
canvas->flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/flow/embedded_views.h"
|
||||
#include "flutter/flow/rtree.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/shell/common/canvas_spy.h"
|
||||
@@ -144,18 +145,29 @@ class FlatlandExternalViewEmbedder final
|
||||
|
||||
struct EmbedderLayer {
|
||||
EmbedderLayer(const SkISize& frame_size,
|
||||
std::optional<flutter::EmbeddedViewParams> view_params)
|
||||
: embedded_view_params(std::move(view_params)),
|
||||
std::optional<flutter::EmbeddedViewParams> view_params,
|
||||
flutter::RTreeFactory rtree_factory)
|
||||
: rtree(rtree_factory.getInstance()),
|
||||
embedded_view_params(std::move(view_params)),
|
||||
recorder(std::make_unique<SkPictureRecorder>()),
|
||||
canvas_spy(std::make_unique<flutter::CanvasSpy>(
|
||||
recorder->beginRecording(frame_size.width(),
|
||||
frame_size.height()))),
|
||||
surface_size(frame_size) {}
|
||||
recorder->beginRecording(SkRect::Make(frame_size),
|
||||
&rtree_factory))),
|
||||
surface_size(frame_size),
|
||||
picture(nullptr) {}
|
||||
|
||||
// Records paint operations applied to this layer's `SkCanvas`.
|
||||
// These records are used to determine which portions of this layer
|
||||
// contain content. The embedder propagates this information to scenic, so
|
||||
// that scenic can accurately decide which portions of this layer may
|
||||
// interact with input.
|
||||
sk_sp<flutter::RTree> rtree;
|
||||
|
||||
std::optional<flutter::EmbeddedViewParams> embedded_view_params;
|
||||
std::unique_ptr<SkPictureRecorder> recorder;
|
||||
std::unique_ptr<flutter::CanvasSpy> canvas_spy;
|
||||
SkISize surface_size;
|
||||
sk_sp<SkPicture> picture;
|
||||
};
|
||||
using EmbedderLayerId = std::optional<uint32_t>;
|
||||
constexpr static EmbedderLayerId kRootLayerId = EmbedderLayerId{};
|
||||
|
||||
@@ -850,7 +850,7 @@ void FakeFlatland::SetHitRegions(
|
||||
|
||||
auto& transform = found_transform->second;
|
||||
FML_CHECK(transform);
|
||||
transform->num_hit_regions = regions.size();
|
||||
transform->hit_regions = std::move(regions);
|
||||
}
|
||||
|
||||
void FakeFlatland::Clear() {
|
||||
|
||||
@@ -72,7 +72,7 @@ std::shared_ptr<FakeTransform> CloneFakeTransform(
|
||||
.children = CloneFakeTransformVector(
|
||||
transform->children, transform_cache),
|
||||
.content = CloneFakeContent(transform->content),
|
||||
.num_hit_regions = transform->num_hit_regions,
|
||||
.hit_regions = transform->hit_regions,
|
||||
}));
|
||||
FML_CHECK(success);
|
||||
|
||||
@@ -136,7 +136,7 @@ bool FakeTransform::operator==(const FakeTransform& other) const {
|
||||
return id == other.id && translation == other.translation &&
|
||||
*clip_bounds == *other.clip_bounds &&
|
||||
orientation == other.orientation && children == other.children &&
|
||||
content == other.content && num_hit_regions == other.num_hit_regions;
|
||||
content == other.content && hit_regions == other.hit_regions;
|
||||
}
|
||||
|
||||
bool FakeGraph::operator==(const FakeGraph& other) const {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <lib/fidl/cpp/interface_request.h>
|
||||
#include <zircon/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
@@ -98,6 +99,31 @@ inline bool operator==(const fuchsia::ui::composition::ImageProperties& a,
|
||||
return size_equal;
|
||||
}
|
||||
|
||||
inline bool operator==(const fuchsia::ui::composition::HitRegion& a,
|
||||
const fuchsia::ui::composition::HitRegion& b) {
|
||||
return a.region == b.region && a.hit_test == b.hit_test;
|
||||
}
|
||||
|
||||
inline bool operator!=(const fuchsia::ui::composition::HitRegion& a,
|
||||
const fuchsia::ui::composition::HitRegion& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator==(
|
||||
const std::vector<fuchsia::ui::composition::HitRegion>& a,
|
||||
const std::vector<fuchsia::ui::composition::HitRegion>& b) {
|
||||
if (a.size() != b.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < a.size(); ++i) {
|
||||
if (a[i] != b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace flutter_runner::testing {
|
||||
|
||||
constexpr static fuchsia::ui::composition::TransformId kInvalidTransformId{0};
|
||||
@@ -194,7 +220,7 @@ struct FakeTransform {
|
||||
|
||||
std::vector<std::shared_ptr<FakeTransform>> children;
|
||||
std::shared_ptr<FakeContent> content;
|
||||
size_t num_hit_regions;
|
||||
std::vector<fuchsia::ui::composition::HitRegion> hit_regions;
|
||||
};
|
||||
|
||||
struct FakeGraph {
|
||||
|
||||
@@ -202,6 +202,15 @@ Matcher<fuchsia::ui::composition::ViewportProperties> IsViewportProperties(
|
||||
inset));
|
||||
}
|
||||
|
||||
Matcher<fuchsia::ui::composition::HitRegion> IsHitRegion(
|
||||
const float x,
|
||||
const float y,
|
||||
const float width,
|
||||
const float height,
|
||||
const fuchsia::ui::composition::HitTestInteraction hit_test) {
|
||||
return FieldsAre(FieldsAre(x, y, width, height), hit_test);
|
||||
}
|
||||
|
||||
Matcher<FakeGraph> IsEmptyGraph() {
|
||||
return FieldsAre(IsEmpty(), IsEmpty(), Eq(nullptr), Eq(std::nullopt));
|
||||
}
|
||||
@@ -224,7 +233,7 @@ Matcher<FakeGraph> IsFlutterGraph(
|
||||
/*scale*/ scale, FakeTransform::kDefaultOrientation,
|
||||
/*clip_bounds*/ _, FakeTransform::kDefaultOpacity,
|
||||
/*children*/ ElementsAreArray(layer_matchers),
|
||||
/*content*/ Eq(nullptr), /*num_hit_regions*/ _)),
|
||||
/*content*/ Eq(nullptr), /*hit_regions*/ _)),
|
||||
Eq(FakeView{
|
||||
.view_token = viewport_token_koids.second,
|
||||
.view_ref = view_ref_koids.first,
|
||||
@@ -240,7 +249,8 @@ Matcher<FakeGraph> IsFlutterGraph(
|
||||
Matcher<std::shared_ptr<FakeTransform>> IsImageLayer(
|
||||
const fuchsia::math::SizeU& layer_size,
|
||||
fuchsia::ui::composition::BlendMode blend_mode,
|
||||
size_t num_hit_regions) {
|
||||
std::vector<Matcher<fuchsia::ui::composition::HitRegion>>
|
||||
hit_region_matchers) {
|
||||
return Pointee(FieldsAre(
|
||||
/*id*/ _, FakeTransform::kDefaultTranslation,
|
||||
FakeTransform::kDefaultScale, FakeTransform::kDefaultOrientation,
|
||||
@@ -252,7 +262,7 @@ Matcher<std::shared_ptr<FakeTransform>> IsImageLayer(
|
||||
FakeImage::kDefaultSampleRegion, layer_size,
|
||||
FakeImage::kDefaultOpacity, blend_mode,
|
||||
/*buffer_import_token*/ _, /*vmo_index*/ 0))),
|
||||
num_hit_regions));
|
||||
/* hit_regions*/ ElementsAreArray(hit_region_matchers)));
|
||||
}
|
||||
|
||||
Matcher<std::shared_ptr<FakeTransform>> IsViewportLayer(
|
||||
@@ -271,7 +281,7 @@ Matcher<std::shared_ptr<FakeTransform>> IsViewportLayer(
|
||||
/* id */ _, IsViewportProperties(view_logical_size, view_inset),
|
||||
/* viewport_token */ GetKoids(view_token).second,
|
||||
/* child_view_watcher */ _))),
|
||||
/*num_hit_regions*/ 0));
|
||||
/*hit_regions*/ _));
|
||||
}
|
||||
|
||||
fuchsia::ui::composition::OnNextFrameBeginValues WithPresentCredits(
|
||||
@@ -478,11 +488,21 @@ TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene) {
|
||||
|
||||
// Pump the message loop. The scene updates should propagate to flatland.
|
||||
loop().RunUntilIdle();
|
||||
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
}
|
||||
|
||||
TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) {
|
||||
@@ -598,10 +618,26 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) {
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1),
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)}),
|
||||
IsViewportLayer(child_view_token, child_view_size, child_view_inset,
|
||||
{0, 0}, kScale, kOpacityFloat),
|
||||
IsImageLayer(frame_size, kUpperLayerBlendMode, 1)},
|
||||
IsImageLayer(
|
||||
frame_size, kUpperLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 384.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})},
|
||||
{kInvDPR, kInvDPR}));
|
||||
|
||||
// Destroy the view. The scene graph shouldn't change yet.
|
||||
@@ -611,10 +647,26 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) {
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1),
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)}),
|
||||
IsViewportLayer(child_view_token, child_view_size, child_view_inset,
|
||||
{0, 0}, kScale, kOpacityFloat),
|
||||
IsImageLayer(frame_size, kUpperLayerBlendMode, 1)},
|
||||
IsImageLayer(
|
||||
frame_size, kUpperLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 384.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})},
|
||||
{kInvDPR, kInvDPR}));
|
||||
|
||||
// Draw another frame without the view. The scene graph shouldn't change yet.
|
||||
@@ -634,19 +686,43 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) {
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1),
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)}),
|
||||
IsViewportLayer(child_view_token, child_view_size, child_view_inset,
|
||||
{0, 0}, kScale, kOpacityFloat),
|
||||
IsImageLayer(frame_size, kUpperLayerBlendMode, 1)},
|
||||
IsImageLayer(
|
||||
frame_size, kUpperLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 384.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})},
|
||||
{kInvDPR, kInvDPR}));
|
||||
|
||||
// Pump the message loop. The scene updates should propagate to flatland.
|
||||
loop().RunUntilIdle();
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref, /*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
}
|
||||
|
||||
TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView_NoOverlay) {
|
||||
@@ -736,24 +812,40 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView_NoOverlay) {
|
||||
loop().RunUntilIdle();
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref, /*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1),
|
||||
IsViewportLayer(child_view_token, child_view_size,
|
||||
FakeViewport::kDefaultViewportInset,
|
||||
{0, 0}, kScale, kOpacityFloat)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)}),
|
||||
IsViewportLayer(child_view_token, child_view_size,
|
||||
FakeViewport::kDefaultViewportInset, {0, 0}, kScale,
|
||||
kOpacityFloat)}));
|
||||
|
||||
// Destroy the view. The scene graph shouldn't change yet.
|
||||
external_view_embedder.DestroyView(
|
||||
child_view_id, [](fuchsia::ui::composition::ContentId) {});
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref, /*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1),
|
||||
IsViewportLayer(child_view_token, child_view_size,
|
||||
FakeViewport::kDefaultViewportInset,
|
||||
{0, 0}, kScale, kOpacityFloat)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)}),
|
||||
IsViewportLayer(child_view_token, child_view_size,
|
||||
FakeViewport::kDefaultViewportInset, {0, 0}, kScale,
|
||||
kOpacityFloat)}));
|
||||
|
||||
// Draw another frame without the view. The scene graph shouldn't change yet.
|
||||
DrawSimpleFrame(
|
||||
@@ -771,20 +863,36 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView_NoOverlay) {
|
||||
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref, /*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1),
|
||||
IsViewportLayer(child_view_token, child_view_size,
|
||||
FakeViewport::kDefaultViewportInset,
|
||||
{0, 0}, kScale, kOpacityFloat)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)}),
|
||||
IsViewportLayer(child_view_token, child_view_size,
|
||||
FakeViewport::kDefaultViewportInset, {0, 0}, kScale,
|
||||
kOpacityFloat)}));
|
||||
|
||||
// Pump the message loop. The scene updates should propagate to flatland.
|
||||
loop().RunUntilIdle();
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref, /*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
}
|
||||
|
||||
TEST_F(FlatlandExternalViewEmbedderTest,
|
||||
@@ -850,18 +958,36 @@ TEST_F(FlatlandExternalViewEmbedderTest,
|
||||
loop().RunUntilIdle();
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
|
||||
// Destroy the view. The scene graph shouldn't change yet.
|
||||
external_view_embedder.DestroyView(
|
||||
child_view_id, [](fuchsia::ui::composition::ContentId) {});
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
|
||||
// Draw another frame without the view and change the size. The scene graph
|
||||
// shouldn't change yet.
|
||||
@@ -883,17 +1009,208 @@ TEST_F(FlatlandExternalViewEmbedderTest,
|
||||
});
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(frame_size, kFirstLayerBlendMode, 1)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
|
||||
// Pump the message loop. The scene updates should propagate to flatland.
|
||||
loop().RunUntilIdle();
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref, /*layers*/
|
||||
{IsImageLayer(new_frame_size, kFirstLayerBlendMode, 1)}));
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/
|
||||
{IsImageLayer(
|
||||
new_frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 64.f,
|
||||
/* y */ 128.f,
|
||||
/* width */ 8.f,
|
||||
/* height */ 8.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
}
|
||||
|
||||
// This test case exercises the scenario in which the view contains two disjoint
|
||||
// regions with painted content; we should generate two separate hit regions
|
||||
// matching the bounds of the painted regions in this case.
|
||||
TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene_DisjointHitRegions) {
|
||||
fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher;
|
||||
fuchsia::ui::views::ViewportCreationToken viewport_creation_token;
|
||||
fuchsia::ui::views::ViewCreationToken view_creation_token;
|
||||
fuchsia::ui::views::ViewRef view_ref;
|
||||
auto view_creation_token_status = zx::channel::create(
|
||||
0u, &viewport_creation_token.value, &view_creation_token.value);
|
||||
ASSERT_EQ(view_creation_token_status, ZX_OK);
|
||||
auto view_ref_pair = scenic::ViewRefPair::New();
|
||||
view_ref_pair.view_ref.Clone(&view_ref);
|
||||
|
||||
// Create the `FlatlandExternalViewEmbedder` and pump the message loop until
|
||||
// the initial scene graph is setup.
|
||||
FlatlandExternalViewEmbedder external_view_embedder(
|
||||
std::move(view_creation_token),
|
||||
fuchsia::ui::views::ViewIdentityOnCreation{
|
||||
.view_ref = std::move(view_ref_pair.view_ref),
|
||||
.view_ref_control = std::move(view_ref_pair.control_ref),
|
||||
},
|
||||
fuchsia::ui::composition::ViewBoundProtocols{},
|
||||
parent_viewport_watcher.NewRequest(), flatland_connection(),
|
||||
fake_surface_producer());
|
||||
flatland_connection()->Present();
|
||||
loop().RunUntilIdle();
|
||||
fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u));
|
||||
loop().RunUntilIdle();
|
||||
EXPECT_THAT(fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref));
|
||||
|
||||
// Draw the scene. The scene graph shouldn't change yet.
|
||||
const SkISize frame_size_signed = SkISize::Make(512, 512);
|
||||
const fuchsia::math::SizeU frame_size{
|
||||
static_cast<uint32_t>(frame_size_signed.width()),
|
||||
static_cast<uint32_t>(frame_size_signed.height())};
|
||||
DrawSimpleFrame(
|
||||
external_view_embedder, frame_size_signed, 1.f, [](SkCanvas* canvas) {
|
||||
const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(),
|
||||
canvas->imageInfo().height());
|
||||
|
||||
SkRect paint_region_1, paint_region_2;
|
||||
|
||||
paint_region_1 = SkRect::MakeXYWH(
|
||||
canvas_size.width() / 4.f, canvas_size.height() / 2.f,
|
||||
canvas_size.width() / 32.f, canvas_size.height() / 32.f);
|
||||
|
||||
SkPaint rect_paint;
|
||||
rect_paint.setColor(SK_ColorGREEN);
|
||||
canvas->drawRect(paint_region_1, rect_paint);
|
||||
|
||||
paint_region_2 = SkRect::MakeXYWH(
|
||||
canvas_size.width() * 3.f / 4.f, canvas_size.height() / 2.f,
|
||||
canvas_size.width() / 32.f, canvas_size.height() / 32.f);
|
||||
|
||||
rect_paint.setColor(SK_ColorRED);
|
||||
canvas->drawRect(paint_region_2, rect_paint);
|
||||
});
|
||||
EXPECT_THAT(fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref));
|
||||
|
||||
// Pump the message loop. The scene updates should propagate to flatland.
|
||||
loop().RunUntilIdle();
|
||||
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT),
|
||||
IsHitRegion(
|
||||
/* x */ 384.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 16.f,
|
||||
/* height */ 16.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
}
|
||||
|
||||
// This test case exercises the scenario in which the view contains two
|
||||
// overlapping regions with painted content; we should generate one hit
|
||||
// region matching the union of the bounds of the two painted regions in
|
||||
// this case.
|
||||
TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene_OverlappingHitRegions) {
|
||||
fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher;
|
||||
fuchsia::ui::views::ViewportCreationToken viewport_creation_token;
|
||||
fuchsia::ui::views::ViewCreationToken view_creation_token;
|
||||
fuchsia::ui::views::ViewRef view_ref;
|
||||
auto view_creation_token_status = zx::channel::create(
|
||||
0u, &viewport_creation_token.value, &view_creation_token.value);
|
||||
ASSERT_EQ(view_creation_token_status, ZX_OK);
|
||||
auto view_ref_pair = scenic::ViewRefPair::New();
|
||||
view_ref_pair.view_ref.Clone(&view_ref);
|
||||
|
||||
// Create the `FlatlandExternalViewEmbedder` and pump the message loop until
|
||||
// the initial scene graph is setup.
|
||||
FlatlandExternalViewEmbedder external_view_embedder(
|
||||
std::move(view_creation_token),
|
||||
fuchsia::ui::views::ViewIdentityOnCreation{
|
||||
.view_ref = std::move(view_ref_pair.view_ref),
|
||||
.view_ref_control = std::move(view_ref_pair.control_ref),
|
||||
},
|
||||
fuchsia::ui::composition::ViewBoundProtocols{},
|
||||
parent_viewport_watcher.NewRequest(), flatland_connection(),
|
||||
fake_surface_producer());
|
||||
flatland_connection()->Present();
|
||||
loop().RunUntilIdle();
|
||||
fake_flatland().FireOnNextFrameBeginEvent(WithPresentCredits(1u));
|
||||
loop().RunUntilIdle();
|
||||
EXPECT_THAT(fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref));
|
||||
|
||||
// Draw the scene. The scene graph shouldn't change yet.
|
||||
const SkISize frame_size_signed = SkISize::Make(512, 512);
|
||||
const fuchsia::math::SizeU frame_size{
|
||||
static_cast<uint32_t>(frame_size_signed.width()),
|
||||
static_cast<uint32_t>(frame_size_signed.height())};
|
||||
DrawSimpleFrame(
|
||||
external_view_embedder, frame_size_signed, 1.f, [](SkCanvas* canvas) {
|
||||
const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(),
|
||||
canvas->imageInfo().height());
|
||||
|
||||
SkRect paint_region_1, paint_region_2;
|
||||
|
||||
paint_region_1 = SkRect::MakeXYWH(
|
||||
canvas_size.width() / 4.f, canvas_size.height() / 2.f,
|
||||
3.f * canvas_size.width() / 8.f, canvas_size.height() / 4.f);
|
||||
|
||||
SkPaint rect_paint;
|
||||
rect_paint.setColor(SK_ColorGREEN);
|
||||
canvas->drawRect(paint_region_1, rect_paint);
|
||||
|
||||
paint_region_2 = SkRect::MakeXYWH(
|
||||
canvas_size.width() * 3.f / 8.f, canvas_size.height() / 2.f,
|
||||
3.f * canvas_size.width() / 8.f, canvas_size.height() / 4.f);
|
||||
|
||||
rect_paint.setColor(SK_ColorRED);
|
||||
canvas->drawRect(paint_region_2, rect_paint);
|
||||
});
|
||||
EXPECT_THAT(fake_flatland().graph(),
|
||||
IsFlutterGraph(parent_viewport_watcher, viewport_creation_token,
|
||||
view_ref));
|
||||
|
||||
// Pump the message loop. The scene updates should propagate to flatland.
|
||||
loop().RunUntilIdle();
|
||||
|
||||
EXPECT_THAT(
|
||||
fake_flatland().graph(),
|
||||
IsFlutterGraph(
|
||||
parent_viewport_watcher, viewport_creation_token, view_ref,
|
||||
/*layers*/
|
||||
{IsImageLayer(
|
||||
frame_size, kFirstLayerBlendMode,
|
||||
{IsHitRegion(
|
||||
/* x */ 128.f,
|
||||
/* y */ 256.f,
|
||||
/* width */ 256.f,
|
||||
/* height */ 128.f,
|
||||
/* hit_test */
|
||||
fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
|
||||
}
|
||||
|
||||
} // namespace flutter_runner::testing
|
||||
|
||||
Reference in New Issue
Block a user