From 62135be777629ad3d024610c9bfc2ff7ae2c9c93 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 28 Feb 2022 11:40:43 -0800 Subject: [PATCH] Remove break corner cases, simplify strokes, and generate closed path joins (#41) --- impeller/entity/contents.cc | 77 +++++++-------- impeller/geometry/geometry_unittests.cc | 123 ++++++++++++++++++++++-- impeller/geometry/path.cc | 98 ++++++++++++------- impeller/geometry/path.h | 43 ++++++--- impeller/geometry/path_builder.cc | 21 +++- impeller/geometry/path_component.cc | 2 +- impeller/geometry/path_component.h | 12 ++- impeller/renderer/tessellator.cc | 22 ++--- 8 files changed, 281 insertions(+), 117 deletions(-) diff --git a/impeller/entity/contents.cc b/impeller/entity/contents.cc index 6288d3b3c118e..44bea6c025b9c 100644 --- a/impeller/entity/contents.cc +++ b/impeller/entity/contents.cc @@ -5,6 +5,7 @@ #include "impeller/entity/contents.h" #include +#include #include "flutter/fml/logging.h" #include "impeller/entity/content_context.h" @@ -324,62 +325,60 @@ static VertexBuffer CreateSolidStrokeVertices(const Path& path, VertexBufferBuilder vtx_builder; auto polyline = path.CreatePolyline(); - size_t point_i = 0; if (polyline.points.size() < 2) { return {}; // Nothing to render. } VS::PerVertexData vtx; - // Cursor state. - Point direction; + // Normal state. Point normal; Point previous_normal; // Used for computing joins. - auto compute_normals = [&](size_t point_i) { + + auto compute_normal = [&polyline, &normal, &previous_normal](size_t point_i) { previous_normal = normal; - direction = + Point direction = (polyline.points[point_i] - polyline.points[point_i - 1]).Normalize(); normal = {-direction.y, direction.x}; }; - compute_normals(1); - // Break state. - auto breaks_it = polyline.breaks.begin(); - size_t break_end = - breaks_it != polyline.breaks.end() ? *breaks_it : polyline.points.size(); + for (size_t contour_i = 0; contour_i < polyline.contours.size(); + contour_i++) { + size_t contour_start_point_i, contour_end_point_i; + 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. + } - while (point_i < polyline.points.size()) { - if (point_i > 0) { - compute_normals(point_i); + // The first point's normal is always the same as + compute_normal(contour_start_point_i + 1); + const Point contour_first_normal = normal; + if (contour_i > 0) { // This branch only executes when we've just finished drawing a contour // and are switching to a new one. // We're drawing a triangle strip, so we need to "pick up the pen" by // appending transparent vertices between the end of the previous contour // and the beginning of the new contour. - vtx.vertex_position = polyline.points[point_i - 1]; + vtx.vertex_position = polyline.points[contour_start_point_i - 1]; vtx.vertex_normal = {}; vtx.pen_down = 0.0; vtx_builder.AppendVertex(vtx); - vtx.vertex_position = polyline.points[point_i]; + vtx.vertex_position = polyline.points[contour_start_point_i]; vtx_builder.AppendVertex(vtx); } // Generate start cap. - CreateCap(vtx_builder, polyline.points[point_i], -direction); + if (!polyline.contours[contour_i].is_closed) { + CreateCap(vtx_builder, polyline.points[contour_start_point_i], -normal); + } // Generate contour geometry. - size_t contour_point_i = 0; - while (point_i < break_end) { - if (contour_point_i > 0) { - if (contour_point_i > 1) { - // Generate join from the previous line to the current line. - CreateJoin(vtx_builder, polyline.points[point_i - 1], previous_normal, - normal); - } else { - compute_normals(point_i); - } - + for (size_t point_i = contour_start_point_i; point_i < contour_end_point_i; + point_i++) { + if (point_i > contour_start_point_i) { // Generate line rect. vtx.vertex_position = polyline.points[point_i - 1]; vtx.pen_down = 1.0; @@ -393,20 +392,22 @@ static VertexBuffer CreateSolidStrokeVertices(const Path& path, vtx.vertex_normal = -normal; vtx_builder.AppendVertex(vtx); - compute_normals(point_i + 1); - } + if (point_i < contour_end_point_i - 1) { + compute_normal(point_i + 1); - ++contour_point_i; - ++point_i; + // Generate join from the current line to the next line. + CreateJoin(vtx_builder, polyline.points[point_i], previous_normal, + normal); + } + } } - // Generate end cap. - CreateCap(vtx_builder, polyline.points[point_i - 1], -direction); - - if (break_end < polyline.points.size()) { - ++breaks_it; - break_end = breaks_it != polyline.breaks.end() ? *breaks_it - : polyline.points.size(); + // Generate end cap or join. + if (!polyline.contours[contour_i].is_closed) { + CreateCap(vtx_builder, polyline.points[contour_end_point_i - 1], normal); + } else { + CreateJoin(vtx_builder, polyline.points[contour_start_point_i], normal, + contour_first_normal); } } diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 2d551d32ee9f8..c663764512f57 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -149,13 +149,13 @@ TEST(GeometryTest, SimplePath) { .AddQuadraticComponent({100, 100}, {200, 200}, {300, 300}) .AddCubicComponent({300, 300}, {400, 400}, {500, 500}, {600, 600}); - ASSERT_EQ(path.GetComponentCount(), 3u); + ASSERT_EQ(path.GetComponentCount(), 4u); path.EnumerateComponents( [](size_t index, const LinearPathComponent& linear) { Point p1(0, 0); Point p2(100, 100); - ASSERT_EQ(index, 0u); + ASSERT_EQ(index, 1u); ASSERT_EQ(linear.p1, p1); ASSERT_EQ(linear.p2, p2); }, @@ -163,7 +163,7 @@ TEST(GeometryTest, SimplePath) { Point p1(100, 100); Point cp(200, 200); Point p2(300, 300); - ASSERT_EQ(index, 1u); + ASSERT_EQ(index, 2u); ASSERT_EQ(quad.p1, p1); ASSERT_EQ(quad.cp, cp); ASSERT_EQ(quad.p2, p2); @@ -173,13 +173,18 @@ TEST(GeometryTest, SimplePath) { Point cp1(400, 400); Point cp2(500, 500); Point p2(600, 600); - ASSERT_EQ(index, 2u); + ASSERT_EQ(index, 3u); ASSERT_EQ(cubic.p1, p1); ASSERT_EQ(cubic.cp1, cp1); ASSERT_EQ(cubic.cp2, cp2); ASSERT_EQ(cubic.p2, p2); }, - [](size_t index, const MovePathComponent& move) { ASSERT_TRUE(false); }); + [](size_t index, const ContourComponent& contour) { + Point p1(0, 0); + ASSERT_EQ(index, 0u); + ASSERT_EQ(contour.destination, p1); + ASSERT_FALSE(contour.is_closed); + }); } TEST(GeometryTest, BoundingBoxCubic) { @@ -638,15 +643,15 @@ TEST(GeometryTest, CubicPathComponentPolylineDoesNotIncludePointOne) { TEST(GeometryTest, PathCreatePolyLineDoesNotDuplicatePoints) { Path path; - path.AddMoveComponent({10, 10}); + path.AddContourComponent({10, 10}); path.AddLinearComponent({10, 10}, {20, 20}); path.AddLinearComponent({20, 20}, {30, 30}); - path.AddMoveComponent({40, 40}); + path.AddContourComponent({40, 40}); path.AddLinearComponent({40, 40}, {50, 50}); auto polyline = path.CreatePolyline(); - ASSERT_EQ(polyline.breaks.size(), 2u); + ASSERT_EQ(polyline.contours.size(), 2u); ASSERT_EQ(polyline.points.size(), 5u); ASSERT_EQ(polyline.points[0].x, 10); ASSERT_EQ(polyline.points[1].x, 20); @@ -655,5 +660,107 @@ TEST(GeometryTest, PathCreatePolyLineDoesNotDuplicatePoints) { ASSERT_EQ(polyline.points[4].x, 50); } +TEST(GeometryTest, PathBuilderSetsCorrectContourPropertiesForAddCommands) { + // Closed shapes. + { + Path path = PathBuilder{}.AddCircle({100, 100}, 50).TakePath(); + ContourComponent contour; + path.GetContourComponentAtIndex(0, contour); + ASSERT_POINT_NEAR(contour.destination, Point(100, 50)); + ASSERT_TRUE(contour.is_closed); + } + + { + Path path = PathBuilder{}.AddOval(Rect(100, 100, 100, 100)).TakePath(); + ContourComponent contour; + path.GetContourComponentAtIndex(0, contour); + ASSERT_POINT_NEAR(contour.destination, Point(150, 100)); + ASSERT_TRUE(contour.is_closed); + } + + { + Path path = PathBuilder{}.AddRect(Rect(100, 100, 100, 100)).TakePath(); + ContourComponent contour; + path.GetContourComponentAtIndex(0, contour); + ASSERT_POINT_NEAR(contour.destination, Point(100, 100)); + ASSERT_TRUE(contour.is_closed); + } + + { + Path path = + PathBuilder{}.AddRoundedRect(Rect(100, 100, 100, 100), 10).TakePath(); + ContourComponent contour; + path.GetContourComponentAtIndex(0, contour); + ASSERT_POINT_NEAR(contour.destination, Point(110, 100)); + ASSERT_TRUE(contour.is_closed); + } + + // Open shapes. + { + Point p(100, 100); + Path path = PathBuilder{}.AddLine(p, {200, 100}).TakePath(); + ContourComponent contour; + path.GetContourComponentAtIndex(0, contour); + ASSERT_POINT_NEAR(contour.destination, p); + ASSERT_FALSE(contour.is_closed); + } + + { + Path path = + PathBuilder{} + .AddCubicCurve({100, 100}, {100, 50}, {100, 150}, {200, 100}) + .TakePath(); + ContourComponent contour; + path.GetContourComponentAtIndex(0, contour); + ASSERT_POINT_NEAR(contour.destination, Point(100, 100)); + ASSERT_FALSE(contour.is_closed); + } + + { + Path path = PathBuilder{} + .AddQuadraticCurve({100, 100}, {100, 50}, {200, 100}) + .TakePath(); + ContourComponent contour; + path.GetContourComponentAtIndex(0, contour); + ASSERT_POINT_NEAR(contour.destination, Point(100, 100)); + ASSERT_FALSE(contour.is_closed); + } +} + +TEST(GeometryTest, PathCreatePolylineGeneratesCorrectContourData) { + Path::Polyline polyline = PathBuilder{} + .AddLine({100, 100}, {200, 100}) + .MoveTo({100, 200}) + .LineTo({150, 250}) + .LineTo({200, 200}) + .Close() + .TakePath() + .CreatePolyline(); + ASSERT_EQ(polyline.points.size(), 6u); + ASSERT_EQ(polyline.contours.size(), 2u); + ASSERT_EQ(polyline.contours[0].is_closed, false); + ASSERT_EQ(polyline.contours[0].start_index, 0u); + ASSERT_EQ(polyline.contours[1].is_closed, true); + ASSERT_EQ(polyline.contours[1].start_index, 2u); +} + +TEST(GeometryTest, PolylineGetContourPointBoundsReturnsCorrectRanges) { + Path::Polyline polyline = PathBuilder{} + .AddLine({100, 100}, {200, 100}) + .MoveTo({100, 200}) + .LineTo({150, 250}) + .LineTo({200, 200}) + .Close() + .TakePath() + .CreatePolyline(); + size_t a1, a2, b1, b2; + std::tie(a1, a2) = polyline.GetContourPointBounds(0); + std::tie(b1, b2) = polyline.GetContourPointBounds(1); + ASSERT_EQ(a1, 0u); + ASSERT_EQ(a2, 2u); + ASSERT_EQ(b1, 2u); + ASSERT_EQ(b2, 6u); +} + } // namespace testing } // namespace impeller diff --git a/impeller/geometry/path.cc b/impeller/geometry/path.cc index 4bacb04ea9bb0..3a31ac61b96d7 100644 --- a/impeller/geometry/path.cc +++ b/impeller/geometry/path.cc @@ -6,12 +6,28 @@ #include +#include "flutter/fml/logging.h" +#include "impeller/geometry/path_component.h" + namespace impeller { -Path::Path() = default; +Path::Path() { + AddContourComponent({}); +}; Path::~Path() = default; +std::tuple Path::Polyline::GetContourPointBounds( + size_t contour_index) const { + FML_DCHECK(contour_index < contours.size()); + + const size_t start_index = contours[contour_index].start_index; + const size_t end_index = (contour_index >= contours.size() - 1) + ? points.size() + : contours[contour_index + 1].start_index; + return std::make_tuple(start_index, end_index); +} + size_t Path::GetComponentCount() const { return components_.size(); } @@ -42,16 +58,27 @@ Path& Path::AddCubicComponent(Point p1, Point cp1, Point cp2, Point p2) { return *this; } -Path& Path::AddMoveComponent(Point destination) { - moves_.emplace_back(destination); - components_.emplace_back(ComponentType::kMove, moves_.size() - 1); +Path& Path::AddContourComponent(Point destination, bool is_closed) { + if (components_.size() > 0 && + components_.back().type == ComponentType::kContour) { + // Never insert contiguous contours. + contours_.back() = ContourComponent(destination, is_closed); + } else { + contours_.emplace_back(ContourComponent(destination, is_closed)); + components_.emplace_back(ComponentType::kContour, contours_.size() - 1); + } return *this; } -void Path::EnumerateComponents(Applier linear_applier, - Applier quad_applier, - Applier cubic_applier, - Applier move_applier) const { +void Path::SetContourClosed(bool is_closed) { + contours_.back().is_closed = is_closed; +} + +void Path::EnumerateComponents( + Applier linear_applier, + Applier quad_applier, + Applier cubic_applier, + Applier contour_applier) const { size_t currentIndex = 0; for (const auto& component : components_) { switch (component.type) { @@ -70,9 +97,9 @@ void Path::EnumerateComponents(Applier linear_applier, cubic_applier(currentIndex, cubics_[component.index]); } break; - case ComponentType::kMove: - if (move_applier) { - move_applier(currentIndex, moves_[component.index]); + case ComponentType::kContour: + if (contour_applier) { + contour_applier(currentIndex, contours_[component.index]); } break; } @@ -123,17 +150,17 @@ bool Path::GetCubicComponentAtIndex(size_t index, return true; } -bool Path::GetMoveComponentAtIndex(size_t index, - MovePathComponent& move) const { +bool Path::GetContourComponentAtIndex(size_t index, + ContourComponent& move) const { if (index >= components_.size()) { return false; } - if (components_[index].type != ComponentType::kMove) { + if (components_[index].type != ComponentType::kContour) { return false; } - move = moves_[components_[index].index]; + move = contours_[components_[index].index]; return true; } @@ -180,38 +207,32 @@ bool Path::UpdateCubicComponentAtIndex(size_t index, return true; } -bool Path::UpdateMoveComponentAtIndex(size_t index, - const MovePathComponent& move) { +bool Path::UpdateContourComponentAtIndex(size_t index, + const ContourComponent& move) { if (index >= components_.size()) { return false; } - if (components_[index].type != ComponentType::kMove) { + if (components_[index].type != ComponentType::kContour) { return false; } - moves_[components_[index].index] = move; + contours_[components_[index].index] = move; return true; } Path::Polyline Path::CreatePolyline( const SmoothingApproximation& approximation) const { Polyline polyline; - // TODO(99177): Refactor this to have component polyline creation always - // exclude the first point, and append the destination point for - // move components. See issue for details. - bool new_contour = true; - auto collect_points = [&polyline, - &new_contour](const std::vector& collection) { - size_t offset = new_contour ? 0 : 1; - new_contour = false; - - polyline.points.reserve(polyline.points.size() + collection.size() - - offset); - polyline.points.insert(polyline.points.end(), collection.begin() + offset, + auto collect_points = [&polyline](const std::vector& collection) { + polyline.points.reserve(polyline.points.size() + collection.size()); + polyline.points.insert(polyline.points.end(), collection.begin(), collection.end()); }; - for (const auto& component : components_) { + // for (const auto& component : components_) { + for (size_t component_i = 0; component_i < components_.size(); + component_i++) { + const auto& component = components_[component_i]; switch (component.type) { case ComponentType::kLinear: collect_points(linears_[component.index].CreatePolyline()); @@ -222,9 +243,16 @@ Path::Polyline Path::CreatePolyline( case ComponentType::kCubic: collect_points(cubics_[component.index].CreatePolyline(approximation)); break; - case ComponentType::kMove: - polyline.breaks.insert(polyline.points.size()); - new_contour = true; + case ComponentType::kContour: + if (component_i == components_.size() - 1) { + // If the last component is a contour, that means it's an empty + // contour, so skip it. + continue; + } + const auto& contour = contours_[component.index]; + polyline.contours.push_back({.start_index = polyline.points.size(), + .is_closed = contour.is_closed}); + collect_points({contour.destination}); break; } } diff --git a/impeller/geometry/path.h b/impeller/geometry/path.h index 450000e896f3e..061664742f4a6 100644 --- a/impeller/geometry/path.h +++ b/impeller/geometry/path.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "impeller/geometry/path_component.h" @@ -39,7 +40,15 @@ class Path { kLinear, kQuadratic, kCubic, - kMove, + kContour, + }; + + struct PolylineContour { + /// Index that denotes the first point of this contour. + size_t start_index; + /// Denotes whether the last point of this contour is connected to the first + /// point of this contour or not. + bool is_closed; }; /// One or more contours represented as a series of points and indices in @@ -48,8 +57,12 @@ class Path { /// Points in the polyline, which may represent multiple contours specified /// by indices in |breaks|. std::vector points; - /// Indices of points that end a subcontour. - std::set breaks; + std::vector contours; + + /// Convenience method to compute the start (inclusive) and end (exclusive) + /// point of the given contour index. + std::tuple GetContourPointBounds( + size_t contour_index) const; }; Path(); @@ -68,14 +81,16 @@ class Path { Path& AddCubicComponent(Point p1, Point cp1, Point cp2, Point p2); - Path& AddMoveComponent(Point destination); + Path& AddContourComponent(Point destination, bool is_closed = false); + + void SetContourClosed(bool is_closed); template using Applier = std::function; - void EnumerateComponents(Applier linearApplier, - Applier quadApplier, - Applier cubicApplier, - Applier moveApplier) const; + void EnumerateComponents(Applier linear_applier, + Applier quad_applier, + Applier cubic_applier, + Applier contour_applier) const; bool GetLinearComponentAtIndex(size_t index, LinearPathComponent& linear) const; @@ -85,7 +100,8 @@ class Path { bool GetCubicComponentAtIndex(size_t index, CubicPathComponent& cubic) const; - bool GetMoveComponentAtIndex(size_t index, MovePathComponent& move) const; + bool GetContourComponentAtIndex(size_t index, + ContourComponent& contour) const; bool UpdateLinearComponentAtIndex(size_t index, const LinearPathComponent& linear); @@ -95,7 +111,8 @@ class Path { bool UpdateCubicComponentAtIndex(size_t index, CubicPathComponent& cubic); - bool UpdateMoveComponentAtIndex(size_t index, const MovePathComponent& move); + bool UpdateContourComponentAtIndex(size_t index, + const ContourComponent& contour); Polyline CreatePolyline( const SmoothingApproximation& approximation = {}) const; @@ -111,8 +128,8 @@ class Path { ComponentIndexPair() {} - ComponentIndexPair(ComponentType aType, size_t aIndex) - : type(aType), index(aIndex) {} + ComponentIndexPair(ComponentType a_type, size_t a_index) + : type(a_type), index(a_index) {} }; FillType fill_ = FillType::kNonZero; @@ -120,7 +137,7 @@ class Path { std::vector linears_; std::vector quads_; std::vector cubics_; - std::vector moves_; + std::vector contours_; }; } // namespace impeller diff --git a/impeller/geometry/path_builder.cc b/impeller/geometry/path_builder.cc index aba307b0893bf..1e97b52afba6f 100644 --- a/impeller/geometry/path_builder.cc +++ b/impeller/geometry/path_builder.cc @@ -27,12 +27,14 @@ Path PathBuilder::TakePath(FillType fill) { PathBuilder& PathBuilder::MoveTo(Point point, bool relative) { current_ = relative ? current_ + point : point; subpath_start_ = current_; - prototype_.AddMoveComponent(current_); + prototype_.AddContourComponent(current_); return *this; } PathBuilder& PathBuilder::Close() { LineTo(subpath_start_); + prototype_.SetContourClosed(true); + prototype_.AddContourComponent(current_); return *this; } @@ -152,6 +154,7 @@ PathBuilder& PathBuilder::SmoothCubicCurveTo(Point controlPoint2, } PathBuilder& PathBuilder::AddQuadraticCurve(Point p1, Point cp, Point p2) { + MoveTo(p1); prototype_.AddQuadraticComponent(p1, cp, p2); return *this; } @@ -160,6 +163,7 @@ PathBuilder& PathBuilder::AddCubicCurve(Point p1, Point cp1, Point cp2, Point p2) { + MoveTo(p1); prototype_.AddCubicComponent(p1, cp1, cp2, p2); return *this; } @@ -172,10 +176,12 @@ PathBuilder& PathBuilder::AddRect(Rect rect) { auto br = rect.origin + Point{rect.size.width, rect.size.height}; auto tr = rect.origin + Point{rect.size.width, 0.0}; + MoveTo(tl); prototype_.AddLinearComponent(tl, tr) .AddLinearComponent(tr, br) .AddLinearComponent(br, bl) .AddLinearComponent(bl, tl); + Close(); return *this; } @@ -201,6 +207,8 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) { const auto magic_bottom_left = radii.bottom_left * kArcApproximationMagic; const auto magic_top_left = radii.top_left * kArcApproximationMagic; + MoveTo({rect.origin.x + radii.top_left.x, rect.origin.y}); + //---------------------------------------------------------------------------- // Top line. // @@ -277,6 +285,8 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) { {rect.origin.x + radii.top_left.x - magic_top_left.x, rect.origin.y}, {rect.origin.x + radii.top_left.x, rect.origin.y}); + Close(); + return *this; } @@ -286,6 +296,8 @@ PathBuilder& PathBuilder::AddOval(const Rect& container) { container.origin.y + (container.size.height * 0.5f)}; const Point m = {kArcApproximationMagic * r.x, kArcApproximationMagic * r.y}; + MoveTo({c.x, c.y - r.y}); + //---------------------------------------------------------------------------- // Top right arc. // @@ -322,10 +334,13 @@ PathBuilder& PathBuilder::AddOval(const Rect& container) { {c.x, c.y - r.y} // p2 ); + Close(); + return *this; } PathBuilder& PathBuilder::AddLine(const Point& p1, const Point& p2) { + MoveTo(p1); prototype_.AddLinearComponent(p1, p2); return *this; } @@ -344,8 +359,8 @@ PathBuilder& PathBuilder::AddPath(const Path& path) { auto cubic = [&](size_t index, const CubicPathComponent& c) { prototype_.AddCubicComponent(c.p1, c.cp1, c.cp2, c.p2); }; - auto move = [&](size_t index, const MovePathComponent& m) { - prototype_.AddMoveComponent(m.destination); + auto move = [&](size_t index, const ContourComponent& m) { + prototype_.AddContourComponent(m.destination); }; path.EnumerateComponents(linear, quadratic, cubic, move); return *this; diff --git a/impeller/geometry/path_component.cc b/impeller/geometry/path_component.cc index 919a14c939b6c..eb842e509e9c1 100644 --- a/impeller/geometry/path_component.cc +++ b/impeller/geometry/path_component.cc @@ -64,7 +64,7 @@ Point LinearPathComponent::Solve(Scalar time) const { } std::vector LinearPathComponent::CreatePolyline() const { - return {p1, p2}; + return {p2}; } std::vector LinearPathComponent::Extrema() const { diff --git a/impeller/geometry/path_component.h b/impeller/geometry/path_component.h index c9f03ddad8db4..60331ef899232 100644 --- a/impeller/geometry/path_component.h +++ b/impeller/geometry/path_component.h @@ -107,15 +107,17 @@ struct CubicPathComponent { } }; -struct MovePathComponent { +struct ContourComponent { Point destination; + bool is_closed; - MovePathComponent() {} + ContourComponent() {} - MovePathComponent(Point p) : destination(p) {} + ContourComponent(Point p, bool is_closed = false) + : destination(p), is_closed(is_closed) {} - bool operator==(const MovePathComponent& other) const { - return destination == other.destination; + bool operator==(const ContourComponent& other) const { + return destination == other.destination && is_closed == other.is_closed; } }; diff --git a/impeller/renderer/tessellator.cc b/impeller/renderer/tessellator.cc index d98225d54f6d5..44f18306e0bb8 100644 --- a/impeller/renderer/tessellator.cc +++ b/impeller/renderer/tessellator.cc @@ -36,7 +36,7 @@ static void DestroyTessellator(TESStesselator* tessellator) { } } -bool Tessellator::Tessellate(const Path::Polyline& contours, +bool Tessellator::Tessellate(const Path::Polyline& polyline, VertexCallback callback) const { TRACE_EVENT0("impeller", "Tessellator::Tessellate"); if (!callback) { @@ -61,24 +61,18 @@ bool Tessellator::Tessellate(const Path::Polyline& contours, /// Feed contour information to the tessellator. /// static_assert(sizeof(Point) == 2 * sizeof(float)); - size_t start_point_index = 0; - for (size_t end_point_index : contours.breaks) { - end_point_index = std::min(end_point_index, contours.points.size()); + for (size_t contour_i = 0; contour_i < polyline.contours.size(); + contour_i++) { + size_t start_point_index, end_point_index; + std::tie(start_point_index, end_point_index) = + polyline.GetContourPointBounds(contour_i); + ::tessAddContour(tessellator.get(), // the C tessellator kVertexSize, // - contours.points.data() + start_point_index, // + polyline.points.data() + start_point_index, // sizeof(Point), // end_point_index - start_point_index // ); - start_point_index = end_point_index; - } - if (start_point_index < contours.points.size()) { - ::tessAddContour(tessellator.get(), // the C tessellator - kVertexSize, // - contours.points.data() + start_point_index, // - sizeof(Point), // - contours.points.size() - start_point_index // - ); } //----------------------------------------------------------------------------