10 #include "flutter/fml/logging.h"
17 AddContourComponent({});
23 size_t contour_index)
const {
24 if (contour_index >=
contours.size()) {
27 const size_t start_index =
contours.at(contour_index).start_index;
28 const size_t end_index = (contour_index >=
contours.size() - 1)
30 :
contours.at(contour_index + 1).start_index;
31 return std::make_tuple(start_index, end_index);
35 if (!type.has_value()) {
36 return components_.size();
38 auto type_value = type.value();
40 return contours_.size();
43 for (
const auto& component : components_) {
44 if (component.type == type_value) {
51 void Path::SetFillType(
FillType fill) {
63 void Path::SetConvexity(
Convexity value) {
67 void Path::Shift(
Point shift) {
68 for (
auto i = 0u; i < points_.size(); i++) {
71 for (
auto& contour : contours_) {
72 contour.destination += shift;
77 Path new_path = *
this;
82 auto index = points_.size();
83 points_.emplace_back(p1);
84 points_.emplace_back(p2);
89 Path& Path::AddQuadraticComponent(
const Point& p1,
92 auto index = points_.size();
93 points_.emplace_back(p1);
94 points_.emplace_back(cp);
95 points_.emplace_back(p2);
100 Path& Path::AddCubicComponent(
const Point& p1,
104 auto index = points_.size();
105 points_.emplace_back(p1);
106 points_.emplace_back(cp1);
107 points_.emplace_back(cp2);
108 points_.emplace_back(p2);
113 Path& Path::AddContourComponent(
const Point& destination,
bool is_closed) {
114 if (components_.size() > 0 &&
117 contours_.back() = ContourComponent(destination, is_closed);
119 contours_.emplace_back(ContourComponent(destination, is_closed));
125 void Path::SetContourClosed(
bool is_closed) {
126 contours_.back().is_closed = is_closed;
134 size_t currentIndex = 0;
135 for (
const auto& component : components_) {
136 switch (component.type) {
138 if (linear_applier) {
139 linear_applier(currentIndex,
141 points_[component.index + 1]));
146 quad_applier(currentIndex,
148 points_[component.index + 1],
149 points_[component.index + 2]));
154 cubic_applier(currentIndex,
156 points_[component.index + 1],
157 points_[component.index + 2],
158 points_[component.index + 3]));
162 if (contour_applier) {
163 contour_applier(currentIndex, contours_[component.index]);
173 if (index >= components_.size()) {
181 auto point_index = components_[index].index;
189 if (index >= components_.size()) {
197 auto point_index = components_[index].index;
199 points_[point_index], points_[point_index + 1], points_[point_index + 2]);
205 if (index >= components_.size()) {
213 auto point_index = components_[index].index;
216 points_[point_index + 2], points_[point_index + 3]);
222 if (index >= components_.size()) {
230 move = contours_[components_[index].index];
236 : points(
std::move(point_buffer)), reclaim_points_(
std::move(reclaim)) {
241 points = std::move(other.points);
242 reclaim_points_ = std::move(other.reclaim_points_);
243 contours = std::move(other.contours);
247 if (reclaim_points_) {
249 reclaim_points_(std::move(points));
257 Polyline polyline(std::move(point_buffer), std::move(reclaim));
260 if (component_i >= components_.size()) {
261 return std::monostate{};
263 const auto& component = components_[component_i];
264 switch (component.type) {
267 &points_[component.index]);
270 &points_[component.index]);
273 &points_[component.index]);
275 return std::monostate{};
279 auto compute_contour_start_direction =
280 [&get_path_component](
size_t current_path_component_index) {
281 size_t next_component_index = current_path_component_index + 1;
282 while (!std::holds_alternative<std::monostate>(
283 get_path_component(next_component_index))) {
284 auto next_component = get_path_component(next_component_index);
287 if (maybe_vector.has_value()) {
288 return maybe_vector.value();
290 next_component_index++;
296 std::vector<PolylineContour::Component> components;
297 std::optional<size_t> previous_path_component_index;
298 auto end_contour = [&polyline, &previous_path_component_index,
299 &get_path_component, &components]() {
306 if (!previous_path_component_index.has_value()) {
310 auto& contour = polyline.
contours.back();
311 contour.end_direction =
Vector2(0, 1);
312 contour.components = components;
315 size_t previous_index = previous_path_component_index.value();
316 while (!std::holds_alternative<std::monostate>(
317 get_path_component(previous_index))) {
318 auto previous_component = get_path_component(previous_index);
321 if (maybe_vector.has_value()) {
322 contour.end_direction = maybe_vector.value();
325 if (previous_index == 0) {
333 for (
size_t component_i = 0; component_i < components_.size();
335 const auto& component = components_[component_i];
336 switch (component.type) {
338 components.push_back({
339 .component_start_index = polyline.
points->size() - 1,
343 ->AppendPolylinePoints(*polyline.
points);
344 previous_path_component_index = component_i;
347 components.push_back({
348 .component_start_index = polyline.
points->size() - 1,
352 &points_[component.index])
353 ->AppendPolylinePoints(scale, *polyline.
points);
354 previous_path_component_index = component_i;
357 components.push_back({
358 .component_start_index = polyline.
points->size() - 1,
362 ->AppendPolylinePoints(scale, *polyline.
points);
363 previous_path_component_index = component_i;
366 if (component_i == components_.size() - 1) {
373 Vector2 start_direction = compute_contour_start_direction(component_i);
374 const auto& contour = contours_[component.index];
375 polyline.
contours.push_back({.start_index = polyline.
points->size(),
376 .is_closed = contour.is_closed,
377 .start_direction = start_direction,
378 .components = components});
380 polyline.
points->push_back(contour.destination);
389 return computed_bounds_;
392 void Path::ComputeBounds() {
394 if (!min_max.has_value()) {
395 computed_bounds_ = std::nullopt;
398 auto min = min_max->first;
399 auto max = min_max->second;
400 const auto difference = max - min;
401 computed_bounds_ =
Rect::MakeXYWH(min.x, min.y, difference.x, difference.y);
405 const Matrix& transform)
const {
407 if (!bounds.has_value()) {
410 return bounds->TransformBounds(transform);
414 if (points_.empty()) {
418 std::optional<Point> min, max;
420 auto clamp = [&min, &max](
const Point& point) {
421 if (min.has_value()) {
422 min = min->Min(point);
427 if (max.has_value()) {
428 max = max->Max(point);
434 for (
const auto& component : components_) {
435 switch (component.type) {
438 &points_[component.index]);
444 for (
const auto& extrema :
446 &points_[component.index])
453 &points_[component.index])
463 if (!min.has_value() || !max.has_value()) {
467 return std::make_pair(min.value(), max.value());
470 void Path::SetBounds(
Rect rect) {
471 computed_bounds_ = rect;