14 AddContourComponent({});
20 prototype_.fill = fill;
21 prototype_.single_countour =
22 current_contour_location_ == 0u ||
23 (contour_count_ == 2 &&
25 return Path(prototype_);
29 prototype_.fill = fill;
31 prototype_.single_countour =
32 current_contour_location_ == 0u ||
33 (contour_count_ == 2 &&
35 current_contour_location_ = 0u;
37 return Path(std::move(prototype_));
41 prototype_.points.reserve(point_size);
42 prototype_.components.reserve(verb_size);
46 current_ = relative ? current_ + point : point;
47 subpath_start_ = current_;
48 AddContourComponent(current_);
56 if (subpath_start_ != current_) {
59 SetContourClosed(
true);
60 AddContourComponent(current_);
65 point = relative ? current_ + point : point;
66 AddLinearComponent(current_, point);
74 AddLinearComponent(current_, endpoint);
81 relative ?
Point{current_.
x, current_.
y + y} :
Point{current_.
x, y};
82 AddLinearComponent(current_, endpoint);
90 point = relative ? current_ + point : point;
91 controlPoint = relative ? current_ + controlPoint : controlPoint;
92 AddQuadraticComponent(current_, controlPoint, point);
98 prototype_.convexity =
value;
106 controlPoint1 = relative ? current_ + controlPoint1 : controlPoint1;
107 controlPoint2 = relative ? current_ + controlPoint2 : controlPoint2;
108 point = relative ? current_ + point : point;
109 AddCubicComponent(current_, controlPoint1, controlPoint2, point);
116 AddQuadraticComponent(p1, cp, p2);
125 AddCubicComponent(p1, cp1, cp2, p2);
134 auto bl = origin +
Point{0.0, size.height};
135 auto br = origin + size;
136 auto tr = origin +
Point{size.width, 0.0};
154 if (radii.AreAllCornersEmpty()) {
158 auto rect_origin = rect.GetOrigin();
159 auto rect_size = rect.GetSize();
161 current_ = rect_origin +
Point{radii.top_left.width, 0.0};
163 MoveTo({rect_origin.x + radii.top_left.width, rect_origin.y});
168 AddLinearComponentIfNeeded(
169 {rect_origin.x + radii.top_left.width, rect_origin.y},
170 {rect_origin.x + rect_size.width - radii.top_right.width, rect_origin.y});
175 AddRoundedRectTopRight(rect, radii);
180 AddLinearComponentIfNeeded(
181 {rect_origin.x + rect_size.width, rect_origin.y + radii.top_right.height},
182 {rect_origin.x + rect_size.width,
183 rect_origin.y + rect_size.height - radii.bottom_right.height});
188 AddRoundedRectBottomRight(rect, radii);
193 AddLinearComponentIfNeeded(
194 {rect_origin.x + rect_size.width - radii.bottom_right.width,
195 rect_origin.y + rect_size.height},
196 {rect_origin.x + radii.bottom_left.width,
197 rect_origin.y + rect_size.height});
202 AddRoundedRectBottomLeft(rect, radii);
207 AddLinearComponentIfNeeded(
209 rect_origin.y + rect_size.height - radii.bottom_left.height},
210 {rect_origin.x, rect_origin.y + radii.top_left.height});
215 AddRoundedRectTopLeft(rect, radii);
228 {corner.x, corner.y + radii.
top_left.
height - magic_top_left.height},
229 {corner.x + radii.
top_left.
width - magic_top_left.width, corner.y},
234 PathBuilder& PathBuilder::AddRoundedRectTopRight(
Rect rect,
235 RoundingRadii radii) {
237 const auto corner = rect.GetOrigin() +
Point{rect.GetWidth(), 0};
239 {corner.x - radii.top_right.width, corner.y},
240 {corner.x - radii.top_right.width + magic_top_right.width, corner.y},
241 {corner.x, corner.y + radii.top_right.height - magic_top_right.height},
242 {corner.x, corner.y + radii.top_right.height});
246 PathBuilder& PathBuilder::AddRoundedRectBottomRight(
Rect rect,
247 RoundingRadii radii) {
249 const auto corner = rect.GetOrigin() + rect.GetSize();
251 {corner.x, corner.y - radii.bottom_right.height},
253 corner.y - radii.bottom_right.height + magic_bottom_right.height},
254 {corner.x - radii.bottom_right.width + magic_bottom_right.width,
256 {corner.x - radii.bottom_right.width, corner.y});
260 PathBuilder& PathBuilder::AddRoundedRectBottomLeft(
Rect rect,
261 RoundingRadii radii) {
263 const auto corner = rect.GetOrigin() +
Point{0, rect.GetHeight()};
265 {corner.x + radii.bottom_left.width, corner.y},
266 {corner.x + radii.bottom_left.width - magic_bottom_left.width, corner.y},
268 corner.y - radii.bottom_left.height + magic_bottom_left.height},
269 {corner.x, corner.y - radii.bottom_left.height});
273 void PathBuilder::AddContourComponent(
const Point& destination,
275 auto& components = prototype_.components;
276 auto& points = prototype_.points;
277 auto closed = is_closed ?
Point{0, 0} :
Point{1, 1};
278 if (components.size() > 0 &&
281 points[current_contour_location_] = destination;
282 points[current_contour_location_ + 1] = closed;
284 current_contour_location_ = points.size();
285 points.push_back(destination);
286 points.push_back(closed);
290 prototype_.bounds.reset();
293 void PathBuilder::AddLinearComponentIfNeeded(
const Point& p1,
const Point& p2) {
298 AddLinearComponent(p1, p2);
301 void PathBuilder::AddLinearComponent(
const Point& p1,
const Point& p2) {
302 auto& points = prototype_.points;
303 points.push_back(p1);
304 points.push_back(p2);
306 prototype_.bounds.reset();
309 void PathBuilder::AddQuadraticComponent(
const Point& p1,
312 auto& points = prototype_.points;
313 points.push_back(p1);
314 points.push_back(cp);
315 points.push_back(p2);
317 prototype_.bounds.reset();
320 void PathBuilder::AddCubicComponent(
const Point& p1,
324 auto& points = prototype_.points;
325 points.push_back(p1);
326 points.push_back(cp1);
327 points.push_back(cp2);
328 points.push_back(p2);
330 prototype_.bounds.reset();
333 void PathBuilder::SetContourClosed(
bool is_closed) {
334 prototype_.points[current_contour_location_ + 1] =
356 LineTo(center + p1_unit * radius);
358 MoveTo(center + p1_unit * radius);
365 quadrant_angle = sweep.
radians;
367 std::sin(start.
radians + quadrant_angle));
370 p2_unit =
Vector2(-p1_unit.
y, p1_unit.
x);
376 Point p1 = center + p1_unit * radius;
377 Point p2 = center + p2_unit * radius;
381 AddCubicComponent(p1, cp1, cp2, p2);
384 start.
radians += quadrant_angle;
385 sweep.
radians -= quadrant_angle;
406 AddCubicComponent({c.
x, c.
y - r.
y},
407 {c.
x + m.
x, c.
y - r.
y},
408 {c.
x + r.
x, c.
y - m.
y},
415 AddCubicComponent({c.
x + r.
x, c.
y},
416 {c.
x + r.
x, c.
y + m.
y},
417 {c.
x + m.
x, c.
y + r.
y},
424 AddCubicComponent({c.
x, c.
y + r.
y},
425 {c.
x - m.
x, c.
y + r.
y},
426 {c.
x - r.
x, c.
y + m.
y},
433 AddCubicComponent({c.
x - r.
x, c.
y},
434 {c.
x - r.
x, c.
y - m.
y},
435 {c.
x - m.
x, c.
y - r.
y},
446 AddLinearComponent(p1, p2);
451 auto& points = prototype_.points;
452 auto& components = prototype_.components;
454 points.insert(points.end(), path.data_->points.begin(),
455 path.data_->points.end());
456 components.insert(components.end(), path.data_->components.begin(),
457 path.data_->components.end());
459 size_t source_offset = points.size();
460 for (
auto component : path.data_->components) {
462 current_contour_location_ = source_offset;
471 auto& points = prototype_.points;
472 size_t storage_offset = 0u;
473 for (
const auto& component : prototype_.components) {
506 prototype_.bounds.reset();
511 prototype_.bounds = bounds;
515 void PathBuilder::UpdateBounds() {
516 if (!prototype_.bounds.has_value()) {
517 auto min_max = GetMinMaxCoveragePoints();
518 if (!min_max.has_value()) {
519 prototype_.bounds.reset();
522 auto min = min_max->first;
523 auto max = min_max->second;
524 const auto difference = max - min;
530 std::optional<std::pair<Point, Point>> PathBuilder::GetMinMaxCoveragePoints()
532 auto& points = prototype_.points;
534 if (points.empty()) {
538 std::optional<Point> min, max;
540 auto clamp = [&min, &max](
const Point& point) {
541 if (min.has_value()) {
542 min = min->Min(point);
547 if (max.has_value()) {
548 max = max->Max(point);
554 size_t storage_offset = 0u;
555 for (
const auto& component : prototype_.components) {
558 auto* linear =
reinterpret_cast<const LinearPathComponent*
>(
559 &points[storage_offset]);
565 for (
const auto& extrema :
566 reinterpret_cast<const QuadraticPathComponent*
>(
567 &points[storage_offset])
573 for (
const auto& extrema :
reinterpret_cast<const CubicPathComponent*
>(
574 &points[storage_offset])
585 if (!min.has_value() || !max.has_value()) {
589 return std::make_pair(min.value(), max.value());
PathBuilder & AddRect(Rect rect)
Path TakePath(FillType fill=FillType::kNonZero)
PathBuilder & AddArc(const Rect &oval_bounds, Radians start, Radians sweep, bool use_center=false)
PathBuilder & AddRoundRect(RoundRect rect)
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
PathBuilder & MoveTo(Point point, bool relative=false)
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
void Reserve(size_t point_size, size_t verb_size)
Reserve [point_size] points and [verb_size] verbs in the underlying path buffer.
PathBuilder & AddOval(const Rect &rect)
PathBuilder & AddCircle(const Point ¢er, Scalar radius)
PathBuilder & AddPath(const Path &path)
Path CopyPath(FillType fill=FillType::kNonZero)
PathBuilder & VerticalLineTo(Scalar y, bool relative=false)
PathBuilder & Shift(Point offset)
Transform the existing path segments and contours by the given offset.
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
constexpr static const Scalar kArcApproximationMagic
PathBuilder & AddQuadraticCurve(Point p1, Point cp, Point p2)
Move to point p1, then insert a quadradic curve from p1 to p2 with the control point cp.
PathBuilder & CubicCurveTo(Point controlPoint1, Point controlPoint2, Point point, bool relative=false)
Insert a cubic curve from the curren position to point using the control points controlPoint1 and con...
PathBuilder & AddCubicCurve(Point p1, Point cp1, Point cp2, Point p2)
Move to point p1, then insert a cubic curve from p1 to p2 with control points cp1 and cp2.
PathBuilder & HorizontalLineTo(Scalar x, bool relative=false)
PathBuilder & SetConvexity(Convexity value)
PathBuilder & QuadraticCurveTo(Point controlPoint, Point point, bool relative=false)
Insert a quadradic curve from the current position to point using the control point controlPoint.
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
static constexpr size_t VerbToOffset(Path::ComponentType verb)
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr Point GetCenter() const
Get the center point as a |Point|.