diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 4950aae8496fc..f1557d2c6ad8e 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -13,6 +13,7 @@ #include "flutter/testing/testing.h" #include "impeller/aiks/aiks_playground.h" #include "impeller/aiks/canvas.h" +#include "impeller/aiks/color_filter.h" #include "impeller/aiks/image.h" #include "impeller/aiks/image_filter.h" #include "impeller/aiks/paint_pass_delegate.h" @@ -123,16 +124,47 @@ TEST_P(AiksTest, CanRenderImage) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, CanRenderInvertedImage) { +constexpr ColorMatrix kColorInversion = {.array = { + -1.0, 0, 0, 1.0, 0, // + 0, -1.0, 0, 1.0, 0, // + 0, 0, -1.0, 1.0, 0, // + 1.0, 1.0, 1.0, 1.0, 0 // + }}; + +TEST_P(AiksTest, CanRenderMergedColorFilterImage) { Canvas canvas; Paint paint; auto image = std::make_shared(CreateTextureForFixture("kalimba.jpg")); paint.color = Color::Red(); - paint.invert_colors = true; + paint.color_filter = ColorFilter::MakeComposed( + ColorFilter::MakeMatrix(kColorInversion), + ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Yellow())); canvas.DrawImage(image, Point::MakeXY(100.0, 100.0), paint); ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, CanRenderMergedColorFilter) { + Canvas canvas; + Paint paint; + paint.color = Color::Red(); + paint.color_filter = ColorFilter::MakeComposed( + ColorFilter::MakeMatrix(kColorInversion), + ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Yellow())); + canvas.DrawRect(Rect::MakeLTRB(0, 0, 100, 100), paint); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderMergedColorFilterDrawPaint) { + Canvas canvas; + Paint paint; + paint.color = Color::Red(); + paint.color_filter = ColorFilter::MakeComposed( + ColorFilter::MakeMatrix(kColorInversion), + ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Yellow())); + canvas.DrawPaint(paint); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + namespace { bool GenerateMipmap(const std::shared_ptr& context, std::shared_ptr texture, diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index ae4c9d512037f..80f0cc734809e 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -4,7 +4,6 @@ #include "impeller/aiks/canvas.h" -#include #include #include diff --git a/impeller/aiks/color_filter.cc b/impeller/aiks/color_filter.cc index 87f7022e1cd1f..b5498a195408b 100644 --- a/impeller/aiks/color_filter.cc +++ b/impeller/aiks/color_filter.cc @@ -3,7 +3,10 @@ // found in the LICENSE file. #include "impeller/aiks/color_filter.h" + +#include #include "impeller/entity/contents/filters/color_filter_contents.h" +#include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/geometry/color.h" @@ -34,6 +37,12 @@ std::shared_ptr ColorFilter::MakeLinearToSrgb() { return std::make_shared(); } +std::shared_ptr ColorFilter::MakeComposed( + const std::shared_ptr& outer, + const std::shared_ptr& inner) { + return std::make_shared(outer, inner); +} + /******************************************************************************* ******* BlendColorFilter ******************************************************************************/ @@ -142,4 +151,40 @@ std::shared_ptr LinearToSrgbColorFilter::Clone() const { return std::make_shared(*this); } +/******************************************************************************* + ******* ComposedColorFilter + ******************************************************************************/ + +ComposedColorFilter::ComposedColorFilter( + const std::shared_ptr& outer, + const std::shared_ptr& inner) + : outer_(outer), inner_(inner) {} + +ComposedColorFilter::~ComposedColorFilter() = default; + +std::shared_ptr +ComposedColorFilter::WrapWithGPUColorFilter( + std::shared_ptr input, + ColorFilterContents::AbsorbOpacity absorb_opacity) const { + std::shared_ptr inner = inner_->WrapWithGPUColorFilter( + input, ColorFilterContents::AbsorbOpacity::kNo); + return outer_->WrapWithGPUColorFilter(FilterInput::Make(inner), + absorb_opacity); +} + +// |ColorFilter| +ColorFilter::ColorFilterProc ComposedColorFilter::GetCPUColorFilterProc() + const { + return [inner = inner_, outer = outer_](Color color) { + auto inner_proc = inner->GetCPUColorFilterProc(); + auto outer_proc = outer->GetCPUColorFilterProc(); + return outer_proc(inner_proc(color)); + }; +} + +// |ColorFilter| +std::shared_ptr ComposedColorFilter::Clone() const { + return std::make_shared(outer_, inner_); +} + } // namespace impeller diff --git a/impeller/aiks/color_filter.h b/impeller/aiks/color_filter.h index 1c5bf32dd9f8a..84dfbbd19b40d 100644 --- a/impeller/aiks/color_filter.h +++ b/impeller/aiks/color_filter.h @@ -34,6 +34,10 @@ class ColorFilter { static std::shared_ptr MakeLinearToSrgb(); + static std::shared_ptr MakeComposed( + const std::shared_ptr& outer, + const std::shared_ptr& inner); + /// @brief Wraps the given filter input with a GPU-based filter that will /// perform the color operation. The given input will first be /// rendered to a texture and then filtered. @@ -147,4 +151,28 @@ class LinearToSrgbColorFilter final : public ColorFilter { std::shared_ptr Clone() const override; }; +/// @brief Applies color filters as f(g(x)), where x is the input color. +class ComposedColorFilter final : public ColorFilter { + public: + ComposedColorFilter(const std::shared_ptr& outer, + const std::shared_ptr& inner); + + ~ComposedColorFilter() override; + + // |ColorFilter| + std::shared_ptr WrapWithGPUColorFilter( + std::shared_ptr input, + ColorFilterContents::AbsorbOpacity absorb_opacity) const override; + + // |ColorFilter| + ColorFilterProc GetCPUColorFilterProc() const override; + + // |ColorFilter| + std::shared_ptr Clone() const override; + + private: + std::shared_ptr outer_; + std::shared_ptr inner_; +}; + } // namespace impeller diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 66a3f7280f70a..f9651f31c0ee0 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -59,7 +59,6 @@ std::shared_ptr Paint::CreateContentsForGeometry( std::shared_ptr Paint::WithFilters( std::shared_ptr input) const { input = WithColorFilter(input, ColorFilterContents::AbsorbOpacity::kYes); - input = WithInvertFilter(input); auto image_filter = WithImageFilter(input, Matrix(), Entity::RenderingMode::kDirect); if (image_filter) { @@ -121,33 +120,10 @@ std::shared_ptr Paint::WithColorFilter( if (input->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) { return input; } - return color_filter->WrapWithGPUColorFilter(FilterInput::Make(input), absorb_opacity); } -/// A color matrix which inverts colors. -// clang-format off -constexpr ColorMatrix kColorInversion = { - .array = { - -1.0, 0, 0, 1.0, 0, // - 0, -1.0, 0, 1.0, 0, // - 0, 0, -1.0, 1.0, 0, // - 1.0, 1.0, 1.0, 1.0, 0 // - } -}; -// clang-format on - -std::shared_ptr Paint::WithInvertFilter( - std::shared_ptr input) const { - if (!invert_colors) { - return input; - } - - return ColorFilterContents::MakeColorMatrix( - {FilterInput::Make(std::move(input))}, kColorInversion); -} - std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( std::shared_ptr color_source_contents, const std::shared_ptr& color_filter) const { diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index c2e907a1cc5b0..0fba8a628d12b 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -61,7 +61,6 @@ struct Paint { Scalar stroke_miter = 4.0; Style style = Style::kFill; BlendMode blend_mode = BlendMode::kSourceOver; - bool invert_colors = false; std::shared_ptr image_filter; std::shared_ptr color_filter; @@ -108,9 +107,6 @@ struct Paint { std::shared_ptr input, ColorFilterContents::AbsorbOpacity absorb_opacity = ColorFilterContents::AbsorbOpacity::kNo) const; - - std::shared_ptr WithInvertFilter( - std::shared_ptr input) const; }; } // namespace impeller diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 0b19cefb5b79b..c0b610157e1c6 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -16,20 +15,13 @@ #include "flutter/fml/trace_event.h" #include "impeller/aiks/color_filter.h" #include "impeller/core/formats.h" -#include "impeller/display_list/dl_image_impeller.h" #include "impeller/display_list/dl_vertices_geometry.h" #include "impeller/display_list/nine_patch_converter.h" #include "impeller/display_list/skia_conversions.h" -#include "impeller/entity/contents/conical_gradient_contents.h" #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" -#include "impeller/entity/contents/linear_gradient_contents.h" -#include "impeller/entity/contents/radial_gradient_contents.h" #include "impeller/entity/contents/runtime_effect_contents.h" -#include "impeller/entity/contents/sweep_gradient_contents.h" -#include "impeller/entity/contents/tiled_texture_contents.h" #include "impeller/entity/entity.h" -#include "impeller/entity/geometry/geometry.h" #include "impeller/geometry/path.h" #include "impeller/geometry/path_builder.h" #include "impeller/geometry/scalar.h" @@ -41,6 +33,18 @@ namespace impeller { +/// A color matrix which inverts colors. +// clang-format off +constexpr ColorMatrix kColorInversion = { + .array = { + -1.0, 0, 0, 1.0, 0, // + 0, -1.0, 0, 1.0, 0, // + 0, 0, -1.0, 1.0, 0, // + 1.0, 1.0, 1.0, 1.0, 0 // + } +}; +// clang-format on + #define UNIMPLEMENTED \ FML_DLOG(ERROR) << "Unimplemented detail in " << __FUNCTION__; @@ -484,12 +488,24 @@ static std::shared_ptr ToColorFilter( // |flutter::DlOpReceiver| void DlDispatcher::setColorFilter(const flutter::DlColorFilter* filter) { // Needs https://github.com/flutter/flutter/issues/95434 - paint_.color_filter = ToColorFilter(filter); + if (paint_.color_filter) { + auto color_filter = ToColorFilter(filter); + paint_.color_filter = + ColorFilter::MakeComposed(paint_.color_filter, color_filter); + } else { + paint_.color_filter = ToColorFilter(filter); + } } // |flutter::DlOpReceiver| void DlDispatcher::setInvertColors(bool invert) { - paint_.invert_colors = invert; + if (paint_.color_filter) { + auto invert_filter = ColorFilter::MakeMatrix(kColorInversion); + paint_.color_filter = + ColorFilter::MakeComposed(invert_filter, paint_.color_filter); + } else { + paint_.color_filter = ColorFilter::MakeMatrix(kColorInversion); + } } // |flutter::DlOpReceiver|