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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1819,6 +1819,96 @@ TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, FilledRoundRectPathsRenderCorrectly) {
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);

auto draw_rrect_as_path = [&canvas](const Rect& rect, const Size& radii,
const Paint& paint) {
PathBuilder builder = PathBuilder();
builder.AddRoundedRect(rect, radii);
canvas.DrawPath(builder.TakePath(), 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];
draw_rrect_as_path(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];
draw_rrect_as_path(Rect::MakeXYWH(10, 420, 380, 80), Size(40, 40), paint);
paint.color = colors[(c_index++) % color_count];
draw_rrect_as_path(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;
draw_rrect_as_path(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, {});
draw_rrect_as_path(Rect::MakeLTRB(100, 610, 300, 690), Size(40, 40), paint);
draw_rrect_as_path(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;
draw_rrect_as_path(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}));
draw_rrect_as_path(Rect::MakeLTRB(800, 410, 1000, 490), Size(40, 40), paint);
draw_rrect_as_path(Rect::MakeLTRB(860, 350, 940, 550), Size(40, 40), paint);

ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
Canvas canvas;
Expand Down
96 changes: 46 additions & 50 deletions impeller/geometry/path_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,13 @@ PathBuilder& PathBuilder::AddCubicCurve(Point p1,
}

PathBuilder& PathBuilder::AddRect(Rect rect) {
current_ = rect.origin;
auto origin = rect.GetOrigin();
auto size = rect.GetSize();

auto tl = rect.origin;
auto bl = rect.origin + Point{0.0, rect.size.height};
auto br = rect.origin + Point{rect.size.width, rect.size.height};
auto tr = rect.origin + Point{rect.size.width, 0.0};
auto tl = origin;
auto bl = origin + Point{0.0, size.height};
auto br = origin + size;
auto tr = origin + Point{size.width, 0.0};

MoveTo(tl);
LineTo(tr);
Expand Down Expand Up @@ -150,16 +151,19 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) {
return AddRect(rect);
}

current_ = rect.origin + Point{radii.top_left.x, 0.0};
auto rect_origin = rect.GetOrigin();
auto rect_size = rect.GetSize();

MoveTo({rect.origin.x + radii.top_left.x, rect.origin.y});
current_ = rect_origin + Point{radii.top_left.x, 0.0};

MoveTo({rect_origin.x + radii.top_left.x, rect_origin.y});

//----------------------------------------------------------------------------
// Top line.
//
prototype_.AddLinearComponent(
{rect.origin.x + radii.top_left.x, rect.origin.y},
{rect.origin.x + rect.size.width - radii.top_right.x, rect.origin.y});
{rect_origin.x + radii.top_left.x, rect_origin.y},
{rect_origin.x + rect_size.width - radii.top_right.x, rect_origin.y});

//----------------------------------------------------------------------------
// Top right arc.
Expand All @@ -170,9 +174,9 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) {
// Right line.
//
prototype_.AddLinearComponent(
{rect.origin.x + rect.size.width, rect.origin.y + radii.top_right.y},
{rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height - radii.bottom_right.y});
{rect_origin.x + rect_size.width, rect_origin.y + radii.top_right.y},
{rect_origin.x + rect_size.width,
rect_origin.y + rect_size.height - radii.bottom_right.y});

//----------------------------------------------------------------------------
// Bottom right arc.
Expand All @@ -183,9 +187,9 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) {
// Bottom line.
//
prototype_.AddLinearComponent(
{rect.origin.x + rect.size.width - radii.bottom_right.x,
rect.origin.y + rect.size.height},
{rect.origin.x + radii.bottom_left.x, rect.origin.y + rect.size.height});
{rect_origin.x + rect_size.width - radii.bottom_right.x,
rect_origin.y + rect_size.height},
{rect_origin.x + radii.bottom_left.x, rect_origin.y + rect_size.height});

//----------------------------------------------------------------------------
// Bottom left arc.
Expand All @@ -196,8 +200,8 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) {
// Left line.
//
prototype_.AddLinearComponent(
{rect.origin.x, rect.origin.y + rect.size.height - radii.bottom_left.y},
{rect.origin.x, rect.origin.y + radii.top_left.y});
{rect_origin.x, rect_origin.y + rect_size.height - radii.bottom_left.y},
{rect_origin.x, rect_origin.y + radii.top_left.y});

//----------------------------------------------------------------------------
// Top left arc.
Expand All @@ -212,54 +216,48 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) {
PathBuilder& PathBuilder::AddRoundedRectTopLeft(Rect rect,
RoundingRadii radii) {
const auto magic_top_left = radii.top_left * kArcApproximationMagic;
const auto corner = rect.GetOrigin();
prototype_.AddCubicComponent(
{rect.origin.x, rect.origin.y + radii.top_left.y},
{rect.origin.x, rect.origin.y + radii.top_left.y - magic_top_left.y},
{rect.origin.x + radii.top_left.x - magic_top_left.x, rect.origin.y},
{rect.origin.x + radii.top_left.x, rect.origin.y});
{corner.x, corner.y + radii.top_left.y},
{corner.x, corner.y + radii.top_left.y - magic_top_left.y},
{corner.x + radii.top_left.x - magic_top_left.x, corner.y},
{corner.x + radii.top_left.x, corner.y});
return *this;
}

