diff --git a/engine/src/flutter/ci/licenses_golden/excluded_files b/engine/src/flutter/ci/licenses_golden/excluded_files index 4227a1f8b0..e30a502627 100644 --- a/engine/src/flutter/ci/licenses_golden/excluded_files +++ b/engine/src/flutter/ci/licenses_golden/excluded_files @@ -151,6 +151,7 @@ ../../../flutter/impeller/display_list/dl_golden_unittests.cc ../../../flutter/impeller/display_list/dl_golden_unittests.h ../../../flutter/impeller/display_list/dl_unittests.cc +../../../flutter/impeller/display_list/paint_unittests.cc ../../../flutter/impeller/display_list/skia_conversions_unittests.cc ../../../flutter/impeller/display_list/testing ../../../flutter/impeller/docs diff --git a/engine/src/flutter/impeller/display_list/BUILD.gn b/engine/src/flutter/impeller/display_list/BUILD.gn index 4d9c4f8a90..c9d0003256 100644 --- a/engine/src/flutter/impeller/display_list/BUILD.gn +++ b/engine/src/flutter/impeller/display_list/BUILD.gn @@ -78,6 +78,7 @@ template("display_list_unittests_component") { "dl_playground.cc", "dl_playground.h", "dl_unittests.cc", + "paint_unittests.cc", "testing/render_text_in_canvas.cc", "testing/render_text_in_canvas.h", "testing/rmse.cc", diff --git a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc index 11e5e6a844..ffb530ce05 100644 --- a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc +++ b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc @@ -137,6 +137,13 @@ static impeller::SamplerDescriptor ToSamplerDescriptor( return desc; } +static std::optional ToOptRect(const flutter::DlRect* rect) { + if (rect == nullptr) { + return std::nullopt; + } + return *rect; +} + // |flutter::DlOpReceiver| void DlDispatcherBase::setAntiAlias(bool aa) { AUTO_DEPTH_WATCHER(0u); @@ -506,8 +513,8 @@ void DlDispatcherBase::clipPath(const DlPath& path, } else { SkRRect rrect; if (path.IsSkRRect(&rrect) && rrect.isSimple()) { - RoundRectGeometry geom(skia_conversions::ToRect(rrect.rect()), - skia_conversions::ToSize(rrect.getSimpleRadii())); + RoundRectGeometry geom(flutter::ToDlRect(rrect.rect()), + flutter::ToDlSize(rrect.getSimpleRadii())); GetCanvas().ClipGeometry(geom, clip_op); } else { FillPathGeometry geom(path.GetPath()); @@ -820,7 +827,7 @@ void DlDispatcherBase::drawAtlas(const sk_sp atlas, static_cast(count), // skia_conversions::ToBlendMode(mode), // skia_conversions::ToSamplerDescriptor(sampling), // - skia_conversions::ToRect(cull_rect) // + ToOptRect(cull_rect) // ); auto atlas_contents = std::make_shared(); atlas_contents->SetGeometry(&geometry); @@ -854,10 +861,10 @@ void DlDispatcherBase::drawDisplayList( if (opacity < SK_Scalar1) { Paint save_paint; save_paint.color = Color(0, 0, 0, opacity); - GetCanvas().SaveLayer( - save_paint, skia_conversions::ToRect(display_list->bounds()), nullptr, - ContentBoundsPromise::kContainsContents, display_list->total_depth(), - display_list->can_apply_group_opacity()); + GetCanvas().SaveLayer(save_paint, display_list->GetBounds(), nullptr, + ContentBoundsPromise::kContainsContents, + display_list->total_depth(), + display_list->can_apply_group_opacity()); } else { // The display list may alter the clip, which must be restored to the // current clip at the end of playback. diff --git a/engine/src/flutter/impeller/display_list/image_filter.cc b/engine/src/flutter/impeller/display_list/image_filter.cc index 1546cbf31f..f54687985f 100644 --- a/engine/src/flutter/impeller/display_list/image_filter.cc +++ b/engine/src/flutter/impeller/display_list/image_filter.cc @@ -4,6 +4,7 @@ #include "impeller/display_list/image_filter.h" +#include "flutter/display_list/effects/dl_color_sources.h" #include "flutter/display_list/effects/dl_image_filters.h" #include "fml/logging.h" #include "impeller/display_list/color_filter.h" diff --git a/engine/src/flutter/impeller/display_list/paint.cc b/engine/src/flutter/impeller/display_list/paint.cc index e5d03980ff..245d21447f 100644 --- a/engine/src/flutter/impeller/display_list/paint.cc +++ b/engine/src/flutter/impeller/display_list/paint.cc @@ -34,6 +34,31 @@ using DlRect = flutter::DlRect; using DlIRect = flutter::DlIRect; using DlPath = flutter::DlPath; +void Paint::ConvertStops(const flutter::DlGradientColorSourceBase* gradient, + std::vector& colors, + std::vector& stops) { + FML_DCHECK(gradient->stop_count() >= 2) + << "stop_count:" << gradient->stop_count(); + + auto* dl_colors = gradient->colors(); + auto* dl_stops = gradient->stops(); + if (dl_stops[0] != 0.0) { + colors.emplace_back(skia_conversions::ToColor(dl_colors[0])); + stops.emplace_back(0); + } + for (auto i = 0; i < gradient->stop_count(); i++) { + colors.emplace_back(skia_conversions::ToColor(dl_colors[i])); + stops.emplace_back(std::clamp(dl_stops[i], 0.0f, 1.0f)); + } + if (dl_stops[gradient->stop_count() - 1] != 1.0) { + colors.emplace_back(colors.back()); + stops.emplace_back(1.0); + } + for (auto i = 1; i < gradient->stop_count(); i++) { + stops[i] = std::clamp(stops[i], stops[i - 1], stops[i]); + } +} + std::shared_ptr Paint::CreateContents() const { if (color_source == nullptr) { auto contents = std::make_shared(); @@ -50,7 +75,7 @@ std::shared_ptr Paint::CreateContents() const { auto end_point = linear->end_point(); std::vector colors; std::vector stops; - skia_conversions::ConvertStops(linear, colors, stops); + ConvertStops(linear, colors, stops); auto tile_mode = static_cast(linear->tile_mode()); auto effect_transform = linear->matrix(); @@ -78,7 +103,7 @@ std::shared_ptr Paint::CreateContents() const { auto radius = radialGradient->radius(); std::vector colors; std::vector stops; - skia_conversions::ConvertStops(radialGradient, colors, stops); + ConvertStops(radialGradient, colors, stops); auto tile_mode = static_cast(radialGradient->tile_mode()); @@ -110,7 +135,7 @@ std::shared_ptr Paint::CreateContents() const { DlScalar focus_radius = conical_gradient->start_radius(); std::vector colors; std::vector stops; - skia_conversions::ConvertStops(conical_gradient, colors, stops); + ConvertStops(conical_gradient, colors, stops); auto tile_mode = static_cast(conical_gradient->tile_mode()); @@ -144,7 +169,7 @@ std::shared_ptr Paint::CreateContents() const { auto end_angle = Degrees(sweepGradient->end()); std::vector colors; std::vector stops; - skia_conversions::ConvertStops(sweepGradient, colors, stops); + ConvertStops(sweepGradient, colors, stops); auto tile_mode = static_cast(sweepGradient->tile_mode()); diff --git a/engine/src/flutter/impeller/display_list/paint.h b/engine/src/flutter/impeller/display_list/paint.h index 830b72673b..2fd33e1352 100644 --- a/engine/src/flutter/impeller/display_list/paint.h +++ b/engine/src/flutter/impeller/display_list/paint.h @@ -8,7 +8,7 @@ #include #include "display_list/effects/dl_color_filter.h" -#include "display_list/effects/dl_color_source.h" +#include "display_list/effects/dl_color_sources.h" #include "display_list/effects/dl_image_filter.h" #include "impeller/display_list/color_filter.h" #include "impeller/display_list/image_filter.h" @@ -119,6 +119,25 @@ struct Paint { const Matrix& effect_transform, Entity::RenderingMode rendering_mode) const; + /// @brief Convert display list colors + stops into impeller colors and + /// stops, taking care to ensure that the stops monotonically + /// increase from 0.0 to 1.0. + /// + /// The general process is: + /// * Ensure that the first gradient stop value is 0.0. If not, insert a + /// new stop with a value of 0.0 and use the first gradient color as this + /// new stops color. + /// * Ensure the last gradient stop value is 1.0. If not, insert a new stop + /// with a value of 1.0 and use the last gradient color as this stops color. + /// * Clamp all gradient values between the values of 0.0 and 1.0. + /// * For all stop values, ensure that the values are monotonically + /// increasing by clamping each value to a minimum of the previous stop + /// value and itself. For example, with stop values of 0.0, 0.5, 0.4, 1.0, + /// we would clamp such that the values were 0.0, 0.5, 0.5, 1.0. + static void ConvertStops(const flutter::DlGradientColorSourceBase* gradient, + std::vector& colors, + std::vector& stops); + private: std::shared_ptr WithColorFilter( std::shared_ptr input, diff --git a/engine/src/flutter/impeller/display_list/paint_unittests.cc b/engine/src/flutter/impeller/display_list/paint_unittests.cc new file mode 100644 index 0000000000..29fc16648e --- /dev/null +++ b/engine/src/flutter/impeller/display_list/paint_unittests.cc @@ -0,0 +1,149 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/impeller/display_list/paint.h" + +#include "gtest/gtest.h" + +#include "flutter/display_list/dl_color.h" +#include "flutter/display_list/dl_tile_mode.h" +#include "flutter/display_list/effects/dl_color_source.h" +#include "flutter/impeller/geometry/scalar.h" + +namespace impeller { +namespace testing { + +TEST(PaintTest, GradientStopConversion) { + // Typical gradient. + std::vector colors = {flutter::DlColor::kBlue(), + flutter::DlColor::kRed(), + flutter::DlColor::kGreen()}; + std::vector stops = {0.0, 0.5, 1.0}; + const auto gradient = + flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // + flutter::DlPoint(1.0, 1.0), // + 3, // + colors.data(), // + stops.data(), // + flutter::DlTileMode::kClamp, // + nullptr // + ); + + std::vector converted_colors; + std::vector converted_stops; + Paint::ConvertStops(gradient->asLinearGradient(), converted_colors, + converted_stops); + + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f)); +} + +TEST(PaintTest, GradientMissing0) { + std::vector colors = {flutter::DlColor::kBlue(), + flutter::DlColor::kRed()}; + std::vector stops = {0.5, 1.0}; + const auto gradient = + flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // + flutter::DlPoint(1.0, 1.0), // + 2, // + colors.data(), // + stops.data(), // + flutter::DlTileMode::kClamp, // + nullptr // + ); + + std::vector converted_colors; + std::vector converted_stops; + Paint::ConvertStops(gradient->asLinearGradient(), converted_colors, + converted_stops); + + // First color is inserted as blue. + ASSERT_TRUE(ScalarNearlyEqual(converted_colors[0].blue, 1.0f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f)); +} + +TEST(PaintTest, GradientMissingLastValue) { + std::vector colors = {flutter::DlColor::kBlue(), + flutter::DlColor::kRed()}; + std::vector stops = {0.0, .5}; + const auto gradient = + flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // + flutter::DlPoint(1.0, 1.0), // + 2, // + colors.data(), // + stops.data(), // + flutter::DlTileMode::kClamp, // + nullptr // + ); + + std::vector converted_colors; + std::vector converted_stops; + Paint::ConvertStops(gradient->asLinearGradient(), converted_colors, + converted_stops); + + // Last color is inserted as red. + ASSERT_TRUE(ScalarNearlyEqual(converted_colors[2].red, 1.0f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f)); +} + +TEST(PaintTest, GradientStopGreaterThan1) { + std::vector colors = {flutter::DlColor::kBlue(), + flutter::DlColor::kGreen(), + flutter::DlColor::kRed()}; + std::vector stops = {0.0, 100, 1.0}; + const auto gradient = + flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // + flutter::DlPoint(1.0, 1.0), // + 3, // + colors.data(), // + stops.data(), // + flutter::DlTileMode::kClamp, // + nullptr // + ); + + std::vector converted_colors; + std::vector converted_stops; + Paint::ConvertStops(gradient->asLinearGradient(), converted_colors, + converted_stops); + + // Value is clamped to 1.0 + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 1.0f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f)); +} + +TEST(PaintTest, GradientConversionNonMonotonic) { + std::vector colors = { + flutter::DlColor::kBlue(), flutter::DlColor::kGreen(), + flutter::DlColor::kGreen(), flutter::DlColor::kRed()}; + std::vector stops = {0.0, 0.5, 0.4, 1.0}; + const auto gradient = + flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // + flutter::DlPoint(1.0, 1.0), // + 4, // + colors.data(), // + stops.data(), // + flutter::DlTileMode::kClamp, // + nullptr // + ); + + std::vector converted_colors; + std::vector converted_stops; + Paint::ConvertStops(gradient->asLinearGradient(), converted_colors, + converted_stops); + + // Value is clamped to 0.5 + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 0.5f)); + ASSERT_TRUE(ScalarNearlyEqual(converted_stops[3], 1.0f)); +} + +} // namespace testing +} // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/skia_conversions.cc b/engine/src/flutter/impeller/display_list/skia_conversions.cc index 2e7e28f84a..8920f3bd38 100644 --- a/engine/src/flutter/impeller/display_list/skia_conversions.cc +++ b/engine/src/flutter/impeller/display_list/skia_conversions.cc @@ -10,82 +10,6 @@ namespace impeller { namespace skia_conversions { -static inline bool SkScalarsNearlyEqual(SkScalar a, - SkScalar b, - SkScalar c, - SkScalar d) { - return SkScalarNearlyEqual(a, b, kEhCloseEnough) && - SkScalarNearlyEqual(a, c, kEhCloseEnough) && - SkScalarNearlyEqual(a, d, kEhCloseEnough); -} - -bool IsNearlySimpleRRect(const SkRRect& rr) { - auto [xa, ya] = rr.radii(SkRRect::kUpperLeft_Corner); - auto [xb, yb] = rr.radii(SkRRect::kLowerLeft_Corner); - auto [xc, yc] = rr.radii(SkRRect::kUpperRight_Corner); - auto [xd, yd] = rr.radii(SkRRect::kLowerRight_Corner); - return SkScalarsNearlyEqual(xa, xb, xc, xd) && - SkScalarsNearlyEqual(ya, yb, yc, yd); -} - -Rect ToRect(const SkRect& rect) { - return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); -} - -std::optional ToRect(const SkRect* rect) { - if (rect == nullptr) { - return std::nullopt; - } - return Rect::MakeLTRB(rect->fLeft, rect->fTop, rect->fRight, rect->fBottom); -} - -std::optional ToRect(const flutter::DlRect* rect) { - if (rect == nullptr) { - return std::nullopt; - } - return *rect; -} - -std::vector ToRects(const SkRect tex[], int count) { - auto result = std::vector(); - for (int i = 0; i < count; i++) { - result.push_back(ToRect(tex[i])); - } - return result; -} - -std::vector ToRects(const flutter::DlRect tex[], int count) { - auto result = std::vector(); - for (int i = 0; i < count; i++) { - result.push_back(tex[i]); - } - return result; -} - -std::vector ToPoints(const SkPoint points[], int count) { - std::vector result(count); - for (auto i = 0; i < count; i++) { - result[i] = ToPoint(points[i]); - } - return result; -} - -std::vector ToPoints(const flutter::DlPoint points[], int count) { - std::vector result(count); - for (auto i = 0; i < count; i++) { - result[i] = points[i]; - } - return result; -} - -Point ToPoint(const SkPoint& point) { - return Point::MakeXY(point.fX, point.fY); -} - -Size ToSize(const SkPoint& point) { - return Size(point.fX, point.fY); -} - Color ToColor(const flutter::DlColor& color) { FML_DCHECK(color.getColorSpace() == flutter::DlColorSpace::kExtendedSRGB || color.getColorSpace() == flutter::DlColorSpace::kSRGB); @@ -97,47 +21,6 @@ Color ToColor(const flutter::DlColor& color) { }; } -std::optional ToPixelFormat(SkColorType type) { - switch (type) { - case kRGBA_8888_SkColorType: - return impeller::PixelFormat::kR8G8B8A8UNormInt; - case kBGRA_8888_SkColorType: - return impeller::PixelFormat::kB8G8R8A8UNormInt; - case kRGBA_F16_SkColorType: - return impeller::PixelFormat::kR16G16B16A16Float; - case kBGR_101010x_XR_SkColorType: - return impeller::PixelFormat::kB10G10R10XR; - default: - return std::nullopt; - } - return std::nullopt; -} - -void ConvertStops(const flutter::DlGradientColorSourceBase* gradient, - std::vector& colors, - std::vector& stops) { - FML_DCHECK(gradient->stop_count() >= 2) - << "stop_count:" << gradient->stop_count(); - - auto* dl_colors = gradient->colors(); - auto* dl_stops = gradient->stops(); - if (dl_stops[0] != 0.0) { - colors.emplace_back(skia_conversions::ToColor(dl_colors[0])); - stops.emplace_back(0); - } - for (auto i = 0; i < gradient->stop_count(); i++) { - colors.emplace_back(skia_conversions::ToColor(dl_colors[i])); - stops.emplace_back(std::clamp(dl_stops[i], 0.0f, 1.0f)); - } - if (dl_stops[gradient->stop_count() - 1] != 1.0) { - colors.emplace_back(colors.back()); - stops.emplace_back(1.0); - } - for (auto i = 1; i < gradient->stop_count(); i++) { - stops[i] = std::clamp(stops[i], stops[i - 1], stops[i]); - } -} - impeller::SamplerDescriptor ToSamplerDescriptor( const flutter::DlImageSampling options) { impeller::SamplerDescriptor desc; @@ -162,17 +45,6 @@ impeller::SamplerDescriptor ToSamplerDescriptor( return desc; } -Matrix ToMatrix(const SkMatrix& m) { - return Matrix{ - // clang-format off - m[0], m[3], 0, m[6], - m[1], m[4], 0, m[7], - 0, 0, 1, 0, - m[2], m[5], 0, m[8], - // clang-format on - }; -} - BlendMode ToBlendMode(flutter::DlBlendMode mode) { switch (mode) { case flutter::DlBlendMode::kClear: diff --git a/engine/src/flutter/impeller/display_list/skia_conversions.h b/engine/src/flutter/impeller/display_list/skia_conversions.h index fccf05beab..4418373016 100644 --- a/engine/src/flutter/impeller/display_list/skia_conversions.h +++ b/engine/src/flutter/impeller/display_list/skia_conversions.h @@ -7,73 +7,20 @@ #include "flutter/display_list/dl_blend_mode.h" #include "flutter/display_list/dl_color.h" -#include "flutter/display_list/effects/dl_color_sources.h" -#include "impeller/core/formats.h" -#include "impeller/core/sampler_descriptor.h" -#include "impeller/geometry/color.h" -#include "impeller/geometry/path.h" -#include "impeller/geometry/path_builder.h" -#include "impeller/geometry/point.h" -#include "impeller/geometry/rect.h" -#include "third_party/skia/include/core/SkColorType.h" -#include "third_party/skia/include/core/SkPoint.h" -#include "third_party/skia/include/core/SkRRect.h" -#include "third_party/skia/include/core/SkTextBlob.h" +#include "flutter/display_list/dl_sampling_options.h" +#include "flutter/impeller/core/sampler_descriptor.h" +#include "flutter/impeller/geometry/color.h" namespace impeller { namespace skia_conversions { -/// @brief Like SkRRect.isSimple, but allows the corners to differ by -/// kEhCloseEnough. -/// -/// An RRect is simple if all corner radii are approximately -/// equal. -bool IsNearlySimpleRRect(const SkRRect& rr); - -Rect ToRect(const SkRect& rect); - -std::optional ToRect(const SkRect* rect); -std::optional ToRect(const flutter::DlRect* rect); - -std::vector ToRects(const SkRect tex[], int count); -std::vector ToRects(const flutter::DlRect tex[], int count); - -std::vector ToPoints(const SkPoint points[], int count); -std::vector ToPoints(const flutter::DlPoint points[], int count); - -Point ToPoint(const SkPoint& point); - -Size ToSize(const SkPoint& point); - Color ToColor(const flutter::DlColor& color); -std::optional ToPixelFormat(SkColorType type); - impeller::SamplerDescriptor ToSamplerDescriptor( const flutter::DlImageSampling options); -Matrix ToMatrix(const SkMatrix& m); - BlendMode ToBlendMode(flutter::DlBlendMode mode); -/// @brief Convert display list colors + stops into impeller colors and stops, -/// taking care to ensure that the stops monotonically increase from 0.0 to 1.0. -/// -/// The general process is: -/// * Ensure that the first gradient stop value is 0.0. If not, insert a new -/// stop with a value of 0.0 and use the first gradient color as this new -/// stops color. -/// * Ensure the last gradient stop value is 1.0. If not, insert a new stop -/// with a value of 1.0 and use the last gradient color as this stops color. -/// * Clamp all gradient values between the values of 0.0 and 1.0. -/// * For all stop values, ensure that the values are monotonically increasing -/// by clamping each value to a minimum of the previous stop value and itself. -/// For example, with stop values of 0.0, 0.5, 0.4, 1.0, we would clamp such -/// that the values were 0.0, 0.5, 0.5, 1.0. -void ConvertStops(const flutter::DlGradientColorSourceBase* gradient, - std::vector& colors, - std::vector& stops); - } // namespace skia_conversions } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/skia_conversions_unittests.cc b/engine/src/flutter/impeller/display_list/skia_conversions_unittests.cc index a06dd7adc8..a9e8ced932 100644 --- a/engine/src/flutter/impeller/display_list/skia_conversions_unittests.cc +++ b/engine/src/flutter/impeller/display_list/skia_conversions_unittests.cc @@ -16,56 +16,6 @@ namespace impeller { namespace testing { -TEST(SkiaConversionTest, ToMatrixTranslate) { - SkMatrix sk_matrix = SkMatrix::Translate(100, 100); - Matrix matrix = skia_conversions::ToMatrix(sk_matrix); - - EXPECT_EQ(matrix.m[12], 100); - EXPECT_EQ(matrix.m[13], 100); - EXPECT_TRUE(matrix.IsTranslationScaleOnly()); - - matrix.m[12] = 0; - matrix.m[13] = 0; - - EXPECT_TRUE(matrix.IsIdentity()); -} - -TEST(SkiaConversionTest, ToMatrixScale) { - SkMatrix sk_matrix = SkMatrix::Scale(2, 2); - Matrix matrix = skia_conversions::ToMatrix(sk_matrix); - - EXPECT_EQ(matrix.m[0], 2); - EXPECT_EQ(matrix.m[5], 2); - EXPECT_TRUE(matrix.IsTranslationScaleOnly()); - - matrix.m[0] = 1; - matrix.m[5] = 1; - - EXPECT_TRUE(matrix.IsIdentity()); -} - -TEST(SkiaConversionTest, ToMatrixRotate) { - SkMatrix sk_matrix = SkMatrix::RotateDeg(90); - Matrix matrix = skia_conversions::ToMatrix(sk_matrix); - - EXPECT_EQ(matrix.vec[0], Vector4(0, 1, 0, 0)); - EXPECT_EQ(matrix.vec[1], Vector4(-1, 0, 0, 0)); - EXPECT_EQ(matrix.vec[2], Vector4(0, 0, 1, 0)); - EXPECT_EQ(matrix.vec[3], Vector4(0, 0, 0, 1)); - EXPECT_FALSE(matrix.IsTranslationScaleOnly()); -} - -TEST(SkiaConversionTest, ToMatrixSkew) { - SkMatrix sk_matrix = SkMatrix::Skew(2, 2); - Matrix matrix = skia_conversions::ToMatrix(sk_matrix); - - EXPECT_EQ(matrix.vec[0], Vector4(1, 2, 0, 0)); - EXPECT_EQ(matrix.vec[1], Vector4(2, 1, 0, 0)); - EXPECT_EQ(matrix.vec[2], Vector4(0, 0, 1, 0)); - EXPECT_EQ(matrix.vec[3], Vector4(0, 0, 0, 1)); - EXPECT_FALSE(matrix.IsTranslationScaleOnly()); -} - TEST(SkiaConversionTest, ToSamplerDescriptor) { EXPECT_EQ(skia_conversions::ToSamplerDescriptor( flutter::DlImageSampling::kNearestNeighbor) @@ -95,24 +45,6 @@ TEST(SkiaConversionTest, ToSamplerDescriptor) { impeller::MipFilter::kLinear); } -TEST(SkiaConversionsTest, SkPointToPoint) { - for (int x = -100; x < 100; x += 4) { - for (int y = -100; y < 100; y += 4) { - EXPECT_EQ(skia_conversions::ToPoint(SkPoint::Make(x * 0.25f, y * 0.25f)), - Point(x * 0.25f, y * 0.25f)); - } - } -} - -TEST(SkiaConversionsTest, SkPointToSize) { - for (int x = -100; x < 100; x += 4) { - for (int y = -100; y < 100; y += 4) { - EXPECT_EQ(skia_conversions::ToSize(SkPoint::Make(x * 0.25f, y * 0.25f)), - Size(x * 0.25f, y * 0.25f)); - } - } -} - TEST(SkiaConversionsTest, ToColor) { // Create a color with alpha, red, green, and blue values that are all // trivially divisible by 255 so that we can test the conversion results in @@ -127,173 +59,6 @@ TEST(SkiaConversionsTest, ToColor) { ASSERT_TRUE(ScalarNearlyEqual(converted_color.blue, 0x20 * (1.0f / 255))); } -TEST(SkiaConversionsTest, GradientStopConversion) { - // Typical gradient. - std::vector colors = {flutter::DlColor::kBlue(), - flutter::DlColor::kRed(), - flutter::DlColor::kGreen()}; - std::vector stops = {0.0, 0.5, 1.0}; - const auto gradient = - flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // - flutter::DlPoint(1.0, 1.0), // - 3, // - colors.data(), // - stops.data(), // - flutter::DlTileMode::kClamp, // - nullptr // - ); - - std::vector converted_colors; - std::vector converted_stops; - skia_conversions::ConvertStops(gradient->asLinearGradient(), converted_colors, - converted_stops); - - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f)); -} - -TEST(SkiaConversionsTest, GradientMissing0) { - std::vector colors = {flutter::DlColor::kBlue(), - flutter::DlColor::kRed()}; - std::vector stops = {0.5, 1.0}; - const auto gradient = - flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // - flutter::DlPoint(1.0, 1.0), // - 2, // - colors.data(), // - stops.data(), // - flutter::DlTileMode::kClamp, // - nullptr // - ); - - std::vector converted_colors; - std::vector converted_stops; - skia_conversions::ConvertStops(gradient->asLinearGradient(), converted_colors, - converted_stops); - - // First color is inserted as blue. - ASSERT_TRUE(ScalarNearlyEqual(converted_colors[0].blue, 1.0f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f)); -} - -TEST(SkiaConversionsTest, GradientMissingLastValue) { - std::vector colors = {flutter::DlColor::kBlue(), - flutter::DlColor::kRed()}; - std::vector stops = {0.0, .5}; - const auto gradient = - flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // - flutter::DlPoint(1.0, 1.0), // - 2, // - colors.data(), // - stops.data(), // - flutter::DlTileMode::kClamp, // - nullptr // - ); - - std::vector converted_colors; - std::vector converted_stops; - skia_conversions::ConvertStops(gradient->asLinearGradient(), converted_colors, - converted_stops); - - // Last color is inserted as red. - ASSERT_TRUE(ScalarNearlyEqual(converted_colors[2].red, 1.0f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f)); -} - -TEST(SkiaConversionsTest, GradientStopGreaterThan1) { - std::vector colors = {flutter::DlColor::kBlue(), - flutter::DlColor::kGreen(), - flutter::DlColor::kRed()}; - std::vector stops = {0.0, 100, 1.0}; - const auto gradient = - flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // - flutter::DlPoint(1.0, 1.0), // - 3, // - colors.data(), // - stops.data(), // - flutter::DlTileMode::kClamp, // - nullptr // - ); - - std::vector converted_colors; - std::vector converted_stops; - skia_conversions::ConvertStops(gradient->asLinearGradient(), converted_colors, - converted_stops); - - // Value is clamped to 1.0 - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 1.0f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f)); -} - -TEST(SkiaConversionsTest, GradientConversionNonMonotonic) { - std::vector colors = { - flutter::DlColor::kBlue(), flutter::DlColor::kGreen(), - flutter::DlColor::kGreen(), flutter::DlColor::kRed()}; - std::vector stops = {0.0, 0.5, 0.4, 1.0}; - const auto gradient = - flutter::DlColorSource::MakeLinear(flutter::DlPoint(0, 0), // - flutter::DlPoint(1.0, 1.0), // - 4, // - colors.data(), // - stops.data(), // - flutter::DlTileMode::kClamp, // - nullptr // - ); - - std::vector converted_colors; - std::vector converted_stops; - skia_conversions::ConvertStops(gradient->asLinearGradient(), converted_colors, - converted_stops); - - // Value is clamped to 0.5 - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 0.5f)); - ASSERT_TRUE(ScalarNearlyEqual(converted_stops[3], 1.0f)); -} - -TEST(SkiaConversionsTest, IsNearlySimpleRRect) { - EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect( - SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 10, 10), 10, 10))); - EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect( - SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 10, 10), 10, 9.999))); - EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect( - SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 10, 10), 10, 9))); - EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect( - SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 10, 10), 10, 5))); - SkRect rect = SkRect::MakeLTRB(0, 0, 10, 10); - SkRRect rrect; - union { - SkPoint radii[4] = { - {10.0f, 9.0f}, - {10.0f, 9.0f}, - {10.0f, 9.0f}, - {10.0f, 9.0f}, - }; - SkScalar values[8]; - } test; - rrect.setRectRadii(rect, test.radii); - EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect(rrect)); - for (int i = 0; i < 8; i++) { - auto save = test.values[i]; - test.values[i] -= kEhCloseEnough * 0.5f; - rrect.setRectRadii(rect, test.radii); - EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect(rrect)) - << "values[" << i << "] == " << test.values[i]; - test.values[i] -= kEhCloseEnough * 2.0f; - rrect.setRectRadii(rect, test.radii); - EXPECT_FALSE(skia_conversions::IsNearlySimpleRRect(rrect)) - << "values[" << i << "] == " << test.values[i]; - test.values[i] = save; - } -} - TEST(SkiaConversionsTest, BlendMode) { for (auto i = 0; i < static_cast(flutter::DlBlendMode::kLastMode); i++) { EXPECT_EQ( diff --git a/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc b/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc index ba6a83e83b..a2830bc2b1 100644 --- a/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc +++ b/engine/src/flutter/lib/ui/painting/image_decoder_impeller.cc @@ -74,6 +74,22 @@ bool IsWideGamut(const SkColorSpace* color_space) { float area = CalculateArea(rgb); return area > kSrgbGamutArea; } + +static std::optional ToPixelFormat(SkColorType type) { + switch (type) { + case kRGBA_8888_SkColorType: + return impeller::PixelFormat::kR8G8B8A8UNormInt; + case kBGRA_8888_SkColorType: + return impeller::PixelFormat::kB8G8R8A8UNormInt; + case kRGBA_F16_SkColorType: + return impeller::PixelFormat::kR16G16B16A16Float; + case kBGR_101010x_XR_SkColorType: + return impeller::PixelFormat::kB10G10R10XR; + default: + return std::nullopt; + } + return std::nullopt; +} } // namespace ImageDecoderImpeller::ImageDecoderImpeller( @@ -163,8 +179,7 @@ DecompressResult ImageDecoderImpeller::DecompressTexture( .makeAlphaType(alpha_type); } - const auto pixel_format = - impeller::skia_conversions::ToPixelFormat(image_info.colorType()); + const auto pixel_format = ToPixelFormat(image_info.colorType()); if (!pixel_format.has_value()) { std::string decode_error(impeller::SPrintF( "Codec pixel format is not supported (SkColorType=%d)", @@ -289,8 +304,7 @@ ImageDecoderImpeller::UnsafeUploadTextureToPrivate( const std::shared_ptr& buffer, const SkImageInfo& image_info, const std::optional& resize_info) { - const auto pixel_format = - impeller::skia_conversions::ToPixelFormat(image_info.colorType()); + const auto pixel_format = ToPixelFormat(image_info.colorType()); if (!pixel_format) { std::string decode_error(impeller::SPrintF( "Unsupported pixel format (SkColorType=%d)", image_info.colorType())); @@ -456,8 +470,7 @@ ImageDecoderImpeller::UploadTextureToStorage( return std::make_pair(nullptr, "No texture bitmap is available"); } const auto image_info = bitmap->info(); - const auto pixel_format = - impeller::skia_conversions::ToPixelFormat(image_info.colorType()); + const auto pixel_format = ToPixelFormat(image_info.colorType()); if (!pixel_format) { std::string decode_error(impeller::SPrintF( "Unsupported pixel format (SkColorType=%d)", image_info.colorType()));