diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc index b250ffe8cf6e7..36362242e0933 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc @@ -258,6 +258,14 @@ void FlatlandExternalViewEmbedder::SubmitFrame( {static_cast(surface_for_layer->GetSize().width()), static_cast(surface_for_layer->GetSize().height())}); + // Flutter Embedder lacks an API to detect if a layer has alpha or not. + // For now, we assume any layer beyond the first has alpha. + flatland_->flatland()->SetImageBlendingFunction( + {surface_for_layer->GetImageId()}, + flatland_layer_index == 0 + ? fuchsia::ui::composition::BlendMode::SRC + : fuchsia::ui::composition::BlendMode::SRC_OVER); + // Attach the FlatlandLayer to the main scene graph. flatland_->flatland()->AddChild( root_transform_id_, @@ -267,7 +275,6 @@ void FlatlandExternalViewEmbedder::SubmitFrame( } // Reset for the next pass: - // +The next layer will not be the first layer. flatland_layer_index++; } } diff --git a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc index d3007145eb72f..5aec9989a702d 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc +++ b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.cc @@ -621,6 +621,37 @@ void FakeFlatland::SetImageDestinationSize( image->destination_size = size; } +void FakeFlatland::SetImageBlendingFunction( + fuchsia::ui::composition::ContentId image_id, + fuchsia::ui::composition::BlendMode blend_mode) { + if (image_id.value == 0) { + // TODO(fxb/85619): Raise a FlatlandError here + FML_CHECK(false) + << "FakeFlatland::SetImageDestinationSize: ContentId 0 is invalid."; + return; + } + + auto found_content = pending_graph_.content_map.find(image_id.value); + if (found_content == pending_graph_.content_map.end()) { + // TODO(fxb/85619): Raise a FlatlandError here + FML_CHECK(false) << "FakeFlatland::SetImageDestinationSize: ContentId " + << image_id.value << " does not exist."; + return; + } + + auto& content = found_content->second; + FML_CHECK(content); + FakeImage* image = std::get_if(content.get()); + if (image == nullptr) { + // TODO(fxb/85619): Raise a FlatlandError here + FML_CHECK(false) << "FakeFlatland::SetImageDestinationSize: ContentId " + << image_id.value << " is not an Image."; + return; + } + + image->blend_mode = blend_mode; +} + void FakeFlatland::SetViewportProperties( fuchsia::ui::composition::ContentId viewport_id, fuchsia::ui::composition::ViewportProperties properties) { diff --git a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.h b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.h index 1f219198dc45a..c951199302f5e 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.h +++ b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland.h @@ -276,6 +276,11 @@ class FakeFlatland void SetImageDestinationSize(fuchsia::ui::composition::ContentId image_id, fuchsia::math::SizeU size) override; + // |fuchsia::ui::composition::Flatland| + void SetImageBlendingFunction( + fuchsia::ui::composition::ContentId image_id, + fuchsia::ui::composition::BlendMode blend_mode) override; + // |fuchsia::ui::composition::Flatland| void SetViewportProperties( fuchsia::ui::composition::ContentId viewport_id, diff --git a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc index a79e702af944a..9c1faea3bc649 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc +++ b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.cc @@ -40,6 +40,7 @@ std::shared_ptr CloneFakeContent( .sample_region = image->sample_region, .destination_size = image->destination_size, .opacity = image->opacity, + .blend_mode = image->blend_mode, .import_token = image->import_token, .vmo_index = image->vmo_index, }); @@ -124,8 +125,8 @@ bool FakeImage::operator==(const FakeImage& other) const { return id == other.id && image_properties == other.image_properties && sample_region == other.sample_region && destination_size == other.destination_size && - opacity == other.opacity && import_token == other.import_token && - vmo_index == other.vmo_index; + opacity == other.opacity && blend_mode == other.blend_mode && + import_token == other.import_token && vmo_index == other.vmo_index; } bool FakeTransform::operator==(const FakeTransform& other) const { diff --git a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h index 4a76a00171cc4..723a64ecdbc17 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h +++ b/shell/platform/fuchsia/flutter/tests/fakes/scenic/fake_flatland_types.h @@ -144,6 +144,8 @@ struct FakeImage { constexpr static fuchsia::math::RectF kDefaultSampleRegion{}; constexpr static fuchsia::math::SizeU kDefaultDestinationSize{}; constexpr static float kDefaultOpacity{1.f}; + constexpr static fuchsia::ui::composition::BlendMode kDefaultBlendMode{ + fuchsia::ui::composition::BlendMode::SRC_OVER}; fuchsia::ui::composition::ContentId id{kInvalidContentId}; @@ -151,6 +153,7 @@ struct FakeImage { fuchsia::math::RectF sample_region{kDefaultSampleRegion}; fuchsia::math::SizeU destination_size{kDefaultDestinationSize}; float opacity{kDefaultOpacity}; + fuchsia::ui::composition::BlendMode blend_mode{kDefaultBlendMode}; zx_koid_t import_token{}; uint32_t vmo_index{0}; diff --git a/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc b/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc index 53a0f5a88b21f..9582fa8c41898 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_external_view_embedder_unittests.cc @@ -51,6 +51,11 @@ using ::testing::VariantWith; namespace flutter_runner::testing { namespace { +constexpr static fuchsia::ui::composition::BlendMode kFirstLayerBlendMode{ + fuchsia::ui::composition::BlendMode::SRC}; +constexpr static fuchsia::ui::composition::BlendMode kUpperLayerBlendMode{ + fuchsia::ui::composition::BlendMode::SRC_OVER}; + class FakeSurfaceProducerSurface : public SurfaceProducerSurface { public: explicit FakeSurfaceProducerSurface( @@ -226,7 +231,8 @@ Matcher IsFlutterGraph( } Matcher> IsImageLayer( - const fuchsia::math::SizeU& layer_size) { + const fuchsia::math::SizeU& layer_size, + fuchsia::ui::composition::BlendMode blend_mode) { return Pointee(FieldsAre( /*id*/ _, FakeTransform::kDefaultTranslation, FakeTransform::kDefaultClipBounds, FakeTransform::kDefaultOrientation, @@ -235,7 +241,7 @@ Matcher> IsImageLayer( Pointee(VariantWith(FieldsAre( /*id*/ _, IsImageProperties(layer_size), FakeImage::kDefaultSampleRegion, layer_size, - FakeImage::kDefaultOpacity, + FakeImage::kDefaultOpacity, blend_mode, /*buffer_import_token*/ _, /*vmo_index*/ 0))))); } @@ -454,13 +460,13 @@ TEST_F(FlatlandExternalViewEmbedderTest, SimpleScene) { IsFlutterGraph(parent_viewport_watcher, viewport_creation_token, view_ref)); - // Pump the message loop. The scene updates should propagate to flatland. + // 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)})); + {IsImageLayer(frame_size, kFirstLayerBlendMode)})); } TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { @@ -549,9 +555,9 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { fake_flatland().graph(), IsFlutterGraph( parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ - {IsImageLayer(frame_size), + {IsImageLayer(frame_size, kFirstLayerBlendMode), IsViewportLayer(child_view_token, child_view_size, {0, 0}), - IsImageLayer(frame_size)})); + IsImageLayer(frame_size, kUpperLayerBlendMode)})); // Destroy the view. The scene graph shouldn't change yet. external_view_embedder.DestroyView( @@ -560,9 +566,9 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { fake_flatland().graph(), IsFlutterGraph( parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ - {IsImageLayer(frame_size), + {IsImageLayer(frame_size, kFirstLayerBlendMode), IsViewportLayer(child_view_token, child_view_size, {0, 0}), - IsImageLayer(frame_size)})); + IsImageLayer(frame_size, kUpperLayerBlendMode)})); // Draw another frame without the view. The scene graph shouldn't change yet. DrawSimpleFrame( @@ -581,16 +587,16 @@ TEST_F(FlatlandExternalViewEmbedderTest, SceneWithOneView) { fake_flatland().graph(), IsFlutterGraph( parent_viewport_watcher, viewport_creation_token, view_ref, /*layers*/ - {IsImageLayer(frame_size), + {IsImageLayer(frame_size, kFirstLayerBlendMode), IsViewportLayer(child_view_token, child_view_size, {0, 0}), - IsImageLayer(frame_size)})); + IsImageLayer(frame_size, kUpperLayerBlendMode)})); // 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)})); + {IsImageLayer(frame_size, kFirstLayerBlendMode)})); } } // namespace flutter_runner::testing