Flutter Impeller
line_contents_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 
6 
7 #include <algorithm>
8 
10 #include "third_party/googletest/googletest/include/gtest/gtest.h"
11 
12 namespace impeller {
13 namespace testing {
14 
15 namespace {
16 float lookup(Scalar x) {
17  return std::clamp(x, /*lo=*/0.f, /*hi=*/1.f);
18 }
19 
20 // This mirrors the function in line.frag.
21 float CalculateLine(const LineVertexShader::PerVertexData& per_vertex,
22  Point position) {
23  Vector3 pos = Vector3(position.x, position.y, 1.0);
24  Scalar d[4] = {pos.Dot(per_vertex.e0), pos.Dot(per_vertex.e1),
25  pos.Dot(per_vertex.e2), pos.Dot(per_vertex.e3)};
26 
27  for (int i = 0; i < 4; ++i) {
28  if (d[i] < 0.f) {
29  return 0.0;
30  }
31  }
32 
33  return lookup(std::min(d[0], d[2])) * lookup(std::min(d[1], d[3]));
34 }
35 } // namespace
36 
38  Scalar width = 5.0f;
39  auto geometry = std::make_unique<LineGeometry>(
40  /*p0=*/Point{0, 0}, //
41  /*p1=*/Point{100, 100}, //
43  .width = width,
44  .cap = Cap::kSquare,
45  });
46  std::unique_ptr<LineContents> contents =
47  LineContents::Make(std::move(geometry), Color(1.f, 0.f, 0.f, 1.f));
48  EXPECT_TRUE(contents);
49  Entity entity;
50  std::optional<Rect> coverage = contents->GetCoverage(entity);
51  EXPECT_TRUE(coverage.has_value());
52  if (coverage.has_value()) {
53  Scalar lip = sqrt((width * width) / 2.f);
54  EXPECT_EQ(*coverage,
55  Rect::MakeXYWH(-lip, -lip, 100 + 2 * lip, 100 + 2 * lip));
56  }
57 }
58 
59 TEST(LineContents, CalculatePerVertex) {
60  LineVertexShader::PerVertexData per_vertex[4];
61  auto geometry = std::make_unique<LineGeometry>(
62  /*p0=*/Point{100, 100}, //
63  /*p1=*/Point{200, 100}, //
65  .width = 5.f,
66  .cap = Cap::kButt,
67  });
69 
70  fml::StatusOr<LineContents::EffectiveLineParameters> status =
71  LineContents::CalculatePerVertex(per_vertex, geometry.get(), transform);
72  Scalar offset =
73  (LineContents::kSampleRadius * 2.0 + geometry->GetWidth()) / 2.f;
74  ASSERT_TRUE(status.ok());
75  EXPECT_EQ(status.value().width, 5.f);
76  EXPECT_EQ(status.value().radius, LineContents::kSampleRadius);
77  EXPECT_POINT_NEAR(per_vertex[0].position,
78  Point(100 - LineContents::kSampleRadius, 100 + offset));
79  EXPECT_POINT_NEAR(per_vertex[1].position,
80  Point(200 + LineContents::kSampleRadius, 100 + offset));
81  EXPECT_POINT_NEAR(per_vertex[2].position,
82  Point(100 - LineContents::kSampleRadius, 100 - offset));
83  EXPECT_POINT_NEAR(per_vertex[3].position,
84  Point(200 + LineContents::kSampleRadius, 100 - offset));
85 
86  for (int i = 1; i < 4; ++i) {
87  EXPECT_VECTOR3_NEAR(per_vertex[0].e0, per_vertex[i].e0) << i;
88  EXPECT_VECTOR3_NEAR(per_vertex[0].e1, per_vertex[i].e1) << i;
89  EXPECT_VECTOR3_NEAR(per_vertex[0].e2, per_vertex[i].e2) << i;
90  EXPECT_VECTOR3_NEAR(per_vertex[0].e3, per_vertex[i].e3) << i;
91  }
92 
93  EXPECT_EQ(CalculateLine(per_vertex[0], Point(0, 0)), 0.f);
94  EXPECT_NEAR(CalculateLine(per_vertex[0], Point(150, 100 + offset)), 0.f,
96  EXPECT_NEAR(CalculateLine(per_vertex[0], Point(150, 100 + offset * 0.5)),
97  0.5f, kEhCloseEnough);
98  EXPECT_NEAR(CalculateLine(per_vertex[0], Point(150, 100)), 1.f,
100 }
101 
102 TEST(LineContents, CreateCurveData) {
103  std::vector<uint8_t> data = LineContents::CreateCurveData(/*width=*/31,
104  /*radius=*/1,
105  /*scale=*/1);
106  EXPECT_EQ(data.size(), 32u);
107  EXPECT_NEAR(data[0] / 255.f, 0.f, kEhCloseEnough);
108  EXPECT_NEAR(data[1] / 255.f, 0.5f, 0.02);
109  EXPECT_NEAR(data[2] / 255.f, 1.f, kEhCloseEnough);
110  EXPECT_NEAR(data[3] / 255.f, 1.f, kEhCloseEnough);
111 }
112 
113 TEST(LineContents, CreateCurveDataScaled) {
114  std::vector<uint8_t> data = LineContents::CreateCurveData(/*width=*/15.5,
115  /*radius=*/1,
116  /*scale=*/2);
117  EXPECT_EQ(data.size(), 32u);
118  EXPECT_NEAR(data[0] / 255.f, 0.f, kEhCloseEnough);
119  EXPECT_NEAR(data[1] / 255.f, 0.5f, 0.02);
120  EXPECT_NEAR(data[2] / 255.f, 1.f, kEhCloseEnough);
121  EXPECT_NEAR(data[3] / 255.f, 1.f, kEhCloseEnough);
122 }
123 
124 // This scales the line to be less than 1 pixel.
125 TEST(LineContents, CalculatePerVertexLimit) {
126  LineVertexShader::PerVertexData per_vertex[4];
127  Scalar scale = 0.05;
128  auto geometry = std::make_unique<LineGeometry>(
129  /*p0=*/Point{100, 100}, //
130  /*p1=*/Point{200, 100}, //
132  .width = 10.f,
133  .cap = Cap::kButt,
134  });
135  Matrix transform = Matrix::MakeTranslation({100, 100, 1.0}) *
136  Matrix::MakeScale({scale, scale, 1.0}) *
137  Matrix::MakeTranslation({-100, -100, 1.0});
138 
139  fml::StatusOr<LineContents::EffectiveLineParameters> status =
140  LineContents::CalculatePerVertex(per_vertex, geometry.get(), transform);
141 
142  Scalar one_radius_size = std::max(LineContents::kSampleRadius / scale,
144  Scalar one_px_size = 1.f / scale;
145  Scalar offset = one_px_size / 2.f + one_radius_size;
146  ASSERT_TRUE(status.ok());
147  EXPECT_NEAR(status.value().width, 20.f, kEhCloseEnough);
148  EXPECT_NEAR(status.value().radius, one_px_size * LineContents::kSampleRadius,
150  EXPECT_POINT_NEAR(per_vertex[0].position,
151  Point(100 - one_radius_size, 100 + offset));
152  EXPECT_POINT_NEAR(per_vertex[1].position,
153  Point(200 + one_radius_size, 100 + offset));
154  EXPECT_POINT_NEAR(per_vertex[2].position,
155  Point(100 - one_radius_size, 100 - offset));
156  EXPECT_POINT_NEAR(per_vertex[3].position,
157  Point(200 + one_radius_size, 100 - offset));
158 
159  EXPECT_NEAR(CalculateLine(per_vertex[0], Point(150, 100)), 1.f,
161  // EXPECT_NEAR(CalculateLine(per_vertex[0], Point(150, 100 +
162  // one_px_size)), 1.f,
163  // kEhCloseEnough);
164 }
165 
166 } // namespace testing
167 } // namespace impeller
std::optional< Rect > GetCoverage() const
Definition: entity.cc:64
static std::unique_ptr< LineContents > Make(std::unique_ptr< LineGeometry > geometry, Color color)
static std::vector< uint8_t > CreateCurveData(Scalar width, Scalar radius, Scalar scale)
static const Scalar kSampleRadius
Definition: line_contents.h:17
static fml::StatusOr< EffectiveLineParameters > CalculatePerVertex(LineVertexShader::PerVertexData *per_vertex, const LineGeometry *geometry, const Matrix &entity_transform)
int32_t x
#define EXPECT_VECTOR3_NEAR(a, b)
#define EXPECT_POINT_NEAR(a, b)
Vector3 e0
Vector3 e3
Vector3 e2
Vector3 e1
ScopedObject< Object > Create(CtorArgs &&... args)
Definition: object.h:161
TEST(AllocationSizeTest, CanCreateTypedAllocations)
float Scalar
Definition: scalar.h:19
constexpr float kEhCloseEnough
Definition: constants.h:57
TPoint< Scalar > Point
Definition: point.h:327
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
A structure to store all of the parameters related to stroking a path or basic geometry object.
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:68