| Flutter Impeller |

Classes | Public Types | Public Member Functions | Static 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 }

## Public Member Functions
| Path ()
| ~Path ()
size_t | GetComponentCount (std::optional< ComponentType > type={}) const
FillType | GetFillType () const
bool | IsConvex () const
bool | IsEmpty () 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
void | EndContour (size_t storage_offset, Polyline &polyline, size_t component_index, std::vector< PolylineContour::Component > &poly_components) const
std::optional< Rect > | GetBoundingBox () const
std::optional< Rect > | GetTransformedBoundingBox (const Matrix &transform) const
void | WritePolyline (Scalar scale, VertexWriter &writer) const

## Static Public Member Functions
static constexpr size_t | VerbToOffset (Path::ComponentType verb)

## 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 52 of file path.h.

## Member Enumeration Documentation

## ◆ ComponentType

enum impeller::Path::ComponentType
| strong

Enumerator
kLinear |
kQuadratic |
kCubic |
kContour |

Definition at line 54 of file path.h.

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

## Constructor & Destructor Documentation

## ◆ Path()

impeller::Path::Path | ( |  | ) |

Definition at line 15 of file path.cc.

15 : 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 289 of file path.cc.

292 {
293 Polyline polyline(std::move(point_buffer), std::move(reclaim));
294
295 auto& path_components = data_->components;
296 auto& path_points = data_->points;
297 std::optional<Vector2> start_direction;
298 std::vector<PolylineContour::Component> poly_components;
299 size_t storage_offset = 0u;
300 size_t component_i = 0;
301
302 for (; component_i < path_components.size(); component_i++) {
303 auto path_component = path_components[component_i];
304 switch (path_component) {
305 case ComponentType::kLinear: {
306 poly_components.push_back({
307 .component_start_index = polyline.points->size() - 1,
308 .is_curve = false,
309 });
310 auto* linear = reinterpret_cast<const LinearPathComponent*>(
311 &path_points[storage_offset]);
312 linear->AppendPolylinePoints(*polyline.points);
313 if (!start_direction.has_value()) {
314 start_direction = linear->GetStartDirection();
315 }
316 break;
317 }
318 case ComponentType::kQuadratic: {
319 poly_components.push_back({
320 .component_start_index = polyline.points->size() - 1,
321 .is_curve = true,
322 });
323 auto* quad = reinterpret_cast<const QuadraticPathComponent*>(
324 &path_points[storage_offset]);
325 quad->AppendPolylinePoints(scale, *polyline.points);
326 if (!start_direction.has_value()) {
327 start_direction = quad->GetStartDirection();
328 }
329 break;
330 }
331 case ComponentType::kCubic: {
332 poly_components.push_back({
333 .component_start_index = polyline.points->size() - 1,
334 .is_curve = true,
335 });
336 auto* cubic = reinterpret_cast<const CubicPathComponent*>(
337 &path_points[storage_offset]);
338 cubic->AppendPolylinePoints(scale, *polyline.points);
339 if (!start_direction.has_value()) {
340 start_direction = cubic->GetStartDirection();
341 }
342 break;
343 }
344 case ComponentType::kContour:
345 if (component_i == path_components.size() - 1) {
346 // If the last component is a contour, that means it's an empty
347 // contour, so skip it.
348 break;
349 }
350 if (!polyline.contours.empty()) {
351 polyline.contours.back().start_direction =
352 start_direction.value_or(Vector2(0, -1));
353 start_direction = std::nullopt;
354 }
355 EndContour(storage_offset, polyline, component_i, poly_components);
356
357 auto* contour = reinterpret_cast<const ContourComponent*>(
358 &path_points[storage_offset]);
359 polyline.contours.push_back(PolylineContour{
360 .start_index = polyline.points->size(), //
361 .is_closed = contour->IsClosed(), //
362 .start_direction = Vector2(0, -1), //
363 .components = poly_components //
364 });
365
366 polyline.points->push_back(contour->destination);
367 break;
368 }
369 storage_offset += VerbToOffset(path_component);
370 }
371
372 // Subtract the last storage offset increment so that the storage lookup is
373 // correct, including potentially an empty contour as well.
374 if (component_i > 0 && path_components.back() == ComponentType::kContour) {
375 storage_offset -= VerbToOffset(ComponentType::kContour);
376 component_i--;
377 }
378
379 if (!polyline.contours.empty()) {
380 polyline.contours.back().start_direction =
381 start_direction.value_or(Vector2(0, -1));
382 }
383 EndContour(storage_offset, polyline, component_i, poly_components);
384 return polyline;
385 }

