From e17287da31b1f755811cf091722c40beab19a33b Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 27 Mar 2025 15:27:03 +0000 Subject: [PATCH] [Impeller] Move to the new location before rendering a stroke path contour containing only one point (#165940) Fixes https://github.com/flutter/flutter/issues/165190 --- .../display_list/aiks_dl_path_unittests.cc | 20 +++++++++++++ .../entity/geometry/stroke_path_geometry.cc | 28 ++++++++++--------- .../testing/impeller_golden_tests_output.txt | 3 ++ 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/engine/src/flutter/impeller/display_list/aiks_dl_path_unittests.cc b/engine/src/flutter/impeller/display_list/aiks_dl_path_unittests.cc index dc0ee7de24..8d0e905c96 100644 --- a/engine/src/flutter/impeller/display_list/aiks_dl_path_unittests.cc +++ b/engine/src/flutter/impeller/display_list/aiks_dl_path_unittests.cc @@ -641,5 +641,25 @@ TEST_P(AiksTest, CanRenderOverlappingMultiContourPath) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(AiksTest, TwoContourPathWithSinglePointContour) { + DisplayListBuilder builder; + + DlPaint paint; + paint.setColor(DlColor::kRed()); + paint.setDrawStyle(DlDrawStyle::kStroke); + paint.setStrokeWidth(15.0); + paint.setStrokeCap(DlStrokeCap::kRound); + + DlPathBuilder path_builder; + path_builder.MoveTo(DlPoint(100, 100)); + path_builder.LineTo(DlPoint(150, 150)); + path_builder.MoveTo(DlPoint(200, 200)); + path_builder.LineTo(DlPoint(200, 200)); + + builder.DrawPath(DlPath(path_builder), paint); + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc b/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc index 4a56e13000..6df79c453c 100644 --- a/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc +++ b/engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc @@ -87,22 +87,10 @@ class StrokeGenerator { polyline.GetContourPointBounds(contour_i); size_t contour_delta = contour_end_point_i - contour_start_point_i; - if (contour_delta == 1) { - Point p = polyline.GetPoint(contour_start_point_i); - cap_proc(vtx_builder, p, {-stroke_width * 0.5f, 0}, scale, - /*reverse=*/false); - cap_proc(vtx_builder, p, {stroke_width * 0.5f, 0}, scale, - /*reverse=*/false); - continue; - } else if (contour_delta == 0) { + if (contour_delta == 0) { continue; // This contour has no renderable content. } - previous_offset = offset; - offset = ComputeOffset(contour_start_point_i, contour_start_point_i, - contour_end_point_i, contour); - const Point contour_first_offset = offset.GetVector(); - if (contour_i > 0) { // This branch only executes when we've just finished drawing a contour // and are switching to a new one. @@ -125,6 +113,20 @@ class StrokeGenerator { vtx_builder.AppendVertex(vtx.position); } + if (contour_delta == 1) { + Point p = polyline.GetPoint(contour_start_point_i); + cap_proc(vtx_builder, p, {-stroke_width * 0.5f, 0}, scale, + /*reverse=*/false); + cap_proc(vtx_builder, p, {stroke_width * 0.5f, 0}, scale, + /*reverse=*/false); + continue; + } + + previous_offset = offset; + offset = ComputeOffset(contour_start_point_i, contour_start_point_i, + contour_end_point_i, contour); + const Point contour_first_offset = offset.GetVector(); + // Generate start cap. if (!polyline.contours[contour_i].is_closed) { Point cap_offset = diff --git a/engine/src/flutter/testing/impeller_golden_tests_output.txt b/engine/src/flutter/testing/impeller_golden_tests_output.txt index 1a54e9d1f6..d0cd95b64e 100644 --- a/engine/src/flutter/testing/impeller_golden_tests_output.txt +++ b/engine/src/flutter/testing/impeller_golden_tests_output.txt @@ -963,6 +963,9 @@ impeller_Play_AiksTest_TranslucentSaveLayerWithColorMatrixImageFilterDrawsCorrec impeller_Play_AiksTest_TransparentShadowProducesCorrectColor_Metal.png impeller_Play_AiksTest_TransparentShadowProducesCorrectColor_OpenGLES.png impeller_Play_AiksTest_TransparentShadowProducesCorrectColor_Vulkan.png +impeller_Play_AiksTest_TwoContourPathWithSinglePointContour_Metal.png +impeller_Play_AiksTest_TwoContourPathWithSinglePointContour_OpenGLES.png +impeller_Play_AiksTest_TwoContourPathWithSinglePointContour_Vulkan.png impeller_Play_AiksTest_VerifyNonOptimizedGradient_Metal.png impeller_Play_AiksTest_VerifyNonOptimizedGradient_OpenGLES.png impeller_Play_AiksTest_VerifyNonOptimizedGradient_Vulkan.png