PathBuilder& PathBuilder::AddRoundedRectTopRight(Rect rect,
RoundingRadii radii) {
const auto magic_top_right = radii.top_right * kArcApproximationMagic;
const auto corner = rect.GetOrigin() + Point{rect.GetWidth(), 0};
prototype_.AddCubicComponent(
{rect.origin.x + rect.size.width - radii.top_right.x, rect.origin.y},
{rect.origin.x + rect.size.width - radii.top_right.x + magic_top_right.x,
rect.origin.y},
{rect.origin.x + rect.size.width,
rect.origin.y + radii.top_right.y - magic_top_right.y},
{rect.origin.x + rect.size.width, rect.origin.y + radii.top_right.y});
{corner.x - radii.top_right.x, corner.y},
{corner.x - radii.top_right.x + magic_top_right.x, corner.y},
{corner.x, corner.y + radii.top_right.y - magic_top_right.y},
{corner.x, corner.y + radii.top_right.y});
return *this;
}

PathBuilder& PathBuilder::AddRoundedRectBottomRight(Rect rect,
RoundingRadii radii) {
const auto magic_bottom_right = radii.bottom_right * kArcApproximationMagic;
const auto corner = rect.GetOrigin() + rect.GetSize();
prototype_.AddCubicComponent(
{rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height - radii.bottom_right.y},
{rect.origin.x + rect.size.width, rect.origin.y + rect.size.height -
radii.bottom_right.y +
magic_bottom_right.y},
{rect.origin.x + rect.size.width - radii.bottom_right.x +
magic_bottom_right.x,
rect.origin.y + rect.size.height},
{rect.origin.x + rect.size.width - radii.bottom_right.x,
rect.origin.y + rect.size.height});
{corner.x, corner.y - radii.bottom_right.y},
{corner.x, corner.y - radii.bottom_right.y + magic_bottom_right.y},
{corner.x - radii.bottom_right.x + magic_bottom_right.x, corner.y},
{corner.x - radii.bottom_right.x, corner.y});
return *this;
}

PathBuilder& PathBuilder::AddRoundedRectBottomLeft(Rect rect,
RoundingRadii radii) {
const auto magic_bottom_left = radii.bottom_left * kArcApproximationMagic;
const auto corner = rect.GetOrigin() + Point{0, rect.GetHeight()};
prototype_.AddCubicComponent(
{rect.origin.x + radii.bottom_left.x, rect.origin.y + rect.size.height},
{rect.origin.x + radii.bottom_left.x - magic_bottom_left.x,
rect.origin.y + rect.size.height},
{rect.origin.x, rect.origin.y + rect.size.height - radii.bottom_left.y +
magic_bottom_left.y},
{rect.origin.x, rect.origin.y + rect.size.height - radii.bottom_left.y});
{corner.x + radii.bottom_left.x, corner.y},
{corner.x + radii.bottom_left.x - magic_bottom_left.x, corner.y},
{corner.x, corner.y - radii.bottom_left.y + magic_bottom_left.y},
{corner.x, corner.y - radii.bottom_left.y});
return *this;
}

Expand All @@ -274,10 +272,8 @@ PathBuilder& PathBuilder::AddArc(const Rect& oval_bounds,
sweep.radians = std::min(k2Pi, sweep.radians);
start.radians = std::fmod(start.radians, k2Pi);

const Point radius = {oval_bounds.size.width * 0.5f,
oval_bounds.size.height * 0.5f};
const Point center = {oval_bounds.origin.x + radius.x,
oval_bounds.origin.y + radius.y};
const Point center = oval_bounds.GetCenter();
const Point radius = center - oval_bounds.GetOrigin();

Vector2 p1_unit(std::cos(start.radians), std::sin(start.radians));

Expand Down Expand Up @@ -324,9 +320,9 @@ PathBuilder& PathBuilder::AddArc(const Rect& oval_bounds,
}

PathBuilder& PathBuilder::AddOval(const Rect& container) {
const Point r = {container.size.width * 0.5f, container.size.height * 0.5f};
const Point c = {container.origin.x + r.x, container.origin.y + r.y};
const Point m = {kArcApproximationMagic * r.x, kArcApproximationMagic * r.y};
const Point c = container.GetCenter();
const Point r = c - container.GetOrigin();
const Point m = r * kArcApproximationMagic;

MoveTo({c.x, c.y - r.y});

Expand Down
2 changes: 0 additions & 2 deletions impeller/geometry/rect.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,6 @@ struct TRect {
TPoint<Type> origin;
TSize<Type> size;
// NOLINTEND

friend class PathBuilder;
};

using Rect = TRect<Scalar>;
Expand Down