Skip to content

Commit 6e8368c

Browse files
bderodnfield
authored andcommitted
Remove extra point from DrawRect; skip over duplicate contour points when generating polylines (flutter#114)
1 parent 2dd3797 commit 6e8368c

File tree

5 files changed

+125
-10
lines changed

5 files changed

+125
-10
lines changed

impeller/aiks/aiks_unittests.cc

+14
Original file line numberDiff line numberDiff line change
@@ -551,5 +551,19 @@ TEST_F(AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {
551551
ASSERT_TRUE(OpenPlaygroundHere(callback));
552552
}
553553

554+
TEST_F(AiksTest, DrawRectStrokesRenderCorrectly) {
555+
Canvas canvas;
556+
Paint paint;
557+
paint.color = Color::Red();
558+
paint.style = Paint::Style::kStroke;
559+
paint.stroke_width = 10;
560+
561+
canvas.Translate({100, 100});
562+
canvas.DrawPath(PathBuilder{}.AddRect(Rect::MakeSize({100, 100})).TakePath(),
563+
paint);
564+
565+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
566+
}
567+
554568
} // namespace testing
555569
} // namespace impeller

impeller/display_list/display_list_unittests.cc

+46
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,51 @@ TEST_F(DisplayListTest, CanDrawArc) {
127127
ASSERT_TRUE(OpenPlaygroundHere(callback));
128128
}
129129

130+
TEST_F(DisplayListTest, StrokedPathsDrawCorrectly) {
131+
flutter::DisplayListBuilder builder;
132+
builder.setColor(SK_ColorRED);
133+
builder.setStyle(SkPaint::Style::kStroke_Style);
134+
builder.setStrokeWidth(10);
135+
136+
// Rectangle
137+
builder.translate(100, 100);
138+
builder.drawRect(SkRect::MakeSize({100, 100}));
139+
140+
// Rounded rectangle
141+
builder.translate(150, 0);
142+
builder.drawRRect(SkRRect::MakeRectXY(SkRect::MakeSize({100, 50}), 10, 10));
143+
144+
// Double rounded rectangle
145+
builder.translate(150, 0);
146+
builder.drawDRRect(
147+
SkRRect::MakeRectXY(SkRect::MakeSize({100, 50}), 10, 10),
148+
SkRRect::MakeRectXY(SkRect::MakeXYWH(10, 10, 80, 30), 10, 10));
149+
150+
// Contour with duplicate join points
151+
{
152+
builder.translate(150, 0);
153+
SkPath path;
154+
path.lineTo({100, 0});
155+
path.lineTo({100, 0});
156+
path.lineTo({100, 100});
157+
builder.drawPath(path);
158+
}
159+
160+
// Contour with duplicate end points
161+
{
162+
builder.setStrokeCap(SkPaint::Cap::kRound_Cap);
163+
builder.translate(150, 0);
164+
SkPath path;
165+
path.moveTo(0, 0);
166+
path.lineTo({0, 0});
167+
path.lineTo({50, 50});
168+
path.lineTo({100, 0});
169+
path.lineTo({100, 0});
170+
builder.drawPath(path);
171+
}
172+
173+
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
174+
}
175+
130176
} // namespace testing
131177
} // namespace impeller

impeller/geometry/geometry_unittests.cc

+44-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// found in the LICENSE file.
44

55
#include "impeller/geometry/geometry_unittests.h"
6+
67
#include <limits>
8+
79
#include "flutter/testing/testing.h"
810
#include "impeller/geometry/path.h"
911
#include "impeller/geometry/path_builder.h"
@@ -982,11 +984,49 @@ TEST(GeometryTest, PolylineGetContourPointBoundsReturnsCorrectRanges) {
982984
ASSERT_EQ(b2, 6u);
983985
}
984986

