diff --git a/engine/src/flutter/impeller/geometry/geometry_unittests.cc b/engine/src/flutter/impeller/geometry/geometry_unittests.cc index 3ec5d5ab992..ef431240f69 100644 --- a/engine/src/flutter/impeller/geometry/geometry_unittests.cc +++ b/engine/src/flutter/impeller/geometry/geometry_unittests.cc @@ -853,5 +853,12 @@ TEST(GeometryTest, PolylineGetContourPointBoundsReturnsCorrectRanges) { ASSERT_EQ(b2, 6u); } +TEST(GeometryTest, PolylineGetContourOutOfBoundsAborts) { + Path::Polyline polyline = + PathBuilder{}.AddLine({100, 100}, {200, 100}).TakePath().CreatePolyline(); + ASSERT_EQ(polyline.GetContourPointBounds(0), std::make_tuple(2u, 2u)); + ASSERT_EQ(polyline.GetContourPointBounds(14), std::make_tuple(2u, 2u)); +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/geometry/path.cc b/engine/src/flutter/impeller/geometry/path.cc index 98196946170..d74a15fe4b8 100644 --- a/engine/src/flutter/impeller/geometry/path.cc +++ b/engine/src/flutter/impeller/geometry/path.cc @@ -18,10 +18,13 @@ Path::~Path() = default; std::tuple Path::Polyline::GetContourPointBounds( size_t contour_index) const { - const size_t start_index = contours[contour_index].start_index; + if (contour_index >= contours.size()) { + return {points.size(), points.size()}; + } + const size_t start_index = contours.at(contour_index).start_index; const size_t end_index = (contour_index >= contours.size() - 1) ? points.size() - : contours[contour_index + 1].start_index; + : contours.at(contour_index + 1).start_index; return std::make_tuple(start_index, end_index); } diff --git a/engine/src/flutter/impeller/geometry/path.h b/engine/src/flutter/impeller/geometry/path.h index 061664742f4..7add50e1783 100644 --- a/engine/src/flutter/impeller/geometry/path.h +++ b/engine/src/flutter/impeller/geometry/path.h @@ -61,6 +61,8 @@ class Path { /// Convenience method to compute the start (inclusive) and end (exclusive) /// point of the given contour index. + /// + /// The contour_index parameter is clamped to contours.size(). std::tuple GetContourPointBounds( size_t contour_index) const; }; diff --git a/engine/src/flutter/impeller/renderer/tessellator.cc b/engine/src/flutter/impeller/renderer/tessellator.cc deleted file mode 100644 index eb8bb3ec43a..00000000000 --- a/engine/src/flutter/impeller/renderer/tessellator.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "impeller/tessellator/tessellator.h" - -#include "flutter/fml/logging.h" -#include "flutter/fml/trace_event.h" -#include "third_party/libtess2/Include/tesselator.h" - -namespace impeller { - -Tessellator::Tessellator(FillType type) : fill_type_(type) {} - -Tessellator::~Tessellator() = default; - -static int ToTessWindingRule(FillType fill_type) { - switch (fill_type) { - case FillType::kOdd: - return TESS_WINDING_ODD; - case FillType::kNonZero: - return TESS_WINDING_NONZERO; - case FillType::kPositive: - return TESS_WINDING_POSITIVE; - case FillType::kNegative: - return TESS_WINDING_NEGATIVE; - case FillType::kAbsGeqTwo: - return TESS_WINDING_ABS_GEQ_TWO; - } - return TESS_WINDING_ODD; -} - -static void DestroyTessellator(TESStesselator* tessellator) { - if (tessellator != nullptr) { - ::tessDeleteTess(tessellator); - } -} - -bool Tessellator::Tessellate(const Path::Polyline& polyline, - VertexCallback callback) const { - TRACE_EVENT0("impeller", "Tessellator::Tessellate"); - if (!callback) { - return false; - } - - using CTessellator = - std::unique_ptr; - - CTessellator tessellator( - ::tessNewTess(nullptr /* the default ::malloc based allocator */), - DestroyTessellator); - - if (!tessellator) { - return false; - } - - constexpr int kVertexSize = 2; - constexpr int kPolygonSize = 3; - - //---------------------------------------------------------------------------- - /// Feed contour information to the tessellator. - /// - static_assert(sizeof(Point) == 2 * sizeof(float)); - 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, // - polyline.points.data() + start_point_index, // - sizeof(Point), // - end_point_index - start_point_index // - ); - } - - //---------------------------------------------------------------------------- - /// Let's tessellate. - /// - auto result = ::tessTesselate(tessellator.get(), // tessellator - ToTessWindingRule(fill_type_), // winding - TESS_POLYGONS, // element type - kPolygonSize, // polygon size - kVertexSize, // vertex size - nullptr // normal (null is automatic) - ); - - if (result != 1) { - return false; - } - - // TODO(csg): This copy can be elided entirely for the current use case. - std::vector points; - std::vector indices; - - int vertexItemCount = tessGetVertexCount(tessellator.get()) * kVertexSize; - auto vertices = tessGetVertices(tessellator.get()); - for (int i = 0; i < vertexItemCount; i += 2) { - points.emplace_back(vertices[i], vertices[i + 1]); - } - - int elementItemCount = tessGetElementCount(tessellator.get()) * kPolygonSize; - auto elements = tessGetElements(tessellator.get()); - for (int i = 0; i < elementItemCount; i++) { - indices.emplace_back(elements[i]); - } - - for (auto index : indices) { - auto vtx = points[index]; - callback(vtx); - } - - return true; -} - -WindingOrder Tessellator::GetFrontFaceWinding() const { - return WindingOrder::kClockwise; -} - -} // namespace impeller