Flutter Engine
The Flutter Engine
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
 
void WritePolyline (Scalar scale, VertexWriter &writer) 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 52 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 142 of file path.h.

Member Enumeration Documentation

◆ ComponentType

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

Definition at line 54 of file path.h.

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

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

267 {
268 Polyline polyline(std::move(point_buffer), std::move(reclaim));
269
270 auto& path_components = data_->components;
271 auto& path_points = data_->points;
272
273 auto get_path_component = [&path_components, &path_points](
274 size_t component_i) -> PathComponentVariant {
275 if (component_i >= path_components.size()) {
276 return std::monostate{};
277 }
278 const auto& component = path_components[component_i];
279 switch (component.type) {
281 return reinterpret_cast<const LinearPathComponent*>(
282 &path_points[component.index]);
284 return reinterpret_cast<const QuadraticPathComponent*>(
285 &path_points[component.index]);
287 return reinterpret_cast<const CubicPathComponent*>(
288 &path_points[component.index]);
290 return std::monostate{};
291 }
292 };
293
294 auto compute_contour_start_direction =
295 [&get_path_component](size_t current_path_component_index) {
296 size_t next_component_index = current_path_component_index + 1;
297 while (!std::holds_alternative<std::monostate>(
298 get_path_component(next_component_index))) {
299 auto next_component = get_path_component(next_component_index);
300 auto maybe_vector =
301 std::visit(PathComponentStartDirectionVisitor(), next_component);
302 if (maybe_vector.has_value()) {
303 return maybe_vector.value();
304 } else {
305 next_component_index++;
306 }
307 }
308 return Vector2(0, -1);
309 };
310
311 std::vector<PolylineContour::Component> poly_components;
312 std::optional<size_t> previous_path_component_index;
313 auto end_contour = [&polyline, &previous_path_component_index,
314 &get_path_component, &poly_components]() {
315 // Whenever a contour has ended, extract the exact end direction from
316 // the last component.
317 if (polyline.contours.empty()) {
318 return;
319 }
320
321 if (!previous_path_component_index.has_value()) {
322 return;
323 }
324
325 auto& contour = polyline.contours.back();
326 contour.end_direction = Vector2(0, 1);
327 contour.components = poly_components;
328 poly_components.clear();
329
330 size_t previous_index = previous_path_component_index.value();
331 while (!std::holds_alternative<std::monostate>(
332 get_path_component(previous_index))) {
333 auto previous_component = get_path_component(previous_index);
334 auto maybe_vector =
335 std::visit(PathComponentEndDirectionVisitor(), previous_component);
336 if (maybe_vector.has_value()) {
337 contour.end_direction = maybe_vector.value();
338 break;
339 } else {
340 if (previous_index == 0) {
341 break;
342 }
343 previous_index--;
344 }
345 }
346 };
347
348 for (size_t component_i = 0; component_i < path_components.size();
349 component_i++) {
350 const auto& path_component = path_components[component_i];
351 switch (path_component.type) {
353 poly_components.push_back({
354 .component_start_index = polyline.points->size() - 1,
355 .is_curve = false,
356 });
357 reinterpret_cast<const LinearPathComponent*>(
358 &path_points[path_component.index])
359 ->AppendPolylinePoints(*polyline.points);
360 previous_path_component_index = component_i;
361 break;
363 poly_components.push_back({
364 .component_start_index = polyline.points->size() - 1,
365 .is_curve = true,
366 });
367 reinterpret_cast<const QuadraticPathComponent*>(
368 &path_points[path_component.index])
369 ->AppendPolylinePoints(scale, *polyline.points);
370 previous_path_component_index = component_i;
371 break;
373 poly_components.push_back({
374 .component_start_index = polyline.points->size() - 1,
375 .is_curve = true,
376 });
377 reinterpret_cast<const CubicPathComponent*>(
378 &path_points[path_component.index])
379 ->AppendPolylinePoints(scale, *polyline.points);
380 previous_path_component_index = component_i;
381 break;
383 if (component_i == path_components.size() - 1) {
384 // If the last component is a contour, that means it's an empty
385 // contour, so skip it.
386 continue;
387 }
388 end_contour();
389
390 Vector2 start_direction = compute_contour_start_direction(component_i);
391 const auto& contour = data_->contours[path_component.index];
392 polyline.contours.push_back({.start_index = polyline.points->size(),
393 .is_closed = contour.is_closed,
394 .start_direction = start_direction,
395 .components = poly_components});
396
397 polyline.points->push_back(contour.destination);
398 break;
399 }
400 }
401 end_contour();
402 return polyline;
403}
Point Vector2
Definition: point.h:326
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 405 of file path.cc.

