Flutter Impeller
impeller::Path Class Reference

Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments. These segments may be broken up by move commands, which are effectively linear commands that pick up the pen rather than continuing to draw. More...

#include <path.h>

Classes

struct  Polyline
 
struct  PolylineContour
 

Public Types

enum  ComponentType {
  ComponentType::kLinear,
  ComponentType::kQuadratic,
  ComponentType::kCubic,
  ComponentType::kContour
}
 
template<class T >
using Applier = std::function< void(size_t index, const T &component)>
 

Public Member Functions

 Path ()
 
 ~Path ()
 
size_t GetComponentCount (std::optional< ComponentType > type={}) const
 
FillType GetFillType () const
 
bool IsConvex () const
 
bool IsEmpty () const
 
void EnumerateComponents (const Applier< LinearPathComponent > &linear_applier, const Applier< QuadraticPathComponent > &quad_applier, const Applier< CubicPathComponent > &cubic_applier, const Applier< ContourComponent > &contour_applier) const
 
bool GetLinearComponentAtIndex (size_t index, LinearPathComponent &linear) const
 
bool GetQuadraticComponentAtIndex (size_t index, QuadraticPathComponent &quadratic) const
 
bool GetCubicComponentAtIndex (size_t index, CubicPathComponent &cubic) const
 
bool GetContourComponentAtIndex (size_t index, ContourComponent &contour) const
 
Polyline CreatePolyline (Scalar scale, Polyline::PointBufferPtr point_buffer=std::make_unique< std::vector< Point >>(), Polyline::ReclaimPointBufferCallback reclaim=nullptr) const
 
std::optional< RectGetBoundingBox () const
 
std::optional< RectGetTransformedBoundingBox (const Matrix &transform) const
 

Friends

class PathBuilder
 

Detailed Description

Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments. These segments may be broken up by move commands, which are effectively linear commands that pick up the pen rather than continuing to draw.

All shapes supported by Impeller are paths either directly or via approximation (in the case of circles).

Paths are externally immutable once created, Creating paths must be done using a path builder.

Definition at line 51 of file path.h.

Member Typedef Documentation

◆ Applier

template<class T >
using impeller::Path::Applier = std::function<void(size_t index, const T& component)>

Definition at line 141 of file path.h.

Member Enumeration Documentation

◆ ComponentType

Enumerator
kLinear 
kQuadratic 
kCubic 
kContour 

Definition at line 53 of file path.h.

53  {
54  kLinear,
55  kQuadratic,
56  kCubic,
57  kContour,
58  };

Constructor & Destructor Documentation

◆ Path()

impeller::Path::Path ( )

Definition at line 16 of file path.cc.

16 : data_(new Data()) {}

◆ ~Path()

impeller::Path::~Path ( )
default

Member Function Documentation

◆ CreatePolyline()

Path::Polyline impeller::Path::CreatePolyline ( Scalar  scale,
Polyline::PointBufferPtr  point_buffer = std::make_unique<std::vector<Point>>(),
Polyline::ReclaimPointBufferCallback  reclaim = nullptr 
) const

Callers must provide the scale factor for how this path will be transformed.

It is suitable to use the max basis length of the matrix used to transform the path. If the provided scale is 0, curves will revert to straight lines.

Definition at line 198 of file path.cc.

201  {
202  Polyline polyline(std::move(point_buffer), std::move(reclaim));
203 
204  auto& path_components = data_->components;
205  auto& path_points = data_->points;
206 
207  auto get_path_component = [&path_components, &path_points](
208  size_t component_i) -> PathComponentVariant {
209  if (component_i >= path_components.size()) {
210  return std::monostate{};
211  }
212  const auto& component = path_components[component_i];
213  switch (component.type) {
215  return reinterpret_cast<const LinearPathComponent*>(
216  &path_points[component.index]);
218  return reinterpret_cast<const QuadraticPathComponent*>(
219  &path_points[component.index]);
221  return reinterpret_cast<const CubicPathComponent*>(
222  &path_points[component.index]);
224  return std::monostate{};
225  }
226  };
227 
228  auto compute_contour_start_direction =
229  [&get_path_component](size_t current_path_component_index) {
230  size_t next_component_index = current_path_component_index + 1;
231  while (!std::holds_alternative<std::monostate>(
232  get_path_component(next_component_index))) {
233  auto next_component = get_path_component(next_component_index);
234  auto maybe_vector =
235  std::visit(PathComponentStartDirectionVisitor(), next_component);
236  if (maybe_vector.has_value()) {
237  return maybe_vector.value();
238  } else {
239  next_component_index++;
240  }
241  }
242  return Vector2(0, -1);
243  };
244 
245  std::vector<PolylineContour::Component> poly_components;
246  std::optional<size_t> previous_path_component_index;
247  auto end_contour = [&polyline, &previous_path_component_index,
248  &get_path_component, &poly_components]() {
249  // Whenever a contour has ended, extract the exact end direction from
250  // the last component.
251  if (polyline.contours.empty()) {
252  return;
253  }
254 
255  if (!previous_path_component_index.has_value()) {
256  return;
257  }
258 
259  auto& contour = polyline.contours.back();
260  contour.end_direction = Vector2(0, 1);
261  contour.components = poly_components;
262  poly_components.clear();
263 
264  size_t previous_index = previous_path_component_index.value();
265  while (!std::holds_alternative<std::monostate>(
266  get_path_component(previous_index))) {
267  auto previous_component = get_path_component(previous_index);
268  auto maybe_vector =
269  std::visit(PathComponentEndDirectionVisitor(), previous_component);
270  if (maybe_vector.has_value()) {
271  contour.end_direction = maybe_vector.value();
272  break;
273  } else {
274  if (previous_index == 0) {
275  break;
276  }
277  previous_index--;
278  }
279  }
280  };
281 
282  for (size_t component_i = 0; component_i < path_components.size();
283  component_i++) {
284  const auto& path_component = path_components[component_i];
285  switch (path_component.type) {
287  poly_components.push_back({
288  .component_start_index = polyline.points->size() - 1,
289  .is_curve = false,
290  });
291  reinterpret_cast<const LinearPathComponent*>(
292  &path_points[path_component.index])
293  ->AppendPolylinePoints(*polyline.points);
294  previous_path_component_index = component_i;
295  break;
297  poly_components.push_back({
298  .component_start_index = polyline.points->size() - 1,
299  .is_curve = true,
300  });
301  reinterpret_cast<const QuadraticPathComponent*>(
302  &path_points[path_component.index])
303  ->AppendPolylinePoints(scale, *polyline.points);
304  previous_path_component_index = component_i;
305  break;
307  poly_components.push_back({
308  .component_start_index = polyline.points->size() - 1,
309  .is_curve = true,
310  });
311  reinterpret_cast<const CubicPathComponent*>(
312  &path_points[path_component.index])
313  ->AppendPolylinePoints(scale, *polyline.points);
314  previous_path_component_index = component_i;
315  break;
317  if (component_i == path_components.size() - 1) {
318  // If the last component is a contour, that means it's an empty
319  // contour, so skip it.
320  continue;
321  }
322  end_contour();
323 
324  Vector2 start_direction = compute_contour_start_direction(component_i);
325  const auto& contour = data_->contours[path_component.index];
326  polyline.contours.push_back({.start_index = polyline.points->size(),
327  .is_closed = contour.is_closed,
328  .start_direction = start_direction,
329  .components = poly_components});
330 
331  polyline.points->push_back(contour.destination);
332  break;
333  }
334  }
335  end_contour();
336  return polyline;
337 }

References kContour, kCubic, kLinear, kQuadratic, polyline, and scale.

Referenced by impeller::Tessellator::CreateTempPolyline(), impeller::Tessellator::Tessellate(), impeller::Tessellator::TessellateConvex(), and impeller::testing::TEST().

◆ EnumerateComponents()

void impeller::Path::EnumerateComponents ( const Applier< LinearPathComponent > &  linear_applier,
const Applier< QuadraticPathComponent > &  quad_applier,
const Applier< CubicPathComponent > &  cubic_applier,
const Applier< ContourComponent > &  contour_applier 
) const

Definition at line 63 of file path.cc.

67  {
68  auto& points = data_->points;
69  size_t currentIndex = 0;
70  for (const auto& component : data_->components) {
71  switch (component.type) {
73  if (linear_applier) {
74  linear_applier(currentIndex,
75  LinearPathComponent(points[component.index],
76  points[component.index + 1]));
77  }
78  break;
80  if (quad_applier) {
81  quad_applier(currentIndex,
82  QuadraticPathComponent(points[component.index],
83  points[component.index + 1],
84  points[component.index + 2]));
85  }
86  break;
88  if (cubic_applier) {
89  cubic_applier(currentIndex,
90  CubicPathComponent(points[component.index],
91  points[component.index + 1],
92  points[component.index + 2],
93  points[component.index + 3]));
94  }
95  break;
97  if (contour_applier) {
98  contour_applier(currentIndex, data_->contours[component.index]);
99  }
100  break;
101  }
102  currentIndex++;
103  }
104 }

References kContour, kCubic, kLinear, and kQuadratic.

Referenced by impeller::PathBuilder::AddPath(), and impeller::ComputeTessellator::Tessellate().

◆ GetBoundingBox()

std::optional< Rect > impeller::Path::GetBoundingBox ( ) const

Definition at line 339 of file path.cc.

339  {
340  return data_->bounds;
341 }

Referenced by impeller::Canvas::ClipPath(), GetTransformedBoundingBox(), impeller::testing::TEST(), and impeller::testing::TEST_P().

◆ GetComponentCount()

size_t impeller::Path::GetComponentCount ( std::optional< ComponentType type = {}) const

Definition at line 34 of file path.cc.

34  {
35  if (!type.has_value()) {
36  return data_->components.size();
37  }
38  auto type_value = type.value();
39  if (type_value == ComponentType::kContour) {
40  return data_->contours.size();
41  }
42  size_t count = 0u;
43  for (const auto& component : data_->components) {
44  if (component.type == type_value) {
45  count++;
46  }
47  }
48  return count;
49 }

References kContour.

Referenced by impeller::ComputeTessellator::Tessellate(), and impeller::testing::TEST().

◆ GetContourComponentAtIndex()

bool impeller::Path::GetContourComponentAtIndex ( size_t  index,
ContourComponent contour 
) const

Definition at line 163 of file path.cc.

164  {
165  auto& components = data_->components;
166 
167  if (index >= components.size()) {
168  return false;
169  }
170 
171  if (components[index].type != ComponentType::kContour) {
172  return false;
173  }
174 
175  move = data_->contours[components[index].index];
176  return true;
177 }

References kContour.

Referenced by impeller::testing::TEST().

◆ GetCubicComponentAtIndex()

bool impeller::Path::GetCubicComponentAtIndex ( size_t  index,
CubicPathComponent cubic 
) const

Definition at line 144 of file path.cc.

145  {
146  auto& components = data_->components;
147 
148  if (index >= components.size()) {
149  return false;
150  }
151 
152  if (components[index].type != ComponentType::kCubic) {
153  return false;
154  }
155 
156  auto& points = data_->points;
157  auto point_index = components[index].index;
158  cubic = CubicPathComponent(points[point_index], points[point_index + 1],
159  points[point_index + 2], points[point_index + 3]);
160  return true;
161 }

References kCubic.

◆ GetFillType()

FillType impeller::Path::GetFillType ( ) const

Definition at line 51 of file path.cc.

51  {
52  return data_->fill;
53 }

Referenced by impeller::Tessellator::Tessellate().

◆ GetLinearComponentAtIndex()

bool impeller::Path::GetLinearComponentAtIndex ( size_t  index,
LinearPathComponent linear 
) const

Definition at line 106 of file path.cc.

107  {
108  auto& components = data_->components;
109 
110  if (index >= components.size()) {
111  return false;
112  }
113 
114  if (components[index].type != ComponentType::kLinear) {
115  return false;
116  }
117 
118  auto& points = data_->points;
119  auto point_index = components[index].index;
120  linear = LinearPathComponent(points[point_index], points[point_index + 1]);
121  return true;
122 }

References kLinear.

Referenced by impeller::testing::TEST().

◆ GetQuadraticComponentAtIndex()

bool impeller::Path::GetQuadraticComponentAtIndex ( size_t  index,
QuadraticPathComponent quadratic 
) const

Definition at line 124 of file path.cc.

126  {
127  auto& components = data_->components;
128 
129  if (index >= components.size()) {
130  return false;
131  }
132 
133  if (components[index].type != ComponentType::kQuadratic) {
134  return false;
135  }
136 
137  auto& points = data_->points;
138  auto point_index = components[index].index;
139  quadratic = QuadraticPathComponent(
140  points[point_index], points[point_index + 1], points[point_index + 2]);
141  return true;
142 }

References kQuadratic.

◆ GetTransformedBoundingBox()

std::optional< Rect > impeller::Path::GetTransformedBoundingBox ( const Matrix transform) const

Definition at line 343 of file path.cc.

344  {
345  auto bounds = GetBoundingBox();
346  if (!bounds.has_value()) {
347  return std::nullopt;
348  }
349  return bounds->TransformBounds(transform);
350 }

References GetBoundingBox().

◆ IsConvex()

bool impeller::Path::IsConvex ( ) const

Definition at line 55 of file path.cc.

55  {
56  return data_->convexity == Convexity::kConvex;
57 }

References impeller::kConvex.

◆ IsEmpty()

bool impeller::Path::IsEmpty ( ) const

Definition at line 59 of file path.cc.

59  {
60  return data_->points.empty();
61 }

Friends And Related Function Documentation

◆ PathBuilder

friend class PathBuilder
friend

Definition at line 176 of file path.h.


The documentation for this class was generated from the following files:
polyline
const Path::Polyline & polyline
Definition: stroke_path_geometry.cc:292
impeller::Path::ComponentType::kLinear
@ kLinear
impeller::Path::ComponentType::kCubic
@ kCubic
impeller::Vector2
Point Vector2
Definition: point.h:320
impeller::Path::GetBoundingBox
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:339
impeller::Path::ComponentType::kQuadratic
@ kQuadratic
impeller::MinMagFilter::kLinear
@ kLinear
scale
const Scalar scale
Definition: stroke_path_geometry.cc:297
impeller::PathComponentVariant
std::variant< std::monostate, const LinearPathComponent *, const QuadraticPathComponent *, const CubicPathComponent * > PathComponentVariant
Definition: path_component.h:169
impeller::Convexity::kConvex
@ kConvex
impeller::Path::ComponentType::kContour
@ kContour