14 AddContourComponent({});
20 prototype_.fill = fill;
21 return Path(prototype_);
25 prototype_.fill = fill;
27 current_contour_location_ = 0u;
28 return Path(std::move(prototype_));
32 prototype_.points.reserve(point_size);
33 prototype_.components.reserve(verb_size);
37 current_ = relative ? current_ + point : point;
38 subpath_start_ = current_;
39 AddContourComponent(current_);
47 if (subpath_start_ != current_) {
50 SetContourClosed(
true);
51 AddContourComponent(current_);
56 point = relative ? current_ + point : point;
57 AddLinearComponent(current_, point);
64 relative ?
Point{current_.
x + x, current_.
y} :
Point{x, current_.
y};
65 AddLinearComponent(current_, endpoint);
72 relative ?
Point{current_.
x, current_.
y + y} :
Point{current_.
x, y};
73 AddLinearComponent(current_, endpoint);
81 point = relative ? current_ + point : point;
82 controlPoint = relative ? current_ + controlPoint : controlPoint;
83 AddQuadraticComponent(current_, controlPoint, point);
89 prototype_.convexity = value;
97 controlPoint1 = relative ? current_ + controlPoint1 : controlPoint1;
98 controlPoint2 = relative ? current_ + controlPoint2 : controlPoint2;
99 point = relative ? current_ + point : point;
100 AddCubicComponent(current_, controlPoint1, controlPoint2, point);
107 AddQuadraticComponent(p1, cp, p2);
116 AddCubicComponent(p1, cp1, cp2, p2);
125 auto bl = origin +
Point{0.0, size.height};
126 auto br = origin + size;
127 auto tr = origin +
Point{size.width, 0.0};
143 return radius <= 0.0 ?
AddRect(rect)
159 auto rect_size = rect.
GetSize();
169 {rect_origin.x + radii.
top_left.
x, rect_origin.y},
170 {rect_origin.x + rect_size.width - radii.
top_right.
x, rect_origin.y});
175 AddRoundedRectTopRight(rect, radii);
181 {rect_origin.x + rect_size.width, rect_origin.y + radii.
top_right.
y},
182 {rect_origin.x + rect_size.width,
188 AddRoundedRectBottomRight(rect, radii);
195 rect_origin.y + rect_size.height},
196 {rect_origin.x + radii.
bottom_left.
x, rect_origin.y + rect_size.height});
201 AddRoundedRectBottomLeft(rect, radii);
207 {rect_origin.x, rect_origin.y + rect_size.height - radii.
bottom_left.
y},
208 {rect_origin.x, rect_origin.y + radii.
top_left.
y});
213 AddRoundedRectTopLeft(rect, radii);
221 RoundingRadii radii) {
224 AddCubicComponent({corner.x, corner.y + radii.top_left.y},
225 {corner.x, corner.y + radii.top_left.y - magic_top_left.y},
226 {corner.x + radii.top_left.x - magic_top_left.x, corner.y},
227 {corner.x + radii.top_left.x, corner.y});
231 PathBuilder& PathBuilder::AddRoundedRectTopRight(
Rect rect,
232 RoundingRadii radii) {
234 const auto corner = rect.GetOrigin() +
Point{rect.GetWidth(), 0};
236 {corner.x - radii.top_right.x, corner.y},
237 {corner.x - radii.top_right.x + magic_top_right.x, corner.y},
238 {corner.x, corner.y + radii.top_right.y - magic_top_right.y},
239 {corner.x, corner.y + radii.top_right.y});
243 PathBuilder& PathBuilder::AddRoundedRectBottomRight(
Rect rect,
244 RoundingRadii radii) {
246 const auto corner = rect.GetOrigin() + rect.GetSize();
248 {corner.x, corner.y - radii.bottom_right.y},
249 {corner.x, corner.y - radii.bottom_right.y + magic_bottom_right.y},
250 {corner.x - radii.bottom_right.x + magic_bottom_right.x, corner.y},
251 {corner.x - radii.bottom_right.x, corner.y});
255 PathBuilder& PathBuilder::AddRoundedRectBottomLeft(
Rect rect,
256 RoundingRadii radii) {
258 const auto corner = rect.GetOrigin() +
Point{0, rect.GetHeight()};
260 {corner.x + radii.bottom_left.x, corner.y},
261 {corner.x + radii.bottom_left.x - magic_bottom_left.x, corner.y},
262 {corner.x, corner.y - radii.bottom_left.y + magic_bottom_left.y},
263 {corner.x, corner.y - radii.bottom_left.y});
267 void PathBuilder::AddContourComponent(
const Point& destination,
269 auto& components = prototype_.components;
270 auto& points = prototype_.points;
271 auto closed = is_closed ?
Point{0, 0} :
Point{1, 1};
272 if (components.size() > 0 &&
275 points[current_contour_location_] = destination;
276 points[current_contour_location_ + 1] = closed;
278 current_contour_location_ = points.size();
279 points.push_back(destination);
280 points.push_back(closed);
283 prototype_.bounds.reset();
286 void PathBuilder::AddLinearComponent(
const Point& p1,
const Point& p2) {
287 auto& points = prototype_.points;
288 points.push_back(p1);
289 points.push_back(p2);
291 prototype_.bounds.reset();
294 void PathBuilder::AddQuadraticComponent(
const Point& p1,
297 auto& points = prototype_.points;
298 points.push_back(p1);
299 points.push_back(cp);
300 points.push_back(p2);
302 prototype_.bounds.reset();
305 void PathBuilder::AddCubicComponent(
const Point& p1,
309 auto& points = prototype_.points;
310 points.push_back(p1);
311 points.push_back(cp1);
312 points.push_back(cp2);
313 points.push_back(p2);
315 prototype_.bounds.reset();
318 void PathBuilder::SetContourClosed(
bool is_closed) {
319 prototype_.points[current_contour_location_ + 1] =
341 LineTo(center + p1_unit * radius);
343 MoveTo(center + p1_unit * radius);
350 quadrant_angle = sweep.
radians;
352 std::sin(start.
radians + quadrant_angle));
355 p2_unit =
Vector2(-p1_unit.
y, p1_unit.
x);
361 Point p1 = center + p1_unit * radius;
362 Point p2 = center + p2_unit * radius;
366 AddCubicComponent(p1, cp1, cp2, p2);
369 start.
radians += quadrant_angle;
370 sweep.
radians -= quadrant_angle;
391 AddCubicComponent({c.
x, c.
y - r.
y},
392 {c.
x + m.
x, c.
y - r.
y},
393 {c.
x + r.
x, c.
y - m.
y},
400 AddCubicComponent({c.
x + r.
x, c.
y},
401 {c.
x + r.
x, c.
y + m.
y},
402 {c.
x + m.
x, c.
y + r.
y},
409 AddCubicComponent({c.
x, c.
y + r.
y},
410 {c.
x - m.
x, c.
y + r.
y},
411 {c.
x - r.
x, c.
y + m.
y},
418 AddCubicComponent({c.
x - r.
x, c.
y},
419 {c.
x - r.
x, c.
y - m.
y},
420 {c.
x - m.
x, c.
y - r.
y},
431 AddLinearComponent(p1, p2);
436 auto& points = prototype_.points;
437 auto& components = prototype_.components;
439 points.insert(points.end(), path.data_->points.begin(),
440 path.data_->points.end());
441 components.insert(components.end(), path.data_->components.begin(),
442 path.data_->components.end());
444 size_t source_offset = points.size();
445 for (
auto component : path.data_->components) {
447 current_contour_location_ = source_offset;
455 auto& points = prototype_.points;
456 size_t storage_offset = 0u;
457 for (
const auto& component : prototype_.components) {
490 prototype_.bounds.reset();
495 prototype_.bounds = bounds;
499 void PathBuilder::UpdateBounds() {
500 if (!prototype_.bounds.has_value()) {
501 auto min_max = GetMinMaxCoveragePoints();
502 if (!min_max.has_value()) {
503 prototype_.bounds.reset();
506 auto min = min_max->first;
507 auto max = min_max->second;
508 const auto difference = max - min;
514 std::optional<std::pair<Point, Point>> PathBuilder::GetMinMaxCoveragePoints()
516 auto& points = prototype_.points;
518 if (points.empty()) {
522 std::optional<Point> min, max;
524 auto clamp = [&min, &max](
const Point& point) {
525 if (min.has_value()) {
526 min = min->Min(point);
531 if (max.has_value()) {
532 max = max->Max(point);
538 size_t storage_offset = 0u;
539 for (
const auto& component : prototype_.components) {
542 auto* linear =
reinterpret_cast<const LinearPathComponent*
>(
543 &points[storage_offset]);
549 for (
const auto& extrema :
550 reinterpret_cast<const QuadraticPathComponent*
>(
551 &points[storage_offset])
557 for (
const auto& extrema :
reinterpret_cast<const CubicPathComponent*
>(
558 &points[storage_offset])
569 if (!min.has_value() || !max.has_value()) {
573 return std::make_pair(min.value(), max.value());