985-
TEST(GeometryTest, PolylineGetContourOutOfBoundsAborts) {
987+
TEST(GeometryTest, PathAddRectPolylineHasCorrectContourData) {
988+
Path::Polyline polyline = PathBuilder{}
989+
.AddRect(Rect::MakeLTRB(50, 60, 70, 80))
990+
.TakePath()
991+
.CreatePolyline();
992+
ASSERT_EQ(polyline.contours.size(), 1u);
993+
ASSERT_TRUE(polyline.contours[0].is_closed);
994+
ASSERT_EQ(polyline.contours[0].start_index, 0u);
995+
ASSERT_EQ(polyline.points.size(), 5u);
996+
ASSERT_EQ(polyline.points[0], Point(50, 60));
997+
ASSERT_EQ(polyline.points[1], Point(70, 60));
998+
ASSERT_EQ(polyline.points[2], Point(70, 80));
999+
ASSERT_EQ(polyline.points[3], Point(50, 80));
1000+
ASSERT_EQ(polyline.points[4], Point(50, 60));
1001+
}
1002+
1003+
TEST(GeometryTest, PathPolylineDuplicatesAreRemovedForSameContour) {
9861004
Path::Polyline polyline =
987-
PathBuilder{}.AddLine({100, 100}, {200, 100}).TakePath().CreatePolyline();
988-
ASSERT_EQ(polyline.GetContourPointBounds(0), std::make_tuple(0u, 2u));
989-
ASSERT_EQ(polyline.GetContourPointBounds(14), std::make_tuple(2u, 2u));
1005+
PathBuilder{}
1006+
.MoveTo({50, 50})
1007+
.LineTo({50, 50}) // Insert duplicate at beginning of contour.
1008+
.LineTo({100, 50})
1009+
.LineTo({100, 50}) // Insert duplicate at contour join.
1010+
.LineTo({100, 100})
1011+
.Close() // Implicitly insert duplicate {50, 50} across contours.
1012+
.LineTo({0, 50})
1013+
.LineTo({0, 100})
1014+
.LineTo({0, 100}) // Insert duplicate at end of contour.
1015+
.TakePath()
1016+
.CreatePolyline();
1017+
ASSERT_EQ(polyline.contours.size(), 2u);
1018+
ASSERT_EQ(polyline.contours[0].start_index, 0u);
1019+
ASSERT_TRUE(polyline.contours[0].is_closed);
1020+
ASSERT_EQ(polyline.contours[1].start_index, 4u);
1021+
ASSERT_FALSE(polyline.contours[1].is_closed);
1022+
ASSERT_EQ(polyline.points.size(), 7u);
1023+
ASSERT_EQ(polyline.points[0], Point(50, 50));
1024+
ASSERT_EQ(polyline.points[1], Point(100, 50));
1025+
ASSERT_EQ(polyline.points[2], Point(100, 100));
1026+
ASSERT_EQ(polyline.points[3], Point(50, 50));
1027+
ASSERT_EQ(polyline.points[4], Point(50, 50));
1028+
ASSERT_EQ(polyline.points[5], Point(0, 50));
1029+
ASSERT_EQ(polyline.points[6], Point(0, 100));
9901030
}
9911031

9921032
} // namespace testing

impeller/geometry/path.cc

+20-4
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,27 @@ bool Path::UpdateContourComponentAtIndex(size_t index,
224224
Path::Polyline Path::CreatePolyline(
225225
const SmoothingApproximation& approximation) const {
226226
Polyline polyline;
227-
auto collect_points = [&polyline](const std::vector<Point>& collection) {
227+
228+
std::optional<Point> previous_contour_point;
229+
auto collect_points = [&polyline, &previous_contour_point](
230+
const std::vector<Point>& collection) {
231+
if (collection.empty()) {
232+
return;
233+
}
234+
228235
polyline.points.reserve(polyline.points.size() + collection.size());
229-
polyline.points.insert(polyline.points.end(), collection.begin(),
230-
collection.end());
236+
237+
for (const auto& point : collection) {
238+
if (previous_contour_point.has_value() &&
239+
previous_contour_point.value() == point) {
240+
// Slip over duplicate points in the same contour.
241+
continue;
242+
}
243+
previous_contour_point = point;
244+
polyline.points.push_back(point);
245+
}
231246
};
232-
// for (const auto& component : components_) {
247+
233248
for (size_t component_i = 0; component_i < components_.size();
234249
component_i++) {
235250
const auto& component = components_[component_i];
@@ -252,6 +267,7 @@ Path::Polyline Path::CreatePolyline(
252267
const auto& contour = contours_[component.index];
253268
polyline.contours.push_back({.start_index = polyline.points.size(),
254269
.is_closed = contour.is_closed});
270+
previous_contour_point = std::nullopt;
255271
collect_points({contour.destination});
256272
break;
257273
}

impeller/geometry/path_builder.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,7 @@ PathBuilder& PathBuilder::AddRect(Rect rect) {
179179
MoveTo(tl);
180180
prototype_.AddLinearComponent(tl, tr)
181181
.AddLinearComponent(tr, br)
182-
.AddLinearComponent(br, bl)
183-
.AddLinearComponent(bl, tl);
182+
.AddLinearComponent(br, bl);
184183
Close();
185184

186185
return *this;

0 commit comments

Comments
 (0)