mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Convert basic AIKS golden tests to use DisplayList (flutter/engine#53969)
Converts several AIKS golden tests to use DisplayList as the mechanism. In order to convert some of the tests, new factory methods were added to DlColor and tested with new unit tests (an earlier golden test conversion PR had a version of this as well). Also, a new DisplayList record op was created for ClipOval to handle the AIKS clipping golden tests, but this new recording op is not used from Flutter `ui` code (no plumbing to call it from `lib/ui/painting` or to convert any other DisplayList call to use the new record). An earlier attempt to add the new recording op caused a large number of golden changes upstream so this version will only be used for internal tests and support to use it from apps will follow in more targeted PRs to better manage golden changes. This PR should not result in any changes to goldens outside of internal engine tests.
This commit is contained in:
parent
4f9e912bef
commit
2d58c39615
@ -140,6 +140,7 @@
|
||||
../../../flutter/impeller/compiler/switches_unittests.cc
|
||||
../../../flutter/impeller/core/allocator_unittests.cc
|
||||
../../../flutter/impeller/display_list/aiks_dl_atlas_unittests.cc
|
||||
../../../flutter/impeller/display_list/aiks_dl_basic_unittests.cc
|
||||
../../../flutter/impeller/display_list/aiks_dl_clip_unittests.cc
|
||||
../../../flutter/impeller/display_list/aiks_dl_gradient_unittests.cc
|
||||
../../../flutter/impeller/display_list/aiks_dl_opacity_unittests.cc
|
||||
|
||||
@ -98,9 +98,11 @@ namespace flutter {
|
||||
V(TransformReset) \
|
||||
\
|
||||
V(ClipIntersectRect) \
|
||||
V(ClipIntersectOval) \
|
||||
V(ClipIntersectRRect) \
|
||||
V(ClipIntersectPath) \
|
||||
V(ClipDifferenceRect) \
|
||||
V(ClipDifferenceOval) \
|
||||
V(ClipDifferenceRRect) \
|
||||
V(ClipDifferencePath) \
|
||||
\
|
||||
|
||||
@ -4332,36 +4332,66 @@ TEST_F(DisplayListTest, DrawDisplayListForwardsBackdropFlag) {
|
||||
|
||||
#define CLIP_EXPECTOR(name) ClipExpector name(__FILE__, __LINE__)
|
||||
|
||||
struct ClipExpectation {
|
||||
std::variant<SkRect, SkRRect, SkPath> shape;
|
||||
bool is_oval;
|
||||
ClipOp clip_op;
|
||||
bool is_aa;
|
||||
|
||||
std::string shape_name() {
|
||||
switch (shape.index()) {
|
||||
case 0:
|
||||
return is_oval ? "SkOval" : "SkRect";
|
||||
case 1:
|
||||
return "SkRRect";
|
||||
case 2:
|
||||
return "SkPath";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
::std::ostream& operator<<(::std::ostream& os, const ClipExpectation& expect) {
|
||||
os << "Expectation(";
|
||||
switch (expect.shape.index()) {
|
||||
case 0:
|
||||
os << std::get<SkRect>(expect.shape);
|
||||
if (expect.is_oval) {
|
||||
os << " (oval)";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
os << std::get<SkRRect>(expect.shape);
|
||||
break;
|
||||
case 2:
|
||||
os << std::get<SkPath>(expect.shape);
|
||||
break;
|
||||
case 3:
|
||||
os << "Unknown";
|
||||
}
|
||||
os << ", " << expect.clip_op;
|
||||
os << ", " << expect.is_aa;
|
||||
os << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
class ClipExpector : public virtual DlOpReceiver,
|
||||
virtual IgnoreAttributeDispatchHelper,
|
||||
virtual IgnoreTransformDispatchHelper,
|
||||
virtual IgnoreDrawDispatchHelper {
|
||||
public:
|
||||
struct Expectation {
|
||||
std::variant<SkRect, SkRRect, SkPath> shape;
|
||||
ClipOp clip_op;
|
||||
bool is_aa;
|
||||
|
||||
std::string shape_name() {
|
||||
switch (shape.index()) {
|
||||
case 0:
|
||||
return "SkRect";
|
||||
case 1:
|
||||
return "SkRRect";
|
||||
case 2:
|
||||
return "SkPath";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// file and line supplied automatically from CLIP_EXPECTOR macro
|
||||
explicit ClipExpector(const std::string& file, int line)
|
||||
: file_(file), line_(line) {}
|
||||
|
||||
~ClipExpector() { //
|
||||
EXPECT_EQ(index_, clip_expectations_.size()) << label();
|
||||
while (index_ < clip_expectations_.size()) {
|
||||
auto expect = clip_expectations_[index_];
|
||||
FML_LOG(ERROR) << "leftover clip shape[" << index_ << "] = " << expect;
|
||||
index_++;
|
||||
}
|
||||
}
|
||||
|
||||
ClipExpector& addExpectation(const SkRect& rect,
|
||||
@ -4369,6 +4399,19 @@ class ClipExpector : public virtual DlOpReceiver,
|
||||
bool is_aa = false) {
|
||||
clip_expectations_.push_back({
|
||||
.shape = rect,
|
||||
.is_oval = false,
|
||||
.clip_op = clip_op,
|
||||
.is_aa = is_aa,
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
|
||||
ClipExpector& addOvalExpectation(const SkRect& rect,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) {
|
||||
clip_expectations_.push_back({
|
||||
.shape = rect,
|
||||
.is_oval = true,
|
||||
.clip_op = clip_op,
|
||||
.is_aa = is_aa,
|
||||
});
|
||||
@ -4380,6 +4423,7 @@ class ClipExpector : public virtual DlOpReceiver,
|
||||
bool is_aa = false) {
|
||||
clip_expectations_.push_back({
|
||||
.shape = rrect,
|
||||
.is_oval = false,
|
||||
.clip_op = clip_op,
|
||||
.is_aa = is_aa,
|
||||
});
|
||||
@ -4391,6 +4435,7 @@ class ClipExpector : public virtual DlOpReceiver,
|
||||
bool is_aa = false) {
|
||||
clip_expectations_.push_back({
|
||||
.shape = path,
|
||||
.is_oval = false,
|
||||
.clip_op = clip_op,
|
||||
.is_aa = is_aa,
|
||||
});
|
||||
@ -4402,6 +4447,11 @@ class ClipExpector : public virtual DlOpReceiver,
|
||||
bool is_aa) override {
|
||||
check(rect, clip_op, is_aa);
|
||||
}
|
||||
void clipOval(const SkRect& bounds,
|
||||
DlCanvas::ClipOp clip_op,
|
||||
bool is_aa) override {
|
||||
check(bounds, clip_op, is_aa, true);
|
||||
}
|
||||
void clipRRect(const SkRRect& rrect,
|
||||
DlCanvas::ClipOp clip_op,
|
||||
bool is_aa) override {
|
||||
@ -4415,22 +4465,23 @@ class ClipExpector : public virtual DlOpReceiver,
|
||||
|
||||
private:
|
||||
size_t index_ = 0;
|
||||
std::vector<Expectation> clip_expectations_;
|
||||
std::vector<ClipExpectation> clip_expectations_;
|
||||
|
||||
template <typename T>
|
||||
void check(T shape, ClipOp clip_op, bool is_aa) {
|
||||
void check(T shape, ClipOp clip_op, bool is_aa, bool is_oval = false) {
|
||||
ASSERT_LT(index_, clip_expectations_.size())
|
||||
<< label() << std::endl
|
||||
<< "extra clip shape = " << shape;
|
||||
<< "extra clip shape = " << shape << (is_oval ? " (oval)" : "");
|
||||
auto expected = clip_expectations_[index_];
|
||||
EXPECT_EQ(expected.clip_op, clip_op) << label();
|
||||
EXPECT_EQ(expected.is_aa, is_aa) << label();
|
||||
if (!std::holds_alternative<T>(expected.shape)) {
|
||||
EXPECT_TRUE(std::holds_alternative<T>(expected.shape))
|
||||
<< label() << ", expected type: " << expected.shape_name();
|
||||
} else {
|
||||
EXPECT_EQ(std::get<T>(expected.shape), shape) << label();
|
||||
}
|
||||
EXPECT_EQ(expected.is_oval, is_oval) << label();
|
||||
EXPECT_EQ(expected.clip_op, clip_op) << label();
|
||||
EXPECT_EQ(expected.is_aa, is_aa) << label();
|
||||
index_++;
|
||||
}
|
||||
|
||||
@ -4570,9 +4621,47 @@ TEST_F(DisplayListTest, ClipRectNestedNonCullingComplex) {
|
||||
cull_dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipOvalCulling) {
|
||||
auto clip = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
// A 10x10 rectangle extends 5x5 from the center to each corner. To have
|
||||
// an oval that encompasses that rectangle, the radius must be at least
|
||||
// length(5, 5), or 7.071+ so we expand the radius 5 square clip by 2.072
|
||||
// on each side to barely contain the corners of the square.
|
||||
auto encompassing_oval = clip.makeOutset(2.072f, 2.072f);
|
||||
|
||||
DisplayListBuilder cull_builder;
|
||||
cull_builder.ClipRect(clip, ClipOp::kIntersect, false);
|
||||
cull_builder.ClipOval(encompassing_oval, ClipOp::kIntersect, false);
|
||||
auto cull_dl = cull_builder.Build();
|
||||
|
||||
CLIP_EXPECTOR(expector);
|
||||
expector.addExpectation(clip, ClipOp::kIntersect, false);
|
||||
cull_dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipOvalNonCulling) {
|
||||
auto clip = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
// A 10x10 rectangle extends 5x5 from the center to each corner. To have
|
||||
// an oval that encompasses that rectangle, the radius must be at least
|
||||
// length(5, 5), or 7.071+ so we expand the radius 5 square clip by 2.072
|
||||
// on each side to barely exclude the corners of the square.
|
||||
auto non_encompassing_oval = clip.makeOutset(2.071f, 2.071f);
|
||||
|
||||
DisplayListBuilder cull_builder;
|
||||
cull_builder.ClipRect(clip, ClipOp::kIntersect, false);
|
||||
cull_builder.ClipOval(non_encompassing_oval, ClipOp::kIntersect, false);
|
||||
auto cull_dl = cull_builder.Build();
|
||||
|
||||
CLIP_EXPECTOR(expector);
|
||||
expector.addExpectation(clip, ClipOp::kIntersect, false);
|
||||
expector.addOvalExpectation(non_encompassing_oval, ClipOp::kIntersect, false);
|
||||
cull_dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipRRectCulling) {
|
||||
auto clip = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
auto rrect = SkRRect::MakeRectXY(clip.makeOutset(2.0f, 2.0f), 2.0f, 2.0f);
|
||||
ASSERT_FALSE(rrect.isOval());
|
||||
|
||||
DisplayListBuilder cull_builder;
|
||||
cull_builder.ClipRect(clip, ClipOp::kIntersect, false);
|
||||
@ -4586,7 +4675,8 @@ TEST_F(DisplayListTest, ClipRRectCulling) {
|
||||
|
||||
TEST_F(DisplayListTest, ClipRRectNonCulling) {
|
||||
auto clip = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
auto rrect = SkRRect::MakeRectXY(clip.makeOutset(2.0f, 2.0f), 12.0f, 12.0f);
|
||||
auto rrect = SkRRect::MakeRectXY(clip.makeOutset(1.0f, 1.0f), 4.0f, 4.0f);
|
||||
ASSERT_FALSE(rrect.isOval());
|
||||
|
||||
DisplayListBuilder cull_builder;
|
||||
cull_builder.ClipRect(clip, ClipOp::kIntersect, false);
|
||||
@ -4661,9 +4751,55 @@ TEST_F(DisplayListTest, ClipPathRectNonCulling) {
|
||||
cull_dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipPathOvalCulling) {
|
||||
auto clip = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
// A 10x10 rectangle extends 5x5 from the center to each corner. To have
|
||||
// an oval that encompasses that rectangle, the radius must be at least
|
||||
// length(5, 5), or 7.071+ so we expand the radius 5 square clip by 2.072
|
||||
// on each side to barely contain the corners of the square.
|
||||
auto encompassing_oval = clip.makeOutset(2.072f, 2.072f);
|
||||
SkPath path;
|
||||
path.addOval(encompassing_oval);
|
||||
|
||||
DisplayListBuilder cull_builder;
|
||||
cull_builder.ClipRect(clip, ClipOp::kIntersect, false);
|
||||
cull_builder.ClipPath(path, ClipOp::kIntersect, false);
|
||||
auto cull_dl = cull_builder.Build();
|
||||
|
||||
CLIP_EXPECTOR(expector);
|
||||
expector.addExpectation(clip, ClipOp::kIntersect, false);
|
||||
cull_dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipPathOvalNonCulling) {
|
||||
auto clip = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
// A 10x10 rectangle extends 5x5 from the center to each corner. To have
|
||||
// an oval that encompasses that rectangle, the radius must be at least
|
||||
// length(5, 5), or 7.071+ so we expand the radius 5 square clip by 2.072
|
||||
// on each side to barely exclude the corners of the square.
|
||||
auto non_encompassing_oval = clip.makeOutset(2.071f, 2.071f);
|
||||
SkPath path;
|
||||
path.addOval(non_encompassing_oval);
|
||||
SkRRect rrect;
|
||||
rrect.setOval(non_encompassing_oval);
|
||||
|
||||
DisplayListBuilder cull_builder;
|
||||
cull_builder.ClipRect(clip, ClipOp::kIntersect, false);
|
||||
cull_builder.ClipPath(path, ClipOp::kIntersect, false);
|
||||
auto cull_dl = cull_builder.Build();
|
||||
|
||||
CLIP_EXPECTOR(expector);
|
||||
expector.addExpectation(clip, ClipOp::kIntersect, false);
|
||||
// Builder will not cull this clip, but it will turn it into a ClipRRect
|
||||
// Eventually it should turn it into a ClipOval
|
||||
expector.addExpectation(rrect, ClipOp::kIntersect, false);
|
||||
cull_dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipPathRRectCulling) {
|
||||
auto clip = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
auto rrect = SkRRect::MakeRectXY(clip.makeOutset(2.0f, 2.0f), 2.0f, 2.0f);
|
||||
ASSERT_FALSE(rrect.isOval());
|
||||
SkPath path;
|
||||
path.addRRect(rrect);
|
||||
|
||||
@ -4679,7 +4815,8 @@ TEST_F(DisplayListTest, ClipPathRRectCulling) {
|
||||
|
||||
TEST_F(DisplayListTest, ClipPathRRectNonCulling) {
|
||||
auto clip = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
auto rrect = SkRRect::MakeRectXY(clip.makeOutset(2.0f, 2.0f), 12.0f, 12.0f);
|
||||
auto rrect = SkRRect::MakeRectXY(clip.makeOutset(1.0f, 1.0f), 4.0f, 4.0f);
|
||||
ASSERT_FALSE(rrect.isOval());
|
||||
SkPath path;
|
||||
path.addRRect(rrect);
|
||||
|
||||
@ -4724,5 +4861,323 @@ TEST_F(DisplayListTest, RecordLargeVertices) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, DrawRectRRectPromoteToDrawRect) {
|
||||
SkRect rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.DrawRRect(SkRRect::MakeRect(rect), DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.DrawRect(rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, DrawOvalRRectPromoteToDrawOval) {
|
||||
SkRect rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.DrawRRect(SkRRect::MakeOval(rect), DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.DrawOval(rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, DrawRectPathPromoteToDrawRect) {
|
||||
SkRect rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.DrawPath(SkPath::Rect(rect), DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.DrawRect(rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, DrawOvalPathPromoteToDrawOval) {
|
||||
SkRect rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.DrawPath(SkPath::Oval(rect), DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.DrawOval(rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, DrawRRectPathPromoteToDrawRRect) {
|
||||
SkRect rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRRect rrect = SkRRect::MakeRectXY(rect, 2.0f, 2.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.DrawPath(SkPath::RRect(rrect), DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.DrawRRect(rrect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, DrawRectRRectPathPromoteToDrawRect) {
|
||||
SkRect rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRRect rrect = SkRRect::MakeRect(rect);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.DrawPath(SkPath::RRect(rrect), DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.DrawRect(rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, DrawOvalRRectPathPromoteToDrawOval) {
|
||||
SkRect rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRRect rrect = SkRRect::MakeOval(rect);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.DrawPath(SkPath::RRect(rrect), DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.DrawOval(rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipRectRRectPromoteToClipRect) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipRRect(SkRRect::MakeRect(clip_rect), ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.ClipRect(clip_rect, ClipOp::kIntersect, false);
|
||||
expected.DrawRect(draw_rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipOvalRRectPromoteToClipOval) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipRRect(SkRRect::MakeOval(clip_rect), ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.ClipOval(clip_rect, ClipOp::kIntersect, false);
|
||||
expected.DrawRect(draw_rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipRectPathPromoteToClipRect) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
SkPath clip_path = SkPath::Rect(clip_rect);
|
||||
ASSERT_TRUE(clip_path.isRect(nullptr));
|
||||
ASSERT_FALSE(clip_path.isInverseFillType());
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipPath(clip_path, ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.ClipRect(clip_rect, ClipOp::kIntersect, false);
|
||||
expected.DrawRect(draw_rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipOvalPathPromoteToClipOval) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
SkPath clip_path = SkPath::Oval(clip_rect);
|
||||
ASSERT_TRUE(clip_path.isOval(nullptr));
|
||||
ASSERT_FALSE(clip_path.isInverseFillType());
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipPath(clip_path, ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.ClipOval(clip_rect, ClipOp::kIntersect, false);
|
||||
expected.DrawRect(draw_rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipRRectPathPromoteToClipRRect) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRRect clip_rrect = SkRRect::MakeRectXY(clip_rect, 2.0f, 2.0f);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
SkPath clip_path = SkPath::RRect(clip_rrect);
|
||||
ASSERT_TRUE(clip_path.isRRect(nullptr));
|
||||
ASSERT_FALSE(clip_path.isInverseFillType());
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipPath(clip_path, ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.ClipRRect(clip_rrect, ClipOp::kIntersect, false);
|
||||
expected.DrawRect(draw_rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipRectInversePathNoPromoteToClipRect) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
SkPath clip_path = SkPath::Rect(clip_rect);
|
||||
clip_path.toggleInverseFillType();
|
||||
ASSERT_TRUE(clip_path.isRect(nullptr));
|
||||
ASSERT_TRUE(clip_path.isInverseFillType());
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipPath(clip_path, ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
// Non-promoting tests can't use DL comparisons to verify that the
|
||||
// promotion isn't happening because the test and expectation builders
|
||||
// would both apply or not apply the same optimization. For this case
|
||||
// we use the CLIP_EXPECTOR instead to see exactly which type of
|
||||
// clip operation was recorded.
|
||||
CLIP_EXPECTOR(expector);
|
||||
expector.addExpectation(clip_path, ClipOp::kIntersect, false);
|
||||
dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipOvalInversePathNoPromoteToClipOval) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
SkPath clip_path = SkPath::Oval(clip_rect);
|
||||
clip_path.toggleInverseFillType();
|
||||
ASSERT_TRUE(clip_path.isOval(nullptr));
|
||||
ASSERT_TRUE(clip_path.isInverseFillType());
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipPath(clip_path, ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
// Non-promoting tests can't use DL comparisons to verify that the
|
||||
// promotion isn't happening because the test and expectation builders
|
||||
// would both apply or not apply the same optimization. For this case
|
||||
// we use the CLIP_EXPECTOR instead to see exactly which type of
|
||||
// clip operation was recorded.
|
||||
CLIP_EXPECTOR(expector);
|
||||
expector.addExpectation(clip_path, ClipOp::kIntersect, false);
|
||||
dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipRRectInversePathNoPromoteToClipRRect) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRRect clip_rrect = SkRRect::MakeRectXY(clip_rect, 2.0f, 2.0f);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
SkPath clip_path = SkPath::RRect(clip_rrect);
|
||||
clip_path.toggleInverseFillType();
|
||||
ASSERT_TRUE(clip_path.isRRect(nullptr));
|
||||
ASSERT_TRUE(clip_path.isInverseFillType());
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipPath(clip_path, ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
// Non-promoting tests can't use DL comparisons to verify that the
|
||||
// promotion isn't happening because the test and expectation builders
|
||||
// would both apply or not apply the same optimization. For this case
|
||||
// we use the CLIP_EXPECTOR instead to see exactly which type of
|
||||
// clip operation was recorded.
|
||||
CLIP_EXPECTOR(expector);
|
||||
expector.addExpectation(clip_path, ClipOp::kIntersect, false);
|
||||
dl->Dispatch(expector);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipRectRRectPathPromoteToClipRect) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRRect clip_rrect = SkRRect::MakeRect(clip_rect);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
SkPath clip_path = SkPath::RRect(clip_rrect);
|
||||
ASSERT_TRUE(clip_path.isRRect(nullptr));
|
||||
ASSERT_FALSE(clip_path.isInverseFillType());
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipPath(clip_path, ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.ClipRect(clip_rect, ClipOp::kIntersect, false);
|
||||
expected.DrawRect(draw_rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
TEST_F(DisplayListTest, ClipOvalRRectPathPromoteToClipOval) {
|
||||
SkRect clip_rect = SkRect::MakeLTRB(10.0f, 10.0f, 20.0f, 20.0f);
|
||||
SkRRect clip_rrect = SkRRect::MakeOval(clip_rect);
|
||||
SkRect draw_rect = clip_rect.makeOutset(2.0f, 2.0f);
|
||||
SkPath clip_path = SkPath::RRect(clip_rrect);
|
||||
ASSERT_TRUE(clip_path.isRRect(nullptr));
|
||||
ASSERT_FALSE(clip_path.isInverseFillType());
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.ClipPath(clip_path, ClipOp::kIntersect, false);
|
||||
// Include a rendering op in case DlBuilder ever removes unneeded clips
|
||||
builder.DrawRect(draw_rect, DlPaint());
|
||||
auto dl = builder.Build();
|
||||
|
||||
DisplayListBuilder expected;
|
||||
expected.ClipOval(clip_rect, ClipOp::kIntersect, false);
|
||||
expected.DrawRect(draw_rect, DlPaint());
|
||||
auto expect_dl = expected.Build();
|
||||
|
||||
DisplayListsEQ_Verbose(dl, expect_dl);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@ -963,6 +963,38 @@ void DisplayListBuilder::ClipRect(const SkRect& rect,
|
||||
break;
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::ClipOval(const SkRect& bounds,
|
||||
ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
if (!bounds.isFinite()) {
|
||||
return;
|
||||
}
|
||||
if (current_info().is_nop) {
|
||||
return;
|
||||
}
|
||||
if (current_info().has_valid_clip &&
|
||||
clip_op == DlCanvas::ClipOp::kIntersect &&
|
||||
layer_local_state().oval_covers_cull(bounds)) {
|
||||
return;
|
||||
}
|
||||
global_state().clipOval(bounds, clip_op, is_aa);
|
||||
layer_local_state().clipOval(bounds, clip_op, is_aa);
|
||||
if (global_state().is_cull_rect_empty() ||
|
||||
layer_local_state().is_cull_rect_empty()) {
|
||||
current_info().is_nop = true;
|
||||
return;
|
||||
}
|
||||
current_info().has_valid_clip = true;
|
||||
checkForDeferredSave();
|
||||
switch (clip_op) {
|
||||
case ClipOp::kIntersect:
|
||||
Push<ClipIntersectOvalOp>(0, bounds, is_aa);
|
||||
break;
|
||||
case ClipOp::kDifference:
|
||||
Push<ClipDifferenceOvalOp>(0, bounds, is_aa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::ClipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
|
||||
@ -117,6 +117,10 @@ class DisplayListBuilder final : public virtual DlCanvas,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
// |DlCanvas|
|
||||
void ClipOval(const SkRect& bounds,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
// |DlCanvas|
|
||||
void ClipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
@ -400,6 +404,10 @@ class DisplayListBuilder final : public virtual DlCanvas,
|
||||
ClipRect(rect, clip_op, is_aa);
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void clipOval(const SkRect& bounds, ClipOp clip_op, bool is_aa) override {
|
||||
ClipOval(bounds, clip_op, is_aa);
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override {
|
||||
ClipRRect(rrect, clip_op, is_aa);
|
||||
}
|
||||
|
||||
@ -105,6 +105,9 @@ class DlCanvas {
|
||||
virtual void ClipRect(const SkRect& rect,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) = 0;
|
||||
virtual void ClipOval(const SkRect& bounds,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) = 0;
|
||||
virtual void ClipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) = 0;
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#ifndef FLUTTER_DISPLAY_LIST_DL_COLOR_H_
|
||||
#define FLUTTER_DISPLAY_LIST_DL_COLOR_H_
|
||||
|
||||
#include "third_party/skia/include/core/SkScalar.h"
|
||||
#include "flutter/display_list/geometry/dl_geometry_types.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@ -14,17 +14,29 @@ struct DlColor {
|
||||
constexpr DlColor() : argb_(0xFF000000) {}
|
||||
constexpr explicit DlColor(uint32_t argb) : argb_(argb) {}
|
||||
|
||||
/// @brief Construct a 32 bit color from a floating point A, R, G, and B color
|
||||
/// channel.
|
||||
constexpr explicit DlColor(SkScalar a, SkScalar r, SkScalar g, SkScalar b)
|
||||
: argb_(static_cast<uint8_t>(std::round(a * 255)) << 24 | //
|
||||
static_cast<uint8_t>(std::round(r * 255)) << 16 | //
|
||||
static_cast<uint8_t>(std::round(g * 255)) << 8 | //
|
||||
static_cast<uint8_t>(std::round(b * 255)) << 0 //
|
||||
) {}
|
||||
/// @brief Construct a 32 bit color from floating point R, G, B, and A color
|
||||
/// channels.
|
||||
static constexpr DlColor RGBA(DlScalar r,
|
||||
DlScalar g,
|
||||
DlScalar b,
|
||||
DlScalar a) {
|
||||
return ARGB(a, r, g, b);
|
||||
}
|
||||
|
||||
static constexpr uint8_t toAlpha(SkScalar opacity) { return toC(opacity); }
|
||||
static constexpr SkScalar toOpacity(uint8_t alpha) { return toF(alpha); }
|
||||
/// @brief Construct a 32 bit color from floating point A, R, G, and B color
|
||||
/// channels.
|
||||
static constexpr DlColor ARGB(DlScalar a,
|
||||
DlScalar r,
|
||||
DlScalar g,
|
||||
DlScalar b) {
|
||||
return DlColor(toC(a) << 24 | //
|
||||
toC(r) << 16 | //
|
||||
toC(g) << 8 | //
|
||||
toC(b));
|
||||
}
|
||||
|
||||
static constexpr uint8_t toAlpha(DlScalar opacity) { return toC(opacity); }
|
||||
static constexpr DlScalar toOpacity(uint8_t alpha) { return toF(alpha); }
|
||||
|
||||
// clang-format off
|
||||
static constexpr DlColor kTransparent() {return DlColor(0x00000000);};
|
||||
@ -54,16 +66,16 @@ struct DlColor {
|
||||
constexpr int getGreen() const { return (argb_ >> 8) & 0xFF; }
|
||||
constexpr int getBlue() const { return argb_ & 0xFF; }
|
||||
|
||||
constexpr float getAlphaF() const { return toF(getAlpha()); }
|
||||
constexpr float getRedF() const { return toF(getRed()); }
|
||||
constexpr float getGreenF() const { return toF(getGreen()); }
|
||||
constexpr float getBlueF() const { return toF(getBlue()); }
|
||||
constexpr DlScalar getAlphaF() const { return toF(getAlpha()); }
|
||||
constexpr DlScalar getRedF() const { return toF(getRed()); }
|
||||
constexpr DlScalar getGreenF() const { return toF(getGreen()); }
|
||||
constexpr DlScalar getBlueF() const { return toF(getBlue()); }
|
||||
|
||||
constexpr uint32_t premultipliedArgb() const {
|
||||
if (isOpaque()) {
|
||||
return argb_;
|
||||
}
|
||||
float f = getAlphaF();
|
||||
DlScalar f = getAlphaF();
|
||||
return (argb_ & 0xFF000000) | //
|
||||
toC(getRedF() * f) << 16 | //
|
||||
toC(getGreenF() * f) << 8 | //
|
||||
@ -83,7 +95,7 @@ struct DlColor {
|
||||
return DlColor((argb_ & 0xFFFFFF00) | (blue << 0));
|
||||
}
|
||||
|
||||
constexpr DlColor modulateOpacity(float opacity) const {
|
||||
constexpr DlColor modulateOpacity(DlScalar opacity) const {
|
||||
return opacity <= 0 ? withAlpha(0)
|
||||
: opacity >= 1 ? *this
|
||||
: withAlpha(round(getAlpha() * opacity));
|
||||
@ -99,8 +111,8 @@ struct DlColor {
|
||||
private:
|
||||
uint32_t argb_;
|
||||
|
||||
static float toF(uint8_t comp) { return comp * (1.0f / 255); }
|
||||
static uint8_t toC(float fComp) { return round(fComp * 255); }
|
||||
static constexpr DlScalar toF(uint8_t comp) { return comp * (1.0f / 255); }
|
||||
static constexpr uint8_t toC(DlScalar fComp) { return round(fComp * 255); }
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -45,5 +45,190 @@ TEST(DisplayListColor, DlColorDirectlyComparesToSkColor) {
|
||||
EXPECT_EQ(DlColor::kBlue(), SK_ColorBLUE);
|
||||
}
|
||||
|
||||
TEST(DisplayListColor, DlColorFloatConstructor) {
|
||||
EXPECT_EQ(DlColor::ARGB(1.0f, 1.0f, 1.0f, 1.0f), DlColor(0xFFFFFFFF));
|
||||
EXPECT_EQ(DlColor::ARGB(0.0f, 0.0f, 0.0f, 0.0f), DlColor(0x00000000));
|
||||
EXPECT_EQ(DlColor::ARGB(0.5f, 0.5f, 0.5f, 0.5f), DlColor(0x80808080));
|
||||
EXPECT_EQ(DlColor::ARGB(1.0f, 0.0f, 0.5f, 1.0f), DlColor(0xFF0080FF));
|
||||
|
||||
EXPECT_EQ(DlColor::RGBA(1.0f, 1.0f, 1.0f, 1.0f), DlColor(0xFFFFFFFF));
|
||||
EXPECT_EQ(DlColor::RGBA(0.0f, 0.0f, 0.0f, 0.0f), DlColor(0x00000000));
|
||||
EXPECT_EQ(DlColor::RGBA(0.5f, 0.5f, 0.5f, 0.5f), DlColor(0x80808080));
|
||||
EXPECT_EQ(DlColor::RGBA(1.0f, 0.0f, 0.5f, 1.0f), DlColor(0xFFFF0080));
|
||||
}
|
||||
|
||||
TEST(DisplayListColor, DlColorComponentGetters) {
|
||||
{
|
||||
DlColor test(0xFFFFFFFF);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), 0xFF);
|
||||
EXPECT_EQ(test.getRed(), 0xFF);
|
||||
EXPECT_EQ(test.getGreen(), 0xFF);
|
||||
EXPECT_EQ(test.getBlue(), 0xFF);
|
||||
|
||||
EXPECT_EQ(test.getAlphaF(), 1.0f);
|
||||
EXPECT_EQ(test.getRedF(), 1.0f);
|
||||
EXPECT_EQ(test.getGreenF(), 1.0f);
|
||||
EXPECT_EQ(test.getBlueF(), 1.0f);
|
||||
}
|
||||
|
||||
{
|
||||
DlColor test = DlColor::ARGB(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), 0xFF);
|
||||
EXPECT_EQ(test.getRed(), 0xFF);
|
||||
EXPECT_EQ(test.getGreen(), 0xFF);
|
||||
EXPECT_EQ(test.getBlue(), 0xFF);
|
||||
|
||||
EXPECT_EQ(test.getAlphaF(), 1.0f);
|
||||
EXPECT_EQ(test.getRedF(), 1.0f);
|
||||
EXPECT_EQ(test.getGreenF(), 1.0f);
|
||||
EXPECT_EQ(test.getBlueF(), 1.0f);
|
||||
}
|
||||
|
||||
{
|
||||
DlColor test(0x00000000);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), 0x00);
|
||||
EXPECT_EQ(test.getRed(), 0x00);
|
||||
EXPECT_EQ(test.getGreen(), 0x00);
|
||||
EXPECT_EQ(test.getBlue(), 0x00);
|
||||
|
||||
EXPECT_EQ(test.getAlphaF(), 0.0f);
|
||||
EXPECT_EQ(test.getRedF(), 0.0f);
|
||||
EXPECT_EQ(test.getGreenF(), 0.0f);
|
||||
EXPECT_EQ(test.getBlueF(), 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
DlColor test = DlColor::ARGB(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), 0x00);
|
||||
EXPECT_EQ(test.getRed(), 0x00);
|
||||
EXPECT_EQ(test.getGreen(), 0x00);
|
||||
EXPECT_EQ(test.getBlue(), 0x00);
|
||||
|
||||
EXPECT_EQ(test.getAlphaF(), 0.0f);
|
||||
EXPECT_EQ(test.getRedF(), 0.0f);
|
||||
EXPECT_EQ(test.getGreenF(), 0.0f);
|
||||
EXPECT_EQ(test.getBlueF(), 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
DlColor test(0x7F7F7F7F);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), 0x7F);
|
||||
EXPECT_EQ(test.getRed(), 0x7F);
|
||||
EXPECT_EQ(test.getGreen(), 0x7F);
|
||||
EXPECT_EQ(test.getBlue(), 0x7F);
|
||||
|
||||
const DlScalar half = 127.0f * (1.0f / 255.0f);
|
||||
|
||||
EXPECT_EQ(test.getAlphaF(), half);
|
||||
EXPECT_EQ(test.getRedF(), half);
|
||||
EXPECT_EQ(test.getGreenF(), half);
|
||||
EXPECT_EQ(test.getBlueF(), half);
|
||||
}
|
||||
|
||||
{
|
||||
DlColor test = DlColor::ARGB(0.5f, 0.5f, 0.5f, 0.5f);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), 0x80);
|
||||
EXPECT_EQ(test.getRed(), 0x80);
|
||||
EXPECT_EQ(test.getGreen(), 0x80);
|
||||
EXPECT_EQ(test.getBlue(), 0x80);
|
||||
|
||||
const DlScalar half = 128.0f * (1.0f / 255.0f);
|
||||
|
||||
EXPECT_EQ(test.getAlphaF(), half);
|
||||
EXPECT_EQ(test.getRedF(), half);
|
||||
EXPECT_EQ(test.getGreenF(), half);
|
||||
EXPECT_EQ(test.getBlueF(), half);
|
||||
}
|
||||
|
||||
{
|
||||
DlColor test(0x1F2F3F4F);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), 0x1F);
|
||||
EXPECT_EQ(test.getRed(), 0x2F);
|
||||
EXPECT_EQ(test.getGreen(), 0x3F);
|
||||
EXPECT_EQ(test.getBlue(), 0x4F);
|
||||
|
||||
EXPECT_EQ(test.getAlphaF(), 0x1f * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getRedF(), 0x2f * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getGreenF(), 0x3f * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getBlueF(), 0x4f * (1.0f / 255.0f));
|
||||
}
|
||||
|
||||
{
|
||||
DlColor test = DlColor::ARGB(0.1f, 0.2f, 0.3f, 0.4f);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), round(0.1f * 255));
|
||||
EXPECT_EQ(test.getRed(), round(0.2f * 255));
|
||||
EXPECT_EQ(test.getGreen(), round(0.3f * 255));
|
||||
EXPECT_EQ(test.getBlue(), round(0.4f * 255));
|
||||
|
||||
// Unfortunately conversion from float to 8-bit back to float is lossy
|
||||
EXPECT_EQ(test.getAlphaF(), round(0.1f * 255) * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getRedF(), round(0.2f * 255) * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getGreenF(), round(0.3f * 255) * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getBlueF(), round(0.4f * 255) * (1.0f / 255.0f));
|
||||
}
|
||||
|
||||
{
|
||||
DlColor test = DlColor::RGBA(0.2f, 0.3f, 0.4f, 0.1f);
|
||||
|
||||
EXPECT_EQ(test.getAlpha(), round(0.1f * 255));
|
||||
EXPECT_EQ(test.getRed(), round(0.2f * 255));
|
||||
EXPECT_EQ(test.getGreen(), round(0.3f * 255));
|
||||
EXPECT_EQ(test.getBlue(), round(0.4f * 255));
|
||||
|
||||
// Unfortunately conversion from float to 8-bit back to float is lossy
|
||||
EXPECT_EQ(test.getAlphaF(), round(0.1f * 255) * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getRedF(), round(0.2f * 255) * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getGreenF(), round(0.3f * 255) * (1.0f / 255.0f));
|
||||
EXPECT_EQ(test.getBlueF(), round(0.4f * 255) * (1.0f / 255.0f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DisplayListColor, DlColorOpaqueTransparent) {
|
||||
auto test_argb = [](int a, int r, int g, int b) {
|
||||
ASSERT_TRUE(a >= 0 && a <= 255);
|
||||
ASSERT_TRUE(r >= 0 && r <= 255);
|
||||
ASSERT_TRUE(g >= 0 && g <= 255);
|
||||
ASSERT_TRUE(b >= 0 && b <= 255);
|
||||
|
||||
int argb = ((a << 24) | (r << 16) | (g << 8) | b);
|
||||
bool is_opaque = (a == 255);
|
||||
bool is_transprent = (a == 0);
|
||||
|
||||
EXPECT_EQ(DlColor(argb).isOpaque(), is_opaque);
|
||||
EXPECT_EQ(DlColor(argb).isTransparent(), is_transprent);
|
||||
|
||||
DlScalar aF = a * (1.0f / 255.0f);
|
||||
DlScalar rF = r * (1.0f / 255.0f);
|
||||
DlScalar gF = g * (1.0f / 255.0f);
|
||||
DlScalar bF = b * (1.0f / 255.0f);
|
||||
|
||||
EXPECT_EQ(DlColor::ARGB(aF, rF, gF, bF).isOpaque(), is_opaque);
|
||||
EXPECT_EQ(DlColor::ARGB(aF, rF, gF, bF).isTransparent(), is_transprent);
|
||||
|
||||
EXPECT_EQ(DlColor::RGBA(rF, gF, bF, aF).isOpaque(), is_opaque);
|
||||
EXPECT_EQ(DlColor::RGBA(rF, gF, bF, aF).isTransparent(), is_transprent);
|
||||
};
|
||||
|
||||
for (int r = 0; r <= 255; r += 15) {
|
||||
for (int g = 0; g <= 255; g += 15) {
|
||||
for (int b = 0; b <= 255; b += 15) {
|
||||
test_argb(0, r, g, b);
|
||||
for (int a = 15; a < 255; a += 15) {
|
||||
test_argb(a, r, g, b);
|
||||
}
|
||||
test_argb(255, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@ -328,6 +328,7 @@ class DlOpReceiver {
|
||||
virtual void transformReset() = 0;
|
||||
|
||||
virtual void clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) = 0;
|
||||
virtual void clipOval(const SkRect& bounds, ClipOp clip_op, bool is_aa) = 0;
|
||||
virtual void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) = 0;
|
||||
virtual void clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) = 0;
|
||||
|
||||
|
||||
@ -566,11 +566,11 @@ struct TransformResetOp final : TransformClipOpBase {
|
||||
// the header, but the Windows compiler keeps wanting to expand that
|
||||
// packing into more bytes than needed (even when they are declared as
|
||||
// packed bit fields!)
|
||||
#define DEFINE_CLIP_SHAPE_OP(shapetype, clipop) \
|
||||
struct Clip##clipop##shapetype##Op final : TransformClipOpBase { \
|
||||
static constexpr auto kType = DisplayListOpType::kClip##clipop##shapetype; \
|
||||
#define DEFINE_CLIP_SHAPE_OP(shapename, shapetype, clipop) \
|
||||
struct Clip##clipop##shapename##Op final : TransformClipOpBase { \
|
||||
static constexpr auto kType = DisplayListOpType::kClip##clipop##shapename; \
|
||||
\
|
||||
Clip##clipop##shapetype##Op(Sk##shapetype shape, bool is_aa) \
|
||||
Clip##clipop##shapename##Op(Sk##shapetype shape, bool is_aa) \
|
||||
: is_aa(is_aa), shape(shape) {} \
|
||||
\
|
||||
const bool is_aa; \
|
||||
@ -578,15 +578,17 @@ struct TransformResetOp final : TransformClipOpBase {
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
ctx.receiver.clip##shapetype(shape, DlCanvas::ClipOp::k##clipop, \
|
||||
ctx.receiver.clip##shapename(shape, DlCanvas::ClipOp::k##clipop, \
|
||||
is_aa); \
|
||||
} \
|
||||
} \
|
||||
};
|
||||
DEFINE_CLIP_SHAPE_OP(Rect, Intersect)
|
||||
DEFINE_CLIP_SHAPE_OP(RRect, Intersect)
|
||||
DEFINE_CLIP_SHAPE_OP(Rect, Difference)
|
||||
DEFINE_CLIP_SHAPE_OP(RRect, Difference)
|
||||
DEFINE_CLIP_SHAPE_OP(Rect, Rect, Intersect)
|
||||
DEFINE_CLIP_SHAPE_OP(Oval, Rect, Intersect)
|
||||
DEFINE_CLIP_SHAPE_OP(RRect, RRect, Intersect)
|
||||
DEFINE_CLIP_SHAPE_OP(Rect, Rect, Difference)
|
||||
DEFINE_CLIP_SHAPE_OP(Oval, Rect, Difference)
|
||||
DEFINE_CLIP_SHAPE_OP(RRect, RRect, Difference)
|
||||
#undef DEFINE_CLIP_SHAPE_OP
|
||||
|
||||
#define DEFINE_CLIP_PATH_OP(clipop) \
|
||||
|
||||
@ -153,6 +153,12 @@ void DlSkCanvasAdapter::ClipRect(const SkRect& rect,
|
||||
delegate_->clipRect(rect, ToSk(clip_op), is_aa);
|
||||
}
|
||||
|
||||
void DlSkCanvasAdapter::ClipOval(const SkRect& bounds,
|
||||
ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
delegate_->clipRRect(SkRRect::MakeOval(bounds), ToSk(clip_op), is_aa);
|
||||
}
|
||||
|
||||
void DlSkCanvasAdapter::ClipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
|
||||
@ -72,6 +72,7 @@ class DlSkCanvasAdapter final : public virtual DlCanvas {
|
||||
SkMatrix GetTransform() const override;
|
||||
|
||||
void ClipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override;
|
||||
void ClipOval(const SkRect& bounds, ClipOp clip_op, bool is_aa) override;
|
||||
void ClipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override;
|
||||
void ClipPath(const SkPath& path, ClipOp clip_op, bool is_aa) override;
|
||||
|
||||
|
||||
@ -122,6 +122,11 @@ void DlSkCanvasDispatcher::clipRect(const SkRect& rect,
|
||||
bool is_aa) {
|
||||
canvas_->clipRect(rect, ToSk(clip_op), is_aa);
|
||||
}
|
||||
void DlSkCanvasDispatcher::clipOval(const SkRect& bounds,
|
||||
ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
canvas_->clipRRect(SkRRect::MakeOval(bounds), ToSk(clip_op), is_aa);
|
||||
}
|
||||
void DlSkCanvasDispatcher::clipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
|
||||
@ -51,6 +51,7 @@ class DlSkCanvasDispatcher : public virtual DlOpReceiver,
|
||||
void transformReset() override;
|
||||
|
||||
void clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override;
|
||||
void clipOval(const SkRect& bounds, ClipOp clip_op, bool is_aa) override;
|
||||
void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override;
|
||||
void clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) override;
|
||||
|
||||
|
||||
@ -2073,6 +2073,39 @@ class CanvasCompareTester {
|
||||
ctx.canvas->ClipRect(r_clip, ClipOp::kDifference, false);
|
||||
})
|
||||
.with_diff_clip());
|
||||
// Skia lacks clipOval and requires us to make an oval SkRRect
|
||||
SkRRect rr_oval_clip = SkRRect::MakeOval(r_clip);
|
||||
RenderWith(testP, env, intersect_tolerance,
|
||||
CaseParameters(
|
||||
"Hard ClipOval",
|
||||
[=](const SkSetupContext& ctx) {
|
||||
ctx.canvas->clipRRect(rr_oval_clip, SkClipOp::kIntersect,
|
||||
false);
|
||||
},
|
||||
[=](const DlSetupContext& ctx) {
|
||||
ctx.canvas->ClipOval(r_clip, ClipOp::kIntersect, false);
|
||||
}));
|
||||
RenderWith(testP, env, intersect_tolerance,
|
||||
CaseParameters(
|
||||
"AntiAlias ClipOval",
|
||||
[=](const SkSetupContext& ctx) {
|
||||
ctx.canvas->clipRRect(rr_oval_clip, SkClipOp::kIntersect,
|
||||
true);
|
||||
},
|
||||
[=](const DlSetupContext& ctx) {
|
||||
ctx.canvas->ClipOval(r_clip, ClipOp::kIntersect, true);
|
||||
}));
|
||||
RenderWith(testP, env, diff_tolerance,
|
||||
CaseParameters(
|
||||
"Hard ClipOval Diff",
|
||||
[=](const SkSetupContext& ctx) {
|
||||
ctx.canvas->clipRRect(rr_oval_clip, SkClipOp::kDifference,
|
||||
false);
|
||||
},
|
||||
[=](const DlSetupContext& ctx) {
|
||||
ctx.canvas->ClipOval(r_clip, ClipOp::kDifference, false);
|
||||
})
|
||||
.with_diff_clip());
|
||||
// This test RR clip used to use very small radii, but due to
|
||||
// optimizations in the HW rrect rasterization, this caused small
|
||||
// bulges in the corners of the RRect which were interpreted as
|
||||
@ -2850,12 +2883,14 @@ TEST_F(DisplayListRendering, DrawDiagonalLines) {
|
||||
SkPoint p2 = SkPoint::Make(kRenderRight, kRenderBottom);
|
||||
SkPoint p3 = SkPoint::Make(kRenderLeft, kRenderBottom);
|
||||
SkPoint p4 = SkPoint::Make(kRenderRight, kRenderTop);
|
||||
// Adding some edge to edge diagonals that run through the points about
|
||||
// 16 units in from the center of that edge.
|
||||
// Adding some edge center to edge center diagonals to better fill
|
||||
// out the RRect Clip so bounds checking sees less empty bounds space.
|
||||
SkPoint p5 = SkPoint::Make(kRenderCenterX, kRenderTop);
|
||||
SkPoint p6 = SkPoint::Make(kRenderRight, kRenderCenterY);
|
||||
SkPoint p7 = SkPoint::Make(kRenderLeft, kRenderCenterY);
|
||||
SkPoint p8 = SkPoint::Make(kRenderCenterX, kRenderBottom);
|
||||
SkPoint p5 = SkPoint::Make(kRenderCenterX, kRenderTop + 15);
|
||||
SkPoint p6 = SkPoint::Make(kRenderRight - 15, kRenderCenterY);
|
||||
SkPoint p7 = SkPoint::Make(kRenderCenterX, kRenderBottom - 15);
|
||||
SkPoint p8 = SkPoint::Make(kRenderLeft + 15, kRenderCenterY);
|
||||
|
||||
CanvasCompareTester::RenderAll( //
|
||||
TestParameters(
|
||||
@ -2880,9 +2915,13 @@ TEST_F(DisplayListRendering, DrawDiagonalLines) {
|
||||
.set_draw_line());
|
||||
}
|
||||
|
||||
TEST_F(DisplayListRendering, DrawHorizontalLine) {
|
||||
SkPoint p1 = SkPoint::Make(kRenderLeft, kRenderCenterY);
|
||||
SkPoint p2 = SkPoint::Make(kRenderRight, kRenderCenterY);
|
||||
TEST_F(DisplayListRendering, DrawHorizontalLines) {
|
||||
SkPoint p1 = SkPoint::Make(kRenderLeft, kRenderTop + 16);
|
||||
SkPoint p2 = SkPoint::Make(kRenderRight, kRenderTop + 16);
|
||||
SkPoint p3 = SkPoint::Make(kRenderLeft, kRenderCenterY);
|
||||
SkPoint p4 = SkPoint::Make(kRenderRight, kRenderCenterY);
|
||||
SkPoint p5 = SkPoint::Make(kRenderLeft, kRenderBottom - 16);
|
||||
SkPoint p6 = SkPoint::Make(kRenderRight, kRenderBottom - 16);
|
||||
|
||||
CanvasCompareTester::RenderAll( //
|
||||
TestParameters(
|
||||
@ -2893,18 +2932,26 @@ TEST_F(DisplayListRendering, DrawHorizontalLine) {
|
||||
SkPaint p = ctx.paint;
|
||||
p.setStyle(SkPaint::kStroke_Style);
|
||||
ctx.canvas->drawLine(p1, p2, p);
|
||||
ctx.canvas->drawLine(p3, p4, p);
|
||||
ctx.canvas->drawLine(p5, p6, p);
|
||||
},
|
||||
[=](const DlRenderContext& ctx) { //
|
||||
ctx.canvas->DrawLine(p1, p2, ctx.paint);
|
||||
ctx.canvas->DrawLine(p3, p4, ctx.paint);
|
||||
ctx.canvas->DrawLine(p5, p6, ctx.paint);
|
||||
},
|
||||
kDrawHVLineFlags)
|
||||
.set_draw_line()
|
||||
.set_horizontal_line());
|
||||
}
|
||||
|
||||
TEST_F(DisplayListRendering, DrawVerticalLine) {
|
||||
SkPoint p1 = SkPoint::Make(kRenderCenterX, kRenderTop);
|
||||
SkPoint p2 = SkPoint::Make(kRenderCenterY, kRenderBottom);
|
||||
TEST_F(DisplayListRendering, DrawVerticalLines) {
|
||||
SkPoint p1 = SkPoint::Make(kRenderLeft + 16, kRenderTop);
|
||||
SkPoint p2 = SkPoint::Make(kRenderLeft + 16, kRenderBottom);
|
||||
SkPoint p3 = SkPoint::Make(kRenderCenterX, kRenderTop);
|
||||
SkPoint p4 = SkPoint::Make(kRenderCenterX, kRenderBottom);
|
||||
SkPoint p5 = SkPoint::Make(kRenderRight - 16, kRenderTop);
|
||||
SkPoint p6 = SkPoint::Make(kRenderRight - 16, kRenderBottom);
|
||||
|
||||
CanvasCompareTester::RenderAll( //
|
||||
TestParameters(
|
||||
@ -2915,9 +2962,13 @@ TEST_F(DisplayListRendering, DrawVerticalLine) {
|
||||
SkPaint p = ctx.paint;
|
||||
p.setStyle(SkPaint::kStroke_Style);
|
||||
ctx.canvas->drawLine(p1, p2, p);
|
||||
ctx.canvas->drawLine(p3, p4, p);
|
||||
ctx.canvas->drawLine(p5, p6, p);
|
||||
},
|
||||
[=](const DlRenderContext& ctx) { //
|
||||
ctx.canvas->DrawLine(p1, p2, ctx.paint);
|
||||
ctx.canvas->DrawLine(p3, p4, ctx.paint);
|
||||
ctx.canvas->DrawLine(p5, p6, ctx.paint);
|
||||
},
|
||||
kDrawHVLineFlags)
|
||||
.set_draw_line()
|
||||
@ -2929,12 +2980,14 @@ TEST_F(DisplayListRendering, DrawDiagonalDashedLines) {
|
||||
SkPoint p2 = SkPoint::Make(kRenderRight, kRenderBottom);
|
||||
SkPoint p3 = SkPoint::Make(kRenderLeft, kRenderBottom);
|
||||
SkPoint p4 = SkPoint::Make(kRenderRight, kRenderTop);
|
||||
// Adding some edge to edge diagonals that run through the points about
|
||||
// 16 units in from the center of that edge.
|
||||
// Adding some edge center to edge center diagonals to better fill
|
||||
// out the RRect Clip so bounds checking sees less empty bounds space.
|
||||
SkPoint p5 = SkPoint::Make(kRenderCenterX, kRenderTop);
|
||||
SkPoint p6 = SkPoint::Make(kRenderRight, kRenderCenterY);
|
||||
SkPoint p7 = SkPoint::Make(kRenderLeft, kRenderCenterY);
|
||||
SkPoint p8 = SkPoint::Make(kRenderCenterX, kRenderBottom);
|
||||
SkPoint p5 = SkPoint::Make(kRenderCenterX, kRenderTop + 15);
|
||||
SkPoint p6 = SkPoint::Make(kRenderRight - 15, kRenderCenterY);
|
||||
SkPoint p7 = SkPoint::Make(kRenderCenterX, kRenderBottom - 15);
|
||||
SkPoint p8 = SkPoint::Make(kRenderLeft + 15, kRenderCenterY);
|
||||
|
||||
// Full diagonals are 100x100 which are 140 in length
|
||||
// Dashing them with 25 on, 5 off means that the last
|
||||
@ -2955,7 +3008,7 @@ TEST_F(DisplayListRendering, DrawDiagonalDashedLines) {
|
||||
SkPaint p = ctx.paint;
|
||||
p.setStyle(SkPaint::kStroke_Style);
|
||||
SkScalar intervals[2] = {25.0f, 5.0f};
|
||||
p.setPathEffect(SkDashPathEffect::Make(intervals, 2.0f, 0.0f));
|
||||
p.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0.0f));
|
||||
ctx.canvas->drawLine(p1, p2, p);
|
||||
ctx.canvas->drawLine(p3, p4, p);
|
||||
ctx.canvas->drawLine(p5, p6, p);
|
||||
@ -3125,7 +3178,7 @@ TEST_F(DisplayListRendering, DrawPointsAsPoints) {
|
||||
const SkScalar x3 = kRenderCenterX + 0.1;
|
||||
const SkScalar x4 = (kRenderRight + kRenderCenterX) * 0.5;
|
||||
const SkScalar x5 = kRenderRight - 16;
|
||||
const SkScalar x6 = kRenderRight;
|
||||
const SkScalar x6 = kRenderRight - 1;
|
||||
|
||||
const SkScalar y0 = kRenderTop;
|
||||
const SkScalar y1 = kRenderTop + 16;
|
||||
@ -3133,7 +3186,7 @@ TEST_F(DisplayListRendering, DrawPointsAsPoints) {
|
||||
const SkScalar y3 = kRenderCenterY + 0.1;
|
||||
const SkScalar y4 = (kRenderBottom + kRenderCenterY) * 0.5;
|
||||
const SkScalar y5 = kRenderBottom - 16;
|
||||
const SkScalar y6 = kRenderBottom;
|
||||
const SkScalar y6 = kRenderBottom - 1;
|
||||
|
||||
// clang-format off
|
||||
const SkPoint points[] = {
|
||||
@ -3177,7 +3230,7 @@ TEST_F(DisplayListRendering, DrawPointsAsLines) {
|
||||
const SkScalar y0 = kRenderTop;
|
||||
const SkScalar y1 = kRenderTop + 16;
|
||||
const SkScalar y2 = kRenderBottom - 16;
|
||||
const SkScalar y3 = kRenderBottom;
|
||||
const SkScalar y3 = kRenderBottom - 1;
|
||||
|
||||
// clang-format off
|
||||
const SkPoint points[] = {
|
||||
@ -3226,10 +3279,12 @@ TEST_F(DisplayListRendering, DrawPointsAsPolygon) {
|
||||
SkPoint::Make(kRenderRight, kRenderBottom),
|
||||
SkPoint::Make(kRenderLeft, kRenderBottom),
|
||||
SkPoint::Make(kRenderLeft, kRenderTop),
|
||||
SkPoint::Make(kRenderCenterX, kRenderTop),
|
||||
SkPoint::Make(kRenderRight, kRenderCenterY),
|
||||
SkPoint::Make(kRenderCenterX, kRenderBottom),
|
||||
SkPoint::Make(kRenderLeft, kRenderCenterY),
|
||||
|
||||
SkPoint::Make(kRenderCenterX, kRenderTop + 15),
|
||||
SkPoint::Make(kRenderRight - 15, kRenderCenterY),
|
||||
SkPoint::Make(kRenderCenterX, kRenderBottom - 15),
|
||||
SkPoint::Make(kRenderLeft + 15, kRenderCenterY),
|
||||
SkPoint::Make(kRenderCenterX, kRenderTop + 15),
|
||||
};
|
||||
const int count1 = sizeof(points1) / sizeof(points1[0]);
|
||||
|
||||
@ -3730,7 +3785,7 @@ TEST_F(DisplayListRendering, DrawShadow) {
|
||||
},
|
||||
kRenderCornerRadius, kRenderCornerRadius);
|
||||
const DlColor color = DlColor::kDarkGrey();
|
||||
const SkScalar elevation = 5;
|
||||
const SkScalar elevation = 7;
|
||||
|
||||
CanvasCompareTester::RenderAll( //
|
||||
TestParameters(
|
||||
@ -3756,7 +3811,7 @@ TEST_F(DisplayListRendering, DrawShadowTransparentOccluder) {
|
||||
},
|
||||
kRenderCornerRadius, kRenderCornerRadius);
|
||||
const DlColor color = DlColor::kDarkGrey();
|
||||
const SkScalar elevation = 5;
|
||||
const SkScalar elevation = 7;
|
||||
|
||||
CanvasCompareTester::RenderAll( //
|
||||
TestParameters(
|
||||
@ -3782,7 +3837,7 @@ TEST_F(DisplayListRendering, DrawShadowDpr) {
|
||||
},
|
||||
kRenderCornerRadius, kRenderCornerRadius);
|
||||
const DlColor color = DlColor::kDarkGrey();
|
||||
const SkScalar elevation = 5;
|
||||
const SkScalar elevation = 7;
|
||||
|
||||
CanvasCompareTester::RenderAll( //
|
||||
TestParameters(
|
||||
|
||||
@ -424,6 +424,30 @@ std::vector<DisplayListInvocationGroup> CreateAllClipOps() {
|
||||
r.clipRect(kTestBounds, DlCanvas::ClipOp::kDifference, false);
|
||||
}},
|
||||
}},
|
||||
{"ClipOval",
|
||||
{
|
||||
{1, 24, 0,
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipOval(kTestBounds, DlCanvas::ClipOp::kIntersect, true);
|
||||
}},
|
||||
{1, 24, 0,
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipOval(kTestBounds.makeOffset(1, 1),
|
||||
DlCanvas::ClipOp::kIntersect, true);
|
||||
}},
|
||||
{1, 24, 0,
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipOval(kTestBounds, DlCanvas::ClipOp::kIntersect, false);
|
||||
}},
|
||||
{1, 24, 0,
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipOval(kTestBounds, DlCanvas::ClipOp::kDifference, true);
|
||||
}},
|
||||
{1, 24, 0,
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipOval(kTestBounds, DlCanvas::ClipOp::kDifference, false);
|
||||
}},
|
||||
}},
|
||||
{"ClipRRect",
|
||||
{
|
||||
{1, 64, 0,
|
||||
@ -484,6 +508,11 @@ std::vector<DisplayListInvocationGroup> CreateAllClipOps() {
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipPath(kTestPathOval, DlCanvas::ClipOp::kIntersect, true);
|
||||
}},
|
||||
// clipPath(rrect) becomes clipRRect
|
||||
{1, 64, 0,
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipPath(kTestPathRRect, DlCanvas::ClipOp::kIntersect, true);
|
||||
}},
|
||||
}},
|
||||
};
|
||||
}
|
||||
@ -637,8 +666,10 @@ std::vector<DisplayListInvocationGroup> CreateAllRenderingOps() {
|
||||
{1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath1); }},
|
||||
{1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath2); }},
|
||||
{1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPath3); }},
|
||||
// oval, rect and rrect paths are left as drawPath
|
||||
{1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathRect); }},
|
||||
{1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathOval); }},
|
||||
{1, 40, 1, [](DlOpReceiver& r) { r.drawPath(kTestPathRRect); }},
|
||||
}},
|
||||
{"DrawArc",
|
||||
{
|
||||
|
||||
@ -183,6 +183,7 @@ static const SkRRect kTestInnerRRect =
|
||||
SkRRect::MakeRectXY(kTestBounds.makeInset(5, 5), 2, 2);
|
||||
static const SkPath kTestPathRect = SkPath::Rect(kTestBounds);
|
||||
static const SkPath kTestPathOval = SkPath::Oval(kTestBounds);
|
||||
static const SkPath kTestPathRRect = SkPath::RRect(kTestRRect);
|
||||
static const SkPath kTestPath1 =
|
||||
SkPath::Polygon({{0, 0}, {10, 10}, {10, 0}, {0, 10}}, true);
|
||||
static const SkPath kTestPath2 =
|
||||
|
||||
@ -74,6 +74,24 @@ void DisplayListMatrixClipState::clipRect(const DlRect& rect,
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayListMatrixClipState::clipOval(const DlRect& bounds,
|
||||
ClipOp op,
|
||||
bool is_aa) {
|
||||
if (!bounds.IsFinite()) {
|
||||
return;
|
||||
}
|
||||
switch (op) {
|
||||
case DlCanvas::ClipOp::kIntersect:
|
||||
adjustCullRect(bounds, op, is_aa);
|
||||
break;
|
||||
case DlCanvas::ClipOp::kDifference:
|
||||
if (oval_covers_cull(bounds)) {
|
||||
cull_rect_ = DlRect();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayListMatrixClipState::clipRRect(const SkRRect& rrect,
|
||||
ClipOp op,
|
||||
bool is_aa) {
|
||||
|
||||
@ -149,6 +149,10 @@ class DisplayListMatrixClipState {
|
||||
void clipRect(const SkRect& rect, ClipOp op, bool is_aa) {
|
||||
clipRect(ToDlRect(rect), op, is_aa);
|
||||
}
|
||||
void clipOval(const DlRect& bounds, ClipOp op, bool is_aa);
|
||||
void clipOval(const SkRect& bounds, ClipOp op, bool is_aa) {
|
||||
clipRect(ToDlRect(bounds), op, is_aa);
|
||||
}
|
||||
void clipRRect(const SkRRect& rrect, ClipOp op, bool is_aa);
|
||||
void clipPath(const SkPath& path, ClipOp op, bool is_aa);
|
||||
|
||||
|
||||
@ -44,6 +44,9 @@ class IgnoreClipDispatchHelper : public virtual DlOpReceiver {
|
||||
void clipRect(const SkRect& rect,
|
||||
DlCanvas::ClipOp clip_op,
|
||||
bool is_aa) override {}
|
||||
void clipOval(const SkRect& bounds,
|
||||
DlCanvas::ClipOp clip_op,
|
||||
bool is_aa) override {}
|
||||
void clipRRect(const SkRRect& rrect,
|
||||
DlCanvas::ClipOp clip_op,
|
||||
bool is_aa) override {}
|
||||
|
||||
@ -70,292 +70,6 @@ TEST_P(AiksTest, CanvasCanPushPopCTM) {
|
||||
Matrix::MakeTranslation({100.0, 100.0, 0.0}));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderColoredRect) {
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
paint.color = Color::Blue();
|
||||
canvas.DrawPath(PathBuilder{}
|
||||
.AddRect(Rect::MakeXYWH(100.0, 100.0, 100.0, 100.0))
|
||||
.TakePath(),
|
||||
paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderImage) {
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
auto image = std::make_shared<Image>(CreateTextureForFixture("kalimba.jpg"));
|
||||
paint.color = Color::Red();
|
||||
canvas.DrawImage(image, Point::MakeXY(100.0, 100.0), paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderInvertedImageWithColorFilter) {
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
auto image = std::make_shared<Image>(CreateTextureForFixture("kalimba.jpg"));
|
||||
paint.color = Color::Red();
|
||||
paint.color_filter =
|
||||
ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Yellow());
|
||||
paint.invert_colors = true;
|
||||
|
||||
canvas.DrawImage(image, Point::MakeXY(100.0, 100.0), paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderColorFilterWithInvertColors) {
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
paint.color = Color::Red();
|
||||
paint.color_filter =
|
||||
ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Yellow());
|
||||
paint.invert_colors = true;
|
||||
|
||||
canvas.DrawRect(Rect::MakeLTRB(0, 0, 100, 100), paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderColorFilterWithInvertColorsDrawPaint) {
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
paint.color = Color::Red();
|
||||
paint.color_filter =
|
||||
ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Yellow());
|
||||
paint.invert_colors = true;
|
||||
|
||||
canvas.DrawPaint(paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool GenerateMipmap(const std::shared_ptr<Context>& context,
|
||||
std::shared_ptr<Texture> texture,
|
||||
std::string label) {
|
||||
auto buffer = context->CreateCommandBuffer();
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
auto pass = buffer->CreateBlitPass();
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
pass->GenerateMipmap(std::move(texture), std::move(label));
|
||||
|
||||
pass->EncodeCommands(context->GetResourceAllocator());
|
||||
return context->GetCommandQueue()->Submit({buffer}).ok();
|
||||
}
|
||||
|
||||
void CanRenderTiledTexture(AiksTest* aiks_test,
|
||||
Entity::TileMode tile_mode,
|
||||
Matrix local_matrix = {}) {
|
||||
auto context = aiks_test->GetContext();
|
||||
ASSERT_TRUE(context);
|
||||
auto texture = aiks_test->CreateTextureForFixture("table_mountain_nx.png",
|
||||
/*enable_mipmapping=*/true);
|
||||
GenerateMipmap(context, texture, "table_mountain_nx");
|
||||
Canvas canvas;
|
||||
canvas.Scale(aiks_test->GetContentScale());
|
||||
canvas.Translate({100.0f, 100.0f, 0});
|
||||
Paint paint;
|
||||
paint.color_source =
|
||||
ColorSource::MakeImage(texture, tile_mode, tile_mode, {}, local_matrix);
|
||||
paint.color = Color(1, 1, 1, 1);
|
||||
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
|
||||
|
||||
// Should not change the image.
|
||||
constexpr auto stroke_width = 64;
|
||||
paint.style = Paint::Style::kStroke;
|
||||
paint.stroke_width = stroke_width;
|
||||
if (tile_mode == Entity::TileMode::kDecal) {
|
||||
canvas.DrawRect(Rect::MakeXYWH(stroke_width, stroke_width, 600, 600),
|
||||
paint);
|
||||
} else {
|
||||
canvas.DrawRect(Rect::MakeXYWH(0, 0, 600, 600), paint);
|
||||
}
|
||||
|
||||
{
|
||||
// Should not change the image.
|
||||
PathBuilder path_builder;
|
||||
path_builder.AddCircle({150, 150}, 150);
|
||||
path_builder.AddRoundedRect(Rect::MakeLTRB(300, 300, 600, 600), 10);
|
||||
paint.style = Paint::Style::kFill;
|
||||
canvas.DrawPath(path_builder.TakePath(), paint);
|
||||
}
|
||||
|
||||
{
|
||||
// Should not change the image. Tests the Convex short-cut code.
|
||||
PathBuilder path_builder;
|
||||
path_builder.AddCircle({150, 450}, 150);
|
||||
path_builder.SetConvexity(Convexity::kConvex);
|
||||
paint.style = Paint::Style::kFill;
|
||||
canvas.DrawPath(path_builder.TakePath(), paint);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureClamp) {
|
||||
CanRenderTiledTexture(this, Entity::TileMode::kClamp);
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureRepeat) {
|
||||
CanRenderTiledTexture(this, Entity::TileMode::kRepeat);
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureMirror) {
|
||||
CanRenderTiledTexture(this, Entity::TileMode::kMirror);
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureDecal) {
|
||||
CanRenderTiledTexture(this, Entity::TileMode::kDecal);
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureClampWithTranslate) {
|
||||
CanRenderTiledTexture(this, Entity::TileMode::kClamp,
|
||||
Matrix::MakeTranslation({172.f, 172.f, 0.f}));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderImageRect) {
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
auto image = std::make_shared<Image>(CreateTextureForFixture("kalimba.jpg"));
|
||||
Size image_half_size = Size(image->GetSize()) * 0.5;
|
||||
|
||||
// Render the bottom right quarter of the source image in a stretched rect.
|
||||
auto source_rect = Rect::MakeSize(image_half_size);
|
||||
source_rect = source_rect.Shift(Point(image_half_size));
|
||||
|
||||
canvas.DrawImageRect(image, source_rect, Rect::MakeXYWH(100, 100, 600, 600),
|
||||
paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderSimpleClips) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(GetContentScale());
|
||||
Paint paint;
|
||||
|
||||
paint.color = Color::White();
|
||||
canvas.DrawPaint(paint);
|
||||
|
||||
auto draw = [&canvas](const Paint& paint, Scalar x, Scalar y) {
|
||||
canvas.Save();
|
||||
canvas.Translate({x, y});
|
||||
{
|
||||
canvas.Save();
|
||||
canvas.ClipRect(Rect::MakeLTRB(50, 50, 150, 150));
|
||||
canvas.DrawPaint(paint);
|
||||
canvas.Restore();
|
||||
}
|
||||
{
|
||||
canvas.Save();
|
||||
canvas.ClipOval(Rect::MakeLTRB(200, 50, 300, 150));
|
||||
canvas.DrawPaint(paint);
|
||||
canvas.Restore();
|
||||
}
|
||||
{
|
||||
canvas.Save();
|
||||
canvas.ClipRRect(Rect::MakeLTRB(50, 200, 150, 300), {20, 20});
|
||||
canvas.DrawPaint(paint);
|
||||
canvas.Restore();
|
||||
}
|
||||
{
|
||||
canvas.Save();
|
||||
canvas.ClipRRect(Rect::MakeLTRB(200, 230, 300, 270), {20, 20});
|
||||
canvas.DrawPaint(paint);
|
||||
canvas.Restore();
|
||||
}
|
||||
{
|
||||
canvas.Save();
|
||||
canvas.ClipRRect(Rect::MakeLTRB(230, 200, 270, 300), {20, 20});
|
||||
canvas.DrawPaint(paint);
|
||||
canvas.Restore();
|
||||
}
|
||||
canvas.Restore();
|
||||
};
|
||||
|
||||
paint.color = Color::Blue();
|
||||
draw(paint, 0, 0);
|
||||
|
||||
std::vector<Color> gradient_colors = {
|
||||
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
|
||||
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
|
||||
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
|
||||
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
|
||||
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
|
||||
std::vector<Scalar> stops = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
|
||||
paint.color_source = ColorSource::MakeRadialGradient(
|
||||
{500, 600}, 75, std::move(gradient_colors), std::move(stops),
|
||||
Entity::TileMode::kMirror, {});
|
||||
draw(paint, 0, 300);
|
||||
|
||||
paint.color_source = ColorSource::MakeImage(
|
||||
texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {},
|
||||
Matrix::MakeTranslation({0, 0}));
|
||||
draw(paint, 300, 0);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanSaveLayerStandalone) {
|
||||
Canvas canvas;
|
||||
|
||||
Paint red;
|
||||
red.color = Color::Red();
|
||||
|
||||
Paint alpha;
|
||||
alpha.color = Color::Red().WithAlpha(0.5);
|
||||
|
||||
canvas.SaveLayer(alpha);
|
||||
|
||||
canvas.DrawCircle({125, 125}, 125, red);
|
||||
|
||||
canvas.Restore();
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderDifferentShapesWithSameColorSource) {
|
||||
Canvas canvas;
|
||||
Paint paint;
|
||||
|
||||
std::vector<Color> colors = {Color{0.9568, 0.2627, 0.2118, 1.0},
|
||||
Color{0.1294, 0.5882, 0.9529, 1.0}};
|
||||
std::vector<Scalar> stops = {
|
||||
0.0,
|
||||
1.0,
|
||||
};
|
||||
|
||||
paint.color_source = ColorSource::MakeLinearGradient(
|
||||
{0, 0}, {100, 100}, std::move(colors), std::move(stops),
|
||||
Entity::TileMode::kRepeat, {});
|
||||
|
||||
canvas.Save();
|
||||
canvas.Translate({100, 100, 0});
|
||||
canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), paint);
|
||||
canvas.Restore();
|
||||
|
||||
canvas.Save();
|
||||
canvas.Translate({100, 400, 0});
|
||||
canvas.DrawCircle({100, 100}, 100, paint);
|
||||
canvas.Restore();
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanPictureConvertToImage) {
|
||||
Canvas recorder_canvas;
|
||||
Paint paint;
|
||||
@ -518,27 +232,6 @@ TEST_P(AiksTest,
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderRoundedRectWithNonUniformRadii) {
|
||||
Canvas canvas;
|
||||
|
||||
Paint paint;
|
||||
paint.color = Color::Red();
|
||||
|
||||
PathBuilder::RoundingRadii radii;
|
||||
radii.top_left = {50, 25};
|
||||
radii.top_right = {25, 50};
|
||||
radii.bottom_right = {50, 25};
|
||||
radii.bottom_left = {25, 50};
|
||||
|
||||
auto path = PathBuilder{}
|
||||
.AddRoundedRect(Rect::MakeXYWH(100, 100, 500, 500), radii)
|
||||
.TakePath();
|
||||
|
||||
canvas.DrawPath(path, paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
struct TextRenderOptions {
|
||||
bool stroke = false;
|
||||
Scalar font_size = 50;
|
||||
@ -852,21 +545,6 @@ TEST_P(AiksTest, TextRotated) {
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanDrawPaint) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(Vector2(0.2, 0.2));
|
||||
canvas.DrawPaint({.color = Color::MediumTurquoise()});
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanDrawPaintMultipleTimes) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(Vector2(0.2, 0.2));
|
||||
canvas.DrawPaint({.color = Color::MediumTurquoise()});
|
||||
canvas.DrawPaint({.color = Color::Color::OrangeRed().WithAlpha(0.5)});
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
// This makes sure the WideGamut named tests use 16bit float pixel format.
|
||||
TEST_P(AiksTest, FormatWideGamut) {
|
||||
EXPECT_EQ(GetContext()->GetCapabilities()->GetDefaultColorFormat(),
|
||||
@ -920,344 +598,6 @@ TEST_P(AiksTest, TransformMultipliesCorrectly) {
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, FilledCirclesRenderCorrectly) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(GetContentScale());
|
||||
Paint paint;
|
||||
const int color_count = 3;
|
||||
Color colors[color_count] = {
|
||||
Color::Blue(),
|
||||
Color::Green(),
|
||||
Color::Crimson(),
|
||||
};
|
||||
|
||||
paint.color = Color::White();
|
||||
canvas.DrawPaint(paint);
|
||||
|
||||
int c_index = 0;
|
||||
int radius = 600;
|
||||
while (radius > 0) {
|
||||
paint.color = colors[(c_index++) % color_count];
|
||||
canvas.DrawCircle({10, 10}, radius, paint);
|
||||
if (radius > 30) {
|
||||
radius -= 10;
|
||||
} else {
|
||||
radius -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Color> gradient_colors = {
|
||||
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
|
||||
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
|
||||
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
|
||||
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
|
||||
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
|
||||
std::vector<Scalar> stops = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
|
||||
paint.color_source = ColorSource::MakeRadialGradient(
|
||||
{500, 600}, 75, std::move(gradient_colors), std::move(stops),
|
||||
Entity::TileMode::kMirror, {});
|
||||
canvas.DrawCircle({500, 600}, 100, paint);
|
||||
|
||||
paint.color_source = ColorSource::MakeImage(
|
||||
texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {},
|
||||
Matrix::MakeTranslation({700, 200}));
|
||||
canvas.DrawCircle({800, 300}, 100, paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, StrokedCirclesRenderCorrectly) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(GetContentScale());
|
||||
Paint paint;
|
||||
const int color_count = 3;
|
||||
Color colors[color_count] = {
|
||||
Color::Blue(),
|
||||
Color::Green(),
|
||||
Color::Crimson(),
|
||||
};
|
||||
|
||||
paint.color = Color::White();
|
||||
canvas.DrawPaint(paint);
|
||||
|
||||
int c_index = 0;
|
||||
|
||||
auto draw = [&paint, &colors, &c_index](Canvas& canvas, Point center,
|
||||
Scalar r, Scalar dr, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
paint.color = colors[(c_index++) % color_count];
|
||||
canvas.DrawCircle(center, r, paint);
|
||||
r += dr;
|
||||
}
|
||||
};
|
||||
|
||||
paint.style = Paint::Style::kStroke;
|
||||
paint.stroke_width = 1;
|
||||
draw(canvas, {10, 10}, 2, 2, 14); // r = [2, 28], covers [1,29]
|
||||
paint.stroke_width = 5;
|
||||
draw(canvas, {10, 10}, 35, 10, 56); // r = [35, 585], covers [30,590]
|
||||
|
||||
std::vector<Color> gradient_colors = {
|
||||
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
|
||||
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
|
||||
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
|
||||
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
|
||||
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
|
||||
std::vector<Scalar> stops = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
|
||||
paint.color_source = ColorSource::MakeRadialGradient(
|
||||
{500, 600}, 75, std::move(gradient_colors), std::move(stops),
|
||||
Entity::TileMode::kMirror, {});
|
||||
draw(canvas, {500, 600}, 5, 10, 10);
|
||||
|
||||
paint.color_source = ColorSource::MakeImage(
|
||||
texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {},
|
||||
Matrix::MakeTranslation({700, 200}));
|
||||
draw(canvas, {800, 300}, 5, 10, 10);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, FilledEllipsesRenderCorrectly) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(GetContentScale());
|
||||
Paint paint;
|
||||
const int color_count = 3;
|
||||
Color colors[color_count] = {
|
||||
Color::Blue(),
|
||||
Color::Green(),
|
||||
Color::Crimson(),
|
||||
};
|
||||
|
||||
paint.color = Color::White();
|
||||
canvas.DrawPaint(paint);
|
||||
|
||||
int c_index = 0;
|
||||
int long_radius = 600;
|
||||
int short_radius = 600;
|
||||
while (long_radius > 0 && short_radius > 0) {
|
||||
paint.color = colors[(c_index++) % color_count];
|
||||
canvas.DrawOval(Rect::MakeXYWH(10 - long_radius, 10 - short_radius,
|
||||
long_radius * 2, short_radius * 2),
|
||||
paint);
|
||||
canvas.DrawOval(Rect::MakeXYWH(1000 - short_radius, 750 - long_radius,
|
||||
short_radius * 2, long_radius * 2),
|
||||
paint);
|
||||
if (short_radius > 30) {
|
||||
short_radius -= 10;
|
||||
long_radius -= 5;
|
||||
} else {
|
||||
short_radius -= 2;
|
||||
long_radius -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Color> gradient_colors = {
|
||||
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
|
||||
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
|
||||
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
|
||||
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
|
||||
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
|
||||
std::vector<Scalar> stops = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
|
||||
paint.color = Color::White().WithAlpha(0.5);
|
||||
|
||||
paint.color_source = ColorSource::MakeRadialGradient(
|
||||
{300, 650}, 75, std::move(gradient_colors), std::move(stops),
|
||||
Entity::TileMode::kMirror, {});
|
||||
canvas.DrawOval(Rect::MakeXYWH(200, 625, 200, 50), paint);
|
||||
canvas.DrawOval(Rect::MakeXYWH(275, 550, 50, 200), paint);
|
||||
|
||||
paint.color_source = ColorSource::MakeImage(
|
||||
texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {},
|
||||
Matrix::MakeTranslation({610, 15}));
|
||||
canvas.DrawOval(Rect::MakeXYWH(610, 90, 200, 50), paint);
|
||||
canvas.DrawOval(Rect::MakeXYWH(685, 15, 50, 200), paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(GetContentScale());
|
||||
Paint paint;
|
||||
const int color_count = 3;
|
||||
Color colors[color_count] = {
|
||||
Color::Blue(),
|
||||
Color::Green(),
|
||||
Color::Crimson(),
|
||||
};
|
||||
|
||||
paint.color = Color::White();
|
||||
canvas.DrawPaint(paint);
|
||||
|
||||
int c_index = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
paint.color = colors[(c_index++) % color_count];
|
||||
canvas.DrawRRect(Rect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80),
|
||||
Size(i * 5 + 10, j * 5 + 10), paint);
|
||||
}
|
||||
}
|
||||
paint.color = colors[(c_index++) % color_count];
|
||||
canvas.DrawRRect(Rect::MakeXYWH(10, 420, 380, 80), Size(40, 40), paint);
|
||||
paint.color = colors[(c_index++) % color_count];
|
||||
canvas.DrawRRect(Rect::MakeXYWH(410, 20, 80, 380), Size(40, 40), paint);
|
||||
|
||||
std::vector<Color> gradient_colors = {
|
||||
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
|
||||
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
|
||||
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
|
||||
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
|
||||
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
|
||||
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
|
||||
std::vector<Scalar> stops = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
|
||||
paint.color = Color::White().WithAlpha(0.1);
|
||||
paint.color_source = ColorSource::MakeRadialGradient(
|
||||
{550, 550}, 75, gradient_colors, stops, Entity::TileMode::kMirror, {});
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
int j = 11 - i;
|
||||
canvas.DrawRRect(Rect::MakeLTRB(550 - i * 20, 550 - j * 20, //
|
||||
550 + i * 20, 550 + j * 20),
|
||||
Size(i * 10, j * 10), paint);
|
||||
}
|
||||
paint.color = Color::White().WithAlpha(0.5);
|
||||
paint.color_source = ColorSource::MakeRadialGradient(
|
||||
{200, 650}, 75, std::move(gradient_colors), std::move(stops),
|
||||
Entity::TileMode::kMirror, {});
|
||||
canvas.DrawRRect(Rect::MakeLTRB(100, 610, 300, 690), Size(40, 40), paint);
|
||||
canvas.DrawRRect(Rect::MakeLTRB(160, 550, 240, 750), Size(40, 40), paint);
|
||||
|
||||
paint.color = Color::White().WithAlpha(0.1);
|
||||
paint.color_source = ColorSource::MakeImage(
|
||||
texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {},
|
||||
Matrix::MakeTranslation({520, 20}));
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
int j = 11 - i;
|
||||
canvas.DrawRRect(Rect::MakeLTRB(720 - i * 20, 220 - j * 20, //
|
||||
720 + i * 20, 220 + j * 20),
|
||||
Size(i * 10, j * 10), paint);
|
||||
}
|
||||
paint.color = Color::White().WithAlpha(0.5);
|
||||
paint.color_source = ColorSource::MakeImage(
|
||||
texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {},
|
||||
Matrix::MakeTranslation({800, 300}));
|
||||
canvas.DrawRRect(Rect::MakeLTRB(800, 410, 1000, 490), Size(40, 40), paint);
|
||||
canvas.DrawRRect(Rect::MakeLTRB(860, 350, 940, 550), Size(40, 40), paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, SolidColorCirclesOvalsRRectsMaskBlurCorrectly) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(GetContentScale());
|
||||
Paint paint;
|
||||
paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
|
||||
.style = FilterContents::BlurStyle::kNormal,
|
||||
.sigma = Sigma{1},
|
||||
};
|
||||
|
||||
canvas.DrawPaint({.color = Color::White()});
|
||||
|
||||
paint.color = Color::Crimson();
|
||||
Scalar y = 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 10.0f;
|
||||
canvas.DrawRect(Rect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
|
||||
radius, 60.0f - radius),
|
||||
paint);
|
||||
}
|
||||
|
||||
paint.color = Color::Blue();
|
||||
y += 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 10.0f;
|
||||
canvas.DrawCircle({x + 25, y + 25}, radius, paint);
|
||||
}
|
||||
|
||||
paint.color = Color::Green();
|
||||
y += 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 10.0f;
|
||||
canvas.DrawOval(Rect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
|
||||
radius, 60.0f - radius),
|
||||
paint);
|
||||
}
|
||||
|
||||
paint.color = Color::Purple();
|
||||
y += 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 20.0f;
|
||||
canvas.DrawRRect(Rect::MakeXYWH(x, y, 60.0f, 60.0f), //
|
||||
{radius, radius}, //
|
||||
paint);
|
||||
}
|
||||
|
||||
paint.color = Color::Orange();
|
||||
y += 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 20.0f;
|
||||
canvas.DrawRRect(Rect::MakeXYWH(x, y, 60.0f, 60.0f), //
|
||||
{radius, 5.0f}, paint);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, FastEllipticalRRectMaskBlursRenderCorrectly) {
|
||||
Canvas canvas;
|
||||
canvas.Scale(GetContentScale());
|
||||
|
||||
@ -53,6 +53,7 @@ template("display_list_unittests_component") {
|
||||
target_name = invoker.target_name
|
||||
predefined_sources = [
|
||||
"aiks_dl_atlas_unittests.cc",
|
||||
"aiks_dl_basic_unittests.cc",
|
||||
"aiks_dl_clip_unittests.cc",
|
||||
"aiks_dl_gradient_unittests.cc",
|
||||
"aiks_dl_opacity_unittests.cc",
|
||||
|
||||
@ -0,0 +1,766 @@
|
||||
// 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/aiks/aiks_unittests.h"
|
||||
|
||||
#include "flutter/display_list/dl_blend_mode.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/dl_color.h"
|
||||
#include "flutter/display_list/dl_paint.h"
|
||||
#include "flutter/impeller/display_list/dl_image_impeller.h"
|
||||
#include "flutter/impeller/geometry/scalar.h"
|
||||
#include "flutter/testing/display_list_testing.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace testing {
|
||||
|
||||
using namespace flutter;
|
||||
|
||||
TEST_P(AiksTest, CanRenderColoredRect) {
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kBlue());
|
||||
SkPath path = SkPath();
|
||||
path.addRect(SkRect::MakeXYWH(100.0, 100.0, 100.0, 100.0));
|
||||
builder.DrawPath(path, paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderImage) {
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kRed());
|
||||
auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
|
||||
builder.DrawImage(image, SkPoint::Make(100.0, 100.0),
|
||||
DlImageSampling::kNearestNeighbor, &paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderInvertedImageWithColorFilter) {
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kRed());
|
||||
paint.setColorFilter(
|
||||
DlBlendColorFilter::Make(DlColor::kYellow(), DlBlendMode::kSrcOver));
|
||||
paint.setInvertColors(true);
|
||||
auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
|
||||
|
||||
builder.DrawImage(image, SkPoint::Make(100.0, 100.0),
|
||||
DlImageSampling::kNearestNeighbor, &paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderColorFilterWithInvertColors) {
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kRed());
|
||||
paint.setColorFilter(
|
||||
DlBlendColorFilter::Make(DlColor::kYellow(), DlBlendMode::kSrcOver));
|
||||
paint.setInvertColors(true);
|
||||
|
||||
builder.DrawRect(SkRect::MakeLTRB(0, 0, 100, 100), paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderColorFilterWithInvertColorsDrawPaint) {
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kRed());
|
||||
paint.setColorFilter(
|
||||
DlBlendColorFilter::Make(DlColor::kYellow(), DlBlendMode::kSrcOver));
|
||||
paint.setInvertColors(true);
|
||||
|
||||
builder.DrawPaint(paint);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool GenerateMipmap(const std::shared_ptr<Context>& context,
|
||||
std::shared_ptr<Texture> texture,
|
||||
std::string label) {
|
||||
auto buffer = context->CreateCommandBuffer();
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
auto pass = buffer->CreateBlitPass();
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
pass->GenerateMipmap(std::move(texture), std::move(label));
|
||||
|
||||
pass->EncodeCommands(context->GetResourceAllocator());
|
||||
return context->GetCommandQueue()->Submit({buffer}).ok();
|
||||
}
|
||||
|
||||
void CanRenderTiledTexture(AiksTest* aiks_test,
|
||||
DlTileMode tile_mode,
|
||||
Matrix local_matrix = {}) {
|
||||
auto context = aiks_test->GetContext();
|
||||
ASSERT_TRUE(context);
|
||||
auto texture = aiks_test->CreateTextureForFixture("table_mountain_nx.png",
|
||||
/*enable_mipmapping=*/true);
|
||||
GenerateMipmap(context, texture, "table_mountain_nx");
|
||||
auto image = DlImageImpeller::Make(texture);
|
||||
SkMatrix sk_local_matrix = ToSkMatrix(local_matrix);
|
||||
DlImageColorSource color_source(image, tile_mode, tile_mode,
|
||||
DlImageSampling::kNearestNeighbor,
|
||||
&sk_local_matrix);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kWhite());
|
||||
paint.setColorSource(&color_source);
|
||||
|
||||
builder.Scale(aiks_test->GetContentScale().x, aiks_test->GetContentScale().y);
|
||||
builder.Translate(100.0f, 100.0f);
|
||||
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
|
||||
|
||||
// Should not change the image.
|
||||
constexpr auto stroke_width = 64;
|
||||
paint.setDrawStyle(DlDrawStyle::kStroke);
|
||||
paint.setStrokeWidth(stroke_width);
|
||||
if (tile_mode == DlTileMode::kDecal) {
|
||||
builder.DrawRect(SkRect::MakeXYWH(stroke_width, stroke_width, 600, 600),
|
||||
paint);
|
||||
} else {
|
||||
builder.DrawRect(SkRect::MakeXYWH(0, 0, 600, 600), paint);
|
||||
}
|
||||
|
||||
{
|
||||
// Should not change the image.
|
||||
SkPath path;
|
||||
path.addCircle(150, 150, 150);
|
||||
path.addRoundRect(SkRect::MakeLTRB(300, 300, 600, 600), 10, 10);
|
||||
|
||||
// Make sure path cannot be simplified...
|
||||
EXPECT_FALSE(path.isRect(nullptr));
|
||||
EXPECT_FALSE(path.isOval(nullptr));
|
||||
EXPECT_FALSE(path.isRRect(nullptr));
|
||||
|
||||
// Make sure path will not trigger the optimal convex code
|
||||
EXPECT_FALSE(path.isConvex());
|
||||
|
||||
paint.setDrawStyle(DlDrawStyle::kFill);
|
||||
builder.DrawPath(path, paint);
|
||||
}
|
||||
|
||||
{
|
||||
// Should not change the image. Tests the Convex short-cut code.
|
||||
SkPath circle;
|
||||
circle.addCircle(150, 450, 150);
|
||||
|
||||
// Unfortunately, the circle path can be simplified...
|
||||
EXPECT_TRUE(circle.isOval(nullptr));
|
||||
// At least it's convex, though...
|
||||
EXPECT_TRUE(circle.isConvex());
|
||||
|
||||
// Let's make a copy that doesn't remember that it's just a circle...
|
||||
SkPath path;
|
||||
// This moveTo confuses addPath into appending rather than replacing,
|
||||
// which prevents it from noticing that it's just a circle...
|
||||
path.moveTo(10, 10);
|
||||
path.addPath(circle);
|
||||
|
||||
// Make sure path cannot be simplified...
|
||||
EXPECT_FALSE(path.isRect(nullptr));
|
||||
EXPECT_FALSE(path.isOval(nullptr));
|
||||
EXPECT_FALSE(path.isRRect(nullptr));
|
||||
|
||||
// But check that we will trigger the optimal convex code
|
||||
EXPECT_TRUE(path.isConvex());
|
||||
|
||||
paint.setDrawStyle(DlDrawStyle::kFill);
|
||||
builder.DrawPath(path, paint);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(aiks_test->OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureClamp) {
|
||||
CanRenderTiledTexture(this, DlTileMode::kClamp);
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureRepeat) {
|
||||
CanRenderTiledTexture(this, DlTileMode::kRepeat);
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureMirror) {
|
||||
CanRenderTiledTexture(this, DlTileMode::kMirror);
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureDecal) {
|
||||
CanRenderTiledTexture(this, DlTileMode::kDecal);
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderTiledTextureClampWithTranslate) {
|
||||
CanRenderTiledTexture(this, DlTileMode::kClamp,
|
||||
Matrix::MakeTranslation({172.f, 172.f, 0.f}));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderImageRect) {
|
||||
DisplayListBuilder builder;
|
||||
auto image = DlImageImpeller::Make(CreateTextureForFixture("kalimba.jpg"));
|
||||
|
||||
SkSize image_half_size = SkSize::Make(image->dimensions().fWidth * 0.5f,
|
||||
image->dimensions().fHeight * 0.5f);
|
||||
|
||||
// Render the bottom right quarter of the source image in a stretched rect.
|
||||
auto source_rect = SkRect::MakeSize(image_half_size);
|
||||
source_rect =
|
||||
source_rect.makeOffset(image_half_size.fWidth, image_half_size.fHeight);
|
||||
|
||||
builder.DrawImageRect(image, source_rect,
|
||||
SkRect::MakeXYWH(100, 100, 600, 600),
|
||||
DlImageSampling::kNearestNeighbor);
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderSimpleClips) {
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(GetContentScale().x, GetContentScale().y);
|
||||
DlPaint paint;
|
||||
|
||||
paint.setColor(DlColor::kWhite());
|
||||
builder.DrawPaint(paint);
|
||||
|
||||
auto draw = [&builder](const DlPaint& paint, Scalar x, Scalar y) {
|
||||
builder.Save();
|
||||
builder.Translate(x, y);
|
||||
{
|
||||
builder.Save();
|
||||
builder.ClipRect(SkRect::MakeLTRB(50, 50, 150, 150));
|
||||
builder.DrawPaint(paint);
|
||||
builder.Restore();
|
||||
}
|
||||
{
|
||||
builder.Save();
|
||||
builder.ClipOval(SkRect::MakeLTRB(200, 50, 300, 150));
|
||||
builder.DrawPaint(paint);
|
||||
builder.Restore();
|
||||
}
|
||||
{
|
||||
builder.Save();
|
||||
builder.ClipRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(50, 200, 150, 300), 20, 20));
|
||||
builder.DrawPaint(paint);
|
||||
builder.Restore();
|
||||
}
|
||||
{
|
||||
builder.Save();
|
||||
builder.ClipRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(200, 230, 300, 270), 20, 20));
|
||||
builder.DrawPaint(paint);
|
||||
builder.Restore();
|
||||
}
|
||||
{
|
||||
builder.Save();
|
||||
builder.ClipRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(230, 200, 270, 300), 20, 20));
|
||||
builder.DrawPaint(paint);
|
||||
builder.Restore();
|
||||
}
|
||||
builder.Restore();
|
||||
};
|
||||
|
||||
paint.setColor(DlColor::kBlue());
|
||||
draw(paint, 0, 0);
|
||||
|
||||
DlColor gradient_colors[7] = {
|
||||
DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
|
||||
};
|
||||
Scalar stops[7] = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
auto image = DlImageImpeller::Make(texture);
|
||||
|
||||
paint.setColorSource(DlColorSource::MakeRadial(
|
||||
{500, 600}, 75, 7, gradient_colors, stops, DlTileMode::kMirror));
|
||||
draw(paint, 0, 300);
|
||||
|
||||
DlImageColorSource image_source(image, DlTileMode::kRepeat,
|
||||
DlTileMode::kRepeat,
|
||||
DlImageSampling::kNearestNeighbor);
|
||||
paint.setColorSource(&image_source);
|
||||
draw(paint, 300, 0);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanSaveLayerStandalone) {
|
||||
DisplayListBuilder builder;
|
||||
|
||||
DlPaint red;
|
||||
red.setColor(DlColor::kRed());
|
||||
|
||||
DlPaint alpha;
|
||||
alpha.setColor(DlColor::kRed().modulateOpacity(0.5));
|
||||
|
||||
builder.SaveLayer(nullptr, &alpha);
|
||||
|
||||
builder.DrawCircle({125, 125}, 125, red);
|
||||
|
||||
builder.Restore();
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderDifferentShapesWithSameColorSource) {
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
|
||||
DlColor colors[2] = {
|
||||
DlColor::RGBA(0.9568, 0.2627, 0.2118, 1.0),
|
||||
DlColor::RGBA(0.1294, 0.5882, 0.9529, 1.0),
|
||||
};
|
||||
DlScalar stops[2] = {
|
||||
0.0,
|
||||
1.0,
|
||||
};
|
||||
|
||||
paint.setColorSource(DlColorSource::MakeLinear({0, 0}, {100, 100}, 2, colors,
|
||||
stops, DlTileMode::kRepeat));
|
||||
|
||||
builder.Save();
|
||||
builder.Translate(100, 100);
|
||||
builder.DrawRect(SkRect::MakeXYWH(0, 0, 200, 200), paint);
|
||||
builder.Restore();
|
||||
|
||||
builder.Save();
|
||||
builder.Translate(100, 400);
|
||||
builder.DrawCircle({100, 100}, 100, paint);
|
||||
builder.Restore();
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanRenderRoundedRectWithNonUniformRadii) {
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kRed());
|
||||
|
||||
SkRRect rrect;
|
||||
SkVector radii[4] = {
|
||||
SkVector{50, 25},
|
||||
SkVector{25, 50},
|
||||
SkVector{50, 25},
|
||||
SkVector{25, 50},
|
||||
};
|
||||
rrect.setRectRadii(SkRect::MakeXYWH(100, 100, 500, 500), radii);
|
||||
|
||||
builder.DrawRRect(rrect, paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanDrawPaint) {
|
||||
auto medium_turquoise =
|
||||
DlColor::RGBA(72.0f / 255.0f, 209.0f / 255.0f, 204.0f / 255.0f, 1.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(0.2, 0.2);
|
||||
builder.DrawPaint(DlPaint().setColor(medium_turquoise));
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, CanDrawPaintMultipleTimes) {
|
||||
auto medium_turquoise =
|
||||
DlColor::RGBA(72.0f / 255.0f, 209.0f / 255.0f, 204.0f / 255.0f, 1.0f);
|
||||
auto orange_red =
|
||||
DlColor::RGBA(255.0f / 255.0f, 69.0f / 255.0f, 0.0f / 255.0f, 1.0f);
|
||||
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(0.2, 0.2);
|
||||
builder.DrawPaint(DlPaint().setColor(medium_turquoise));
|
||||
builder.DrawPaint(DlPaint().setColor(orange_red.modulateOpacity(0.5f)));
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, FilledCirclesRenderCorrectly) {
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(GetContentScale().x, GetContentScale().y);
|
||||
DlPaint paint;
|
||||
const int color_count = 3;
|
||||
DlColor colors[color_count] = {
|
||||
DlColor::kBlue(),
|
||||
DlColor::kGreen(),
|
||||
DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
|
||||
};
|
||||
|
||||
paint.setColor(DlColor::kWhite());
|
||||
builder.DrawPaint(paint);
|
||||
|
||||
int c_index = 0;
|
||||
int radius = 600;
|
||||
while (radius > 0) {
|
||||
paint.setColor(colors[(c_index++) % color_count]);
|
||||
builder.DrawCircle({10, 10}, radius, paint);
|
||||
if (radius > 30) {
|
||||
radius -= 10;
|
||||
} else {
|
||||
radius -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
DlColor gradient_colors[7] = {
|
||||
DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
|
||||
};
|
||||
DlScalar stops[7] = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
auto image = DlImageImpeller::Make(texture);
|
||||
|
||||
paint.setColorSource(DlColorSource::MakeRadial(
|
||||
{500, 600}, 75, 7, gradient_colors, stops, DlTileMode::kMirror));
|
||||
builder.DrawCircle({500, 600}, 100, paint);
|
||||
|
||||
SkMatrix local_matrix = SkMatrix::Translate(700, 200);
|
||||
DlImageColorSource image_source(
|
||||
image, DlTileMode::kRepeat, DlTileMode::kRepeat,
|
||||
DlImageSampling::kNearestNeighbor, &local_matrix);
|
||||
paint.setColorSource(&image_source);
|
||||
builder.DrawCircle({800, 300}, 100, paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, StrokedCirclesRenderCorrectly) {
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(GetContentScale().x, GetContentScale().y);
|
||||
DlPaint paint;
|
||||
const int color_count = 3;
|
||||
DlColor colors[color_count] = {
|
||||
DlColor::kBlue(),
|
||||
DlColor::kGreen(),
|
||||
DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
|
||||
};
|
||||
|
||||
paint.setColor(DlColor::kWhite());
|
||||
builder.DrawPaint(paint);
|
||||
|
||||
int c_index = 0;
|
||||
|
||||
auto draw = [&paint, &colors, &c_index](DlCanvas& canvas, SkPoint center,
|
||||
Scalar r, Scalar dr, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
paint.setColor(colors[(c_index++) % color_count]);
|
||||
canvas.DrawCircle(center, r, paint);
|
||||
r += dr;
|
||||
}
|
||||
};
|
||||
|
||||
paint.setDrawStyle(DlDrawStyle::kStroke);
|
||||
paint.setStrokeWidth(1);
|
||||
draw(builder, {10, 10}, 2, 2, 14); // r = [2, 28], covers [1,29]
|
||||
paint.setStrokeWidth(5);
|
||||
draw(builder, {10, 10}, 35, 10, 56); // r = [35, 585], covers [30,590]
|
||||
|
||||
DlColor gradient_colors[7] = {
|
||||
DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
|
||||
};
|
||||
DlScalar stops[7] = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
auto image = DlImageImpeller::Make(texture);
|
||||
|
||||
paint.setColorSource(DlColorSource::MakeRadial(
|
||||
{500, 600}, 75, 7, gradient_colors, stops, DlTileMode::kMirror));
|
||||
draw(builder, {500, 600}, 5, 10, 10);
|
||||
|
||||
SkMatrix local_matrix = SkMatrix::Translate(700, 200);
|
||||
DlImageColorSource image_source(
|
||||
image, DlTileMode::kRepeat, DlTileMode::kRepeat,
|
||||
DlImageSampling::kNearestNeighbor, &local_matrix);
|
||||
paint.setColorSource(&image_source);
|
||||
draw(builder, {800, 300}, 5, 10, 10);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, FilledEllipsesRenderCorrectly) {
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(GetContentScale().x, GetContentScale().y);
|
||||
DlPaint paint;
|
||||
const int color_count = 3;
|
||||
DlColor colors[color_count] = {
|
||||
DlColor::kBlue(),
|
||||
DlColor::kGreen(),
|
||||
DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
|
||||
};
|
||||
|
||||
paint.setColor(DlColor::kWhite());
|
||||
builder.DrawPaint(paint);
|
||||
|
||||
int c_index = 0;
|
||||
int long_radius = 600;
|
||||
int short_radius = 600;
|
||||
while (long_radius > 0 && short_radius > 0) {
|
||||
paint.setColor(colors[(c_index++) % color_count]);
|
||||
builder.DrawOval(SkRect::MakeXYWH(10 - long_radius, 10 - short_radius,
|
||||
long_radius * 2, short_radius * 2),
|
||||
paint);
|
||||
builder.DrawOval(SkRect::MakeXYWH(1000 - short_radius, 750 - long_radius,
|
||||
short_radius * 2, long_radius * 2),
|
||||
paint);
|
||||
if (short_radius > 30) {
|
||||
short_radius -= 10;
|
||||
long_radius -= 5;
|
||||
} else {
|
||||
short_radius -= 2;
|
||||
long_radius -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
DlColor gradient_colors[7] = {
|
||||
DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
|
||||
};
|
||||
DlScalar stops[7] = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
auto image = DlImageImpeller::Make(texture);
|
||||
|
||||
paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
|
||||
|
||||
paint.setColorSource(DlColorSource::MakeRadial(
|
||||
{300, 650}, 75, 7, gradient_colors, stops, DlTileMode::kMirror));
|
||||
builder.DrawOval(SkRect::MakeXYWH(200, 625, 200, 50), paint);
|
||||
builder.DrawOval(SkRect::MakeXYWH(275, 550, 50, 200), paint);
|
||||
|
||||
SkMatrix local_matrix = SkMatrix::Translate(610, 15);
|
||||
DlImageColorSource image_source(
|
||||
image, DlTileMode::kRepeat, DlTileMode::kRepeat,
|
||||
DlImageSampling::kNearestNeighbor, &local_matrix);
|
||||
paint.setColorSource(&image_source);
|
||||
builder.DrawOval(SkRect::MakeXYWH(610, 90, 200, 50), paint);
|
||||
builder.DrawOval(SkRect::MakeXYWH(685, 15, 50, 200), paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) {
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(GetContentScale().x, GetContentScale().y);
|
||||
DlPaint paint;
|
||||
const int color_count = 3;
|
||||
DlColor colors[color_count] = {
|
||||
DlColor::kBlue(),
|
||||
DlColor::kGreen(),
|
||||
DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f),
|
||||
};
|
||||
|
||||
paint.setColor(DlColor::kWhite());
|
||||
builder.DrawPaint(paint);
|
||||
|
||||
int c_index = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
paint.setColor(colors[(c_index++) % color_count]);
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(
|
||||
SkRect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80), //
|
||||
i * 5 + 10, j * 5 + 10),
|
||||
paint);
|
||||
}
|
||||
}
|
||||
paint.setColor(colors[(c_index++) % color_count]);
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeXYWH(10, 420, 380, 80), 40, 40), paint);
|
||||
paint.setColor(colors[(c_index++) % color_count]);
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeXYWH(410, 20, 80, 380), 40, 40), paint);
|
||||
|
||||
DlColor gradient_colors[7] = {
|
||||
DlColor::RGBA(0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0),
|
||||
DlColor::RGBA(0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0),
|
||||
DlColor::RGBA(0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0),
|
||||
};
|
||||
DlScalar stops[7] = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
(1.0 / 6.0) * 2,
|
||||
(1.0 / 6.0) * 3,
|
||||
(1.0 / 6.0) * 4,
|
||||
(1.0 / 6.0) * 5,
|
||||
1.0,
|
||||
};
|
||||
auto texture = CreateTextureForFixture("airplane.jpg",
|
||||
/*enable_mipmapping=*/true);
|
||||
auto image = DlImageImpeller::Make(texture);
|
||||
|
||||
paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
|
||||
paint.setColorSource(DlColorSource::MakeRadial(
|
||||
{550, 550}, 75, 7, gradient_colors, stops, DlTileMode::kMirror));
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
int j = 11 - i;
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(550 - i * 20, 550 - j * 20, //
|
||||
550 + i * 20, 550 + j * 20),
|
||||
i * 10, j * 10),
|
||||
paint);
|
||||
}
|
||||
|
||||
paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
|
||||
paint.setColorSource(DlColorSource::MakeRadial(
|
||||
{200, 650}, 75, 7, gradient_colors, stops, DlTileMode::kMirror));
|
||||
paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(100, 610, 300, 690), 40, 40), paint);
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(160, 550, 240, 750), 40, 40), paint);
|
||||
|
||||
paint.setColor(DlColor::kWhite().modulateOpacity(0.1));
|
||||
SkMatrix local_matrix = SkMatrix::Translate(520, 20);
|
||||
DlImageColorSource image_source(
|
||||
image, DlTileMode::kRepeat, DlTileMode::kRepeat,
|
||||
DlImageSampling::kNearestNeighbor, &local_matrix);
|
||||
paint.setColorSource(&image_source);
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
int j = 11 - i;
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(720 - i * 20, 220 - j * 20, //
|
||||
720 + i * 20, 220 + j * 20),
|
||||
i * 10, j * 10),
|
||||
paint);
|
||||
}
|
||||
|
||||
paint.setColor(DlColor::kWhite().modulateOpacity(0.5));
|
||||
local_matrix = SkMatrix::Translate(800, 300);
|
||||
DlImageColorSource image_source2(
|
||||
image, DlTileMode::kRepeat, DlTileMode::kRepeat,
|
||||
DlImageSampling::kNearestNeighbor, &local_matrix);
|
||||
paint.setColorSource(&image_source2);
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(800, 410, 1000, 490), 40, 40),
|
||||
paint);
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeLTRB(860, 350, 940, 550), 40, 40), paint);
|
||||
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(AiksTest, SolidColorCirclesOvalsRRectsMaskBlurCorrectly) {
|
||||
DisplayListBuilder builder;
|
||||
builder.Scale(GetContentScale().x, GetContentScale().y);
|
||||
DlPaint paint;
|
||||
paint.setMaskFilter(DlBlurMaskFilter::Make(DlBlurStyle::kNormal, 1.0f));
|
||||
|
||||
builder.DrawPaint(DlPaint().setColor(DlColor::kWhite()));
|
||||
|
||||
paint.setColor(
|
||||
DlColor::RGBA(220.0f / 255.0f, 20.0f / 255.0f, 60.0f / 255.0f, 1.0f));
|
||||
Scalar y = 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 10.0f;
|
||||
builder.DrawRect(SkRect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
|
||||
radius, 60.0f - radius),
|
||||
paint);
|
||||
}
|
||||
|
||||
paint.setColor(DlColor::kBlue());
|
||||
y += 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 10.0f;
|
||||
builder.DrawCircle({x + 25, y + 25}, radius, paint);
|
||||
}
|
||||
|
||||
paint.setColor(DlColor::kGreen());
|
||||
y += 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 10.0f;
|
||||
builder.DrawOval(SkRect::MakeXYWH(x + 25 - radius / 2, y + radius / 2, //
|
||||
radius, 60.0f - radius),
|
||||
paint);
|
||||
}
|
||||
|
||||
paint.setColor(
|
||||
DlColor::RGBA(128.0f / 255.0f, 0.0f / 255.0f, 128.0f / 255.0f, 1.0f));
|
||||
y += 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 20.0f;
|
||||
builder.DrawRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(x, y, 60.0f, 60.0f),
|
||||
radius, radius),
|
||||
paint);
|
||||
}
|
||||
|
||||
paint.setColor(
|
||||
DlColor::RGBA(255.0f / 255.0f, 165.0f / 255.0f, 0.0f / 255.0f, 1.0f));
|
||||
y += 100.0f;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Scalar x = (i + 1) * 100;
|
||||
Scalar radius = x / 20.0f;
|
||||
builder.DrawRRect(
|
||||
SkRRect::MakeRectXY(SkRect::MakeXYWH(x, y, 60.0f, 60.0f), radius, 5.0f),
|
||||
paint);
|
||||
}
|
||||
|
||||
auto dl = builder.Build();
|
||||
ASSERT_TRUE(OpenPlaygroundHere(dl));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
@ -246,7 +246,8 @@ TEST_P(AiksTest, SolidStrokesRenderCorrectly) {
|
||||
paint.setColor(DlColor::kWhite());
|
||||
builder.DrawPaint(paint);
|
||||
|
||||
paint.setColor(DlColor(color.alpha, color.red, color.green, color.blue));
|
||||
paint.setColor(
|
||||
DlColor::ARGB(color.alpha, color.red, color.green, color.blue));
|
||||
paint.setDrawStyle(DlDrawStyle::kStroke);
|
||||
paint.setStrokeWidth(10);
|
||||
|
||||
@ -339,13 +340,13 @@ TEST_P(AiksTest, DrawLinesRenderCorrectly) {
|
||||
};
|
||||
|
||||
std::vector<DlColor> colors = {
|
||||
DlColor{1, 0x1f / 255.0, 0.0, 0x5c / 255.0},
|
||||
DlColor{1, 0x5b / 255.0, 0.0, 0x60 / 255.0},
|
||||
DlColor{1, 0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0},
|
||||
DlColor{1, 0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0},
|
||||
DlColor{1, 0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0},
|
||||
DlColor{1, 0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0},
|
||||
DlColor{1, 0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0}};
|
||||
DlColor::ARGB(1, 0x1f / 255.0, 0.0, 0x5c / 255.0),
|
||||
DlColor::ARGB(1, 0x5b / 255.0, 0.0, 0x60 / 255.0),
|
||||
DlColor::ARGB(1, 0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0),
|
||||
DlColor::ARGB(1, 0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0),
|
||||
DlColor::ARGB(1, 0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0),
|
||||
DlColor::ARGB(1, 0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0),
|
||||
DlColor::ARGB(1, 0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0)};
|
||||
std::vector<Scalar> stops = {
|
||||
0.0,
|
||||
(1.0 / 6.0) * 1,
|
||||
@ -432,8 +433,8 @@ TEST_P(AiksTest, ArcWithZeroSweepAndBlur) {
|
||||
DlPaint paint;
|
||||
paint.setColor(DlColor::kRed());
|
||||
|
||||
std::vector<DlColor> colors = {DlColor{1.0, 0.0, 0.0, 1.0},
|
||||
DlColor{0.0, 0.0, 0.0, 1.0}};
|
||||
std::vector<DlColor> colors = {DlColor::RGBA(1.0, 0.0, 0.0, 1.0),
|
||||
DlColor::RGBA(0.0, 0.0, 0.0, 1.0)};
|
||||
std::vector<Scalar> stops = {0.0, 1.0};
|
||||
|
||||
paint.setColorSource(
|
||||
|
||||
@ -723,6 +723,14 @@ void DlDispatcherBase::clipRect(const SkRect& rect,
|
||||
ToClipOperation(clip_op));
|
||||
}
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void DlDispatcherBase::clipOval(const SkRect& bounds,
|
||||
ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
GetCanvas().ClipOval(skia_conversions::ToRect(bounds),
|
||||
ToClipOperation(clip_op));
|
||||
}
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void DlDispatcherBase::clipRRect(const SkRRect& rrect,
|
||||
ClipOp sk_op,
|
||||
|
||||
@ -123,6 +123,9 @@ class DlDispatcherBase : public flutter::DlOpReceiver {
|
||||
// |flutter::DlOpReceiver|
|
||||
void clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override;
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void clipOval(const SkRect& bounds, ClipOp clip_op, bool is_aa) override;
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override;
|
||||
|
||||
|
||||
@ -742,6 +742,14 @@ void DisplayListStreamDispatcher::clipRect(const SkRect& rect, ClipOp clip_op,
|
||||
<< "isaa: " << is_aa
|
||||
<< ");" << std::endl;
|
||||
}
|
||||
void DisplayListStreamDispatcher::clipOval(const SkRect& bounds, ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
startl() << "clipOval("
|
||||
<< bounds << ", "
|
||||
<< clip_op << ", "
|
||||
<< "isaa: " << is_aa
|
||||
<< ");" << std::endl;
|
||||
}
|
||||
void DisplayListStreamDispatcher::clipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op,
|
||||
bool is_aa) {
|
||||
|
||||
@ -118,6 +118,7 @@ class DisplayListStreamDispatcher final : public DlOpReceiver {
|
||||
void transformReset() override;
|
||||
|
||||
void clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override;
|
||||
void clipOval(const SkRect& bounds, ClipOp clip_op, bool is_aa) override;
|
||||
void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override;
|
||||
void clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) override;
|
||||
|
||||
|
||||
@ -214,6 +214,13 @@ void MockCanvas::ClipRect(const SkRect& rect, ClipOp op, bool is_aa) {
|
||||
state_stack_.back().clipRect(rect, op, is_aa);
|
||||
}
|
||||
|
||||
void MockCanvas::ClipOval(const SkRect& bounds, ClipOp op, bool is_aa) {
|
||||
ClipEdgeStyle style = is_aa ? kSoftClipEdgeStyle : kHardClipEdgeStyle;
|
||||
draw_calls_.emplace_back(
|
||||
DrawCall{current_layer_, ClipOvalData{bounds, op, style}});
|
||||
state_stack_.back().clipOval(bounds, op, is_aa);
|
||||
}
|
||||
|
||||
void MockCanvas::ClipRRect(const SkRRect& rrect, ClipOp op, bool is_aa) {
|
||||
ClipEdgeStyle style = is_aa ? kSoftClipEdgeStyle : kHardClipEdgeStyle;
|
||||
draw_calls_.emplace_back(
|
||||
@ -520,6 +527,16 @@ std::ostream& operator<<(std::ostream& os,
|
||||
return os << data.rect << " " << data.clip_op << " " << data.style;
|
||||
}
|
||||
|
||||
bool operator==(const MockCanvas::ClipOvalData& a,
|
||||
const MockCanvas::ClipOvalData& b) {
|
||||
return a.bounds == b.bounds && a.clip_op == b.clip_op && a.style == b.style;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const MockCanvas::ClipOvalData& data) {
|
||||
return os << data.bounds << " " << data.clip_op << " " << data.style;
|
||||
}
|
||||
|
||||
bool operator==(const MockCanvas::ClipRRectData& a,
|
||||
const MockCanvas::ClipRRectData& b) {
|
||||
return a.rrect == b.rrect && a.clip_op == b.clip_op && a.style == b.style;
|
||||
|
||||
@ -114,6 +114,12 @@ class MockCanvas final : public DlCanvas {
|
||||
ClipEdgeStyle style;
|
||||
};
|
||||
|
||||
struct ClipOvalData {
|
||||
SkRect bounds;
|
||||
ClipOp clip_op;
|
||||
ClipEdgeStyle style;
|
||||
};
|
||||
|
||||
struct ClipRRectData {
|
||||
SkRRect rrect;
|
||||
ClipOp clip_op;
|
||||
@ -145,6 +151,7 @@ class MockCanvas final : public DlCanvas {
|
||||
DrawDisplayListData,
|
||||
DrawShadowData,
|
||||
ClipRectData,
|
||||
ClipOvalData,
|
||||
ClipRRectData,
|
||||
ClipPathData,
|
||||
DrawPaintData>;
|
||||
@ -206,6 +213,7 @@ class MockCanvas final : public DlCanvas {
|
||||
SkMatrix GetTransform() const override;
|
||||
|
||||
void ClipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override;
|
||||
void ClipOval(const SkRect& bounds, ClipOp clip_op, bool is_aa) override;
|
||||
void ClipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override;
|
||||
void ClipPath(const SkPath& path, ClipOp clip_op, bool is_aa) override;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user