| Flutter Impeller |

Classes | Public Types | Public Member Functions | Friends | List of all members
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< Rect > | GetBoundingBox () const
std::optional< Rect > | GetTransformedBoundingBox (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

enum impeller::Path::ComponentType
| strong

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) {
214 case ComponentType::kLinear:
215 return reinterpret_cast<const LinearPathComponent*>(
216 &path_points[component.index]);
217 case ComponentType::kQuadratic:
218 return reinterpret_cast<const QuadraticPathComponent*>(
219 &path_points[component.index]);
220 case ComponentType::kCubic:
221 return reinterpret_cast<const CubicPathComponent*>(
222 &path_points[component.index]);
223 case ComponentType::kContour:
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) {
286 case ComponentType::kLinear:
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;
296 case ComponentType::kQuadratic:
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;
306 case ComponentType::kCubic:
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;
316 case ComponentType::kContour:
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) {
72 case ComponentType::kLinear:
73 if (linear_applier) {
74 linear_applier(currentIndex,
75 LinearPathComponent(points[component.index],
76 points[component.index + 1]));
77 }
78 break;
79 case ComponentType::kQuadratic:
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;
87 case ComponentType::kCubic:
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;
96 case ComponentType::kContour:
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:

- impeller/geometry/path.h
- impeller/geometry/path.cc

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