mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Render axis-aligned Caps for zero length lines in Impeller (flutter/engine#35298)
This commit is contained in:
parent
8126a78906
commit
fea6e19d60
@ -888,7 +888,6 @@ void DisplayListDispatcher::drawArc(const SkRect& oval_bounds,
|
||||
void DisplayListDispatcher::drawPoints(SkCanvas::PointMode mode,
|
||||
uint32_t count,
|
||||
const SkPoint points[]) {
|
||||
// auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath();
|
||||
Paint paint = paint_;
|
||||
paint.style = Paint::Style::kStroke;
|
||||
switch (mode) {
|
||||
@ -897,29 +896,28 @@ void DisplayListDispatcher::drawPoints(SkCanvas::PointMode mode,
|
||||
paint.stroke_cap = SolidStrokeContents::Cap::kSquare;
|
||||
}
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
SkPoint p0 = points[i];
|
||||
// kEhCloseEnough works around a bug where Impeller does not draw
|
||||
// anything for zero-length lines.
|
||||
// See: https://github.com/flutter/flutter/issues/109077
|
||||
SkPoint p1 = points[i] + SkPoint{kEhCloseEnough, 0.0};
|
||||
auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath();
|
||||
Point p0 = ToPoint(points[i]);
|
||||
auto path = PathBuilder{}.AddLine(p0, p0).TakePath();
|
||||
canvas_.DrawPath(std::move(path), paint);
|
||||
}
|
||||
break;
|
||||
case SkCanvas::kLines_PointMode:
|
||||
for (uint32_t i = 1; i < count; i += 2) {
|
||||
SkPoint p0 = points[i - 1];
|
||||
SkPoint p1 = points[i];
|
||||
auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath();
|
||||
Point p0 = ToPoint(points[i - 1]);
|
||||
Point p1 = ToPoint(points[i]);
|
||||
auto path = PathBuilder{}.AddLine(p0, p1).TakePath();
|
||||
canvas_.DrawPath(std::move(path), paint);
|
||||
}
|
||||
break;
|
||||
case SkCanvas::kPolygon_PointMode:
|
||||
for (uint32_t i = 1; i < count; i++) {
|
||||
SkPoint p0 = points[i - 1];
|
||||
SkPoint p1 = points[i];
|
||||
auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath();
|
||||
canvas_.DrawPath(std::move(path), paint);
|
||||
if (count > 1) {
|
||||
Point p0 = ToPoint(points[0]);
|
||||
for (uint32_t i = 1; i < count; i++) {
|
||||
Point p1 = ToPoint(points[i]);
|
||||
auto path = PathBuilder{}.AddLine(p0, p1).TakePath();
|
||||
canvas_.DrawPath(std::move(path), paint);
|
||||
p0 = p1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -451,11 +451,13 @@ TEST_P(DisplayListTest, CanDrawPoints) {
|
||||
flutter::DlStrokeCap::kRound,
|
||||
flutter::DlStrokeCap::kSquare,
|
||||
};
|
||||
flutter::DlPaint paint = flutter::DlPaint().setStrokeWidth(20);
|
||||
flutter::DlPaint paint =
|
||||
flutter::DlPaint() //
|
||||
.setColor(flutter::DlColor::kYellow().withAlpha(127)) //
|
||||
.setStrokeWidth(20);
|
||||
builder.translate(50, 50);
|
||||
for (auto cap : caps) {
|
||||
paint.setStrokeCap(cap);
|
||||
paint.setColor(flutter::DlColor::kYellow().withAlpha(127));
|
||||
builder.save();
|
||||
builder.drawPoints(SkCanvas::kPoints_PointMode, 7, points, paint);
|
||||
builder.translate(150, 0);
|
||||
@ -468,5 +470,28 @@ TEST_P(DisplayListTest, CanDrawPoints) {
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
TEST_P(DisplayListTest, CanDrawZeroLengthLine) {
|
||||
flutter::DisplayListBuilder builder;
|
||||
std::vector<flutter::DlStrokeCap> caps = {
|
||||
flutter::DlStrokeCap::kButt,
|
||||
flutter::DlStrokeCap::kRound,
|
||||
flutter::DlStrokeCap::kSquare,
|
||||
};
|
||||
flutter::DlPaint paint =
|
||||
flutter::DlPaint() //
|
||||
.setColor(flutter::DlColor::kYellow().withAlpha(127)) //
|
||||
.setDrawStyle(flutter::DlDrawStyle::kStroke) //
|
||||
.setStrokeCap(flutter::DlStrokeCap::kButt) //
|
||||
.setStrokeWidth(20);
|
||||
SkPath path = SkPath().addPoly({{150, 50}, {150, 50}}, false);
|
||||
for (auto cap : caps) {
|
||||
paint.setStrokeCap(cap);
|
||||
builder.drawLine({50, 50}, {50, 50}, paint);
|
||||
builder.drawPath(path, paint);
|
||||
builder.translate(0, 150);
|
||||
}
|
||||
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace impeller
|
||||
|
||||
@ -72,10 +72,6 @@ static VertexBuffer CreateSolidStrokeVertices(
|
||||
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
|
||||
auto polyline = path.CreatePolyline();
|
||||
|
||||
if (polyline.points.size() < 2) {
|
||||
return {}; // Nothing to render.
|
||||
}
|
||||
|
||||
VS::PerVertexData vtx;
|
||||
|
||||
// Normal state.
|
||||
@ -95,8 +91,17 @@ static VertexBuffer CreateSolidStrokeVertices(
|
||||
std::tie(contour_start_point_i, contour_end_point_i) =
|
||||
polyline.GetContourPointBounds(contour_i);
|
||||
|
||||
if (contour_end_point_i - contour_start_point_i < 2) {
|
||||
continue; // This contour has no renderable content.
|
||||
switch (contour_end_point_i - contour_start_point_i) {
|
||||
case 1: {
|
||||
Point p = polyline.points[contour_start_point_i];
|
||||
cap_proc(vtx_builder, p, {-1, 0}, smoothing);
|
||||
cap_proc(vtx_builder, p, {1, 0}, smoothing);
|
||||
continue;
|
||||
}
|
||||
case 0:
|
||||
continue; // This contour has no renderable content.
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// The first point's normal is always the same as
|
||||
|
||||
@ -237,7 +237,7 @@ Path::Polyline Path::CreatePolyline(
|
||||
for (const auto& point : collection) {
|
||||
if (previous_contour_point.has_value() &&
|
||||
previous_contour_point.value() == point) {
|
||||
// Slip over duplicate points in the same contour.
|
||||
// Skip over duplicate points in the same contour.
|
||||
continue;
|
||||
}
|
||||
previous_contour_point = point;
|
||||
|
||||
@ -189,7 +189,7 @@ struct TPoint {
|
||||
constexpr TPoint Normalize() const {
|
||||
const auto length = GetLength();
|
||||
if (length == 0) {
|
||||
return {};
|
||||
return {1, 0};
|
||||
}
|
||||
return {x / length, y / length};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user