mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Make Path::Polyline::GetContourPointBounds safe for OOB (flutter/engine#60)
This commit is contained in:
parent
6fc72b98a7
commit
45f8edd2a7
@ -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
|
||||
|
||||
@ -18,10 +18,13 @@ Path::~Path() = default;
|
||||
|
||||
std::tuple<size_t, size_t> 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);
|
||||
}
|
||||
|
||||
|
||||
@ -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<size_t, size_t> GetContourPointBounds(
|
||||
size_t contour_index) const;
|
||||
};
|
||||
|
||||
@ -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<TESStesselator, decltype(&DestroyTessellator)>;
|
||||
|
||||
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<Point> points;
|
||||
std::vector<uint32_t> 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
|
||||
Loading…
x
Reference in New Issue
Block a user