Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 135 additions & 8 deletions display_list/display_list_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1367,7 +1367,7 @@ TEST_F(DisplayListTest, SaveLayerFalseWithSrcBlendSupportsGroupOpacity) {
DisplayListBuilder builder;
// This empty draw rect will not actually be inserted into the stream,
// but the Src blend mode will be synchronized as an attribute. The
// saveLayer following it should not use that attribute to base its
// SaveLayer following it should not use that attribute to base its
// decisions about group opacity and the draw rect after that comes
// with its own compatible blend mode.
builder.DrawRect(SkRect{0, 0, 0, 0},
Expand Down Expand Up @@ -1416,7 +1416,7 @@ TEST_F(DisplayListTest, SaveLayerBoundsSnapshotsImageFilter) {
DlPaint save_paint;
builder.SaveLayer(nullptr, &save_paint);
builder.DrawRect(SkRect{50, 50, 100, 100}, DlPaint());
// This image filter should be ignored since it was not set before saveLayer
// This image filter should be ignored since it was not set before SaveLayer
// And the rect drawn with it will not contribute any more area to the bounds
DlPaint draw_paint;
draw_paint.setImageFilter(&kTestBlurImageFilter1);
Expand Down Expand Up @@ -2510,7 +2510,7 @@ TEST_F(DisplayListTest, RTreeOfSaveLayerFilterScene) {
builder.DrawRect(SkRect{10, 10, 20, 20}, default_paint);
builder.SaveLayer(nullptr, &filter_paint);
// the following rectangle will be expanded to 50,50,60,60
// by the saveLayer filter during the restore operation
// by the SaveLayer filter during the restore operation
builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint);
builder.Restore();
auto display_list = builder.Build();
Expand Down Expand Up @@ -3272,7 +3272,7 @@ TEST_F(DisplayListTest, RTreeOfClippedSaveLayerFilterScene) {
builder.ClipRect(SkRect{50, 50, 60, 60}, ClipOp::kIntersect, false);
builder.SaveLayer(nullptr, &filter_paint);
// the following rectangle will be expanded to 23,23,87,87
// by the saveLayer filter during the restore operation
// by the SaveLayer filter during the restore operation
// but it will then be clipped to 50,50,60,60
builder.DrawRect(SkRect{53, 53, 57, 57}, default_paint);
builder.Restore();
Expand Down Expand Up @@ -3862,7 +3862,7 @@ TEST_F(DisplayListTest, TransformResetSaveLayerBoundsComputationOfSimpleRect) {
builder.SaveLayer(nullptr, nullptr);
builder.TransformReset();
builder.Scale(20.0f, 20.0f);
// Net local transform for saveLayer is Scale(2, 2)
// Net local transform for SaveLayer is Scale(2, 2)
{ //
builder.DrawRect(rect, DlPaint());
}
Expand Down Expand Up @@ -4451,7 +4451,7 @@ TEST_F(DisplayListTest, MaxBlendModeInsideComplexSaveLayers) {
builder.Restore();

// Double check that kModulate is the max blend mode for the first
// saveLayer operations
// SaveLayer operations
auto expect = std::max(DlBlendMode::kModulate, DlBlendMode::kSrc);
ASSERT_EQ(expect, DlBlendMode::kModulate);

Expand Down Expand Up @@ -4487,8 +4487,8 @@ TEST_F(DisplayListTest, BackdropDetectionSimpleSaveLayer) {
auto dl = builder.Build();

EXPECT_TRUE(dl->root_has_backdrop_filter());
// The saveLayer itself, though, does not have the contains backdrop
// flag set because its content does not contain a saveLayer with backdrop
// The SaveLayer itself, though, does not have the contains backdrop
// flag set because its content does not contain a SaveLayer with backdrop
SAVE_LAYER_EXPECTOR(expector);
expector.addExpectation(
SaveLayerOptions::kNoAttributes.with_can_distribute_opacity());
Expand Down Expand Up @@ -5948,5 +5948,132 @@ TEST_F(DisplayListTest, RecordSingleLargeDisplayListOperation) {
EXPECT_TRUE(!!builder.Build());
}

TEST_F(DisplayListTest, DisplayListDetectsRuntimeEffect) {
const auto runtime_effect = DlRuntimeEffect::MakeSkia(
SkRuntimeEffect::MakeForShader(
SkString("vec4 main(vec2 p) { return vec4(0); }"))
.effect);
auto color_source = DlColorSource::MakeRuntimeEffect(
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
auto image_filter = DlImageFilter::MakeRuntimeEffect(
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());

{
// Default - no runtime effects, supports group opacity
DisplayListBuilder builder;
DlPaint paint;

builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
EXPECT_TRUE(builder.Build()->can_apply_group_opacity());
}

{
// Draw with RTE color source does not support group opacity
DisplayListBuilder builder;
DlPaint paint;

paint.setColorSource(color_source);
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);

EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
}

{
// Draw with RTE image filter does not support group opacity
DisplayListBuilder builder;
DlPaint paint;

paint.setImageFilter(image_filter);
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);

EXPECT_FALSE(builder.Build()->can_apply_group_opacity());
}

{
// Draw with RTE color source inside SaveLayer does not support group
// opacity on the SaveLayer, but does support it on the DisplayList
DisplayListBuilder builder;
DlPaint paint;

builder.SaveLayer(nullptr, nullptr);
paint.setColorSource(color_source);
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
builder.Restore();

auto display_list = builder.Build();
EXPECT_TRUE(display_list->can_apply_group_opacity());

SAVE_LAYER_EXPECTOR(expector);
expector.addExpectation([](const SaveLayerOptions& options) {
return !options.can_distribute_opacity();
});
display_list->Dispatch(expector);
}

{
// Draw with RTE image filter inside SaveLayer does not support group
// opacity on the SaveLayer, but does support it on the DisplayList
DisplayListBuilder builder;
DlPaint paint;

builder.SaveLayer(nullptr, nullptr);
paint.setImageFilter(image_filter);
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
builder.Restore();

auto display_list = builder.Build();
EXPECT_TRUE(display_list->can_apply_group_opacity());

SAVE_LAYER_EXPECTOR(expector);
expector.addExpectation([](const SaveLayerOptions& options) {
return !options.can_distribute_opacity();
});
display_list->Dispatch(expector);
}

{
// Draw with RTE color source inside nested saveLayers does not support
// group opacity on the inner SaveLayer, but does support it on the
// outer SaveLayer and the DisplayList
DisplayListBuilder builder;
DlPaint paint;

builder.SaveLayer(nullptr, nullptr);

builder.SaveLayer(nullptr, nullptr);
paint.setColorSource(color_source);
builder.DrawRect(DlRect::MakeLTRB(0, 0, 50, 50), paint);
paint.setColorSource(nullptr);
builder.Restore();

builder.SaveLayer(nullptr, nullptr);
paint.setImageFilter(image_filter);
// Make sure these DrawRects are non-overlapping otherwise the outer
// SaveLayer and DisplayList will be incompatible due to overlaps
builder.DrawRect(DlRect::MakeLTRB(60, 60, 100, 100), paint);
paint.setImageFilter(nullptr);
builder.Restore();

builder.Restore();
auto display_list = builder.Build();
EXPECT_TRUE(display_list->can_apply_group_opacity());

SAVE_LAYER_EXPECTOR(expector);
expector.addExpectation([](const SaveLayerOptions& options) {
// outer SaveLayer supports group opacity
return options.can_distribute_opacity();
});
expector.addExpectation([](const SaveLayerOptions& options) {
// first inner SaveLayer does not support group opacity
return !options.can_distribute_opacity();
});
expector.addExpectation([](const SaveLayerOptions& options) {
// second inner SaveLayer does not support group opacity
return !options.can_distribute_opacity();
});
display_list->Dispatch(expector);
}
}

} // namespace testing
} // namespace flutter
2 changes: 2 additions & 0 deletions display_list/dl_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) {
}
}
}
UpdateCurrentOpacityCompatibility();
}
void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
if (filter == nullptr) {
Expand Down Expand Up @@ -289,6 +290,7 @@ void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
}
}
}
UpdateCurrentOpacityCompatibility();
}
void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) {
if (filter == nullptr) {
Expand Down
1 change: 1 addition & 0 deletions display_list/dl_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ class DisplayListBuilder final : public virtual DlCanvas,
current_opacity_compatibility_ = //
current_.getColorFilter() == nullptr && //
!current_.isInvertColors() && //
!current_.usesRuntimeEffect() && //
IsOpacityCompatible(current_.getBlendMode());
}

Expand Down
5 changes: 5 additions & 0 deletions display_list/dl_paint.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ class DlPaint {

bool isDefault() const { return *this == kDefault; }

bool usesRuntimeEffect() const {
return ((color_source_ && color_source_->asRuntimeEffect()) ||
(image_filter_ && image_filter_->asRuntimeEffectFilter()));
}

bool operator==(DlPaint const& other) const;
bool operator!=(DlPaint const& other) const { return !(*this == other); }

Expand Down
44 changes: 44 additions & 0 deletions display_list/dl_paint_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -154,5 +154,49 @@ TEST(DisplayListPaint, ChainingConstructor) {
EXPECT_NE(paint, DlPaint());
}

TEST(DisplayListPaint, PaintDetectsRuntimeEffects) {
const auto runtime_effect = DlRuntimeEffect::MakeSkia(
SkRuntimeEffect::MakeForShader(
SkString("vec4 main(vec2 p) { return vec4(0); }"))
.effect);
auto color_source = DlColorSource::MakeRuntimeEffect(
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
auto image_filter = DlImageFilter::MakeRuntimeEffect(
runtime_effect, {}, std::make_shared<std::vector<uint8_t>>());
DlPaint paint;

EXPECT_FALSE(paint.usesRuntimeEffect());
paint.setColorSource(color_source);
EXPECT_TRUE(paint.usesRuntimeEffect());
paint.setColorSource(nullptr);
EXPECT_FALSE(paint.usesRuntimeEffect());

EXPECT_FALSE(paint.usesRuntimeEffect());
paint.setImageFilter(image_filter);
EXPECT_TRUE(paint.usesRuntimeEffect());
paint.setImageFilter(nullptr);
EXPECT_FALSE(paint.usesRuntimeEffect());

EXPECT_FALSE(paint.usesRuntimeEffect());
paint.setColorSource(color_source);
EXPECT_TRUE(paint.usesRuntimeEffect());
paint.setImageFilter(image_filter);
EXPECT_TRUE(paint.usesRuntimeEffect());
paint.setImageFilter(nullptr);
EXPECT_TRUE(paint.usesRuntimeEffect());
paint.setColorSource(nullptr);
EXPECT_FALSE(paint.usesRuntimeEffect());

EXPECT_FALSE(paint.usesRuntimeEffect());
paint.setColorSource(color_source);
EXPECT_TRUE(paint.usesRuntimeEffect());
paint.setImageFilter(image_filter);
EXPECT_TRUE(paint.usesRuntimeEffect());
paint.setColorSource(nullptr);
EXPECT_TRUE(paint.usesRuntimeEffect());
paint.setImageFilter(nullptr);
EXPECT_FALSE(paint.usesRuntimeEffect());
}

} // namespace testing
} // namespace flutter
Loading