References impeller::LinearPathComponent::AppendPolylinePoints(), impeller::QuadraticPathComponent::AppendPolylinePoints(), impeller::CubicPathComponent::AppendPolylinePoints(), EndContour(), kContour, kCubic, kLinear, kQuadratic, polyline, scale, impeller::Path::PolylineContour::start_index, and VerbToOffset().

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

## ◆ EndContour()

void impeller::Path::EndContour | ( | size_t | storage_offset,
|  | Polyline & | polyline,
|  | size_t | component_index,
|  | std::vector< PolylineContour::Component > & | poly_components
| ) |  | const

Definition at line 225 of file path.cc.

229 {
230 auto& path_components = data_->components;
231 auto& path_points = data_->points;
232 // Whenever a contour has ended, extract the exact end direction from
233 // the last component.
234 if (polyline.contours.empty() || component_index == 0) {
235 return;
236 }
237
238 auto& contour = polyline.contours.back();
239 contour.end_direction = Vector2(0, 1);
240 contour.components = poly_components;
241 poly_components.clear();
242
243 size_t previous_index = component_index - 1;
244 storage_offset -= VerbToOffset(path_components[previous_index]);
245
246 while (previous_index >= 0 && storage_offset >= 0) {
247 const auto& path_component = path_components[previous_index];
248 switch (path_component) {
249 case ComponentType::kLinear: {
250 auto* linear = reinterpret_cast<const LinearPathComponent*>(
251 &path_points[storage_offset]);
252 auto maybe_end = linear->GetEndDirection();
253 if (maybe_end.has_value()) {
254 contour.end_direction = maybe_end.value();
255 return;
256 }
257 break;
258 }
259 case ComponentType::kQuadratic: {
260 auto* quad = reinterpret_cast<const QuadraticPathComponent*>(
261 &path_points[storage_offset]);
262 auto maybe_end = quad->GetEndDirection();
263 if (maybe_end.has_value()) {
264 contour.end_direction = maybe_end.value();
265 return;
266 }
267 break;
268 }
269 case ComponentType::kCubic: {
270 auto* cubic = reinterpret_cast<const CubicPathComponent*>(
271 &path_points[storage_offset]);
272 auto maybe_end = cubic->GetEndDirection();
273 if (maybe_end.has_value()) {
274 contour.end_direction = maybe_end.value();
275 return;
276 }
277 break;
278 }
279 case ComponentType::kContour: {
280 // Hit previous contour, return.
281 return;
282 };
283 }
284 storage_offset -= VerbToOffset(path_component);
285 previous_index--;
286 }
287 };

References impeller::LinearPathComponent::GetEndDirection(), impeller::QuadraticPathComponent::GetEndDirection(), impeller::CubicPathComponent::GetEndDirection(), kContour, kCubic, kLinear, kQuadratic, polyline, and VerbToOffset().

Referenced by CreatePolyline().

## ◆ GetBoundingBox()

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

Definition at line 387 of file path.cc.

387 {
388 return data_->bounds;
389 }

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

## ◆ GetComponentCount()

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

Definition at line 33 of file path.cc.

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

References type.

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

## ◆ GetContourComponentAtIndex()

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

Definition at line 188 of file path.cc.

189 {
190 auto& components = data_->components;
191 if (index >= components.size() ||
192 components[index] != ComponentType::kContour) {
193 return false;
194 }
195
196 size_t storage_offset = 0u;
197 for (auto i = 0u; i < index; i++) {
198 storage_offset += VerbToOffset(components[i]);
199 }
200 auto& points = data_->points;
201
202 move = ContourComponent(points[storage_offset], points[storage_offset + 1]);
203 return true;
204 }

