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"
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 
53  public:
54  static std::vector<SolidFillVertexShader::PerVertexData>
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>
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 
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 =
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 =
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 =
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