405 {
406 return data_->bounds;
407}

◆ 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
Definition: FontMgrTest.cpp:50
GLenum type

◆ GetContourComponentAtIndex()

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

Definition at line 229 of file path.cc.

230 {
231 auto& components = data_->components;
232
233 if (index >= components.size()) {
234 return false;
235 }
236
237 if (components[index].type != ComponentType::kContour) {
238 return false;
239 }
240
241 move = data_->contours[components[index].index];
242 return true;
243}

◆ GetCubicComponentAtIndex()

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

Definition at line 210 of file path.cc.

211 {
212 auto& components = data_->components;
213
214 if (index >= components.size()) {
215 return false;
216 }
217
218 if (components[index].type != ComponentType::kCubic) {
219 return false;
220 }
221
222 auto& points = data_->points;
223 auto point_index = components[index].index;
224 cubic = CubicPathComponent(points[point_index], points[point_index + 1],
225 points[point_index + 2], points[point_index + 3]);
226 return true;
227}
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:195

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

173 {
174 auto& components = data_->components;
175
176 if (index >= components.size()) {
177 return false;
178 }
179
180 if (components[index].type != ComponentType::kLinear) {
181 return false;
182 }
183
184 auto& points = data_->points;
185 auto point_index = components[index].index;
186 linear = LinearPathComponent(points[point_index], points[point_index + 1]);
187 return true;
188}
static sk_sp< SkShader > linear(sk_sp< SkShader > shader)

◆ GetQuadraticComponentAtIndex()

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

Definition at line 190 of file path.cc.

192 {
193 auto& components = data_->components;
194
195 if (index >= components.size()) {
196 return false;
197 }
198
199 if (components[index].type != ComponentType::kQuadratic) {
200 return false;
201 }
202
203 auto& points = data_->points;
204 auto point_index = components[index].index;
205 quadratic = QuadraticPathComponent(
206 points[point_index], points[point_index + 1], points[point_index + 2]);
207 return true;
208}
AI float quadratic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:156

◆ GetTransformedBoundingBox()

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

Definition at line 409 of file path.cc.

410 {
411 auto bounds = GetBoundingBox();
412 if (!bounds.has_value()) {
413 return std::nullopt;
414 }
415 return bounds->TransformBounds(transform);
416}
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:405
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}

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

106 {
107 auto& path_components = data_->components;
108 auto& path_points = data_->points;
109 bool started_contour = false;
110 bool first_point = true;
111
112 for (size_t component_i = 0; component_i < path_components.size();
113 component_i++) {
114 const auto& path_component = path_components[component_i];
115 switch (path_component.type) {
117 const LinearPathComponent* linear =
118 reinterpret_cast<const LinearPathComponent*>(
119 &path_points[path_component.index]);
120 if (first_point) {
121 writer.Write(linear->p1);
122 first_point = false;
123 }
124 writer.Write(linear->p2);
125 break;
126 }
128 const QuadraticPathComponent* quad =
129 reinterpret_cast<const QuadraticPathComponent*>(
130 &path_points[path_component.index]);
131 if (first_point) {
132 writer.Write(quad->p1);
133 first_point = false;
134 }
135 quad->ToLinearPathComponents(scale, writer);
136 break;
137 }
139 const CubicPathComponent* cubic =
140 reinterpret_cast<const CubicPathComponent*>(
141 &path_points[path_component.index]);
142 if (first_point) {
143 writer.Write(cubic->p1);
144 first_point = false;
145 }
146 cubic->ToLinearPathComponents(scale, writer);
147 break;
148 }
150 if (component_i == path_components.size() - 1) {
151 // If the last component is a contour, that means it's an empty
152 // contour, so skip it.
153 continue;
154 }
155 // The contour component type is the first segment in a contour.
156 // Since this should contain the destination (if closed), we
157 // can start with this point. If there was already an open
158 // contour, or we've reached the end of the verb list, we
159 // also close the contour.
160 if (started_contour) {
161 writer.EndContour();
162 }
163 started_contour = true;
164 first_point = true;
165 }
166 }
167 if (started_contour) {
168 writer.EndContour();
169 }
170}

Friends And Related Function Documentation

◆ PathBuilder

friend class PathBuilder
friend

Definition at line 184 of file path.h.


The documentation for this class was generated from the following files: