Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 class  ComponentType { kLinear , kQuadratic , kCubic , 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

enum class impeller::Path::ComponentType
strong
Enumerator
kLinear 
kQuadratic 
kCubic 
kContour 

Definition at line 53 of file path.h.

Constructor & Destructor Documentation

◆ Path()

impeller::Path::Path ( )

Definition at line 16 of file path.cc.

16: data_(new Data()) {}
struct PathData * Data(SkPath *path)
Definition path_ops.cc:52

◆ ~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}
Point Vector2
Definition point.h:320
std::variant< std::monostate, const LinearPathComponent *, const QuadraticPathComponent *, const CubicPathComponent * > PathComponentVariant
const Scalar scale
const Path::Polyline & polyline

◆ 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}
static const int points[]

◆ GetBoundingBox()

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

Definition at line 339 of file path.cc.

339 {
340 return data_->bounds;
341}

◆ 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}
int count

◆ 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}

◆ 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}
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())

◆ GetFillType()

FillType impeller::Path::GetFillType ( ) const

Definition at line 51 of file path.cc.

51 {
52 return data_->fill;
53}

◆ 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}
static sk_sp< SkShader > linear(sk_sp< SkShader > shader)

◆ 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}
AI float quadratic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())

◆ 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}
std::optional< Rect > GetBoundingBox() const
Definition path.cc:339
Optional< SkRect > bounds
Definition SkRecords.h:189
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition p3.cpp:47

◆ IsConvex()

bool impeller::Path::IsConvex ( ) const

Definition at line 55 of file path.cc.

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

◆ IsEmpty()

bool impeller::Path::IsEmpty ( ) const

Definition at line 59 of file path.cc.

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

Friends And Related Symbol 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: