From 979fc44c483173e95aebfaa8bdde949217ae8abf Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 23 Aug 2022 16:28:14 -0700 Subject: [PATCH] [Impeller] Enforce a minimum stroke width (flutter/engine#35576) --- .../display_list/display_list_unittests.cc | 34 +++++++++++++++++++ .../entity/contents/solid_stroke_contents.cc | 16 +++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/engine/src/flutter/impeller/display_list/display_list_unittests.cc b/engine/src/flutter/impeller/display_list/display_list_unittests.cc index b887c22e49b..c29a999cc6c 100644 --- a/engine/src/flutter/impeller/display_list/display_list_unittests.cc +++ b/engine/src/flutter/impeller/display_list/display_list_unittests.cc @@ -521,5 +521,39 @@ TEST_P(DisplayListTest, CanDrawShadow) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(DisplayListTest, CanDrawZeroWidthLine) { + flutter::DisplayListBuilder builder; + std::vector caps = { + flutter::DlStrokeCap::kButt, + flutter::DlStrokeCap::kRound, + flutter::DlStrokeCap::kSquare, + }; + flutter::DlPaint paint = // + flutter::DlPaint() // + .setColor(flutter::DlColor::kWhite()) // + .setDrawStyle(flutter::DlDrawStyle::kStroke) // + .setStrokeWidth(0); + flutter::DlPaint outline_paint = // + flutter::DlPaint() // + .setColor(flutter::DlColor::kYellow()) // + .setDrawStyle(flutter::DlDrawStyle::kStroke) // + .setStrokeCap(flutter::DlStrokeCap::kSquare) // + .setStrokeWidth(1); + SkPath path = SkPath().addPoly({{150, 50}, {160, 50}}, false); + for (auto cap : caps) { + paint.setStrokeCap(cap); + builder.drawLine({50, 50}, {60, 50}, paint); + builder.drawRect({45, 45, 65, 55}, outline_paint); + builder.drawLine({100, 50}, {100, 50}, paint); + if (cap != flutter::DlStrokeCap::kButt) { + builder.drawRect({95, 45, 105, 55}, outline_paint); + } + builder.drawPath(path, paint); + builder.drawRect(path.getBounds().makeOutset(5, 5), outline_paint); + builder.translate(0, 150); + } + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/contents/solid_stroke_contents.cc b/engine/src/flutter/impeller/entity/contents/solid_stroke_contents.cc index 326b90f3428..357498ad18c 100644 --- a/engine/src/flutter/impeller/entity/contents/solid_stroke_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/solid_stroke_contents.cc @@ -52,8 +52,13 @@ std::optional SolidStrokeContents::GetCoverage( if (join_ == Join::kMiter) { max_radius = std::max(max_radius, miter_limit_ * 0.5f); } + Scalar determinant = entity.GetTransformation().GetDeterminant(); + if (determinant == 0) { + return std::nullopt; + } + Scalar min_size = 1.0f / sqrt(std::abs(determinant)); Vector2 max_radius_xy = entity.GetTransformation().TransformDirection( - Vector2(max_radius, max_radius) * stroke_size_); + Vector2(max_radius, max_radius) * std::max(stroke_size_, min_size)); return Rect(path_coverage.origin - max_radius_xy, Size(path_coverage.size.width + max_radius_xy.x * 2, @@ -182,7 +187,7 @@ static VertexBuffer CreateSolidStrokeVertices( bool SolidStrokeContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - if (stroke_size_ <= 0.0) { + if (stroke_size_ < 0.0) { return true; } @@ -192,7 +197,12 @@ bool SolidStrokeContents::Render(const ContentContext& renderer, VS::VertInfo vert_info; vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); - vert_info.size = stroke_size_; + Scalar determinant = entity.GetTransformation().GetDeterminant(); + if (determinant == 0) { + return true; + } + Scalar min_size = 1.0f / sqrt(std::abs(determinant)); + vert_info.size = std::max(stroke_size_, min_size); FS::FragInfo frag_info; frag_info.color = color_.Premultiply();