12 AddContourComponent({});
18 prototype_.fill = fill;
19 return Path(prototype_);
23 prototype_.fill = fill;
25 return Path(std::move(prototype_));
29 prototype_.points.reserve(point_size);
30 prototype_.components.reserve(verb_size);
34 current_ = relative ? current_ + point : point;
35 subpath_start_ = current_;
36 AddContourComponent(current_);
44 if (subpath_start_ != current_) {
47 SetContourClosed(
true);
48 AddContourComponent(current_);
53 point = relative ? current_ + point : point;
54 AddLinearComponent(current_, point);
61 relative ?
Point{current_.
x + x, current_.
y} :
Point{x, current_.
y};
62 AddLinearComponent(current_, endpoint);
69 relative ?
Point{current_.
x, current_.
y + y} :
Point{current_.
x, y};
70 AddLinearComponent(current_, endpoint);
78 point = relative ? current_ + point : point;
79 controlPoint = relative ? current_ + controlPoint : controlPoint;
80 AddQuadraticComponent(current_, controlPoint, point);
86 prototype_.convexity = value;
94 controlPoint1 = relative ? current_ + controlPoint1 : controlPoint1;
95 controlPoint2 = relative ? current_ + controlPoint2 : controlPoint2;
96 point = relative ? current_ + point : point;
97 AddCubicComponent(current_, controlPoint1, controlPoint2, point);
104 AddQuadraticComponent(p1, cp, p2);
113 AddCubicComponent(p1, cp1, cp2, p2);
122 auto bl = origin +
Point{0.0, size.height};
123 auto br = origin + size;
124 auto tr = origin +
Point{size.width, 0.0};
140 return radius <= 0.0 ?
AddRect(rect)
156 auto rect_size = rect.
GetSize();
166 {rect_origin.x + radii.
top_left.
x, rect_origin.y},
167 {rect_origin.x + rect_size.width - radii.
top_right.
x, rect_origin.y});
172 AddRoundedRectTopRight(rect, radii);
178 {rect_origin.x + rect_size.width, rect_origin.y + radii.
top_right.
y},
179 {rect_origin.x + rect_size.width,
185 AddRoundedRectBottomRight(rect, radii);
192 rect_origin.y + rect_size.height},
193 {rect_origin.x + radii.
bottom_left.
x, rect_origin.y + rect_size.height});
198 AddRoundedRectBottomLeft(rect, radii);
204 {rect_origin.x, rect_origin.y + rect_size.height - radii.
bottom_left.
y},
205 {rect_origin.x, rect_origin.y + radii.
top_left.
y});
210 AddRoundedRectTopLeft(rect, radii);
218 RoundingRadii radii) {
221 AddCubicComponent({corner.x, corner.y + radii.top_left.y},
222 {corner.x, corner.y + radii.top_left.y - magic_top_left.y},
223 {corner.x + radii.top_left.x - magic_top_left.x, corner.y},
224 {corner.x + radii.top_left.x, corner.y});
228 PathBuilder& PathBuilder::AddRoundedRectTopRight(
Rect rect,
229 RoundingRadii radii) {
231 const auto corner = rect.GetOrigin() +
Point{rect.GetWidth(), 0};
233 {corner.x - radii.top_right.x, corner.y},
234 {corner.x - radii.top_right.x + magic_top_right.x, corner.y},
235 {corner.x, corner.y + radii.top_right.y - magic_top_right.y},
236 {corner.x, corner.y + radii.top_right.y});
240 PathBuilder& PathBuilder::AddRoundedRectBottomRight(
Rect rect,
241 RoundingRadii radii) {
243 const auto corner = rect.GetOrigin() + rect.GetSize();
245 {corner.x, corner.y - radii.bottom_right.y},
246 {corner.x, corner.y - radii.bottom_right.y + magic_bottom_right.y},
247 {corner.x - radii.bottom_right.x + magic_bottom_right.x, corner.y},
248 {corner.x - radii.bottom_right.x, corner.y});
252 PathBuilder& PathBuilder::AddRoundedRectBottomLeft(
Rect rect,
253 RoundingRadii radii) {
255 const auto corner = rect.GetOrigin() +
Point{0, rect.GetHeight()};
257 {corner.x + radii.bottom_left.x, corner.y},
258 {corner.x + radii.bottom_left.x - magic_bottom_left.x, corner.y},
259 {corner.x, corner.y - radii.bottom_left.y + magic_bottom_left.y},
260 {corner.x, corner.y - radii.bottom_left.y});
264 void PathBuilder::AddContourComponent(
const Point& destination,
266 auto& components = prototype_.components;
267 auto& contours = prototype_.contours;
268 if (components.size() > 0 &&
271 contours.back() = ContourComponent(destination, is_closed);
273 contours.emplace_back(ContourComponent(destination, is_closed));
276 prototype_.bounds.reset();
279 void PathBuilder::AddLinearComponent(
const Point& p1,
const Point& p2) {
280 auto& points = prototype_.points;
281 auto index = points.size();
282 points.emplace_back(p1);
283 points.emplace_back(p2);
285 prototype_.bounds.reset();
288 void PathBuilder::AddQuadraticComponent(
const Point& p1,
291 auto& points = prototype_.points;
292 auto index = points.size();
293 points.emplace_back(p1);
294 points.emplace_back(cp);
295 points.emplace_back(p2);
297 prototype_.bounds.reset();
300 void PathBuilder::AddCubicComponent(
const Point& p1,
304 auto& points = prototype_.points;
305 auto index = points.size();
306 points.emplace_back(p1);
307 points.emplace_back(cp1);
308 points.emplace_back(cp2);
309 points.emplace_back(p2);
311 prototype_.bounds.reset();
314 void PathBuilder::SetContourClosed(
bool is_closed) {
315 prototype_.contours.back().is_closed = is_closed;
336 LineTo(center + p1_unit * radius);
338 MoveTo(center + p1_unit * radius);
345 quadrant_angle = sweep.
radians;
347 std::sin(start.
radians + quadrant_angle));
350 p2_unit =
Vector2(-p1_unit.
y, p1_unit.
x);
356 Point p1 = center + p1_unit * radius;
357 Point p2 = center + p2_unit * radius;
361 AddCubicComponent(p1, cp1, cp2, p2);
364 start.
radians += quadrant_angle;
365 sweep.
radians -= quadrant_angle;
386 AddCubicComponent({c.
x, c.
y - r.
y},
387 {c.
x + m.
x, c.
y - r.
y},
388 {c.
x + r.
x, c.
y - m.
y},
395 AddCubicComponent({c.
x + r.
x, c.
y},
396 {c.
x + r.
x, c.
y + m.
y},
397 {c.
x + m.
x, c.
y + r.
y},
404 AddCubicComponent({c.
x, c.
y + r.
y},
405 {c.
x - m.
x, c.
y + r.
y},
406 {c.
x - r.
x, c.
y + m.
y},
413 AddCubicComponent({c.
x - r.
x, c.
y},
414 {c.
x - r.
x, c.
y - m.
y},
415 {c.
x - m.
x, c.
y - r.
y},
426 AddLinearComponent(p1, p2);
432 AddLinearComponent(l.p1, l.p2);
435 AddQuadraticComponent(q.p1, q.cp, q.p2);
438 AddCubicComponent(c.p1, c.cp1, c.cp2, c.p2);
441 AddContourComponent(m.destination);
448 for (
auto& point : prototype_.points) {
451 for (
auto& contour : prototype_.contours) {
452 contour.destination +=
offset;
454 prototype_.bounds.reset();
459 prototype_.bounds = bounds;
463 void PathBuilder::UpdateBounds() {
464 if (!prototype_.bounds.has_value()) {
465 auto min_max = GetMinMaxCoveragePoints();
466 if (!min_max.has_value()) {
467 prototype_.bounds.reset();
470 auto min = min_max->first;
471 auto max = min_max->second;
472 const auto difference = max - min;
478 std::optional<std::pair<Point, Point>> PathBuilder::GetMinMaxCoveragePoints()
480 auto& points = prototype_.points;
482 if (points.empty()) {
486 std::optional<Point> min, max;
488 auto clamp = [&min, &max](
const Point& point) {
489 if (min.has_value()) {
490 min = min->Min(point);
495 if (max.has_value()) {
496 max = max->Max(point);
502 for (
const auto& component : prototype_.components) {
503 switch (component.type) {
505 auto* linear =
reinterpret_cast<const LinearPathComponent*
>(
506 &points[component.index]);
512 for (
const auto& extrema :
513 reinterpret_cast<const QuadraticPathComponent*
>(
514 &points[component.index])
520 for (
const auto& extrema :
reinterpret_cast<const CubicPathComponent*
>(
521 &points[component.index])
531 if (!min.has_value() || !max.has_value()) {
535 return std::make_pair(min.value(), max.value());