blob: be1bf4730b1173ce0247c9831a7deda4e0ea9c2f [file] [log] [blame]
// 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_H_
#define FLUTTER_IMPELLER_GEOMETRY_PATH_H_
#include <functional>
#include <optional>
#include <tuple>
#include <vector>
#include "impeller/geometry/path_component.h"
namespace impeller {
enum class Cap {
kButt,
kRound,
kSquare,
};
enum class Join {
kMiter,
kRound,
kBevel,
};
enum class FillType {
kNonZero, // The default winding order.
kOdd,
kPositive,
kNegative,
kAbsGeqTwo,
};
enum class Convexity {
kUnknown,
kConvex,
};
//------------------------------------------------------------------------------
/// @brief Paths are lightweight objects that describe a collection of
/// linear, quadratic, or cubic segments. These segments may be
/// broken up by move commands, which are effectively linear
/// commands that pick up the pen rather than continuing to draw.
///
/// All shapes supported by Impeller are paths either directly or
/// via approximation (in the case of circles).
///
/// Paths are externally immutable once created, Creating paths must
/// be done using a path builder.
///
class Path {
public:
enum class ComponentType {
kLinear,
kQuadratic,
kCubic,
kContour,
};
struct PolylineContour {
struct Component {
size_t component_start_index;
/// Denotes whether this component is a curve.
///
/// This is set to true when this component is generated from
/// QuadraticComponent or CubicPathComponent.
bool is_curve;
};
/// Index that denotes the first point of this contour.
size_t start_index;
/// Denotes whether the last point of this contour is connected to the first
/// point of this contour or not.
bool is_closed;
/// The direction of the contour's start cap.
Vector2 start_direction;
/// The direction of the contour's end cap.
Vector2 end_direction;
/// Distinct components in this contour.
///
/// If this contour is generated from multiple path components, each
/// path component forms a component in this vector.
std::vector<Component> components;
};
/// One or more contours represented as a series of points and indices in
/// the point vector representing the start of a new contour.
///
/// Polylines are ephemeral and meant to be used by the tessellator. They do
/// not allocate their own point vectors to allow for optimizations around
/// allocation and reuse of arenas.
struct Polyline {
/// The signature of a method called when it is safe to reclaim the point
/// buffer provided to the constructor of this object.
using PointBufferPtr = std::unique_ptr<std::vector<Point>>;
using ReclaimPointBufferCallback = std::function<void(PointBufferPtr)>;
/// The buffer will be cleared and returned at the destruction of this
/// polyline.
Polyline(PointBufferPtr point_buffer, ReclaimPointBufferCallback reclaim);
Polyline(Polyline&& other);
~Polyline();
/// Points in the polyline, which may represent multiple contours specified
/// by indices in |contours|.
PointBufferPtr points;
Point& GetPoint(size_t index) const { return (*points)[index]; }
/// Contours are disconnected pieces of a polyline, such as when a MoveTo
/// was issued on a PathBuilder.
std::vector<PolylineContour> contours;
/// Convenience method to compute the start (inclusive) and end (exclusive)
/// point of the given contour index.
///
/// The contour_index parameter is clamped to contours.size().
std::tuple<size_t, size_t> GetContourPointBounds(
size_t contour_index) const;
private:
ReclaimPointBufferCallback reclaim_points_;
};
Path();
~Path();
size_t GetComponentCount(std::optional<ComponentType> type = {}) const;
FillType GetFillType() const;
bool IsConvex() const;
bool IsEmpty() const;
template <class T>
using Applier = std::function<void(size_t index, const T& component)>;
void EnumerateComponents(
const Applier<LinearPathComponent>& linear_applier,
const Applier<QuadraticPathComponent>& quad_applier,
const Applier<CubicPathComponent>& cubic_applier,
const Applier<ContourComponent>& contour_applier) const;
bool GetLinearComponentAtIndex(size_t index,
LinearPathComponent& linear) const;
bool GetQuadraticComponentAtIndex(size_t index,
QuadraticPathComponent& quadratic) const;
bool GetCubicComponentAtIndex(size_t index, CubicPathComponent& cubic) const;
bool GetContourComponentAtIndex(size_t index,
ContourComponent& contour) const;
/// Callers must provide the scale factor for how this path will be
/// transformed.
///
/// It is suitable to use the max basis length of the matrix used to transform
/// the path. If the provided scale is 0, curves will revert to straight
/// lines.
Polyline CreatePolyline(
Scalar scale,
Polyline::PointBufferPtr point_buffer =
std::make_unique<std::vector<Point>>(),
Polyline::ReclaimPointBufferCallback reclaim = nullptr) const;
std::optional<Rect> GetBoundingBox() const;
std::optional<Rect> GetTransformedBoundingBox(const Matrix& transform) const;
private:
friend class PathBuilder;
struct ComponentIndexPair {
ComponentType type = ComponentType::kLinear;
size_t index = 0;
ComponentIndexPair() {}
ComponentIndexPair(ComponentType a_type, size_t a_index)
: type(a_type), index(a_index) {}
};
// All of the data for the path is stored in this structure which is
// held by a shared_ptr. Since they all share the structure, the
// copy constructor for Path is very cheap and we don't need to deal
// with shared pointers for Path fields and method arguments.
//
// PathBuilder also uses this structure to accumulate the path data
// but the Path constructor used in |TakePath()| will clone the
// structure to prevent sharing and future modifications within the
// builder from affecting the existing taken paths.
struct Data {
Data() = default;
Data(Data&& other) = default;
Data(const Data& other) = default;
~Data() = default;
FillType fill = FillType::kNonZero;
Convexity convexity = Convexity::kUnknown;
std::vector<ComponentIndexPair> components;
std::vector<Point> points;
std::vector<ContourComponent> contours;
std::optional<Rect> bounds;
};
explicit Path(Data data);
std::shared_ptr<const Data> data_;
};
static_assert(sizeof(Path) == sizeof(std::shared_ptr<struct Anonymous>));
} // namespace impeller
#endif // FLUTTER_IMPELLER_GEOMETRY_PATH_H_