diff --git a/display_list/display_list_color_source.cc b/display_list/display_list_color_source.cc index 6c5a5ce746b81..3fabe565f6559 100644 --- a/display_list/display_list_color_source.cc +++ b/display_list/display_list_color_source.cc @@ -6,8 +6,6 @@ namespace flutter { -static constexpr int kGradientStaticRecaptureCount = 24; - std::shared_ptr DlColorSource::From(SkShader* sk_shader) { if (sk_shader == nullptr) { return nullptr; @@ -27,61 +25,11 @@ std::shared_ptr DlColorSource::From(SkShader* sk_shader) { // of parameters which are missing, including the local matrix in every // gradient, and the sweep angles in the sweep gradients. // - // Since the matrix is a rarely used property and since most sweep - // gradients swing full circle, we will simply assume an Identity matrix - // and 0,360 for the Sweep gradient. - // Possibly the most likely "missing attribute" that might be different - // would be the sweep gradients which might be a full circle, but might - // have their starting angle in a custom direction. - SkColor colors[kGradientStaticRecaptureCount]; - SkScalar stops[kGradientStaticRecaptureCount]; - SkShader::GradientInfo info = {}; - info.fColorCount = kGradientStaticRecaptureCount; - info.fColors = colors; - info.fColorOffsets = stops; - SkShader::GradientType type = sk_shader->asAGradient(&info); - if (type != SkShader::kNone_GradientType && - info.fColorCount > kGradientStaticRecaptureCount) { - int count = info.fColorCount; - info.fColors = new SkColor[count]; - info.fColorOffsets = new SkScalar[count]; - sk_shader->asAGradient(&info); - FML_DCHECK(count == info.fColorCount); - } - DlTileMode mode = ToDl(info.fTileMode); - std::shared_ptr source; - switch (type) { - case SkShader::kNone_GradientType: - source = std::make_shared(sk_ref_sp(sk_shader)); - break; - case SkShader::kColor_GradientType: - source = std::make_shared(info.fColors[0]); - break; - case SkShader::kLinear_GradientType: - source = MakeLinear(info.fPoint[0], info.fPoint[1], info.fColorCount, - info.fColors, info.fColorOffsets, mode); - break; - case SkShader::kRadial_GradientType: - source = MakeRadial(info.fPoint[0], info.fRadius[0], info.fColorCount, - info.fColors, info.fColorOffsets, mode); - break; - case SkShader::kConical_GradientType: - source = MakeConical(info.fPoint[0], info.fRadius[0], info.fPoint[1], - info.fRadius[1], info.fColorCount, info.fColors, - info.fColorOffsets, mode); - break; - case SkShader::kSweep_GradientType: - source = MakeSweep(info.fPoint[0], 0, 360, info.fColorCount, info.fColors, - info.fColorOffsets, mode); - break; - } - if (info.fColors != colors) { - delete info.fColors; - } - if (info.fColorOffsets != stops) { - delete info.fColorOffsets; - } - return source; + // Since we can't reproduce every Gradient, and customers rely on using + // gradients with matrices in text code, we have to just use an Unknown + // ColorSource to express all gradients. + // (see: https://github.com/flutter/flutter/issues/102947) + return std::make_shared(sk_ref_sp(sk_shader)); } static void DlGradientDeleter(void* p) { diff --git a/display_list/display_list_color_source_unittests.cc b/display_list/display_list_color_source_unittests.cc index 642e70e96e449..f6e2fa5e8dd4b 100644 --- a/display_list/display_list_color_source_unittests.cc +++ b/display_list/display_list_color_source_unittests.cc @@ -94,13 +94,20 @@ TEST(DisplayListColorSource, FromSkiaNullShader) { } TEST(DisplayListColorSource, FromSkiaColorShader) { + // We cannot read back the matrix parameter from a Skia LinearGradient + // so we conservatively use an UnknownColorSource wrapper so as to not + // lose any data. Note that the Skia Color shader end is read back from + // the Skia asAGradient() method so while this type of color source + // does not really need the matrix, we represent all of the gradient + // sources using an unknown source. + // Note that this shader should never really happen in practice as it + // represents a degenerate gradient that collapsed to a single color. sk_sp shader = SkShaders::Color(SK_ColorBLUE); std::shared_ptr source = DlColorSource::From(shader); - DlColorColorSource dl_source(SK_ColorBLUE); - ASSERT_EQ(source->type(), DlColorSourceType::kColor); - ASSERT_EQ(*source->asColor(), dl_source); - ASSERT_EQ(source->asColor()->color(), SK_ColorBLUE); + ASSERT_EQ(source->type(), DlColorSourceType::kUnknown); + ASSERT_EQ(source->skia_object(), shader); + ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); @@ -131,126 +138,78 @@ TEST(DisplayListColorSource, FromSkiaImageShader) { } TEST(DisplayListColorSource, FromSkiaLinearGradient) { - // We can read back all of the parameters of a Linear gradient - // except for matrix. + // We cannot read back the matrix parameter from a Skia LinearGradient + // so we conservatively use an UnknownColorSource wrapper so as to not + // lose any data. sk_sp shader = SkGradientShader::MakeLinear( TestPoints, TestColors, TestStops, kTestStopCount, SkTileMode::kClamp); std::shared_ptr source = DlColorSource::From(shader); - std::shared_ptr dl_source = - DlColorSource::MakeLinear(TestPoints[0], TestPoints[1], kTestStopCount, - TestColors, TestStops, DlTileMode::kClamp); - ASSERT_EQ(source->type(), DlColorSourceType::kLinearGradient); - EXPECT_TRUE(*source->asLinearGradient() == *dl_source->asLinearGradient()); - ASSERT_EQ(*source->asLinearGradient(), *dl_source->asLinearGradient()); - ASSERT_EQ(source->asLinearGradient()->start_point(), TestPoints[0]); - ASSERT_EQ(source->asLinearGradient()->end_point(), TestPoints[1]); - ASSERT_EQ(source->asLinearGradient()->stop_count(), kTestStopCount); - for (int i = 0; i < kTestStopCount; i++) { - ASSERT_EQ(source->asLinearGradient()->colors()[i], TestColors[i]); - ASSERT_EQ(source->asLinearGradient()->stops()[i], TestStops[i]); - } - ASSERT_EQ(source->asLinearGradient()->tile_mode(), DlTileMode::kClamp); - ASSERT_EQ(source->asLinearGradient()->matrix(), SkMatrix::I()); + ASSERT_EQ(source->type(), DlColorSourceType::kUnknown); + ASSERT_EQ(source->skia_object(), shader); ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); + ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); } TEST(DisplayListColorSource, FromSkiaRadialGradient) { - // We can read back all of the parameters of a Radial gradient - // except for matrix. + // We cannot read back the matrix parameter from a Skia RadialGradient + // so we conservatively use an UnknownColorSource wrapper so as to not + // lose any data. sk_sp shader = SkGradientShader::MakeRadial(TestPoints[0], 10.0, TestColors, TestStops, kTestStopCount, SkTileMode::kClamp); std::shared_ptr source = DlColorSource::From(shader); - std::shared_ptr dl_source = - DlColorSource::MakeRadial(TestPoints[0], 10.0, kTestStopCount, TestColors, - TestStops, DlTileMode::kClamp); - ASSERT_EQ(source->type(), DlColorSourceType::kRadialGradient); - EXPECT_TRUE(*source->asRadialGradient() == *dl_source->asRadialGradient()); - ASSERT_EQ(*source->asRadialGradient(), *dl_source->asRadialGradient()); - ASSERT_EQ(source->asRadialGradient()->center(), TestPoints[0]); - ASSERT_EQ(source->asRadialGradient()->radius(), 10.0); - ASSERT_EQ(source->asRadialGradient()->stop_count(), kTestStopCount); - for (int i = 0; i < kTestStopCount; i++) { - ASSERT_EQ(source->asRadialGradient()->colors()[i], TestColors[i]); - ASSERT_EQ(source->asRadialGradient()->stops()[i], TestStops[i]); - } - ASSERT_EQ(source->asRadialGradient()->tile_mode(), DlTileMode::kClamp); - ASSERT_EQ(source->asRadialGradient()->matrix(), SkMatrix::I()); + ASSERT_EQ(source->type(), DlColorSourceType::kUnknown); + ASSERT_EQ(source->skia_object(), shader); ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); ASSERT_EQ(source->asLinearGradient(), nullptr); + ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); } TEST(DisplayListColorSource, FromSkiaConicalGradient) { - // We can read back all of the parameters of a Conical gradient - // except for matrix. + // We cannot read back the matrix parameter from a Skia ConicalGradient + // so we conservatively use an UnknownColorSource wrapper so as to not + // lose any data. sk_sp shader = SkGradientShader::MakeTwoPointConical( TestPoints[0], 10.0, TestPoints[1], 20.0, TestColors, TestStops, kTestStopCount, SkTileMode::kClamp); std::shared_ptr source = DlColorSource::From(shader); - std::shared_ptr dl_source = DlColorSource::MakeConical( - TestPoints[0], 10.0, TestPoints[1], 20.0, kTestStopCount, TestColors, - TestStops, DlTileMode::kClamp); - ASSERT_EQ(source->type(), DlColorSourceType::kConicalGradient); - EXPECT_TRUE(*source->asConicalGradient() == *dl_source->asConicalGradient()); - ASSERT_EQ(*source->asConicalGradient(), *dl_source->asConicalGradient()); - ASSERT_EQ(source->asConicalGradient()->start_center(), TestPoints[0]); - ASSERT_EQ(source->asConicalGradient()->start_radius(), 10.0); - ASSERT_EQ(source->asConicalGradient()->end_center(), TestPoints[1]); - ASSERT_EQ(source->asConicalGradient()->end_radius(), 20.0); - ASSERT_EQ(source->asConicalGradient()->stop_count(), kTestStopCount); - for (int i = 0; i < kTestStopCount; i++) { - ASSERT_EQ(source->asConicalGradient()->colors()[i], TestColors[i]); - ASSERT_EQ(source->asConicalGradient()->stops()[i], TestStops[i]); - } - ASSERT_EQ(source->asConicalGradient()->tile_mode(), DlTileMode::kClamp); - ASSERT_EQ(source->asConicalGradient()->matrix(), SkMatrix::I()); + ASSERT_EQ(source->type(), DlColorSourceType::kUnknown); + ASSERT_EQ(source->skia_object(), shader); ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); + ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); } TEST(DisplayListColorSource, FromSkiaSweepGradient) { - // We can read back all of the parameters of a Sweep gradient - // except for matrix and the start/stop angles. - sk_sp shader = - SkGradientShader::MakeSweep(TestPoints[0].fX, TestPoints[0].fY, - TestColors, TestStops, kTestStopCount); + // We cannot read back the matrix parameter, nor the sweep parameters from a + // Skia SweepGradient so we conservatively use an UnknownColorSource wrapper + // so as to not lose any data. + const SkColor* sk_colors = reinterpret_cast(TestColors); + sk_sp shader = SkGradientShader::MakeSweep( + TestPoints[0].fX, TestPoints[0].fY, sk_colors, TestStops, kTestStopCount); std::shared_ptr source = DlColorSource::From(shader); - std::shared_ptr dl_source = - DlColorSource::MakeSweep(TestPoints[0], 0, 360, kTestStopCount, - TestColors, TestStops, DlTileMode::kClamp); - ASSERT_EQ(source->type(), DlColorSourceType::kSweepGradient); - EXPECT_TRUE(*source->asSweepGradient() == *dl_source->asSweepGradient()); - ASSERT_EQ(*source->asSweepGradient(), *dl_source->asSweepGradient()); - ASSERT_EQ(source->asSweepGradient()->center(), TestPoints[0]); - ASSERT_EQ(source->asSweepGradient()->start(), 0); - ASSERT_EQ(source->asSweepGradient()->end(), 360); - ASSERT_EQ(source->asSweepGradient()->stop_count(), kTestStopCount); - for (int i = 0; i < kTestStopCount; i++) { - ASSERT_EQ(source->asSweepGradient()->colors()[i], TestColors[i]); - ASSERT_EQ(source->asSweepGradient()->stops()[i], TestStops[i]); - } - ASSERT_EQ(source->asSweepGradient()->tile_mode(), DlTileMode::kClamp); - ASSERT_EQ(source->asSweepGradient()->matrix(), SkMatrix::I()); + ASSERT_EQ(source->type(), DlColorSourceType::kUnknown); + ASSERT_EQ(source->skia_object(), shader); ASSERT_EQ(source->asColor(), nullptr); ASSERT_EQ(source->asImage(), nullptr); ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); - ASSERT_NE(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asSweepGradient(), nullptr); } TEST(DisplayListColorSource, FromSkiaUnrecognizedShader) {