References kContour, and VerbToOffset().

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

## ◆ GetCubicComponentAtIndex()

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

Definition at line 168 of file path.cc.

169 {
170 auto& components = data_->components;
171 if (index >= components.size() ||
172 components[index] != ComponentType::kCubic) {
173 return false;
174 }
175
176 size_t storage_offset = 0u;
177 for (auto i = 0u; i < index; i++) {
178 storage_offset += VerbToOffset(components[i]);
179 }
180 auto& points = data_->points;
181
182 cubic = CubicPathComponent(points[storage_offset], points[storage_offset + 1],
183 points[storage_offset + 2],
184 points[storage_offset + 3]);
185 return true;
186 }

References kCubic, and VerbToOffset().

## ◆ GetFillType()

FillType impeller::Path::GetFillType | ( |  | ) | const

Definition at line 47 of file path.cc.

47 {
48 return data_->fill;
49 }

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

## ◆ GetLinearComponentAtIndex()

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

Definition at line 129 of file path.cc.

130 {
131 auto& components = data_->components;
132 if (index >= components.size() ||
133 components[index] != ComponentType::kLinear) {
134 return false;
135 }
136
137 size_t storage_offset = 0u;
138 for (auto i = 0u; i < index; i++) {
139 storage_offset += VerbToOffset(components[i]);
140 }
141 auto& points = data_->points;
142 linear =
143 LinearPathComponent(points[storage_offset], points[storage_offset + 1]);
144 return true;
145 }

References kLinear, and VerbToOffset().

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

## ◆ GetQuadraticComponentAtIndex()

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

Definition at line 147 of file path.cc.

149 {
150 auto& components = data_->components;
151 if (index >= components.size() ||
152 components[index] != ComponentType::kQuadratic) {
153 return false;
154 }
155
156 size_t storage_offset = 0u;
157 for (auto i = 0u; i < index; i++) {
158 storage_offset += VerbToOffset(components[i]);
159 }
160 auto& points = data_->points;
161
162 quadratic =
163 QuadraticPathComponent(points[storage_offset], points[storage_offset + 1],
164 points[storage_offset + 2]);
165 return true;
166 }

References kQuadratic, and VerbToOffset().

## ◆ GetTransformedBoundingBox()

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

Definition at line 391 of file path.cc.

392 {
393 auto bounds = GetBoundingBox();
394 if (!bounds.has_value()) {
395 return std::nullopt;
396 }
397 return bounds->TransformBounds(transform);
398 }

References GetBoundingBox(), and transform.

## ◆ IsConvex()

bool impeller::Path::IsConvex | ( |  | ) | const

Definition at line 51 of file path.cc.

51 {
52 return data_->convexity == Convexity::kConvex;
53 }

References impeller::kConvex.

## ◆ IsEmpty()

bool impeller::Path::IsEmpty | ( |  | ) | const

Definition at line 55 of file path.cc.

55 {
56 return data_->points.empty() ||
57 (data_->components.size() == 1 &&
58 data_->components[0] == ComponentType::kContour);
59 }

References kContour.

## ◆ VerbToOffset()

static constexpr size_t impeller::Path::VerbToOffset | ( | Path::ComponentType | verb | ) |
| inline static constexpr

Definition at line 61 of file path.h.

61 {
62 switch (verb) {
63 case Path::ComponentType::kLinear:
64 return 2u;
65 case Path::ComponentType::kQuadratic:
66 return 3u;
67 case Path::ComponentType::kCubic:
68 return 4u;
69 case Path::ComponentType::kContour:
70 return 2u;
71 break;
72 }
73 FML_UNREACHABLE();
74 }

References kContour, kCubic, kLinear, and kQuadratic.

