Flutter Impeller
line_geometry.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 
8 
9 namespace impeller {
10 
12  : p0_(p0), p1_(p1), width_(stroke.width), cap_(stroke.cap) {
13  FML_DCHECK(width_ >= 0);
14 }
15 
16 LineGeometry::~LineGeometry() = default;
17 
19  Scalar width) {
20  Scalar max_basis = transform.GetMaxBasisLengthXY();
21  if (max_basis == 0) {
22  return {};
23  }
24 
25  Scalar min_size = kMinStrokeSize / max_basis;
26  return std::max(width, min_size) * 0.5f;
27 }
28 
30  bool allow_zero_length,
31  Point p0,
32  Point p1,
33  Scalar width) {
34  Scalar stroke_half_width = ComputePixelHalfWidth(transform, width);
35  if (stroke_half_width < kEhCloseEnough) {
36  return {};
37  }
38 
39  auto along = p1 - p0;
40  Scalar length = along.GetLength();
41  if (length < kEhCloseEnough) {
42  if (!allow_zero_length) {
43  // We won't enclose any pixels unless the endpoints are extended
44  return {};
45  }
46  return {stroke_half_width, 0};
47  } else {
48  return along * stroke_half_width / length;
49  }
50 }
51 
53  const Matrix& transform,
54  bool extend_endpoints,
55  Point p0,
56  Point p1,
57  Scalar width) {
58  auto along = ComputeAlongVector(transform, extend_endpoints, p0, p1, width);
59  if (along.IsZero()) {
60  return false;
61  }
62 
63  auto across = Vector2(along.y, -along.x);
64  corners[0] = p0 - across;
65  corners[1] = p1 - across;
66  corners[2] = p0 + across;
67  corners[3] = p1 + across;
68  if (extend_endpoints) {
69  corners[0] -= along;
70  corners[1] += along;
71  corners[2] -= along;
72  corners[3] += along;
73  }
74  return true;
75 }
76 
78  return Geometry::ComputeStrokeAlphaCoverage(entity, width_);
79 }
80 
81 namespace {
82 /// Minimizes the err when rounding to the closest 0.5 value.
83 /// If we round up, it drops down a half. If we round down it bumps up a half.
84 Scalar RoundToHalf(Scalar x) {
85  Scalar whole;
86  std::modf(x, &whole);
87  return whole + 0.5;
88 }
89 } // namespace
90 
91 GeometryResult LineGeometry::GetPositionBuffer(const ContentContext& renderer,
92  const Entity& entity,
93  RenderPass& pass) const {
94  using VT = SolidFillVertexShader::PerVertexData;
95 
96  Matrix transform = entity.GetTransform();
97  auto radius = ComputePixelHalfWidth(transform, width_);
98 
99  Point p0 = p0_;
100  Point p1 = p1_;
101 
102  // Hairline pixel alignment.
103  if (width_ == 0.f && transform.IsTranslationScaleOnly()) {
104  p0 = transform * p0_;
105  p1 = transform * p1_;
106  transform = Matrix();
107  if (std::fabs(p0.x - p1.x) < kEhCloseEnough) {
108  p0.x = RoundToHalf(p0.x);
109  p1.x = p0.x;
110  } else if (std::fabs(p0.y - p1.y) < kEhCloseEnough) {
111  p0.y = RoundToHalf(p0.y);
112  p1.y = p0.y;
113  }
114  }
115 
116  Entity fixed_transform = entity.Clone();
117  fixed_transform.SetTransform(transform);
118 
119  if (cap_ == Cap::kRound) {
120  auto generator =
121  renderer.GetTessellator().RoundCapLine(transform, p0, p1, radius);
122  return ComputePositionGeometry(renderer, generator, fixed_transform, pass);
123  }
124 
125  Point corners[4];
126  if (!ComputeCorners(corners, transform, cap_ == Cap::kSquare, p0, p1,
127  width_)) {
128  return kEmptyResult;
129  }
130 
131  auto& host_buffer = renderer.GetTransientsBuffer();
132 
133  size_t count = 4;
134  BufferView vertex_buffer = host_buffer.Emplace(
135  count * sizeof(VT), alignof(VT), [&corners](uint8_t* buffer) {
136  auto vertices = reinterpret_cast<VT*>(buffer);
137  for (auto& corner : corners) {
138  *vertices++ = {
139  .position = corner,
140  };
141  }
142  });
143 
144  return GeometryResult{
146  .vertex_buffer =
147  {
148  .vertex_buffer = vertex_buffer,
149  .vertex_count = count,
150  .index_type = IndexType::kNone,
151  },
152  .transform = fixed_transform.GetShaderTransform(pass),
153  };
154 }
155 
156 std::optional<Rect> LineGeometry::GetCoverage(const Matrix& transform) const {
157  Point corners[4];
158  // Note: MSAA boolean doesn't matter for coverage computation.
159  if (!ComputeCorners(corners, transform, cap_ != Cap::kButt, p0_, p1_,
160  width_)) {
161  return {};
162  }
163 
164  for (int i = 0; i < 4; i++) {
165  corners[i] = transform * corners[i];
166  }
167  return Rect::MakePointBounds(std::begin(corners), std::end(corners));
168 }
169 
170 bool LineGeometry::CoversArea(const Matrix& transform, const Rect& rect) const {
171  if (!transform.IsTranslationScaleOnly() || !IsAxisAlignedRect()) {
172  return false;
173  }
174  auto coverage = GetCoverage(transform);
175  return coverage.has_value() ? coverage->Contains(rect) : false;
176 }
177 
179  return cap_ != Cap::kRound && (p0_.x == p1_.x || p0_.y == p1_.y);
180 }
181 
182 } // namespace impeller
static Scalar ComputeStrokeAlphaCoverage(const Matrix &entity, Scalar stroke_width)
Compute an alpha value to simulate lower coverage of fractional pixel strokes.
Definition: geometry.cc:149
static GeometryResult ComputePositionGeometry(const ContentContext &renderer, const Tessellator::VertexGenerator &generator, const Entity &entity, RenderPass &pass)
Definition: geometry.cc:26
static Vector2 ComputeAlongVector(const Matrix &transform, bool allow_zero_length, Point p0, Point p1, Scalar width)
static Scalar ComputePixelHalfWidth(const Matrix &transform, Scalar width)
LineGeometry(Point p0, Point p1, const StrokeParameters &stroke)
bool IsAxisAlignedRect() const override
Scalar ComputeAlphaCoverage(const Matrix &transform) const override
static bool ComputeCorners(Point corners[4], const Matrix &transform, bool extend_endpoints, Point p0, Point p1, Scalar width)
std::optional< Rect > GetCoverage(const Matrix &transform) const override
bool CoversArea(const Matrix &transform, const Rect &rect) const override
Determines if this geometry, transformed by the given transform, will completely cover all surface ar...
int32_t x
@ kNone
Does not use the index buffer.
Point Vector2
Definition: point.h:331
float Scalar
Definition: scalar.h:19
constexpr float kEhCloseEnough
Definition: constants.h:57
TPoint< Scalar > Point
Definition: point.h:327
static const GeometryResult kEmptyResult
Definition: geometry.h:43
static constexpr Scalar kMinStrokeSize
Definition: geometry.h:19
PrimitiveType type
Definition: geometry.h:37
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
A structure to store all of the parameters related to stroking a path or basic geometry object.
constexpr Type GetLength() const
Definition: point.h:206
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:165
const size_t end