Flutter Engine
The Flutter Engine
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
path.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <optional>
8#include <variant>
9
10#include "flutter/fml/logging.h"
13
14namespace impeller {
15
16Path::Path() : data_(new Data()) {}
17
18Path::Path(Data data) : data_(std::make_shared<Data>(std::move(data))) {}
19
20Path::~Path() = default;
21
22std::tuple<size_t, size_t> Path::Polyline::GetContourPointBounds(
23 size_t contour_index) const {
24 if (contour_index >= contours.size()) {
25 return {points->size(), points->size()};
26 }
27 const size_t start_index = contours.at(contour_index).start_index;
28 const size_t end_index = (contour_index >= contours.size() - 1)
29 ? points->size()
30 : contours.at(contour_index + 1).start_index;
31 return std::make_tuple(start_index, end_index);
32}
33
34size_t Path::GetComponentCount(std::optional<ComponentType> type) const {
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}
50
52 return data_->fill;
53}
54
55bool Path::IsConvex() const {
56 return data_->convexity == Convexity::kConvex;
57}
58
59bool Path::IsEmpty() const {
60 return data_->points.empty();
61}
62
64 const Applier<LinearPathComponent>& linear_applier,
65 const Applier<QuadraticPathComponent>& quad_applier,
66 const Applier<CubicPathComponent>& cubic_applier,
67 const Applier<ContourComponent>& contour_applier) const {
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}
105
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) {
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 }
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}
171
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}
189
191 size_t index,
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;
206 points[point_index], points[point_index + 1], points[point_index + 2]);
207 return true;
208}
209
211 CubicPathComponent& cubic) const {
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}
228
230 ContourComponent& move) const {
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}
244
247 : points(std::move(point_buffer)), reclaim_points_(std::move(reclaim)) {
249}
250
252 points = std::move(other.points);
253 reclaim_points_ = std::move(other.reclaim_points_);
254 contours = std::move(other.contours);
255}
256
258 if (reclaim_points_) {
259 points->clear();
260 reclaim_points_(std::move(points));
261 }
262}
263
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}
404
405std::optional<Rect> Path::GetBoundingBox() const {
406 return data_->bounds;
407}
408
410 const Matrix& transform) const {
411 auto bounds = GetBoundingBox();
412 if (!bounds.has_value()) {
413 return std::nullopt;
414 }
415 return bounds->TransformBounds(transform);
416}
417
418} // namespace impeller
int count
Definition: FontMgrTest.cpp:50
static const int points[]
GLenum type
FillType GetFillType() const
Definition: path.cc:51
size_t GetComponentCount(std::optional< ComponentType > type={}) const
Definition: path.cc:34
bool GetContourComponentAtIndex(size_t index, ContourComponent &contour) const
Definition: path.cc:229
void EnumerateComponents(const Applier< LinearPathComponent > &linear_applier, const Applier< QuadraticPathComponent > &quad_applier, const Applier< CubicPathComponent > &cubic_applier, const Applier< ContourComponent > &contour_applier) const
Definition: path.cc:63
std::optional< Rect > GetTransformedBoundingBox(const Matrix &transform) const
Definition: path.cc:409
std::function< void(size_t index, const T &component)> Applier
Definition: path.h:142
bool IsConvex() const
Definition: path.cc:55
bool GetLinearComponentAtIndex(size_t index, LinearPathComponent &linear) const
Definition: path.cc:172
void WritePolyline(Scalar scale, VertexWriter &writer) const
Definition: path.cc:106
bool IsEmpty() const
Definition: path.cc:59
bool GetQuadraticComponentAtIndex(size_t index, QuadraticPathComponent &quadratic) const
Definition: path.cc:190
bool GetCubicComponentAtIndex(size_t index, CubicPathComponent &cubic) const
Definition: path.cc:210
Polyline CreatePolyline(Scalar scale, Polyline::PointBufferPtr point_buffer=std::make_unique< std::vector< Point > >(), Polyline::ReclaimPointBufferCallback reclaim=nullptr) const
Definition: path.cc:264
std::optional< Rect > GetBoundingBox() const
Definition: path.cc:405
An interface for generating a multi contour polyline as a triangle strip.
void Write(Point point)
#define FML_DCHECK(condition)
Definition: logging.h:103
Optional< SkRect > bounds
Definition: SkRecords.h:189
struct PathData * Data(SkPath *path)
Definition: path_ops.cc:52
Point Vector2
Definition: point.h:326
float Scalar
Definition: scalar.h:18
FillType
Definition: path.h:30
std::variant< std::monostate, const LinearPathComponent *, const QuadraticPathComponent *, const CubicPathComponent * > PathComponentVariant
AI float quadratic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:156
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:195
Definition: ref_ptr.h:256
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
const Scalar scale
const Path::Polyline & polyline
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
Polyline(PointBufferPtr point_buffer, ReclaimPointBufferCallback reclaim)
Definition: path.cc:245
std::vector< PolylineContour > contours
Definition: path.h:116
std::function< void(PointBufferPtr)> ReclaimPointBufferCallback
Definition: path.h:99
std::unique_ptr< std::vector< Point > > PointBufferPtr
Definition: path.h:98
PointBufferPtr points
Definition: path.h:110
std::tuple< size_t, size_t > GetContourPointBounds(size_t contour_index) const
Definition: path.cc:22
void ToLinearPathComponents(Scalar scale_factor, const PointProc &proc) const
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
static sk_sp< SkShader > linear(sk_sp< SkShader > shader)