Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 5d13a29

Browse files
author
Jonah Williams
authored
[Impeller] render empty filled paths without crashing. (#51713)
Fixes flutter/flutter#145823 If we try to render a solid filled empty size path, the subpath division code creates an obscene number of vertices that hits overflow errors. Just No-op instead.
1 parent f31faf3 commit 5d13a29

File tree

5 files changed

+88
-2
lines changed

5 files changed

+88
-2
lines changed

impeller/entity/contents/color_source_contents.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ class ColorSourceContents : public Contents {
137137

138138
GeometryResult stencil_geometry_result =
139139
GetGeometry()->GetPositionBuffer(renderer, entity, pass);
140+
if (stencil_geometry_result.vertex_buffer.vertex_count == 0u) {
141+
return true;
142+
}
140143
pass.SetVertexBuffer(std::move(stencil_geometry_result.vertex_buffer));
141144
options.primitive_type = stencil_geometry_result.type;
142145

@@ -182,6 +185,9 @@ class ColorSourceContents : public Contents {
182185
? geometry.GetPositionUVBuffer(texture_coverage, effect_transform,
183186
renderer, entity, pass)
184187
: geometry.GetPositionBuffer(renderer, entity, pass);
188+
if (geometry_result.vertex_buffer.vertex_count == 0u) {
189+
return true;
190+
}
185191
pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
186192
options.primitive_type = geometry_result.type;
187193

impeller/entity/entity_unittests.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2813,6 +2813,51 @@ TEST_P(EntityTest, FailOnValidationError) {
28132813
"");
28142814
}
28152815

2816+
TEST_P(EntityTest, CanComputeGeometryForEmptyPathsWithoutCrashing) {
2817+
PathBuilder builder = {};
2818+
builder.AddRect(Rect::MakeLTRB(0, 0, 0, 0));
2819+
Path path = builder.TakePath();
2820+
2821+
EXPECT_TRUE(path.GetBoundingBox()->IsEmpty());
2822+
2823+
auto geom = Geometry::MakeFillPath(path);
2824+
2825+
Entity entity;
2826+
RenderTarget target =
2827+
GetContentContext()->GetRenderTargetCache()->CreateOffscreen(
2828+
*GetContext(), {1, 1}, 1u);
2829+
testing::MockRenderPass render_pass(GetContext(), target);
2830+
auto position_result =
2831+
geom->GetPositionBuffer(*GetContentContext(), entity, render_pass);
2832+
2833+
auto uv_result =
2834+
geom->GetPositionUVBuffer(Rect::MakeLTRB(0, 0, 100, 100), Matrix(),
2835+
*GetContentContext(), entity, render_pass);
2836+
2837+
EXPECT_EQ(position_result.vertex_buffer.vertex_count, 0u);
2838+
EXPECT_EQ(uv_result.vertex_buffer.vertex_count, 0u);
2839+
2840+
EXPECT_EQ(geom->GetResultMode(), GeometryResult::Mode::kNormal);
2841+
}
2842+
2843+
TEST_P(EntityTest, CanRenderEmptyPathsWithoutCrashing) {
2844+
PathBuilder builder = {};
2845+
builder.AddRect(Rect::MakeLTRB(0, 0, 0, 0));
2846+
Path path = builder.TakePath();
2847+
2848+
EXPECT_TRUE(path.GetBoundingBox()->IsEmpty());
2849+
2850+
auto contents = std::make_shared<SolidColorContents>();
2851+
contents->SetGeometry(Geometry::MakeFillPath(path));
2852+
contents->SetColor(Color::Red());
2853+
2854+
Entity entity;
2855+
entity.SetTransform(Matrix::MakeScale(GetContentScale()));
2856+
entity.SetContents(contents);
2857+
2858+
ASSERT_TRUE(OpenPlaygroundHere(std::move(entity)));
2859+
}
2860+
28162861
} // namespace testing
28172862
} // namespace impeller
28182863

impeller/entity/geometry/fill_path_geometry.cc

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "fml/logging.h"
88
#include "impeller/core/formats.h"
9+
#include "impeller/core/vertex_buffer.h"
910
#include "impeller/entity/contents/content_context.h"
1011
#include "impeller/entity/geometry/geometry.h"
1112

@@ -20,8 +21,22 @@ GeometryResult FillPathGeometry::GetPositionBuffer(
2021
const Entity& entity,
2122
RenderPass& pass) const {
2223
auto& host_buffer = renderer.GetTransientsBuffer();
23-
VertexBuffer vertex_buffer;
2424

25+
const auto& bounding_box = path_.GetBoundingBox();
26+
if (bounding_box.has_value() && bounding_box->IsEmpty()) {
27+
return GeometryResult{
28+
.type = PrimitiveType::kTriangle,
29+
.vertex_buffer =
30+
VertexBuffer{
31+
.vertex_buffer = {},
32+
.vertex_count = 0,
33+
.index_type = IndexType::k16bit,
34+
},
35+
.transform = pass.GetOrthographicTransform() * entity.GetTransform(),
36+
};
37+
}
38+
39+
VertexBuffer vertex_buffer;
2540
if constexpr (!ContentContext::kEnableStencilThenCover) {
2641
if (!path_.IsConvex()) {
2742
auto tesselation_result = renderer.GetTessellator()->Tessellate(
@@ -79,6 +94,20 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer(
7994
RenderPass& pass) const {
8095
using VS = TextureFillVertexShader;
8196

97+
const auto& bounding_box = path_.GetBoundingBox();
98+
if (bounding_box.has_value() && bounding_box->IsEmpty()) {
99+
return GeometryResult{
100+
.type = PrimitiveType::kTriangle,
101+
.vertex_buffer =
102+
VertexBuffer{
103+
.vertex_buffer = {},
104+
.vertex_count = 0,
105+
.index_type = IndexType::k16bit,
106+
},
107+
.transform = pass.GetOrthographicTransform() * entity.GetTransform(),
108+
};
109+
}
110+
82111
auto uv_transform =
83112
texture_coverage.GetNormalizingTransform() * effect_transform;
84113

@@ -139,7 +168,9 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer(
139168
}
140169

141170
GeometryResult::Mode FillPathGeometry::GetResultMode() const {
142-
if (!ContentContext::kEnableStencilThenCover || path_.IsConvex()) {
171+
const auto& bounding_box = path_.GetBoundingBox();
172+
if (!ContentContext::kEnableStencilThenCover || path_.IsConvex() ||
173+
(bounding_box.has_value() && bounding_box->IsEmpty())) {
143174
return GeometryResult::Mode::kNormal;
144175
}
145176

impeller/entity/geometry/geometry_unittests.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include <memory>
56
#include "flutter/testing/testing.h"
7+
#include "impeller/entity/contents/content_context.h"
68
#include "impeller/entity/geometry/geometry.h"
79
#include "impeller/entity/geometry/stroke_path_geometry.h"
810
#include "impeller/geometry/geometry_asserts.h"
911
#include "impeller/geometry/path_builder.h"
12+
#include "impeller/renderer/testing/mocks.h"
1013

1114
inline ::testing::AssertionResult SolidVerticesNear(
1215
std::vector<impeller::SolidFillVertexShader::PerVertexData> a,

impeller/tessellator/tessellator.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ Path::Polyline Tessellator::CreateTempPolyline(const Path& path,
179179
std::vector<Point> Tessellator::TessellateConvex(const Path& path,
180180
Scalar tolerance) {
181181
FML_DCHECK(point_buffer_);
182+
182183
std::vector<Point> output;
183184
point_buffer_->clear();
184185
auto polyline =

0 commit comments

Comments
 (0)