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