Flutter Impeller
stroke_path_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 
6 
14 
15 namespace impeller {
16 using VS = SolidFillVertexShader;
17 
18 namespace {
19 
20 template <typename VertexWriter>
21 using CapProc = std::function<void(VertexWriter& vtx_builder,
22  const Point& position,
23  const Point& offset,
24  Scalar scale,
25  bool reverse)>;
26 
27 template <typename VertexWriter>
28 using JoinProc = std::function<void(VertexWriter& vtx_builder,
29  const Point& position,
30  const Point& start_offset,
31  const Point& end_offset,
32  Scalar miter_limit,
33  Scalar scale)>;
34 
35 class PositionWriter {
36  public:
37  void AppendVertex(const Point& point) {
38  data_.emplace_back(SolidFillVertexShader::PerVertexData{.position = point});
39  }
40 
41  const std::vector<SolidFillVertexShader::PerVertexData>& GetData() const {
42  return data_;
43  }
44 
45  private:
46  std::vector<SolidFillVertexShader::PerVertexData> data_ = {};
47 };
48 
49 template <typename VertexWriter>
50 class StrokeGenerator {
51  public:
52  StrokeGenerator(const Path::Polyline& p_polyline,
53  const Scalar p_stroke_width,
54  const Scalar p_scaled_miter_limit,
55  const JoinProc<VertexWriter>& p_join_proc,
56  const CapProc<VertexWriter>& p_cap_proc,
57  const Scalar p_scale)
58  : polyline(p_polyline),
59  stroke_width(p_stroke_width),
60  scaled_miter_limit(p_scaled_miter_limit),
61  join_proc(p_join_proc),
62  cap_proc(p_cap_proc),
63  scale(p_scale) {}
64 
65  void Generate(VertexWriter& vtx_builder) {
66  for (size_t contour_i = 0; contour_i < polyline.contours.size();
67  contour_i++) {
68  const Path::PolylineContour& contour = polyline.contours[contour_i];
69  size_t contour_start_point_i, contour_end_point_i;
70  std::tie(contour_start_point_i, contour_end_point_i) =
71  polyline.GetContourPointBounds(contour_i);
72 
73  auto contour_delta = contour_end_point_i - contour_start_point_i;
74  if (contour_delta == 1) {
75  Point p = polyline.GetPoint(contour_start_point_i);
76  cap_proc(vtx_builder, p, {-stroke_width * 0.5f, 0}, scale,
77  /*reverse=*/false);
78  cap_proc(vtx_builder, p, {stroke_width * 0.5f, 0}, scale,
79  /*reverse=*/false);
80  continue;
81  } else if (contour_delta == 0) {
82  continue; // This contour has no renderable content.
83  }
84 
86  offset = ComputeOffset(contour_start_point_i, contour_start_point_i,
87  contour_end_point_i, contour);
88  const Point contour_first_offset = offset.GetVector();
89 
90  if (contour_i > 0) {
91  // This branch only executes when we've just finished drawing a contour
92  // and are switching to a new one.
93  // We're drawing a triangle strip, so we need to "pick up the pen" by
94  // appending two vertices at the end of the previous contour and two
95  // vertices at the start of the new contour (thus connecting the two
96  // contours with two zero volume triangles, which will be discarded by
97  // the rasterizer).
98  vtx.position = polyline.GetPoint(contour_start_point_i - 1);
99  // Append two vertices when "picking up" the pen so that the triangle
100  // drawn when moving to the beginning of the new contour will have zero
101  // volume.
102  vtx_builder.AppendVertex(vtx.position);
103  vtx_builder.AppendVertex(vtx.position);
104 
105  vtx.position = polyline.GetPoint(contour_start_point_i);
106  // Append two vertices at the beginning of the new contour, which
107  // appends two triangles of zero area.
108  vtx_builder.AppendVertex(vtx.position);
109  vtx_builder.AppendVertex(vtx.position);
110  }
111 
112  // Generate start cap.
113  if (!polyline.contours[contour_i].is_closed) {
114  Point cap_offset =
115  Vector2(-contour.start_direction.y, contour.start_direction.x) *
116  stroke_width * 0.5f; // Counterclockwise normal
117  cap_proc(vtx_builder, polyline.GetPoint(contour_start_point_i),
118  cap_offset, scale, /*reverse=*/true);
119  }
120 
121  for (size_t contour_component_i = 0;
122  contour_component_i < contour.components.size();
123  contour_component_i++) {
124  const Path::PolylineContour::Component& component =
125  contour.components[contour_component_i];
126  bool is_last_component =
127  contour_component_i == contour.components.size() - 1;
128 
129  size_t component_start_index = component.component_start_index;
130  size_t component_end_index =
131  is_last_component ? contour_end_point_i - 1
132  : contour.components[contour_component_i + 1]
133  .component_start_index;
134  if (component.is_curve) {
135  AddVerticesForCurveComponent(
136  vtx_builder, component_start_index, component_end_index,
137  contour_start_point_i, contour_end_point_i, contour);
138  } else {
139  AddVerticesForLinearComponent(
140  vtx_builder, component_start_index, component_end_index,
141  contour_start_point_i, contour_end_point_i, contour);
142  }
143  }
144 
145  // Generate end cap or join.
146  if (!contour.is_closed) {
147  auto cap_offset =
148  Vector2(-contour.end_direction.y, contour.end_direction.x) *
149  stroke_width * 0.5f; // Clockwise normal
150  cap_proc(vtx_builder, polyline.GetPoint(contour_end_point_i - 1),
151  cap_offset, scale, /*reverse=*/false);
152  } else {
153  join_proc(vtx_builder, polyline.GetPoint(contour_start_point_i),
154  offset.GetVector(), contour_first_offset, scaled_miter_limit,
155  scale);
156  }
157  }
158  }
159 
160  /// Computes offset by calculating the direction from point_i - 1 to point_i
161  /// if point_i is within `contour_start_point_i` and `contour_end_point_i`;
162  /// Otherwise, it uses direction from contour.
163  SeparatedVector2 ComputeOffset(const size_t point_i,
164  const size_t contour_start_point_i,
165  const size_t contour_end_point_i,
166  const Path::PolylineContour& contour) const {
167  Point direction;
168  if (point_i >= contour_end_point_i) {
169  direction = contour.end_direction;
170  } else if (point_i <= contour_start_point_i) {
171  direction = -contour.start_direction;
172  } else {
173  direction = (polyline.GetPoint(point_i) - polyline.GetPoint(point_i - 1))
174  .Normalize();
175  }
176  return SeparatedVector2(Vector2{-direction.y, direction.x},
177  stroke_width * 0.5f);
178  }
179 
180  void AddVerticesForLinearComponent(VertexWriter& vtx_builder,
181  const size_t component_start_index,
182  const size_t component_end_index,
183  const size_t contour_start_point_i,
184  const size_t contour_end_point_i,
185  const Path::PolylineContour& contour) {
186  bool is_last_component = component_start_index ==
187  contour.components.back().component_start_index;
188 
189  for (size_t point_i = component_start_index; point_i < component_end_index;
190  point_i++) {
191  bool is_end_of_component = point_i == component_end_index - 1;
192 
193  Point offset_vector = offset.GetVector();
194 
195  vtx.position = polyline.GetPoint(point_i) + offset_vector;
196  vtx_builder.AppendVertex(vtx.position);
197  vtx.position = polyline.GetPoint(point_i) - offset_vector;
198  vtx_builder.AppendVertex(vtx.position);
199 
200  // For line components, two additional points need to be appended
201  // prior to appending a join connecting the next component.
202  vtx.position = polyline.GetPoint(point_i + 1) + offset_vector;
203  vtx_builder.AppendVertex(vtx.position);
204  vtx.position = polyline.GetPoint(point_i + 1) - offset_vector;
205  vtx_builder.AppendVertex(vtx.position);
206 
208  offset = ComputeOffset(point_i + 2, contour_start_point_i,
209  contour_end_point_i, contour);
210  if (!is_last_component && is_end_of_component) {
211  // Generate join from the current line to the next line.
212  join_proc(vtx_builder, polyline.GetPoint(point_i + 1),
213  previous_offset.GetVector(), offset.GetVector(),
215  }
216  }
217  }
218 
219  void AddVerticesForCurveComponent(VertexWriter& vtx_builder,
220  const size_t component_start_index,
221  const size_t component_end_index,
222  const size_t contour_start_point_i,
223  const size_t contour_end_point_i,
224  const Path::PolylineContour& contour) {
225  bool is_last_component = component_start_index ==
226  contour.components.back().component_start_index;
227 
228  for (size_t point_i = component_start_index; point_i < component_end_index;
229  point_i++) {
230  bool is_end_of_component = point_i == component_end_index - 1;
231 
232  vtx.position = polyline.GetPoint(point_i) + offset.GetVector();
233  vtx_builder.AppendVertex(vtx.position);
234  vtx.position = polyline.GetPoint(point_i) - offset.GetVector();
235  vtx_builder.AppendVertex(vtx.position);
236 
238  offset = ComputeOffset(point_i + 2, contour_start_point_i,
239  contour_end_point_i, contour);
240 
241  // If the angle to the next segment is too sharp, round out the join.
242  if (!is_end_of_component) {
243  constexpr Scalar kAngleThreshold = 10 * kPi / 180;
244  // `std::cosf` is not constexpr-able, unfortunately, so we have to bake
245  // the alignment constant.
246  constexpr Scalar kAlignmentThreshold =
247  0.984807753012208; // std::cosf(kThresholdAngle) -- 10 degrees
248 
249  // Use a cheap dot product to determine whether the angle is too sharp.
250  if (previous_offset.GetAlignment(offset) < kAlignmentThreshold) {
251  Scalar angle_total = previous_offset.AngleTo(offset).radians;
252  Scalar angle = kAngleThreshold;
253 
254  // Bridge the large angle with additional geometry at
255  // `kAngleThreshold` interval.
256  while (angle < std::abs(angle_total)) {
257  Scalar signed_angle = angle_total < 0 ? -angle : angle;
258  Point offset =
259  previous_offset.GetVector().Rotate(Radians(signed_angle));
260  vtx.position = polyline.GetPoint(point_i) + offset;
261  vtx_builder.AppendVertex(vtx.position);
262  vtx.position = polyline.GetPoint(point_i) - offset;
263  vtx_builder.AppendVertex(vtx.position);
264 
265  angle += kAngleThreshold;
266  }
267  }
268  }
269 
270  // For curve components, the polyline is detailed enough such that
271  // it can avoid worrying about joins altogether.
272  if (is_end_of_component) {
273  // Append two additional vertices to close off the component. If we're
274  // on the _last_ component of the contour then we need to use the
275  // contour's end direction.
276  // `ComputeOffset` returns the contour's end direction when attempting
277  // to grab offsets past `contour_end_point_i`, so just use `offset` when
278  // we're on the last component.
279  Point last_component_offset = is_last_component
280  ? offset.GetVector()
281  : previous_offset.GetVector();
282  vtx.position = polyline.GetPoint(point_i + 1) + last_component_offset;
283  vtx_builder.AppendVertex(vtx.position);
284  vtx.position = polyline.GetPoint(point_i + 1) - last_component_offset;
285  vtx_builder.AppendVertex(vtx.position);
286  // Generate join from the current line to the next line.
287  if (!is_last_component) {
288  join_proc(vtx_builder, polyline.GetPoint(point_i + 1),
289  previous_offset.GetVector(), offset.GetVector(),
291  }
292  }
293  }
294  }
295 
296  const Path::Polyline& polyline;
299  const JoinProc<VertexWriter>& join_proc;
300  const CapProc<VertexWriter>& cap_proc;
301  const Scalar scale;
302 
303  SeparatedVector2 previous_offset;
304  SeparatedVector2 offset;
305  SolidFillVertexShader::PerVertexData vtx;
306 };
307 
308 template <typename VertexWriter>
309 void CreateButtCap(VertexWriter& vtx_builder,
310  const Point& position,
311  const Point& offset,
312  Scalar scale,
313  bool reverse) {
314  Point orientation = offset * (reverse ? -1 : 1);
315  VS::PerVertexData vtx;
316  vtx.position = position + orientation;
317  vtx_builder.AppendVertex(vtx.position);
318  vtx.position = position - orientation;
319  vtx_builder.AppendVertex(vtx.position);
320 }
321 
322 template <typename VertexWriter>
323 void CreateRoundCap(VertexWriter& vtx_builder,
324  const Point& position,
325  const Point& offset,
326  Scalar scale,
327  bool reverse) {
328  Point orientation = offset * (reverse ? -1 : 1);
329  Point forward(offset.y, -offset.x);
330  Point forward_normal = forward.Normalize();
331 
332  CubicPathComponent arc;
333  if (reverse) {
334  arc = CubicPathComponent(
335  forward, forward + orientation * PathBuilder::kArcApproximationMagic,
336  orientation + forward * PathBuilder::kArcApproximationMagic,
337  orientation);
338  } else {
339  arc = CubicPathComponent(
340  orientation,
341  orientation + forward * PathBuilder::kArcApproximationMagic,
342  forward + orientation * PathBuilder::kArcApproximationMagic, forward);
343  }
344 
345  Point vtx = position + orientation;
346  vtx_builder.AppendVertex(vtx);
347  vtx = position - orientation;
348  vtx_builder.AppendVertex(vtx);
349 
350  arc.ToLinearPathComponents(scale, [&vtx_builder, &vtx, forward_normal,
351  position](const Point& point) {
352  vtx = position + point;
353  vtx_builder.AppendVertex(vtx);
354  vtx = position + (-point).Reflect(forward_normal);
355  vtx_builder.AppendVertex(vtx);
356  });
357 }
358 
359 template <typename VertexWriter>
360 void CreateSquareCap(VertexWriter& vtx_builder,
361  const Point& position,
362  const Point& offset,
363  Scalar scale,
364  bool reverse) {
365  Point orientation = offset * (reverse ? -1 : 1);
366  Point forward(offset.y, -offset.x);
367 
368  Point vtx = position + orientation;
369  vtx_builder.AppendVertex(vtx);
370  vtx = position - orientation;
371  vtx_builder.AppendVertex(vtx);
372  vtx = position + orientation + forward;
373  vtx_builder.AppendVertex(vtx);
374  vtx = position - orientation + forward;
375  vtx_builder.AppendVertex(vtx);
376 }
377 
378 template <typename VertexWriter>
379 Scalar CreateBevelAndGetDirection(VertexWriter& vtx_builder,
380  const Point& position,
381  const Point& start_offset,
382  const Point& end_offset) {
383  Point vtx = position;
384  vtx_builder.AppendVertex(vtx);
385 
386  Scalar dir = start_offset.Cross(end_offset) > 0 ? -1 : 1;
387  vtx = position + start_offset * dir;
388  vtx_builder.AppendVertex(vtx);
389  vtx = position + end_offset * dir;
390  vtx_builder.AppendVertex(vtx);
391 
392  return dir;
393 }
394 
395 template <typename VertexWriter>
396 void CreateMiterJoin(VertexWriter& vtx_builder,
397  const Point& position,
398  const Point& start_offset,
399  const Point& end_offset,
400  Scalar miter_limit,
401  Scalar scale) {
402  Point start_normal = start_offset.Normalize();
403  Point end_normal = end_offset.Normalize();
404 
405  // 1 for no joint (straight line), 0 for max joint (180 degrees).
406  Scalar alignment = (start_normal.Dot(end_normal) + 1) / 2;
407  if (ScalarNearlyEqual(alignment, 1)) {
408  return;
409  }
410 
411  Scalar direction = CreateBevelAndGetDirection(vtx_builder, position,
412  start_offset, end_offset);
413 
414  Point miter_point = (((start_offset + end_offset) / 2) / alignment);
415  if (miter_point.GetDistanceSquared({0, 0}) > miter_limit * miter_limit) {
416  return; // Convert to bevel when we exceed the miter limit.
417  }
418 
419  // Outer miter point.
420  VS::PerVertexData vtx;
421  vtx.position = position + miter_point * direction;
422  vtx_builder.AppendVertex(vtx.position);
423 }
424 
425 template <typename VertexWriter>
426 void CreateRoundJoin(VertexWriter& vtx_builder,
427  const Point& position,
428  const Point& start_offset,
429  const Point& end_offset,
430  Scalar miter_limit,
431  Scalar scale) {
432  Point start_normal = start_offset.Normalize();
433  Point end_normal = end_offset.Normalize();
434 
435  // 0 for no joint (straight line), 1 for max joint (180 degrees).
436  Scalar alignment = 1 - (start_normal.Dot(end_normal) + 1) / 2;
437  if (ScalarNearlyEqual(alignment, 0)) {
438  return;
439  }
440 
441  Scalar direction = CreateBevelAndGetDirection(vtx_builder, position,
442  start_offset, end_offset);
443 
444  Point middle =
445  (start_offset + end_offset).Normalize() * start_offset.GetLength();
446  Point middle_normal = middle.Normalize();
447 
448  Point middle_handle = middle + Point(-middle.y, middle.x) *
450  alignment * direction;
451  Point start_handle = start_offset + Point(start_offset.y, -start_offset.x) *
453  alignment * direction;
454 
455  VS::PerVertexData vtx;
456  CubicPathComponent(start_offset, start_handle, middle_handle, middle)
457  .ToLinearPathComponents(scale, [&vtx_builder, direction, &vtx, position,
458  middle_normal](const Point& point) {
459  vtx.position = position + point * direction;
460  vtx_builder.AppendVertex(vtx.position);
461  vtx.position = position + (-point * direction).Reflect(middle_normal);
462  vtx_builder.AppendVertex(vtx.position);
463  });
464 }
465 
466 template <typename VertexWriter>
467 void CreateBevelJoin(VertexWriter& vtx_builder,
468  const Point& position,
469  const Point& start_offset,
470  const Point& end_offset,
471  Scalar miter_limit,
472  Scalar scale) {
473  CreateBevelAndGetDirection(vtx_builder, position, start_offset, end_offset);
474 }
475 
476 template <typename VertexWriter>
477 void CreateSolidStrokeVertices(VertexWriter& vtx_builder,
478  const Path::Polyline& polyline,
481  const JoinProc<VertexWriter>& join_proc,
482  const CapProc<VertexWriter>& cap_proc,
483  Scalar scale) {
484  StrokeGenerator stroke_generator(polyline, stroke_width, scaled_miter_limit,
486  stroke_generator.Generate(vtx_builder);
487 }
488 
489 // static
490 template <typename VertexWriter>
491 JoinProc<VertexWriter> GetJoinProc(Join stroke_join) {
492  switch (stroke_join) {
493  case Join::kBevel:
494  return &CreateBevelJoin<VertexWriter>;
495  case Join::kMiter:
496  return &CreateMiterJoin<VertexWriter>;
497  case Join::kRound:
498  return &CreateRoundJoin<VertexWriter>;
499  }
500 }
501 
502 template <typename VertexWriter>
503 CapProc<VertexWriter> GetCapProc(Cap stroke_cap) {
504  switch (stroke_cap) {
505  case Cap::kButt:
506  return &CreateButtCap<VertexWriter>;
507  case Cap::kRound:
508  return &CreateRoundCap<VertexWriter>;
509  case Cap::kSquare:
510  return &CreateSquareCap<VertexWriter>;
511  }
512 }
513 } // namespace
514 
515 std::vector<SolidFillVertexShader::PerVertexData>
516 StrokePathGeometry::GenerateSolidStrokeVertices(const Path::Polyline& polyline,
518  Scalar miter_limit,
519  Join stroke_join,
520  Cap stroke_cap,
521  Scalar scale) {
522  auto scaled_miter_limit = stroke_width * miter_limit * 0.5f;
523  auto join_proc = GetJoinProc<PositionWriter>(stroke_join);
524  auto cap_proc = GetCapProc<PositionWriter>(stroke_cap);
525  StrokeGenerator stroke_generator(polyline, stroke_width, scaled_miter_limit,
527  PositionWriter vtx_builder;
528  stroke_generator.Generate(vtx_builder);
529  return vtx_builder.GetData();
530 }
531 
532 StrokePathGeometry::StrokePathGeometry(const Path& path,
534  Scalar miter_limit,
535  Cap stroke_cap,
536  Join stroke_join)
537  : path_(path),
538  stroke_width_(stroke_width),
539  miter_limit_(miter_limit),
540  stroke_cap_(stroke_cap),
541  stroke_join_(stroke_join) {}
542 
544 
546  return stroke_width_;
547 }
548 
550  return miter_limit_;
551 }
552 
554  return stroke_cap_;
555 }
556 
558  return stroke_join_;
559 }
560 
562  return Geometry::ComputeStrokeAlphaCoverage(transform, stroke_width_);
563 }
564 
565 GeometryResult StrokePathGeometry::GetPositionBuffer(
566  const ContentContext& renderer,
567  const Entity& entity,
568  RenderPass& pass) const {
569  if (stroke_width_ < 0.0) {
570  return {};
571  }
572  Scalar max_basis = entity.GetTransform().GetMaxBasisLengthXY();
573  if (max_basis == 0) {
574  return {};
575  }
576 
577  Scalar min_size =
579  : kMinStrokeSize) /
580  max_basis;
581  Scalar stroke_width = std::max(stroke_width_, min_size);
582 
583  auto& host_buffer = renderer.GetTransientsBuffer();
584  auto scale = entity.GetTransform().GetMaxBasisLengthXY();
585 
586  PositionWriter position_writer;
587  auto polyline = renderer.GetTessellator()->CreateTempPolyline(path_, scale);
588  CreateSolidStrokeVertices(position_writer, polyline, stroke_width,
589  miter_limit_ * stroke_width_ * 0.5f,
590  GetJoinProc<PositionWriter>(stroke_join_),
591  GetCapProc<PositionWriter>(stroke_cap_), scale);
592 
593  BufferView buffer_view =
594  host_buffer.Emplace(position_writer.GetData().data(),
595  position_writer.GetData().size() *
596  sizeof(SolidFillVertexShader::PerVertexData),
597  alignof(SolidFillVertexShader::PerVertexData));
598 
599  return GeometryResult{
601  .vertex_buffer =
602  {
603  .vertex_buffer = buffer_view,
604  .vertex_count = position_writer.GetData().size(),
605  .index_type = IndexType::kNone,
606  },
607  .transform = entity.GetShaderTransform(pass),
609 }
610 
611 GeometryResult::Mode StrokePathGeometry::GetResultMode() const {
613 }
614 
615 std::optional<Rect> StrokePathGeometry::GetCoverage(
616  const Matrix& transform) const {
617  auto path_bounds = path_.GetBoundingBox();
618  if (!path_bounds.has_value()) {
619  return std::nullopt;
620  }
621 
622  Scalar max_radius = 0.5;
623  if (stroke_cap_ == Cap::kSquare) {
624  max_radius = max_radius * kSqrt2;
625  }
626  if (stroke_join_ == Join::kMiter) {
627  max_radius = std::max(max_radius, miter_limit_ * 0.5f);
628  }
629  Scalar max_basis = transform.GetMaxBasisLengthXY();
630  if (max_basis == 0) {
631  return {};
632  }
633  // Use the most conervative coverage setting.
634  Scalar min_size = kMinStrokeSize / max_basis;
635  max_radius *= std::max(stroke_width_, min_size);
636  return path_bounds->Expand(max_radius).TransformBounds(transform);
637 }
638 
639 } // namespace impeller
impeller::StrokePathGeometry::~StrokePathGeometry
~StrokePathGeometry() override
impeller::Entity::GetShaderTransform
Matrix GetShaderTransform(const RenderPass &pass) const
Get the vertex shader transform used for drawing this Entity.
Definition: entity.cc:51
impeller::Cap::kRound
@ kRound
separated_vector.h
impeller::Cap::kSquare
@ kSquare
polyline
const Path::Polyline & polyline
Definition: stroke_path_geometry.cc:296
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
geometry.h
impeller::kSqrt2
constexpr float kSqrt2
Definition: constants.h:47
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:47
impeller::Path::PolylineContour
Definition: path.h:76
stroke_path_geometry.h
impeller::kMinStrokeSizeMSAA
static constexpr Scalar kMinStrokeSizeMSAA
The minimum stroke size can be less than one physical pixel because of MSAA, but no less that half a ...
Definition: geometry.h:22
vtx
SolidFillVertexShader::PerVertexData vtx
Definition: stroke_path_geometry.cc:305
impeller::SeparatedVector2
A Vector2, broken down as a separate magnitude and direction. Assumes that the direction given is nor...
Definition: separated_vector.h:21
impeller::Path::PolylineContour::components
std::vector< Component > components
Definition: path.h:101
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::Path::GetBoundingBox
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:387
path_builder.h
impeller::kPi
constexpr float kPi
Definition: constants.h:26
formats.h
buffer_view
BufferView buffer_view
Definition: blit_command_gles.cc:128
impeller::PathBuilder::kArcApproximationMagic
constexpr static const Scalar kArcApproximationMagic
Definition: path_builder.h:23
impeller::Cap::kButt
@ kButt
stroke_width
const Scalar stroke_width
Definition: stroke_path_geometry.cc:297
offset
SeparatedVector2 offset
Definition: stroke_path_geometry.cc:304
previous_offset
SeparatedVector2 previous_offset
Definition: stroke_path_geometry.cc:303
scaled_miter_limit
const Scalar scaled_miter_limit
Definition: stroke_path_geometry.cc:298
impeller::kMinStrokeSize
static constexpr Scalar kMinStrokeSize
Definition: geometry.h:24
impeller::GeometryResult::Mode
Mode
Definition: geometry.h:27
impeller::Join::kMiter
@ kMiter
impeller::VS
SolidFillVertexShader VS
Definition: stroke_path_geometry.cc:16
impeller::Path::Polyline
Definition: path.h:110
impeller::Entity
Definition: entity.h:20
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::Path::PolylineContour::start_direction
Vector2 start_direction
The direction of the contour's start cap.
Definition: path.h:93
impeller::Path
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:52
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:213
impeller::StrokePathGeometry::GetMiterLimit
Scalar GetMiterLimit() const
Definition: stroke_path_geometry.cc:549
impeller::StrokePathGeometry::ComputeAlphaCoverage
Scalar ComputeAlphaCoverage(const Matrix &transform) const override
Definition: stroke_path_geometry.cc:561
impeller::RenderPass::GetSampleCount
SampleCount GetSampleCount() const
The sample count of the attached render target.
Definition: render_pass.cc:23
impeller::GeometryResult
Definition: geometry.h:26
impeller::Radians
Definition: scalar.h:43
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::Path::PolylineContour::Component
Definition: path.h:77
impeller::Join::kRound
@ kRound
impeller::StrokePathGeometry::GetStrokeCap
Cap GetStrokeCap() const
Definition: stroke_path_geometry.cc:553
impeller::ContentContext::GetTessellator
std::shared_ptr< Tessellator > GetTessellator() const
Definition: content_context.cc:546
impeller::Path::PolylineContour::end_direction
Vector2 end_direction
The direction of the contour's end cap.
Definition: path.h:95
impeller::StrokePathGeometry::GetStrokeJoin
Join GetStrokeJoin() const
Definition: stroke_path_geometry.cc:557
join_proc
const JoinProc< VertexWriter > & join_proc
Definition: stroke_path_geometry.cc:299
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:33
cap_proc
const CapProc< VertexWriter > & cap_proc
Definition: stroke_path_geometry.cc:300
impeller::Join::kBevel
@ kBevel
impeller::VertexWriter
An interface for generating a multi contour polyline as a triangle strip.
Definition: path_component.h:20
impeller::Path::PolylineContour::Component::is_curve
bool is_curve
Definition: path.h:83
impeller::Join
Join
Definition: path.h:24
impeller::Matrix::GetMaxBasisLengthXY
constexpr Scalar GetMaxBasisLengthXY() const
Definition: matrix.h:298
impeller::TPoint::GetLength
constexpr Type GetLength() const
Definition: point.h:206
constants.h
buffer_view.h
impeller::TPoint
Definition: point.h:27
scale
const Scalar scale
Definition: stroke_path_geometry.cc:301
impeller::ScalarNearlyEqual
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition: scalar.h:35
impeller::SampleCount::kCount4
@ kCount4
impeller::Geometry::ComputeStrokeAlphaCoverage
static Scalar ComputeStrokeAlphaCoverage(const Matrix &entity, Scalar stroke_width)
Compute an alpha value to simulate lower coverage of fractional pixel strokes.
Definition: geometry.cc:133
impeller::GeometryResult::Mode::kPreventOverdraw
@ kPreventOverdraw
path_component.h
impeller::TPoint::Normalize
constexpr TPoint Normalize() const
Definition: point.h:208
impeller::Path::PolylineContour::Component::component_start_index
size_t component_start_index
Definition: path.h:78
impeller
Definition: allocation.cc:12
impeller::ContentContext
Definition: content_context.h:366
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::StrokePathGeometry::GetStrokeWidth
Scalar GetStrokeWidth() const
Definition: stroke_path_geometry.cc:545
impeller::Path::PolylineContour::is_closed
bool is_closed
Definition: path.h:90
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:753
impeller::Cap
Cap
Definition: path.h:18