| Flutter Impeller |

geometry_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <memory>
6 #include "flutter/testing/testing.h"
7 #include "impeller/entity/contents/content_context.h"
8 #include "impeller/entity/geometry/geometry.h"
9 #include "impeller/entity/geometry/stroke_path_geometry.h"
10 #include "impeller/geometry/geometry_asserts.h"
11 #include "impeller/geometry/path_builder.h"
12 #include "impeller/renderer/testing/mocks.h"
13
14 inline ::testing::AssertionResult SolidVerticesNear(
15 std::vector<impeller::SolidFillVertexShader::PerVertexData> a,
16 std::vector<impeller::SolidFillVertexShader::PerVertexData> b) {
17 if (a.size() != b.size()) {
18 return ::testing::AssertionFailure() << "Colors length does not match";
19 }
20 for (auto i = 0u; i < b.size(); i++) {
21 if (!PointNear(a[i].position, b[i].position)) {
22 return ::testing::AssertionFailure() << "Positions are not equal.";
23 }
24 }
25 return ::testing::AssertionSuccess();
26 }
27
28 inline ::testing::AssertionResult TextureVerticesNear(
29 std::vector<impeller::TextureFillVertexShader::PerVertexData> a,
30 std::vector<impeller::TextureFillVertexShader::PerVertexData> b) {
31 if (a.size() != b.size()) {
32 return ::testing::AssertionFailure() << "Colors length does not match";
33 }
34 for (auto i = 0u; i < b.size(); i++) {
35 if (!PointNear(a[i].position, b[i].position)) {
36 return ::testing::AssertionFailure() << "Positions are not equal.";
37 }
38 if (!PointNear(a[i].texture_coords, b[i].texture_coords)) {
39 return ::testing::AssertionFailure() << "Texture coords are not equal.";
40 }
41 }
42 return ::testing::AssertionSuccess();
43 }
44
45 #define EXPECT_SOLID_VERTICES_NEAR(a, b) \
46 EXPECT_PRED2(&::SolidVerticesNear, a, b)
47 #define EXPECT_TEXTURE_VERTICES_NEAR(a, b) \
48 EXPECT_PRED2(&::TextureVerticesNear, a, b)
49
50 namespace impeller {
51
52 class ImpellerEntityUnitTestAccessor {
53 public:
54 static std::vector<SolidFillVertexShader::PerVertexData>
55 GenerateSolidStrokeVertices(const Path::Polyline& polyline,
56 Scalar stroke_width,
57 Scalar miter_limit,
58 Join stroke_join,
59 Cap stroke_cap,
60 Scalar scale) {
61 return StrokePathGeometry::GenerateSolidStrokeVertices(
62 polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale);
63 }
64
65 static std::vector<TextureFillVertexShader::PerVertexData>
66 GenerateSolidStrokeVerticesUV(const Path::Polyline& polyline,
67 Scalar stroke_width,
68 Scalar miter_limit,
69 Join stroke_join,
70 Cap stroke_cap,
71 Scalar scale,
72 Point texture_origin,
73 Size texture_size,
74 const Matrix& effect_transform) {
75 return StrokePathGeometry::GenerateSolidStrokeVerticesUV(
76 polyline, stroke_width, miter_limit, stroke_join, stroke_cap, scale,
77 texture_origin, texture_size, effect_transform);
78 }
79 };
80
81 namespace testing {
82
83 TEST(EntityGeometryTest, RectGeometryCoversArea) {
84 auto geometry = Geometry::MakeRect(Rect::MakeLTRB(0, 0, 100, 100));
85 ASSERT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(0, 0, 100, 100)));
86 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(-1, 0, 100, 100)));
87 ASSERT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 1, 100, 100)));
88 ASSERT_TRUE(geometry->CoversArea({}, Rect()));
89 }
90
91 TEST(EntityGeometryTest, FillPathGeometryCoversArea) {
92 auto path = PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 100, 100)).TakePath();
93 auto geometry = Geometry::MakeFillPath(
94 path, /* inner rect */ Rect::MakeLTRB(0, 0, 100, 100));
95 ASSERT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(0, 0, 100, 100)));
96 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(-1, 0, 100, 100)));
97 ASSERT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 1, 100, 100)));
98 ASSERT_TRUE(geometry->CoversArea({}, Rect()));
99 }
100
101 TEST(EntityGeometryTest, FillPathGeometryCoversAreaNoInnerRect) {
102 auto path = PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 100, 100)).TakePath();
103 auto geometry = Geometry::MakeFillPath(path);
104 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(0, 0, 100, 100)));
105 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(-1, 0, 100, 100)));
106 ASSERT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(1, 1, 100, 100)));
107 ASSERT_FALSE(geometry->CoversArea({}, Rect()));
108 }
109
110 TEST(EntityGeometryTest, LineGeometryCoverage) {
111 {
112 auto geometry = Geometry::MakeLine({10, 10}, {20, 10}, 2, Cap::kButt);
113 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(10, 9, 20, 11));
114 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(10, 9, 20, 11)));
115 }
116
117 {
118 auto geometry = Geometry::MakeLine({10, 10}, {20, 10}, 2, Cap::kSquare);
119 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 9, 21, 11));
120 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(9, 9, 21, 11)));
121 }
122
123 {
124 auto geometry = Geometry::MakeLine({10, 10}, {10, 20}, 2, Cap::kButt);
125 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 10, 11, 20));
126 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(9, 10, 11, 20)));
127 }
128
129 {
130 auto geometry = Geometry::MakeLine({10, 10}, {10, 20}, 2, Cap::kSquare);
131 EXPECT_EQ(geometry->GetCoverage({}), Rect::MakeLTRB(9, 9, 11, 21));
132 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(9, 9, 11, 21)));
133 }
134 }
135
136 TEST(EntityGeometryTest, RoundRectGeometryCoversArea) {
137 auto geometry =
138 Geometry::MakeRoundRect(Rect::MakeLTRB(0, 0, 100, 100), Size(20, 20));
139 EXPECT_FALSE(geometry->CoversArea({}, Rect::MakeLTRB(15, 15, 85, 85)));
140 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(20, 20, 80, 80)));
141 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(30, 1, 70, 99)));
142 EXPECT_TRUE(geometry->CoversArea({}, Rect::MakeLTRB(1, 30, 99, 70)));
143 }
144
145 TEST(EntityGeometryTest, StrokePathGeometryTransformOfLine) {
146 auto path =
147 PathBuilder().AddLine(Point(100, 100), Point(200, 100)).TakePath();
148 auto points = std::make_unique<std::vector<Point>>();
149 auto polyline =
150 path.CreatePolyline(1.0f, std::move(points),
151 [&points](Path::Polyline::PointBufferPtr reclaimed) {
152 points = std::move(reclaimed);
153 });
154
155 auto vertices = ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices(
156 polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0);
157
158 std::vector<SolidFillVertexShader::PerVertexData> expected = {
159 {.position = Point(100.0f, 105.0f)}, //
160 {.position = Point(100.0f, 95.0f)}, //
161 {.position = Point(100.0f, 105.0f)}, //
162 {.position = Point(100.0f, 95.0f)}, //
163 {.position = Point(200.0f, 105.0f)}, //
164 {.position = Point(200.0f, 95.0f)}, //
165 {.position = Point(200.0f, 105.0f)}, //
166 {.position = Point(200.0f, 95.0f)}, //
167 };
168
169 EXPECT_SOLID_VERTICES_NEAR(vertices, expected);
170
171 {
172 auto uv_vertices =
173 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
174 polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
175 Point(50.0f, 40.0f), Size(20.0f, 40.0f), Matrix());
176 // uvx = (x - 50) / 20
177 // uvy = (y - 40) / 40
178 auto uv = [](const Point& p) {
179 return Point((p.x - 50.0f) / 20.0f, //
180 (p.y - 40.0f) / 40.0f);
181 };
182 std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
183 for (size_t i = 0; i < expected.size(); i++) {
184 auto p = expected[i].position;
185 uv_expected.push_back({.position = p, .texture_coords = uv(p)});
186 }
187
188 EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
189 }
190
191 {
192 auto uv_vertices =
193 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
194 polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
195 Point(50.0f, 40.0f), Size(20.0f, 40.0f),
196 Matrix::MakeScale({8.0f, 4.0f, 1.0f}));
197 // uvx = ((x * 8) - 50) / 20
198 // uvy = ((y * 4) - 40) / 40
199 auto uv = [](const Point& p) {
200 return Point(((p.x * 8.0f) - 50.0f) / 20.0f,
201 ((p.y * 4.0f) - 40.0f) / 40.0f);
202 };
203 std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
204 for (size_t i = 0; i < expected.size(); i++) {
205 auto p = expected[i].position;
206 uv_expected.push_back({.position = p, .texture_coords = uv(p)});
207 }
208
209 EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
210 }
211
212 {
213 auto uv_vertices =
214 ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV(
215 polyline, 10.0f, 10.0f, Join::kBevel, Cap::kButt, 1.0, //
216 Point(50.0f, 40.0f), Size(20.0f, 40.0f),
217 Matrix::MakeTranslation({8.0f, 4.0f}));
218 // uvx = ((x + 8) - 50) / 20
219 // uvy = ((y + 4) - 40) / 40
220 auto uv = [](const Point& p) {
221 return Point(((p.x + 8.0f) - 50.0f) / 20.0f,
222 ((p.y + 4.0f) - 40.0f) / 40.0f);
223 };
224 std::vector<TextureFillVertexShader::PerVertexData> uv_expected;
225 for (size_t i = 0; i < expected.size(); i++) {
226 auto p = expected[i].position;
227 uv_expected.push_back({.position = p, .texture_coords = uv(p)});
228 }
229
230 EXPECT_TEXTURE_VERTICES_NEAR(uv_vertices, uv_expected);
231 }
232 }
233
234 TEST(EntityGeometryTest, GeometryResultHasReasonableDefaults) {
235 GeometryResult result;
236 EXPECT_EQ(result.type, PrimitiveType::kTriangleStrip);
237 EXPECT_EQ(result.transform, Matrix());
238 EXPECT_EQ(result.mode, GeometryResult::Mode::kNormal);
239 }
240
241 } // namespace testing
242 } // namespace impeller
impeller::GeometryResult::Mode::kNormal
@ kNormal
The geometry has no overlapping triangles.
impeller::Cap::kSquare
@ kSquare
polyline
const Path::Polyline & polyline
Definition: stroke_path_geometry.cc:292
impeller::Scalar
float Scalar
Definition: scalar.h:18
geometry_asserts.h
stroke_path_geometry.h
impeller::Geometry::MakeRoundRect
static std::shared_ptr< Geometry > MakeRoundRect(const Rect &rect, const Size &radii)
Definition: geometry.cc:230
SolidVerticesNear
inline ::testing::AssertionResult SolidVerticesNear(std::vector< impeller::SolidFillVertexShader::PerVertexData > a, std::vector< impeller::SolidFillVertexShader::PerVertexData > b)
Definition: geometry_unittests.cc:14
EXPECT_SOLID_VERTICES_NEAR
#define EXPECT_SOLID_VERTICES_NEAR(a, b)
Definition: geometry_unittests.cc:45
impeller::PathBuilder
Definition: path_builder.h:14
impeller::Size
TSize< Scalar > Size
Definition: size.h:137
impeller::Cap::kButt
@ kButt
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
stroke_width
const Scalar stroke_width
Definition: stroke_path_geometry.cc:293
impeller::ImpellerEntityUnitTestAccessor
Definition: geometry_unittests.cc:52
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:112
path_builder.h
impeller::Path::Polyline
Definition: path.h:94
impeller::Geometry::MakeFillPath
static std::shared_ptr< Geometry > MakeFillPath(const Path &path, std::optional< Rect > inner_rect=std::nullopt)
Definition: geometry.cc:175
impeller::TSize< Scalar >
impeller::ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVerticesUV
static std::vector< TextureFillVertexShader::PerVertexData > GenerateSolidStrokeVerticesUV(const Path::Polyline &polyline, Scalar stroke_width, Scalar miter_limit, Join stroke_join, Cap stroke_cap, Scalar scale, Point texture_origin, Size texture_size, const Matrix &effect_transform)
Definition: geometry_unittests.cc:66
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Point
TPoint< Scalar > Point
Definition: point.h:316
impeller::GeometryResult::type
PrimitiveType type
Definition: geometry.h:36
EXPECT_TEXTURE_VERTICES_NEAR
#define EXPECT_TEXTURE_VERTICES_NEAR(a, b)
Definition: geometry_unittests.cc:47
geometry.h
impeller::testing::TEST
TEST(CanvasRecorder, Save)
Definition: canvas_recorder_unittests.cc:65
impeller::GeometryResult
Definition: geometry.h:20
impeller::PathBuilder::AddLine
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
Definition: path_builder.cc:419
impeller::PathBuilder::TakePath
Path TakePath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:22
PointNear
inline ::testing::AssertionResult PointNear(impeller::Point a, impeller::Point b)
Definition: geometry_asserts.h:76
impeller::Geometry::MakeRect
static std::shared_ptr< Geometry > MakeRect(const Rect &rect)
Definition: geometry.cc:204
impeller::GeometryResult::transform
Matrix transform
Definition: geometry.h:38
impeller::ImpellerEntityUnitTestAccessor::GenerateSolidStrokeVertices
static std::vector< SolidFillVertexShader::PerVertexData > GenerateSolidStrokeVertices(const Path::Polyline &polyline, Scalar stroke_width, Scalar miter_limit, Join stroke_join, Cap stroke_cap, Scalar scale)
Definition: geometry_unittests.cc:55
impeller::Join::kBevel
@ kBevel
content_context.h
impeller::Join
Join
Definition: path.h:23
impeller::TPoint< Scalar >
impeller::saturated::b
SI b
Definition: saturated_math.h:87
scale
const Scalar scale
Definition: stroke_path_geometry.cc:297
TextureVerticesNear
inline ::testing::AssertionResult TextureVerticesNear(std::vector< impeller::TextureFillVertexShader::PerVertexData > a, std::vector< impeller::TextureFillVertexShader::PerVertexData > b)
Definition: geometry_unittests.cc:28
impeller::Path::Polyline::PointBufferPtr
std::unique_ptr< std::vector< Point > > PointBufferPtr
Definition: path.h:97
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller
Definition: aiks_blur_unittests.cc:20
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::TRect
Definition: rect.h:122
impeller::GeometryResult::mode
Mode mode
Definition: geometry.h:39
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Cap
Cap
Definition: path.h:17
impeller::Geometry::MakeLine
static std::shared_ptr< Geometry > MakeLine(const Point &p0, const Point &p1, Scalar width, Cap cap)
Definition: geometry.cc:212