Referenced by impeller::PathBuilder::AddPath(), CreatePolyline(), EndContour(), GetContourComponentAtIndex(), GetCubicComponentAtIndex(), GetLinearComponentAtIndex(), GetQuadraticComponentAtIndex(), impeller::PathBuilder::Shift(), and WritePolyline().

## ◆ WritePolyline()

void impeller::Path::WritePolyline | ( | Scalar | scale,
|  | VertexWriter & | writer
| ) |  | const

Generate a polyline into the temporary storage held by the [writer].

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 61 of file path.cc.

61 {
62 auto& path_components = data_->components;
63 auto& path_points = data_->points;
64 bool started_contour = false;
65 bool first_point = true;
66
67 size_t storage_offset = 0u;
68 for (size_t component_i = 0; component_i < path_components.size();
69 component_i++) {
70 const auto& path_component = path_components[component_i];
71 switch (path_component) {
72 case ComponentType::kLinear: {
73 const LinearPathComponent* linear =
74 reinterpret_cast<const LinearPathComponent*>(
75 &path_points[storage_offset]);
76 if (first_point) {
77 writer.Write(linear->p1);
78 first_point = false;
79 }
80 writer.Write(linear->p2);
81 break;
82 }
83 case ComponentType::kQuadratic: {
84 const QuadraticPathComponent* quad =
85 reinterpret_cast<const QuadraticPathComponent*>(
86 &path_points[storage_offset]);
87 if (first_point) {
88 writer.Write(quad->p1);
89 first_point = false;
90 }
91 quad->ToLinearPathComponents(scale, writer);
92 break;
93 }
94 case ComponentType::kCubic: {
95 const CubicPathComponent* cubic =
96 reinterpret_cast<const CubicPathComponent*>(
97 &path_points[storage_offset]);
98 if (first_point) {
99 writer.Write(cubic->p1);
100 first_point = false;
101 }
102 cubic->ToLinearPathComponents(scale, writer);
103 break;
104 }
105 case Path::ComponentType::kContour:
106 if (component_i == path_components.size() - 1) {
107 // If the last component is a contour, that means it's an empty
108 // contour, so skip it.
109 continue;
110 }
111 // The contour component type is the first segment in a contour.
112 // Since this should contain the destination (if closed), we
113 // can start with this point. If there was already an open
114 // contour, or we've reached the end of the verb list, we
115 // also close the contour.
116 if (started_contour) {
117 writer.EndContour();
118 }
119 started_contour = true;
120 first_point = true;
121 }
122 storage_offset += VerbToOffset(path_component);
123 }
124 if (started_contour) {
125 writer.EndContour();
126 }
127 }

References impeller::VertexWriter::EndContour(), kContour, kCubic, kLinear, kQuadratic, impeller::LinearPathComponent::p1, impeller::QuadraticPathComponent::p1, impeller::CubicPathComponent::p1, impeller::LinearPathComponent::p2, scale, impeller::QuadraticPathComponent::ToLinearPathComponents(), impeller::CubicPathComponent::ToLinearPathComponents(), VerbToOffset(), and impeller::VertexWriter::Write().

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

## Friends And Related Function Documentation

## ◆ PathBuilder

friend class PathBuilder
| friend

Definition at line 197 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:296
impeller::Path::ComponentType::kLinear
@ kLinear
impeller::Path::ComponentType::kCubic
@ kCubic
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::Path::GetBoundingBox
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:387
impeller::Path::ComponentType::kQuadratic
@ kQuadratic
impeller::Path::EndContour
void EndContour(size_t storage_offset, Polyline &polyline, size_t component_index, std::vector< PolylineContour::Component > &poly_components) const
Definition: path.cc:225
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:213
impeller::MinMagFilter::kLinear
@ kLinear
type
GLenum type
Definition: blit_command_gles.cc:127
scale
const Scalar scale
Definition: stroke_path_geometry.cc:301
impeller::Path::VerbToOffset
static constexpr size_t VerbToOffset(Path::ComponentType verb)
Definition: path.h:61
impeller::Convexity::kConvex
@ kConvex
impeller::Path::ComponentType::kContour
@ kContour