mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Revert "[fuchsia][a11y] Set explicit hit regions per compositor layer on GFX. (#33852)" (flutter/engine#34360)
This reverts commit c73e679ebf50b1455b207e2eacc70111d8b31acd.
This commit is contained in:
parent
74b2af89ba
commit
6d1dd42a73
@ -10,7 +10,6 @@
|
||||
|
||||
#include <algorithm> // For std::clamp
|
||||
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "third_party/skia/include/core/SkPicture.h"
|
||||
#include "third_party/skia/include/core/SkSurface.h"
|
||||
@ -170,9 +169,8 @@ void GfxExternalViewEmbedder::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, flutter::RTreeFactory())));
|
||||
frame_layers_.emplace(std::make_pair(EmbedderLayerId{handle},
|
||||
EmbedderLayer(frame_size_, *params)));
|
||||
frame_composition_order_.push_back(handle);
|
||||
}
|
||||
|
||||
@ -202,9 +200,8 @@ void GfxExternalViewEmbedder::BeginFrame(
|
||||
frame_dpr_ = device_pixel_ratio;
|
||||
|
||||
// Create the root layer.
|
||||
frame_layers_.emplace(std::make_pair(
|
||||
kRootLayerId,
|
||||
EmbedderLayer(frame_size, std::nullopt, flutter::RTreeFactory())));
|
||||
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.
|
||||
@ -274,19 +271,6 @@ void GfxExternalViewEmbedder::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");
|
||||
@ -453,18 +437,10 @@ void GfxExternalViewEmbedder::SubmitFrame(
|
||||
FML_CHECK(scenic_layer_index <= scenic_layers_.size());
|
||||
if (scenic_layer_index == scenic_layers_.size()) {
|
||||
ScenicLayer new_layer{
|
||||
.layer_node = scenic::EntityNode(session_->get()),
|
||||
.image =
|
||||
ScenicImage{
|
||||
.shape_node = scenic::ShapeNode(session_->get()),
|
||||
.material = scenic::Material(session_->get()),
|
||||
},
|
||||
// We'll set hit regions later.
|
||||
.hit_regions = {},
|
||||
.shape_node = scenic::ShapeNode(session_->get()),
|
||||
.material = scenic::Material(session_->get()),
|
||||
};
|
||||
new_layer.layer_node.SetLabel("Flutter::Layer");
|
||||
new_layer.layer_node.AddChild(new_layer.image.shape_node);
|
||||
new_layer.image.shape_node.SetMaterial(new_layer.image.material);
|
||||
new_layer.shape_node.SetMaterial(new_layer.material);
|
||||
scenic_layers_.emplace_back(std::move(new_layer));
|
||||
}
|
||||
|
||||
@ -515,50 +491,25 @@ void GfxExternalViewEmbedder::SubmitFrame(
|
||||
embedded_views_height;
|
||||
auto& scenic_layer = scenic_layers_[scenic_layer_index];
|
||||
auto& scenic_rect = found_rects->second[rect_index];
|
||||
auto& image = scenic_layer.image;
|
||||
image.shape_node.SetLabel("Flutter::Layer::Image");
|
||||
image.shape_node.SetShape(scenic_rect);
|
||||
image.shape_node.SetTranslation(
|
||||
scenic_layer.shape_node.SetLabel("Flutter::Layer");
|
||||
scenic_layer.shape_node.SetShape(scenic_rect);
|
||||
scenic_layer.shape_node.SetTranslation(
|
||||
layer->second.surface_size.width() * 0.5f,
|
||||
layer->second.surface_size.height() * 0.5f, -layer_elevation);
|
||||
image.material.SetColor(SK_AlphaOPAQUE, SK_AlphaOPAQUE, SK_AlphaOPAQUE,
|
||||
layer_opacity);
|
||||
image.material.SetTexture(surface_for_layer->GetImageId());
|
||||
scenic_layer.material.SetColor(SK_AlphaOPAQUE, SK_AlphaOPAQUE,
|
||||
SK_AlphaOPAQUE, layer_opacity);
|
||||
scenic_layer.material.SetTexture(surface_for_layer->GetImageId());
|
||||
|
||||
// We'll set hit regions expliclty on a separate ShapeNode, so the image
|
||||
// itself should be unhittable and semantically invisible.
|
||||
image.shape_node.SetHitTestBehavior(
|
||||
fuchsia::ui::gfx::HitTestBehavior::kSuppress);
|
||||
image.shape_node.SetSemanticVisibility(false);
|
||||
// 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.
|
||||
const fuchsia::ui::gfx::HitTestBehavior layer_hit_test_behavior =
|
||||
first_layer ? fuchsia::ui::gfx::HitTestBehavior::kDefault
|
||||
: fuchsia::ui::gfx::HitTestBehavior::kSuppress;
|
||||
scenic_layer.shape_node.SetHitTestBehavior(layer_hit_test_behavior);
|
||||
|
||||
// Attach the ScenicLayer to the main scene graph.
|
||||
layer_tree_node_.AddChild(scenic_layer.layer_node);
|
||||
|
||||
// Compute the set of non-overlapping set of bounding boxes for the
|
||||
// painted content in this layer.
|
||||
{
|
||||
FML_CHECK(layer->second.rtree);
|
||||
std::list<SkRect> intersection_rects =
|
||||
layer->second.rtree->searchNonOverlappingDrawnRects(
|
||||
SkRect::Make(layer->second.surface_size));
|
||||
|
||||
// SkRect joined_rect = SkRect::MakeEmpty();
|
||||
for (const SkRect& rect : intersection_rects) {
|
||||
auto paint_bounds =
|
||||
scenic::Rectangle(session_->get(), rect.width(), rect.height());
|
||||
auto hit_region = scenic::ShapeNode(session_->get());
|
||||
hit_region.SetLabel("Flutter::Layer::HitRegion");
|
||||
hit_region.SetShape(paint_bounds);
|
||||
hit_region.SetTranslation(rect.centerX(), rect.centerY(),
|
||||
-layer_elevation);
|
||||
hit_region.SetHitTestBehavior(
|
||||
fuchsia::ui::gfx::HitTestBehavior::kDefault);
|
||||
hit_region.SetSemanticVisibility(true);
|
||||
|
||||
scenic_layer.layer_node.AddChild(hit_region);
|
||||
scenic_layer.hit_regions.push_back(std::move(hit_region));
|
||||
}
|
||||
}
|
||||
layer_tree_node_.AddChild(scenic_layer.shape_node);
|
||||
}
|
||||
|
||||
// Reset for the next pass:
|
||||
@ -576,11 +527,7 @@ void GfxExternalViewEmbedder::SubmitFrame(
|
||||
session_->Present();
|
||||
}
|
||||
|
||||
// Flush pending skia operations.
|
||||
// NOTE: This operation MUST occur AFTER the `Present() ` call above. We
|
||||
// pipeline the Skia rendering work with scenic IPC, and scenic will delay
|
||||
// internally until Skia is finished. So, doing this work before calling
|
||||
// `Present()` would adversely affect performance.
|
||||
// Render the recorded SkPictures into the surfaces.
|
||||
{
|
||||
TRACE_EVENT0("flutter", "RasterizeSurfaces");
|
||||
|
||||
@ -601,10 +548,13 @@ void GfxExternalViewEmbedder::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(layer->second.picture);
|
||||
canvas->drawPicture(picture);
|
||||
canvas->flush();
|
||||
}
|
||||
}
|
||||
@ -686,16 +636,7 @@ void GfxExternalViewEmbedder::Reset() {
|
||||
|
||||
// Clear images on all layers so they aren't cached unnecessarily.
|
||||
for (auto& layer : scenic_layers_) {
|
||||
layer.image.material.SetTexture(0);
|
||||
|
||||
// Detach hit regions; otherwise, they may persist across frames
|
||||
// incorrectly.
|
||||
for (auto& hit_region : layer.hit_regions) {
|
||||
hit_region.Detach();
|
||||
}
|
||||
|
||||
// Remove cached hit regions so that we don't recreate stale ones.
|
||||
layer.hit_regions.clear();
|
||||
layer.material.SetTexture(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
#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"
|
||||
@ -139,29 +138,18 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
|
||||
|
||||
struct EmbedderLayer {
|
||||
EmbedderLayer(const SkISize& frame_size,
|
||||
std::optional<flutter::EmbeddedViewParams> view_params,
|
||||
flutter::RTreeFactory rtree_factory)
|
||||
: rtree(rtree_factory.getInstance()),
|
||||
embedded_view_params(std::move(view_params)),
|
||||
std::optional<flutter::EmbeddedViewParams> view_params)
|
||||
: embedded_view_params(std::move(view_params)),
|
||||
recorder(std::make_unique<SkPictureRecorder>()),
|
||||
canvas_spy(std::make_unique<flutter::CanvasSpy>(
|
||||
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;
|
||||
recorder->beginRecording(frame_size.width(),
|
||||
frame_size.height()))),
|
||||
surface_size(frame_size) {}
|
||||
|
||||
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{};
|
||||
@ -184,34 +172,11 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
|
||||
bool pending_focusable = true;
|
||||
};
|
||||
|
||||
// GFX resources required to render a composited flutter layer (i.e. an
|
||||
// SkPicture).
|
||||
struct ScenicImage {
|
||||
struct ScenicLayer {
|
||||
scenic::ShapeNode shape_node;
|
||||
scenic::Material material;
|
||||
};
|
||||
|
||||
// All resources required to represent a flutter layer in the GFX scene
|
||||
// graph. The structure of the subgraph for a particular layer is:
|
||||
//
|
||||
// layer_node
|
||||
// / \
|
||||
// image node hit regions (zero or more)
|
||||
//
|
||||
// NOTE: `hit_regions` must be cleared before submitting each new frame;
|
||||
// otherwise, we will report stale hittable geometry to scenic.
|
||||
struct ScenicLayer {
|
||||
// Root of the subtree containing the scenic resources for this layer.
|
||||
scenic::EntityNode layer_node;
|
||||
|
||||
// Scenic resources used to render this layer's image.
|
||||
ScenicImage image;
|
||||
|
||||
// Scenic resources that specify which parts of this layer are responsive
|
||||
// to input.
|
||||
std::vector<scenic::ShapeNode> hit_regions;
|
||||
};
|
||||
|
||||
std::shared_ptr<GfxSessionConnection> session_;
|
||||
std::shared_ptr<SurfaceProducer> surface_producer_;
|
||||
|
||||
|
||||
@ -149,6 +149,18 @@ class FakeSurfaceProducer : public SurfaceProducer {
|
||||
uint32_t buffer_id_{1};
|
||||
};
|
||||
|
||||
struct FakeCompositorLayer {
|
||||
enum class LayerType : uint32_t {
|
||||
Image,
|
||||
View,
|
||||
};
|
||||
|
||||
std::shared_ptr<FakeResource> layer_root;
|
||||
|
||||
LayerType layer_type{LayerType::Image};
|
||||
size_t layer_index{0};
|
||||
};
|
||||
|
||||
std::string GetCurrentTestName() {
|
||||
return ::testing::UnitTest::GetInstance()->current_test_info()->name();
|
||||
}
|
||||
@ -241,28 +253,12 @@ void ExpectRootSceneGraph(
|
||||
EXPECT_EQ(scene_graph.resource_map.size(), 3u);
|
||||
}
|
||||
|
||||
/// Verifies the scene subgraph for a particular flutter embedder layer.
|
||||
///
|
||||
/// ARGUMENTS
|
||||
///
|
||||
/// scenic_node: The root of the layer's scenic subgraph.
|
||||
///
|
||||
/// layer_size: The expected dimensions of the layer's image.
|
||||
///
|
||||
/// flutter_layer_index: This layer's 0-indexed position in the list of
|
||||
/// flutter layers present in this frame, sorted in paint order.
|
||||
///
|
||||
/// paint_regions: List of non-overlapping rects, in canvas coordinate space,
|
||||
/// where content was drawn. For each "paint region" present in the frame, the
|
||||
/// embedder reports a corresponding "hit region" to scenic as a hittable
|
||||
/// ShapeNode. ShapeNodes are centered at (0, 0), by default, so they must be
|
||||
/// translated to match the locations of the corresopnding paint regions.
|
||||
void ExpectImageCompositorLayer(const FakeResource& scenic_node,
|
||||
const SkISize layer_size,
|
||||
size_t flutter_layer_index,
|
||||
std::vector<SkRect> paint_regions) {
|
||||
void ExpectImageCompositorLayer(const FakeCompositorLayer& layer,
|
||||
const SkISize layer_size) {
|
||||
const SkSize float_layer_size =
|
||||
SkSize::Make(layer_size.width(), layer_size.height());
|
||||
const size_t flutter_layer_index =
|
||||
(layer.layer_index + 1) / 2; // Integer division
|
||||
const float views_under_layer_depth =
|
||||
flutter_layer_index *
|
||||
GfxExternalViewEmbedder::kScenicZElevationForPlatformView;
|
||||
@ -270,50 +266,27 @@ void ExpectImageCompositorLayer(const FakeResource& scenic_node,
|
||||
flutter_layer_index *
|
||||
GfxExternalViewEmbedder::kScenicZElevationBetweenLayers +
|
||||
views_under_layer_depth;
|
||||
const bool layer_hit_testable = (flutter_layer_index == 0)
|
||||
? FakeNode::kIsHitTestable
|
||||
: FakeNode::kIsNotHitTestable;
|
||||
const float layer_opacity =
|
||||
(flutter_layer_index == 0)
|
||||
? GfxExternalViewEmbedder::kBackgroundLayerOpacity / 255.f
|
||||
: GfxExternalViewEmbedder::kOverlayLayerOpacity / 255.f;
|
||||
|
||||
EXPECT_EQ(layer.layer_type, FakeCompositorLayer::LayerType::Image);
|
||||
EXPECT_EQ(layer.layer_index % 2, 0u);
|
||||
EXPECT_THAT(
|
||||
scenic_node,
|
||||
FieldsAre(
|
||||
_, "Flutter::Layer", FakeResource::kDefaultEmptyEventMask,
|
||||
VariantWith<FakeEntityNode>(FieldsAre(
|
||||
FieldsAre(
|
||||
// Verify children separately below, since the
|
||||
// expected number of children may vary across
|
||||
// different test cases that call this method.
|
||||
_, FakeNode::kDefaultZeroRotation, FakeNode::kDefaultOneScale,
|
||||
FakeNode::kDefaultZeroTranslation,
|
||||
FakeNode::kDefaultZeroAnchor, FakeNode::kIsHitTestable,
|
||||
FakeNode::kIsSemanticallyVisible),
|
||||
_))));
|
||||
|
||||
const auto* layer_node_state =
|
||||
std::get_if<FakeEntityNode>(&scenic_node.state);
|
||||
ASSERT_TRUE(layer_node_state);
|
||||
|
||||
const auto& layer_node_children = layer_node_state->node_state.children;
|
||||
|
||||
// The layer entity node should have a child node for the image, and
|
||||
// separate children for each of the hit regions.
|
||||
ASSERT_EQ(layer_node_children.size(), paint_regions.size() + 1);
|
||||
|
||||
// Verify image node.
|
||||
EXPECT_THAT(
|
||||
layer_node_children[0],
|
||||
layer.layer_root,
|
||||
Pointee(FieldsAre(
|
||||
_, "Flutter::Layer::Image", FakeResource::kDefaultEmptyEventMask,
|
||||
_, "Flutter::Layer", FakeResource::kDefaultEmptyEventMask,
|
||||
VariantWith<FakeShapeNode>(FieldsAre(
|
||||
FieldsAre(IsEmpty(), FakeNode::kDefaultZeroRotation,
|
||||
FakeNode::kDefaultOneScale,
|
||||
std::array<float, 3>{float_layer_size.width() / 2.f,
|
||||
float_layer_size.height() / 2.f,
|
||||
-layer_depth},
|
||||
FakeNode::kDefaultZeroAnchor,
|
||||
FakeNode::kIsNotHitTestable,
|
||||
FakeNode::kIsNotSemanticallyVisible),
|
||||
FakeNode::kDefaultZeroAnchor, layer_hit_testable,
|
||||
FakeNode::kIsSemanticallyVisible),
|
||||
Pointee(
|
||||
FieldsAre(_, "", FakeResource::kDefaultEmptyEventMask,
|
||||
VariantWith<FakeShape>(
|
||||
@ -332,39 +305,13 @@ void ExpectImageCompositorLayer(const FakeResource& scenic_node,
|
||||
IsNull())))),
|
||||
std::array<float, 4>{1.f, 1.f, 1.f,
|
||||
layer_opacity})))))))));
|
||||
|
||||
// Verify hit regions.
|
||||
for (size_t i = 0; i < paint_regions.size(); ++i) {
|
||||
ASSERT_LT(i, layer_node_children.size());
|
||||
const auto& paint_region = paint_regions[i];
|
||||
EXPECT_THAT(
|
||||
layer_node_children[i + 1],
|
||||
Pointee(FieldsAre(
|
||||
_, "Flutter::Layer::HitRegion",
|
||||
FakeResource::kDefaultEmptyEventMask,
|
||||
VariantWith<FakeShapeNode>(FieldsAre(
|
||||
FieldsAre(IsEmpty(), FakeNode::kDefaultZeroRotation,
|
||||
FakeNode::kDefaultOneScale,
|
||||
std::array<float, 3>{
|
||||
paint_region.x() + paint_region.width() / 2.f,
|
||||
paint_region.y() + paint_region.height() / 2.f,
|
||||
-layer_depth},
|
||||
FakeNode::kDefaultZeroAnchor,
|
||||
FakeNode::kIsHitTestable,
|
||||
FakeNode::kIsSemanticallyVisible),
|
||||
Pointee(FieldsAre(
|
||||
_, "", FakeResource::kDefaultEmptyEventMask,
|
||||
VariantWith<FakeShape>(FieldsAre(
|
||||
VariantWith<FakeShape::RectangleDef>(FieldsAre(
|
||||
paint_region.width(), paint_region.height())))))),
|
||||
IsNull())))));
|
||||
}
|
||||
}
|
||||
|
||||
void ExpectViewCompositorLayer(const FakeResource& scenic_node,
|
||||
void ExpectViewCompositorLayer(const FakeCompositorLayer& layer,
|
||||
const fuchsia::ui::views::ViewToken& view_token,
|
||||
const flutter::EmbeddedViewParams& view_params,
|
||||
size_t flutter_layer_index) {
|
||||
const flutter::EmbeddedViewParams& view_params) {
|
||||
const size_t flutter_layer_index =
|
||||
(layer.layer_index + 1) / 2; // Integer division
|
||||
const float views_under_layer_depth =
|
||||
flutter_layer_index > 0
|
||||
? (flutter_layer_index - 1) *
|
||||
@ -374,9 +321,11 @@ void ExpectViewCompositorLayer(const FakeResource& scenic_node,
|
||||
flutter_layer_index *
|
||||
GfxExternalViewEmbedder::kScenicZElevationBetweenLayers +
|
||||
views_under_layer_depth;
|
||||
EXPECT_EQ(layer.layer_type, FakeCompositorLayer::LayerType::View);
|
||||
EXPECT_EQ(layer.layer_index % 2, 1u);
|
||||
EXPECT_THAT(
|
||||
scenic_node,
|
||||
FieldsAre(
|
||||
layer.layer_root,
|
||||
Pointee(FieldsAre(
|
||||
_, _ /*"Flutter::PlatformView::OpacityMutator" */,
|
||||
FakeResource::kDefaultEmptyEventMask,
|
||||
VariantWith<FakeOpacityNode>(FieldsAre(
|
||||
@ -423,10 +372,10 @@ void ExpectViewCompositorLayer(const FakeResource& scenic_node,
|
||||
FakeNode::kDefaultZeroTranslation,
|
||||
FakeNode::kDefaultZeroAnchor, FakeNode::kIsHitTestable,
|
||||
FakeNode::kIsSemanticallyVisible),
|
||||
FakeOpacityNode::kDefaultOneOpacity))));
|
||||
FakeOpacityNode::kDefaultOneOpacity)))));
|
||||
}
|
||||
|
||||
std::vector<FakeResource> ExtractLayersFromSceneGraph(
|
||||
std::vector<FakeCompositorLayer> ExtractLayersFromSceneGraph(
|
||||
const FakeSceneGraph& scene_graph) {
|
||||
AssertRootSceneGraph(scene_graph, false);
|
||||
|
||||
@ -438,12 +387,20 @@ std::vector<FakeResource> ExtractLayersFromSceneGraph(
|
||||
auto* layer_tree_state = std::get_if<FakeEntityNode>(
|
||||
&metrics_watcher_state->node_state.children[0]->state);
|
||||
|
||||
std::vector<FakeResource> scenic_layers;
|
||||
std::vector<FakeCompositorLayer> layers;
|
||||
for (auto& layer_resource : layer_tree_state->node_state.children) {
|
||||
scenic_layers.push_back(*layer_resource);
|
||||
const size_t layer_index = layers.size();
|
||||
const FakeCompositorLayer::LayerType layer_type =
|
||||
(layer_index % 2 == 0) ? FakeCompositorLayer::LayerType::Image
|
||||
: FakeCompositorLayer::LayerType::View;
|
||||
layers.emplace_back(FakeCompositorLayer{
|
||||
.layer_root = layer_resource,
|
||||
.layer_type = layer_type,
|
||||
.layer_index = layer_index,
|
||||
});
|
||||
}
|
||||
|
||||
return scenic_layers;
|
||||
return layers;
|
||||
}
|
||||
|
||||
void DrawSimpleFrame(GfxExternalViewEmbedder& external_view_embedder,
|
||||
@ -571,7 +528,6 @@ class GfxExternalViewEmbedderTest
|
||||
std::shared_ptr<FakeSurfaceProducer> fake_surface_producer_;
|
||||
};
|
||||
|
||||
// Tests the trivial case where flutter does not present any content to scenic.
|
||||
TEST_F(GfxExternalViewEmbedderTest, RootScene) {
|
||||
const std::string debug_name = GetCurrentTestName();
|
||||
auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();
|
||||
@ -602,7 +558,6 @@ TEST_F(GfxExternalViewEmbedderTest, RootScene) {
|
||||
view_holder_token, view_ref);
|
||||
}
|
||||
|
||||
// Tests the case where flutter renders a single image.
|
||||
TEST_F(GfxExternalViewEmbedderTest, SimpleScene) {
|
||||
const std::string debug_name = GetCurrentTestName();
|
||||
auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();
|
||||
@ -624,34 +579,29 @@ TEST_F(GfxExternalViewEmbedderTest, SimpleScene) {
|
||||
|
||||
// Draw the scene. The scene graph shouldn't change yet.
|
||||
const SkISize frame_size = SkISize::Make(512, 512);
|
||||
SkRect paint_region;
|
||||
DrawSimpleFrame(
|
||||
external_view_embedder, frame_size, 1.f,
|
||||
[&paint_region](SkCanvas* canvas) {
|
||||
external_view_embedder, frame_size, 1.f, [](SkCanvas* canvas) {
|
||||
const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(),
|
||||
canvas->imageInfo().height());
|
||||
SkPaint rect_paint;
|
||||
rect_paint.setColor(SK_ColorGREEN);
|
||||
|
||||
paint_region = SkRect::MakeXYWH(
|
||||
canvas_size.width() / 4.f, canvas_size.height() / 2.f,
|
||||
canvas_size.width() / 32.f, canvas_size.height() / 32.f);
|
||||
|
||||
canvas->drawRect(paint_region, rect_paint);
|
||||
canvas->translate(canvas_size.width() / 4.f,
|
||||
canvas_size.height() / 2.f);
|
||||
canvas->drawRect(SkRect::MakeWH(canvas_size.width() / 32.f,
|
||||
canvas_size.height() / 32.f),
|
||||
rect_paint);
|
||||
});
|
||||
ExpectRootSceneGraph(fake_session().SceneGraph(), debug_name,
|
||||
view_holder_token, view_ref);
|
||||
|
||||
// Pump the message loop. The scene updates should propogate to Scenic.
|
||||
loop().RunUntilIdle();
|
||||
std::vector<FakeResource> scenic_layers =
|
||||
std::vector<FakeCompositorLayer> compositor_layers =
|
||||
ExtractLayersFromSceneGraph(fake_session().SceneGraph());
|
||||
EXPECT_EQ(scenic_layers.size(), 1u);
|
||||
ExpectImageCompositorLayer(scenic_layers[0], frame_size,
|
||||
/* flutter layer index = */ 0, {paint_region});
|
||||
EXPECT_EQ(compositor_layers.size(), 1u);
|
||||
ExpectImageCompositorLayer(compositor_layers[0], frame_size);
|
||||
}
|
||||
|
||||
// Tests the case where flutter embeds a platform view on top of an image layer.
|
||||
TEST_F(GfxExternalViewEmbedderTest, SceneWithOneView) {
|
||||
const std::string debug_name = GetCurrentTestName();
|
||||
auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();
|
||||
@ -683,51 +633,42 @@ TEST_F(GfxExternalViewEmbedderTest, SceneWithOneView) {
|
||||
|
||||
// Draw the scene. The scene graph shouldn't change yet.
|
||||
const SkISize frame_size = SkISize::Make(512, 512);
|
||||
|
||||
SkRect main_surface_paint_region, overlay_paint_region;
|
||||
|
||||
DrawFrameWithView(
|
||||
external_view_embedder, frame_size, 1.f, child_view_id, child_view_params,
|
||||
[&main_surface_paint_region](SkCanvas* canvas) {
|
||||
[](SkCanvas* canvas) {
|
||||
const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(),
|
||||
canvas->imageInfo().height());
|
||||
|
||||
main_surface_paint_region = SkRect::MakeXYWH(
|
||||
canvas_size.width() / 4.f, canvas_size.width() / 2.f,
|
||||
canvas_size.width() / 32.f, canvas_size.height() / 32.f);
|
||||
|
||||
SkPaint rect_paint;
|
||||
rect_paint.setColor(SK_ColorGREEN);
|
||||
canvas->drawRect(main_surface_paint_region, rect_paint);
|
||||
canvas->translate(canvas_size.width() / 4.f,
|
||||
canvas_size.height() / 2.f);
|
||||
canvas->drawRect(SkRect::MakeWH(canvas_size.width() / 32.f,
|
||||
canvas_size.height() / 32.f),
|
||||
rect_paint);
|
||||
},
|
||||
[&overlay_paint_region](SkCanvas* canvas) {
|
||||
[](SkCanvas* canvas) {
|
||||
const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(),
|
||||
canvas->imageInfo().height());
|
||||
overlay_paint_region = SkRect::MakeXYWH(
|
||||
canvas_size.width() * 3.f / 4.f, canvas_size.height() / 2.f,
|
||||
canvas_size.width() / 32.f, canvas_size.height() / 32.f);
|
||||
|
||||
SkPaint rect_paint;
|
||||
rect_paint.setColor(SK_ColorRED);
|
||||
canvas->drawRect(overlay_paint_region, rect_paint);
|
||||
canvas->translate(canvas_size.width() * 3.f / 4.f,
|
||||
canvas_size.height() / 2.f);
|
||||
canvas->drawRect(SkRect::MakeWH(canvas_size.width() / 32.f,
|
||||
canvas_size.height() / 32.f),
|
||||
rect_paint);
|
||||
});
|
||||
ExpectRootSceneGraph(fake_session().SceneGraph(), debug_name,
|
||||
view_holder_token, view_ref);
|
||||
|
||||
// Pump the message loop. The scene updates should propagate to Scenic.
|
||||
loop().RunUntilIdle();
|
||||
std::vector<FakeResource> scenic_layers =
|
||||
std::vector<FakeCompositorLayer> compositor_layers =
|
||||
ExtractLayersFromSceneGraph(fake_session().SceneGraph());
|
||||
EXPECT_EQ(scenic_layers.size(), 3u);
|
||||
ExpectImageCompositorLayer(scenic_layers[0], frame_size,
|
||||
/* flutter layer index = */ 0,
|
||||
{main_surface_paint_region});
|
||||
ExpectViewCompositorLayer(scenic_layers[1], child_view_token,
|
||||
child_view_params,
|
||||
/* flutter layer index = */ 1);
|
||||
ExpectImageCompositorLayer(scenic_layers[2], frame_size,
|
||||
/* flutter layer index = */ 1,
|
||||
{overlay_paint_region});
|
||||
EXPECT_EQ(compositor_layers.size(), 3u);
|
||||
ExpectImageCompositorLayer(compositor_layers[0], frame_size);
|
||||
ExpectViewCompositorLayer(compositor_layers[1], child_view_token,
|
||||
child_view_params);
|
||||
ExpectImageCompositorLayer(compositor_layers[2], frame_size);
|
||||
|
||||
// Destroy the view.
|
||||
external_view_embedder.DestroyView(child_view_id, [](scenic::ResourceId) {});
|
||||
@ -736,127 +677,4 @@ TEST_F(GfxExternalViewEmbedderTest, SceneWithOneView) {
|
||||
loop().RunUntilIdle();
|
||||
}
|
||||
|
||||
// Tests the case where flutter renders an image with two non-overlapping pieces
|
||||
// of content. In this case, the embedder should report two separate hit regions
|
||||
// to scenic.
|
||||
TEST_F(GfxExternalViewEmbedderTest, SimpleSceneDisjointHitRegions) {
|
||||
const std::string debug_name = GetCurrentTestName();
|
||||
auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();
|
||||
auto view_ref_pair = scenic::ViewRefPair::New();
|
||||
fuchsia::ui::views::ViewRef view_ref;
|
||||
view_ref_pair.view_ref.Clone(&view_ref);
|
||||
|
||||
// Create the `GfxExternalViewEmbedder` and pump the message loop until
|
||||
// the initial scene graph is setup.
|
||||
GfxExternalViewEmbedder external_view_embedder(
|
||||
debug_name, std::move(view_token), std::move(view_ref_pair),
|
||||
session_connection(), fake_surface_producer());
|
||||
loop().RunUntilIdle();
|
||||
fake_session().FireOnFramePresentedEvent(
|
||||
MakeFramePresentedInfoForOnePresent(0, 0));
|
||||
loop().RunUntilIdle();
|
||||
ExpectRootSceneGraph(fake_session().SceneGraph(), debug_name,
|
||||
view_holder_token, view_ref);
|
||||
|
||||
// Draw the scene. The scene graph shouldn't change yet.
|
||||
SkRect paint_region_1, paint_region_2;
|
||||
const SkISize frame_size = SkISize::Make(512, 512);
|
||||
DrawSimpleFrame(
|
||||
external_view_embedder, frame_size, 1.f,
|
||||
[&paint_region_1, &paint_region_2](SkCanvas* canvas) {
|
||||
const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(),
|
||||
canvas->imageInfo().height());
|
||||
|
||||
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);
|
||||
});
|
||||
ExpectRootSceneGraph(fake_session().SceneGraph(), debug_name,
|
||||
view_holder_token, view_ref);
|
||||
|
||||
// Pump the message loop. The scene updates should propogate to Scenic.
|
||||
loop().RunUntilIdle();
|
||||
std::vector<FakeResource> scenic_layers =
|
||||
ExtractLayersFromSceneGraph(fake_session().SceneGraph());
|
||||
EXPECT_EQ(scenic_layers.size(), 1u);
|
||||
ExpectImageCompositorLayer(scenic_layers[0], frame_size,
|
||||
/* flutter layer index = */ 0,
|
||||
{paint_region_1, paint_region_2});
|
||||
}
|
||||
|
||||
// Tests the case where flutter renders an image with two overlapping pieces of
|
||||
// content. In this case, the embedder should report a single joint hit region
|
||||
// to scenic.
|
||||
TEST_F(GfxExternalViewEmbedderTest, SimpleSceneOverlappingHitRegions) {
|
||||
const std::string debug_name = GetCurrentTestName();
|
||||
auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();
|
||||
auto view_ref_pair = scenic::ViewRefPair::New();
|
||||
fuchsia::ui::views::ViewRef view_ref;
|
||||
view_ref_pair.view_ref.Clone(&view_ref);
|
||||
|
||||
// Create the `GfxExternalViewEmbedder` and pump the message loop until
|
||||
// the initial scene graph is setup.
|
||||
GfxExternalViewEmbedder external_view_embedder(
|
||||
debug_name, std::move(view_token), std::move(view_ref_pair),
|
||||
session_connection(), fake_surface_producer());
|
||||
loop().RunUntilIdle();
|
||||
fake_session().FireOnFramePresentedEvent(
|
||||
MakeFramePresentedInfoForOnePresent(0, 0));
|
||||
loop().RunUntilIdle();
|
||||
ExpectRootSceneGraph(fake_session().SceneGraph(), debug_name,
|
||||
view_holder_token, view_ref);
|
||||
|
||||
// Draw the scene. The scene graph shouldn't change yet.
|
||||
SkRect joined_paint_region = SkRect::MakeEmpty();
|
||||
const SkISize frame_size = SkISize::Make(512, 512);
|
||||
DrawSimpleFrame(
|
||||
external_view_embedder, frame_size, 1.f,
|
||||
[&joined_paint_region](SkCanvas* canvas) {
|
||||
const SkSize canvas_size = SkSize::Make(canvas->imageInfo().width(),
|
||||
canvas->imageInfo().height());
|
||||
|
||||
auto paint_region_1 = SkRect::MakeXYWH(
|
||||
canvas_size.width() / 4.f, canvas_size.height() / 4.f,
|
||||
canvas_size.width() / 2.f, canvas_size.height() / 2.f);
|
||||
SkPaint rect_paint;
|
||||
rect_paint.setColor(SK_ColorGREEN);
|
||||
canvas->drawRect(paint_region_1, rect_paint);
|
||||
|
||||
auto paint_region_2 = SkRect::MakeXYWH(
|
||||
canvas_size.width() * 3.f / 8.f, canvas_size.height() / 4.f,
|
||||
canvas_size.width() / 2.f, canvas_size.height() / 2.f);
|
||||
rect_paint.setColor(SK_ColorRED);
|
||||
canvas->drawRect(paint_region_2, rect_paint);
|
||||
|
||||
joined_paint_region.join(paint_region_1);
|
||||
joined_paint_region.join(paint_region_2);
|
||||
});
|
||||
ExpectRootSceneGraph(fake_session().SceneGraph(), debug_name,
|
||||
view_holder_token, view_ref);
|
||||
|
||||
EXPECT_EQ(joined_paint_region.x(), 128.f);
|
||||
EXPECT_EQ(joined_paint_region.y(), 128.f);
|
||||
EXPECT_EQ(joined_paint_region.width(), 320.f);
|
||||
EXPECT_EQ(joined_paint_region.height(), 256.f);
|
||||
// Pump the message loop. The scene updates should propogate to Scenic.
|
||||
loop().RunUntilIdle();
|
||||
std::vector<FakeResource> scenic_layers =
|
||||
ExtractLayersFromSceneGraph(fake_session().SceneGraph());
|
||||
EXPECT_EQ(scenic_layers.size(), 1u);
|
||||
ExpectImageCompositorLayer(scenic_layers[0], frame_size,
|
||||
/* flutter layer index = */ 0,
|
||||
{joined_paint_region});
|
||||
}
|
||||
|
||||
} // namespace flutter_runner::testing
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user