@@ -38,8 +38,10 @@ using fuchsia::scenic::scheduling::FuturePresentationTimes;
3838using fuchsia::scenic::scheduling::PresentReceivedInfo;
3939using ::testing::_;
4040using ::testing::AllOf;
41+ using ::testing::Contains;
4142using ::testing::ElementsAre;
4243using ::testing::Eq;
44+ using ::testing::Field;
4345using ::testing::FieldsAre;
4446using ::testing::IsEmpty;
4547using ::testing::Matcher;
@@ -297,6 +299,16 @@ Matcher<std::shared_ptr<FakeTransform>> IsClipTransformLayer(
297299 /* content*/ _,
298300 /* hit_regions*/ _));
299301}
302+
303+ Matcher<std::shared_ptr<FakeTransform>> IsInputShield () {
304+ return Pointee (AllOf (
305+ // Must not clip the hit region.
306+ Field (" clip_bounds" , &FakeTransform::clip_bounds, Eq (std::nullopt )),
307+ // Hit region must be "infinite".
308+ Field (" hit_regions" , &FakeTransform::hit_regions,
309+ Contains (flutter_runner::testing::kInfiniteHitRegion ))));
310+ }
311+
300312fuchsia::ui::composition::OnNextFrameBeginValues WithPresentCredits (
301313 uint32_t additional_present_credits) {
302314 fuchsia::ui::composition::OnNextFrameBeginValues values;
@@ -396,15 +408,18 @@ class FlatlandExternalViewEmbedderTest : public ::testing::Test {
396408 fuchsia::ui::composition::FlatlandHandle flatland =
397409 fake_flatland_.ConnectFlatland (session_subloop_->dispatcher ());
398410
399- auto test_name =
411+ const auto test_name =
400412 ::testing::UnitTest::GetInstance ()->current_test_info()->name();
413+ const auto max_frames_in_flight = 1 ;
414+ const auto vsync_offset = fml::TimeDelta::Zero ();
401415 return std::make_shared<FlatlandConnection>(
402- std::move (test_name), std::move (flatland), []() { FAIL (); },
403- [](auto ...) {}, 1 , fml::TimeDelta::Zero ());
416+ std::move (test_name), std::move (flatland),
417+ /* error_callback=*/ [] { FAIL (); }, /* ofpe_callback=*/ [](auto ...) {},
418+ max_frames_in_flight, vsync_offset);
404419 }
405420
406421 // Primary loop and subloop for the FakeFlatland instance to process its
407- // messages. The subloop allocates it's own zx_port_t, allowing us to use a
422+ // messages. The subloop allocates its own zx_port_t, allowing us to use a
408423 // separate port for each end of the message channel, rather than sharing a
409424 // single one. Dual ports allow messages and responses to be intermingled,
410425 // which is how production code behaves; this improves test realism.
@@ -1476,4 +1491,143 @@ TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene_OverlappingHitRegions) {
14761491 fuchsia::ui::composition::HitTestInteraction::DEFAULT)})}));
14771492}
14781493
1494+ TEST_F (FlatlandExternalViewEmbedderTest, ViewportCoveredWithInputInterceptor) {
1495+ fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher;
1496+ fuchsia::ui::views::ViewportCreationToken viewport_creation_token;
1497+ fuchsia::ui::views::ViewCreationToken view_creation_token;
1498+ fuchsia::ui::views::ViewRef view_ref;
1499+ auto view_creation_token_status = zx::channel::create (
1500+ 0u , &viewport_creation_token.value , &view_creation_token.value );
1501+ ASSERT_EQ (view_creation_token_status, ZX_OK);
1502+ auto view_ref_pair = scenic::ViewRefPair::New ();
1503+ view_ref_pair.view_ref .Clone (&view_ref);
1504+
1505+ // Create the `FlatlandExternalViewEmbedder` and pump the message loop until
1506+ // the initial scene graph is setup.
1507+ FlatlandExternalViewEmbedder external_view_embedder (
1508+ std::move (view_creation_token),
1509+ fuchsia::ui::views::ViewIdentityOnCreation{
1510+ .view_ref = std::move (view_ref_pair.view_ref ),
1511+ .view_ref_control = std::move (view_ref_pair.control_ref ),
1512+ },
1513+ fuchsia::ui::composition::ViewBoundProtocols{},
1514+ parent_viewport_watcher.NewRequest (), flatland_connection (),
1515+ fake_surface_producer (),
1516+ /* intercept_all_input=*/ true // Enables the interceptor.
1517+ );
1518+ flatland_connection ()->Present ();
1519+ loop ().RunUntilIdle ();
1520+ fake_flatland ().FireOnNextFrameBeginEvent (WithPresentCredits (1u ));
1521+ loop ().RunUntilIdle ();
1522+ EXPECT_THAT (fake_flatland ().graph (),
1523+ IsFlutterGraph (parent_viewport_watcher, viewport_creation_token,
1524+ view_ref, {IsInputShield ()}));
1525+
1526+ // Create the view before drawing the scene.
1527+ const SkSize child_view_size_signed = SkSize::Make (256 .f , 512 .f );
1528+ const fuchsia::math::SizeU child_view_size{
1529+ static_cast <uint32_t >(child_view_size_signed.width ()),
1530+ static_cast <uint32_t >(child_view_size_signed.height ())};
1531+ auto [child_view_token, child_viewport_token] = ViewTokenPair::New ();
1532+ const uint32_t child_view_id = child_viewport_token.value .get ();
1533+
1534+ const int kOpacity = 200 ;
1535+ const float kOpacityFloat = 200 / 255 .0f ;
1536+ const fuchsia::math::VecF kScale {3 .0f , 4 .0f };
1537+
1538+ auto matrix = SkMatrix::I ();
1539+ matrix.setScaleX (kScale .x );
1540+ matrix.setScaleY (kScale .y );
1541+
1542+ auto mutators_stack = flutter::MutatorsStack ();
1543+ mutators_stack.PushOpacity (kOpacity );
1544+ mutators_stack.PushTransform (matrix);
1545+
1546+ flutter::EmbeddedViewParams child_view_params (matrix, child_view_size_signed,
1547+ mutators_stack);
1548+ external_view_embedder.CreateView (
1549+ child_view_id, []() {},
1550+ [](fuchsia::ui::composition::ContentId,
1551+ fuchsia::ui::composition::ChildViewWatcherHandle) {});
1552+ const SkRect child_view_occlusion_hint = SkRect::MakeLTRB (1 , 2 , 3 , 4 );
1553+ const fuchsia::math::Inset child_view_inset{
1554+ static_cast <int32_t >(child_view_occlusion_hint.top ()),
1555+ static_cast <int32_t >(child_view_occlusion_hint.right ()),
1556+ static_cast <int32_t >(child_view_occlusion_hint.bottom ()),
1557+ static_cast <int32_t >(child_view_occlusion_hint.left ())};
1558+ external_view_embedder.SetViewProperties (
1559+ child_view_id, child_view_occlusion_hint, /* hit_testable=*/ false ,
1560+ /* focusable=*/ false );
1561+
1562+ // We must take into account the effect of DPR on the view scale.
1563+ const float kDPR = 2 .0f ;
1564+ const float kInvDPR = 1 .f / kDPR ;
1565+
1566+ // Draw the scene. The scene graph shouldn't change yet.
1567+ const SkISize frame_size_signed = SkISize::Make (512 , 512 );
1568+ const fuchsia::math::SizeU frame_size{
1569+ static_cast <uint32_t >(frame_size_signed.width ()),
1570+ static_cast <uint32_t >(frame_size_signed.height ())};
1571+ DrawFrameWithView (
1572+ external_view_embedder, frame_size_signed, kDPR , child_view_id,
1573+ child_view_params,
1574+ [](SkCanvas* canvas) {
1575+ const SkSize canvas_size = SkSize::Make (canvas->imageInfo ().width (),
1576+ canvas->imageInfo ().height ());
1577+ SkPaint rect_paint;
1578+ rect_paint.setColor (SK_ColorGREEN);
1579+ canvas->translate (canvas_size.width () / 4 .f ,
1580+ canvas_size.height () / 2 .f );
1581+ canvas->drawRect (SkRect::MakeWH (canvas_size.width () / 32 .f ,
1582+ canvas_size.height () / 32 .f ),
1583+ rect_paint);
1584+ },
1585+ [](SkCanvas* canvas) {
1586+ const SkSize canvas_size = SkSize::Make (canvas->imageInfo ().width (),
1587+ canvas->imageInfo ().height ());
1588+ SkPaint rect_paint;
1589+ rect_paint.setColor (SK_ColorRED);
1590+ canvas->translate (canvas_size.width () * 3 .f / 4 .f ,
1591+ canvas_size.height () / 2 .f );
1592+ canvas->drawRect (SkRect::MakeWH (canvas_size.width () / 32 .f ,
1593+ canvas_size.height () / 32 .f ),
1594+ rect_paint);
1595+ });
1596+ EXPECT_THAT (fake_flatland ().graph (),
1597+ IsFlutterGraph (parent_viewport_watcher, viewport_creation_token,
1598+ view_ref, {IsInputShield ()}));
1599+
1600+ // Pump the message loop. The scene updates should propagate to flatland.
1601+ loop ().RunUntilIdle ();
1602+ fake_flatland ().FireOnNextFrameBeginEvent (WithPresentCredits (1u ));
1603+ loop ().RunUntilIdle ();
1604+
1605+ EXPECT_THAT (
1606+ fake_flatland ().graph (),
1607+ IsFlutterGraph (
1608+ parent_viewport_watcher, viewport_creation_token, view_ref, /* layers*/
1609+ {IsImageLayer (
1610+ frame_size, kFirstLayerBlendMode ,
1611+ {IsHitRegion (
1612+ /* x */ 128 .f ,
1613+ /* y */ 256 .f ,
1614+ /* width */ 16 .f ,
1615+ /* height */ 16 .f ,
1616+ /* hit_test */
1617+ fuchsia::ui::composition::HitTestInteraction::DEFAULT)}),
1618+ IsViewportLayer (child_view_token, child_view_size, child_view_inset,
1619+ {0 , 0 }, kScale , kOpacityFloat ),
1620+ IsImageLayer (
1621+ frame_size, kUpperLayerBlendMode ,
1622+ {IsHitRegion (
1623+ /* x */ 384 .f ,
1624+ /* y */ 256 .f ,
1625+ /* width */ 16 .f ,
1626+ /* height */ 16 .f ,
1627+ /* hit_test */
1628+ fuchsia::ui::composition::HitTestInteraction::DEFAULT)}),
1629+ IsInputShield ()},
1630+ {kInvDPR , kInvDPR }));
1631+ }
1632+
14791633} // namespace flutter_runner::testing
0 commit comments