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_);
42 SetContourClosed(
true);
43 AddContourComponent(current_);
48 point = relative ? current_ + point : point;
49 AddLinearComponent(current_, point);
56 relative ?
Point{current_.
x + x, current_.
y} :
Point{x, current_.
y};
57 AddLinearComponent(current_, endpoint);
64 relative ?
Point{current_.
x, current_.
y + y} :
Point{current_.
x, y};
65 AddLinearComponent(current_, endpoint);
73 point = relative ? current_ + point : point;
74 controlPoint = relative ? current_ + controlPoint : controlPoint;
75 AddQuadraticComponent(current_, controlPoint, point);
81 prototype_.convexity = value;
89 controlPoint1 = relative ? current_ + controlPoint1 : controlPoint1;
90 controlPoint2 = relative ? current_ + controlPoint2 : controlPoint2;
91 point = relative ? current_ + point : point;
92 AddCubicComponent(current_, controlPoint1, controlPoint2, point);
99 AddQuadraticComponent(p1, cp, p2);
108 AddCubicComponent(p1, cp1, cp2, p2);
117 auto bl = origin +
Point{0.0, size.height};
118 auto br = origin + size;
119 auto tr = origin +
Point{size.width, 0.0};
135 return radius <= 0.0 ?
AddRect(rect)
151 auto rect_size = rect.
GetSize();
161 {rect_origin.x + radii.
top_left.
x, rect_origin.y},
162 {rect_origin.x + rect_size.width - radii.
top_right.
x, rect_origin.y});
167 AddRoundedRectTopRight(rect, radii);
173 {rect_origin.x + rect_size.width, rect_origin.y + radii.
top_right.
y},
174 {rect_origin.x + rect_size.width,
180 AddRoundedRectBottomRight(rect, radii);
187 rect_origin.y + rect_size.height},
188 {rect_origin.x + radii.
bottom_left.
x, rect_origin.y + rect_size.height});
193 AddRoundedRectBottomLeft(rect, radii);
199 {rect_origin.x, rect_origin.y + rect_size.height - radii.
bottom_left.
y},
200 {rect_origin.x, rect_origin.y + radii.
top_left.
y});
205 AddRoundedRectTopLeft(rect, radii);
213 RoundingRadii radii) {
216 AddCubicComponent({corner.x, corner.y + radii.top_left.y},
217 {corner.x, corner.y + radii.top_left.y - magic_top_left.y},
218 {corner.x + radii.top_left.x - magic_top_left.x, corner.y},
219 {corner.x + radii.top_left.x, corner.y});
223 PathBuilder& PathBuilder::AddRoundedRectTopRight(
Rect rect,
224 RoundingRadii radii) {
226 const auto corner = rect.GetOrigin() +
Point{rect.GetWidth(), 0};
228 {corner.x - radii.top_right.x, corner.y},
229 {corner.x - radii.top_right.x + magic_top_right.x, corner.y},
230 {corner.x, corner.y + radii.top_right.y - magic_top_right.y},
231 {corner.x, corner.y + radii.top_right.y});
235 PathBuilder& PathBuilder::AddRoundedRectBottomRight(
Rect rect,
236 RoundingRadii radii) {
238 const auto corner = rect.GetOrigin() + rect.GetSize();
240 {corner.x, corner.y - radii.bottom_right.y},
241 {corner.x, corner.y - radii.bottom_right.y + magic_bottom_right.y},
242 {corner.x - radii.bottom_right.x + magic_bottom_right.x, corner.y},
243 {corner.x - radii.bottom_right.x, corner.y});
247 PathBuilder& PathBuilder::AddRoundedRectBottomLeft(
Rect rect,
248 RoundingRadii radii) {
250 const auto corner = rect.GetOrigin() +
Point{0, rect.GetHeight()};
252 {corner.x + radii.bottom_left.x, corner.y},
253 {corner.x + radii.bottom_left.x - magic_bottom_left.x, corner.y},
254 {corner.x, corner.y - radii.bottom_left.y + magic_bottom_left.y},
255 {corner.x, corner.y - radii.bottom_left.y});
259 void PathBuilder::AddContourComponent(
const Point& destination,
261 auto& components = prototype_.components;
262 auto& contours = prototype_.contours;
263 if (components.size() > 0 &&
266 contours.back() = ContourComponent(destination, is_closed);
268 contours.emplace_back(ContourComponent(destination, is_closed));
271 prototype_.bounds.reset();
274 void PathBuilder::AddLinearComponent(
const Point& p1,
const Point& p2) {
275 auto& points = prototype_.points;
276 auto index = points.size();
277 points.emplace_back(p1);
278 points.emplace_back(p2);
280 prototype_.bounds.reset();
283 void PathBuilder::AddQuadraticComponent(
const Point& p1,
286 auto& points = prototype_.points;
287 auto index = points.size();
288 points.emplace_back(p1);
289 points.emplace_back(cp);
290 points.emplace_back(p2);
292 prototype_.bounds.reset();
295 void PathBuilder::AddCubicComponent(
const Point& p1,
299 auto& points = prototype_.points;
300 auto index = points.size();
301 points.emplace_back(p1);
302 points.emplace_back(cp1);
303 points.emplace_back(cp2);
304 points.emplace_back(p2);
306 prototype_.bounds.reset();
309 void PathBuilder::SetContourClosed(
bool is_closed) {
310 prototype_.contours.back().is_closed = is_closed;
331 LineTo(center + p1_unit * radius);
333 MoveTo(center + p1_unit * radius);
340 quadrant_angle = sweep.
radians;
342 std::sin(start.
radians + quadrant_angle));
345 p2_unit =
Vector2(-p1_unit.
y, p1_unit.
x);
351 Point p1 = center + p1_unit * radius;
352 Point p2 = center + p2_unit * radius;
356 AddCubicComponent(p1, cp1, cp2, p2);
359 start.
radians += quadrant_angle;
360 sweep.
radians -= quadrant_angle;
381 AddCubicComponent({c.
x, c.
y - r.
y},
382 {c.
x + m.
x, c.
y - r.
y},
383 {c.
x + r.
x, c.
y - m.
y},
390 AddCubicComponent({c.
x + r.
x, c.
y},
391 {c.
x + r.
x, c.
y + m.
y},
392 {c.
x + m.
x, c.
y + r.
y},
399 AddCubicComponent({c.
x, c.
y + r.
y},
400 {c.
x - m.
x, c.
y + r.
y},
401 {c.
x - r.
x, c.
y + m.
y},
408 AddCubicComponent({c.
x - r.
x, c.
y},
409 {c.
x - r.
x, c.
y - m.
y},
410 {c.
x - m.
x, c.
y - r.
y},
421 AddLinearComponent(p1, p2);
427 AddLinearComponent(l.p1, l.p2);
430 AddQuadraticComponent(q.p1, q.cp, q.p2);
433 AddCubicComponent(c.p1, c.cp1, c.cp2, c.p2);
436 AddContourComponent(m.destination);
443 for (
auto& point : prototype_.points) {
446 for (
auto& contour : prototype_.contours) {
447 contour.destination +=
offset;
449 prototype_.bounds.reset();
454 prototype_.bounds = bounds;
458 void PathBuilder::UpdateBounds() {
459 if (!prototype_.bounds.has_value()) {
460 auto min_max = GetMinMaxCoveragePoints();
461 if (!min_max.has_value()) {
462 prototype_.bounds.reset();
465 auto min = min_max->first;
466 auto max = min_max->second;
467 const auto difference = max - min;
473 std::optional<std::pair<Point, Point>> PathBuilder::GetMinMaxCoveragePoints()
475 auto& points = prototype_.points;
477 if (points.empty()) {
481 std::optional<Point> min, max;
483 auto clamp = [&min, &max](
const Point& point) {
484 if (min.has_value()) {
485 min = min->Min(point);
490 if (max.has_value()) {
491 max = max->Max(point);
497 for (
const auto& component : prototype_.components) {
498 switch (component.type) {
500 auto* linear =
reinterpret_cast<const LinearPathComponent*
>(
501 &points[component.index]);
507 for (
const auto& extrema :
508 reinterpret_cast<const QuadraticPathComponent*
>(
509 &points[component.index])
515 for (
const auto& extrema :
reinterpret_cast<const CubicPathComponent*
>(
516 &points[component.index])
526 if (!min.has_value() || !max.has_value()) {
530 return std::make_pair(min.value(), max.value());