From 2db84b20f916f183f43a41993cc36fb36f84f9fb Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Thu, 20 Mar 2025 10:28:00 -0700 Subject: [PATCH] [Impeller] libImpeller: Expose APIs to draw shadows. (#165517) Fixes https://github.com/flutter/flutter/issues/165146 --- .../impeller/toolkit/interop/dl_builder.cc | 13 +++++++++ .../impeller/toolkit/interop/dl_builder.h | 6 ++++ .../impeller/toolkit/interop/impeller.cc | 15 ++++++++++ .../impeller/toolkit/interop/impeller.h | 24 +++++++++++++++ .../impeller/toolkit/interop/impeller.hpp | 15 ++++++++++ .../toolkit/interop/impeller_unittests.cc | 29 +++++++++++++++++++ 6 files changed, 102 insertions(+) diff --git a/engine/src/flutter/impeller/toolkit/interop/dl_builder.cc b/engine/src/flutter/impeller/toolkit/interop/dl_builder.cc index 8d719bacdb..5a24b56710 100644 --- a/engine/src/flutter/impeller/toolkit/interop/dl_builder.cc +++ b/engine/src/flutter/impeller/toolkit/interop/dl_builder.cc @@ -181,4 +181,17 @@ void DisplayListBuilder::DrawParagraph(const Paragraph& paragraph, handle->Paint(&builder_, point.x, point.y); } +void DisplayListBuilder::DrawShadow(const Path& path, + const flutter::DlColor& color, + float elevation, + bool occluder_is_transparent, + float device_pixel_ratio) { + builder_.DrawShadow(flutter::DlPath(path.GetPath()), // path + color, // shadow color + elevation, // elevation + occluder_is_transparent, // occluder transparency + device_pixel_ratio // dpr + ); +} + } // namespace impeller::interop diff --git a/engine/src/flutter/impeller/toolkit/interop/dl_builder.h b/engine/src/flutter/impeller/toolkit/interop/dl_builder.h index e7be5f3923..a411723838 100644 --- a/engine/src/flutter/impeller/toolkit/interop/dl_builder.h +++ b/engine/src/flutter/impeller/toolkit/interop/dl_builder.h @@ -110,6 +110,12 @@ class DisplayListBuilder final void DrawParagraph(const Paragraph& paragraph, Point point); + void DrawShadow(const Path& path, + const flutter::DlColor& color, + float elevation, + bool occluder_is_transparent, + float device_pixel_ratio); + ScopedObject Build(); private: diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.cc b/engine/src/flutter/impeller/toolkit/interop/impeller.cc index 95d61e3217..ad55da1280 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.cc +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.cc @@ -1150,6 +1150,21 @@ void ImpellerDisplayListBuilderDrawParagraph(ImpellerDisplayListBuilder builder, GetPeer(builder)->DrawParagraph(*GetPeer(paragraph), ToImpellerType(*point)); } +IMPELLER_EXTERN_C +void ImpellerDisplayListBuilderDrawShadow(ImpellerDisplayListBuilder builder, + ImpellerPath path, + const ImpellerColor* color, + float elevation, + bool occluder_is_transparent, + float device_pixel_ratio) { + GetPeer(builder)->DrawShadow(*GetPeer(path), // + ToDisplayListType(*color), // + elevation, // + occluder_is_transparent, // + device_pixel_ratio // + ); +} + IMPELLER_EXTERN_C ImpellerParagraphBuilder ImpellerParagraphBuilderNew( ImpellerTypographyContext context) { diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.h b/engine/src/flutter/impeller/toolkit/interop/impeller.h index 1caa408873..4d65a3cfd9 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.h +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.h @@ -2098,6 +2098,30 @@ void ImpellerDisplayListBuilderDrawParagraph( ImpellerParagraph IMPELLER_NONNULL paragraph, const ImpellerPoint* IMPELLER_NONNULL point); +//------------------------------------------------------------------------------ +/// @brief Draw a shadow for a Path given a material elevation. If the +/// occluding object is not opaque, additional hints (via the +/// `occluder_is_transparent` argument) must be provided to render +/// the shadow correctly. +/// +/// @param[in] builder The builder. +/// @param[in] path The shadow path. +/// @param[in] color The shadow color. +/// @param[in] elevation The material elevation. +/// @param[in] occluder_is_transparent +/// If the object casting the shadow is transparent. +/// @param[in] device_pixel_ratio +/// The device pixel ratio. +/// +IMPELLER_EXPORT +void ImpellerDisplayListBuilderDrawShadow( + ImpellerDisplayListBuilder IMPELLER_NONNULL builder, + ImpellerPath IMPELLER_NONNULL path, + const ImpellerColor* IMPELLER_NONNULL color, + float elevation, + bool occluder_is_transparent, + float device_pixel_ratio); + //------------------------------------------------------------------------------ // Display List Builder: Drawing Textures //------------------------------------------------------------------------------ diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller.hpp b/engine/src/flutter/impeller/toolkit/interop/impeller.hpp index 2c5eb75392..22e5a30ae9 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller.hpp +++ b/engine/src/flutter/impeller/toolkit/interop/impeller.hpp @@ -73,6 +73,7 @@ struct Proc { PROC(ImpellerDisplayListBuilderDrawOval) \ PROC(ImpellerDisplayListBuilderDrawPaint) \ PROC(ImpellerDisplayListBuilderDrawParagraph) \ + PROC(ImpellerDisplayListBuilderDrawShadow) \ PROC(ImpellerDisplayListBuilderDrawPath) \ PROC(ImpellerDisplayListBuilderDrawRect) \ PROC(ImpellerDisplayListBuilderDrawRoundedRect) \ @@ -1345,6 +1346,20 @@ class DisplayListBuilder final return *this; } + //---------------------------------------------------------------------------- + /// @see ImpellerDisplayListBuilderDrawShadow + /// + DisplayListBuilder& DrawShadow(const Path& path, + const ImpellerColor& shadow_color, + float elevation, + bool occluder_is_transparent, + float device_pixel_ratio) { + gGlobalProcTable.ImpellerDisplayListBuilderDrawShadow( + Get(), path.Get(), &shadow_color, elevation, occluder_is_transparent, + device_pixel_ratio); + return *this; + } + //---------------------------------------------------------------------------- /// @see ImpellerDisplayListBuilderDrawPath /// diff --git a/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc b/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc index 14ebfc745d..c512e9473a 100644 --- a/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc +++ b/engine/src/flutter/impeller/toolkit/interop/impeller_unittests.cc @@ -474,4 +474,33 @@ TEST_P(InteropPlaygroundTest, CanRenderTextAlignments) { })); } +TEST_P(InteropPlaygroundTest, CanRenderShadows) { + hpp::DisplayListBuilder builder; + { + builder.DrawRect(ImpellerRect{0, 0, 400, 400}, + hpp::Paint{}.SetColor(ImpellerColor{ + 0.0, 1.0, 0.0, 1.0, kImpellerColorSpaceSRGB})); + } + ImpellerRect box = {100, 100, 100, 100}; + { + hpp::PathBuilder path_builder; + path_builder.AddRect(box); + ImpellerColor shadow_color = {0.0, 0.0, 0.0, 1.0, kImpellerColorSpaceSRGB}; + builder.DrawShadow(path_builder.Build(), shadow_color, 4.0f, false, 1.0f); + } + { + hpp::Paint red_paint; + red_paint.SetColor( + ImpellerColor{1.0, 0.0, 0.0, 1.0, kImpellerColorSpaceSRGB}); + builder.DrawRect(box, red_paint); + } + auto dl = builder.Build(); + ASSERT_TRUE( + OpenPlaygroundHere([&](const auto& context, const auto& surface) -> bool { + hpp::Surface window(surface.GetC()); + window.Draw(dl); + return true; + })); +} + } // namespace impeller::interop::testing