| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef FLUTTER_IMPELLER_GEOMETRY_PATH_BUILDER_H_ |
| #define FLUTTER_IMPELLER_GEOMETRY_PATH_BUILDER_H_ |
| |
| #include "impeller/geometry/path.h" |
| #include "impeller/geometry/rect.h" |
| #include "impeller/geometry/scalar.h" |
| |
| namespace impeller { |
| |
| class PathBuilder { |
| public: |
| /// Used for approximating quarter circle arcs with cubic curves. This is the |
| /// control point distance which results in the smallest possible unit circle |
| /// integration for a right angle arc. It can be used to approximate arcs less |
| /// than 90 degrees to great effect by simply reducing it proportionally to |
| /// the angle. However, accuracy rapidly diminishes if magnified for obtuse |
| /// angle arcs, and so multiple cubic curves should be used when approximating |
| /// arcs greater than 90 degrees. |
| constexpr static const Scalar kArcApproximationMagic = 0.551915024494f; |
| |
| PathBuilder(); |
| |
| ~PathBuilder(); |
| |
| Path CopyPath(FillType fill = FillType::kNonZero); |
| |
| Path TakePath(FillType fill = FillType::kNonZero); |
| |
| /// @brief Reserve [point_size] points and [verb_size] verbs in the underlying |
| /// path buffer. |
| void Reserve(size_t point_size, size_t verb_size); |
| |
| PathBuilder& SetConvexity(Convexity value); |
| |
| PathBuilder& MoveTo(Point point, bool relative = false); |
| |
| PathBuilder& Close(); |
| |
| /// @brief Insert a line from the current position to `point`. |
| /// |
| /// If `relative` is true, then `point` is relative to the current location. |
| PathBuilder& LineTo(Point point, bool relative = false); |
| |
| PathBuilder& HorizontalLineTo(Scalar x, bool relative = false); |
| |
| PathBuilder& VerticalLineTo(Scalar y, bool relative = false); |
| |
| /// @brief Insert a quadradic curve from the current position to `point` using |
| /// the control point `controlPoint`. |
| /// |
| /// If `relative` is true the `point` and `controlPoint` are relative to |
| /// current location. |
| PathBuilder& QuadraticCurveTo(Point controlPoint, |
| Point point, |
| bool relative = false); |
| |
| /// @brief Insert a cubic curve from the curren position to `point` using the |
| /// control points `controlPoint1` and `controlPoint2`. |
| /// |
| /// If `relative` is true the `point`, `controlPoint1`, and `controlPoint2` |
| /// are relative to current location. |
| PathBuilder& CubicCurveTo(Point controlPoint1, |
| Point controlPoint2, |
| Point point, |
| bool relative = false); |
| |
| PathBuilder& AddRect(Rect rect); |
| |
| PathBuilder& AddCircle(const Point& center, Scalar radius); |
| |
| PathBuilder& AddArc(const Rect& oval_bounds, |
| Radians start, |
| Radians sweep, |
| bool use_center = false); |
| |
| PathBuilder& AddOval(const Rect& rect); |
| |
| /// @brief Move to point `p1`, then insert a line from `p1` to `p2`. |
| PathBuilder& AddLine(const Point& p1, const Point& p2); |
| |
| /// @brief Move to point `p1`, then insert a quadradic curve from `p1` to `p2` |
| /// with the control point `cp`. |
| PathBuilder& AddQuadraticCurve(Point p1, Point cp, Point p2); |
| |
| /// @brief Move to point `p1`, then insert a cubic curve from `p1` to `p2` |
| /// with control points `cp1` and `cp2`. |
| PathBuilder& AddCubicCurve(Point p1, Point cp1, Point cp2, Point p2); |
| |
| /// @brief Transform the existing path segments and contours by the given |
| /// `offset`. |
| PathBuilder& Shift(Point offset); |
| |
| /// @brief Set the bounding box that will be used by `Path.GetBoundingBox` in |
| /// place of performing the computation. |
| /// |
| /// When Impeller recieves Skia Path objects, many of these already |
| /// have computed bounds. This method is used to avoid needlessly |
| /// recomputing these bounds. |
| PathBuilder& SetBounds(Rect bounds); |
| |
| struct RoundingRadii { |
| Point top_left; |
| Point bottom_left; |
| Point top_right; |
| Point bottom_right; |
| |
| RoundingRadii() = default; |
| |
| RoundingRadii(Scalar p_top_left, |
| Scalar p_bottom_left, |
| Scalar p_top_right, |
| Scalar p_bottom_right) |
| : top_left(p_top_left, p_top_left), |
| bottom_left(p_bottom_left, p_bottom_left), |
| top_right(p_top_right, p_top_right), |
| bottom_right(p_bottom_right, p_bottom_right) {} |
| |
| explicit RoundingRadii(Scalar radius) |
| : top_left(radius, radius), |
| bottom_left(radius, radius), |
| top_right(radius, radius), |
| bottom_right(radius, radius) {} |
| |
| explicit RoundingRadii(Point radii) |
| : top_left(radii), |
| bottom_left(radii), |
| top_right(radii), |
| bottom_right(radii) {} |
| |
| explicit RoundingRadii(Size radii) |
| : top_left(radii), |
| bottom_left(radii), |
| top_right(radii), |
| bottom_right(radii) {} |
| |
| bool AreAllZero() const { |
| return top_left.IsZero() && // |
| bottom_left.IsZero() && // |
| top_right.IsZero() && // |
| bottom_right.IsZero(); |
| } |
| }; |
| |
| PathBuilder& AddRoundedRect(Rect rect, RoundingRadii radii); |
| |
| PathBuilder& AddRoundedRect(Rect rect, Size radii); |
| |
| PathBuilder& AddRoundedRect(Rect rect, Scalar radius); |
| |
| PathBuilder& AddPath(const Path& path); |
| |
| private: |
| Point subpath_start_; |
| Point current_; |
| Path::Data prototype_; |
| |
| PathBuilder& AddRoundedRectTopLeft(Rect rect, RoundingRadii radii); |
| |
| PathBuilder& AddRoundedRectTopRight(Rect rect, RoundingRadii radii); |
| |
| PathBuilder& AddRoundedRectBottomRight(Rect rect, RoundingRadii radii); |
| |
| PathBuilder& AddRoundedRectBottomLeft(Rect rect, RoundingRadii radii); |
| |
| void AddContourComponent(const Point& destination, bool is_closed = false); |
| |
| void SetContourClosed(bool is_closed); |
| |
| void AddLinearComponent(const Point& p1, const Point& p2); |
| |
| void AddQuadraticComponent(const Point& p1, const Point& cp, const Point& p2); |
| |
| void AddCubicComponent(const Point& p1, |
| const Point& cp1, |
| const Point& cp2, |
| const Point& p2); |
| |
| /// Compute the bounds of the path unless they are already computed or |
| /// set by an external source, such as |SetBounds|. Any call which mutates |
| /// the path data can invalidate the computed/set bounds. |
| void UpdateBounds(); |
| |
| std::optional<std::pair<Point, Point>> GetMinMaxCoveragePoints() const; |
| |
| PathBuilder(const PathBuilder&) = delete; |
| PathBuilder& operator=(const PathBuilder&&) = delete; |
| }; |
| |
| } // namespace impeller |
| |
| #endif // FLUTTER_IMPELLER_GEOMETRY_PATH_BUILDER_H_ |