37 explicit PathPruner(SegmentReceiver& receiver,
bool is_stroking =
false)
38 : receiver_(receiver), is_stroking_(is_stroking) {}
40 void MoveTo(
const Point& p2,
bool will_be_closed)
override {
42 if (contour_has_segments_ && !contour_has_points_) {
46 receiver_.RecordLine(contour_origin_, contour_origin_);
49 if (current_point_ != contour_origin_) {
56 receiver_.RecordLine(current_point_, contour_origin_);
59 if (contour_has_segments_) {
62 receiver_.EndContour(contour_origin_,
false);
64 contour_origin_ = current_point_ = p2;
65 contour_has_segments_ = contour_has_points_ =
false;
66 contour_will_be_closed_ = will_be_closed;
72 void LineTo(
const Point& p2)
override {
74 if (p2 != current_point_) {
75 receiver_.RecordLine(current_point_, p2);
77 contour_has_points_ =
true;
81 void QuadTo(
const Point& cp,
const Point& p2)
override {
82 if (cp == current_point_ || p2 == cp) {
87 receiver_.RecordQuad(current_point_, cp, p2);
89 contour_has_points_ =
true;
93 bool ConicTo(
const Point& cp,
const Point& p2, Scalar weight)
override {
96 }
else if (cp == current_point_ || p2 == cp || weight == 0.0f) {
100 receiver_.RecordConic(current_point_, cp, p2, weight);
102 contour_has_points_ =
true;
107 void CubicTo(
const Point& cp1,
const Point& cp2,
const Point& p2)
override {
108 SegmentEncountered();
109 if (cp1 != current_point_ ||
110 cp2 != current_point_ ||
111 p2 != current_point_) {
117 receiver_.RecordCubic(current_point_, cp1, cp2, p2);
119 contour_has_points_ =
true;
123 void Close()
override {
127 SegmentEncountered();
129 if (!contour_has_points_) {
131 receiver_.RecordLine(current_point_, contour_origin_);
132 contour_has_points_ =
true;
135 if (current_point_ != contour_origin_) {
138 receiver_.RecordLine(current_point_, contour_origin_);
141 receiver_.EndContour(contour_origin_,
true);
145 current_point_ = contour_origin_;
146 contour_has_segments_ = contour_has_points_ =
false;
153 if (!is_stroking_ && current_point_ != contour_origin_) {
156 receiver_.RecordLine(current_point_, contour_origin_);
158 if (contour_has_segments_) {
159 receiver_.EndContour(contour_origin_,
false);
164 SegmentReceiver& receiver_;
165 const bool is_stroking_;
167 void SegmentEncountered() {
168 if (!contour_has_segments_) {
169 receiver_.BeginContour(contour_origin_, contour_will_be_closed_);
170 contour_has_segments_ =
true;
174 bool contour_has_segments_ =
false;
175 bool contour_has_points_ =
false;
176 bool contour_will_be_closed_ =
false;
177 Point contour_origin_;
178 Point current_point_;
181class StorageCounter :
public SegmentReceiver {
185 void BeginContour(Point origin,
bool will_be_closed)
override {
194 void RecordLine(Point p1, Point p2)
override { point_count_++; }
196 void RecordQuad(Point p1, Point cp, Point p2)
override {
199 point_count_ += std::max<size_t>(count, 1);
202 void RecordConic(Point p1, Point cp, Point p2, Scalar weight)
override {
205 point_count_ += std::max<size_t>(count, 1);
208 void RecordCubic(Point p1, Point cp1, Point cp2, Point p2)
override {
211 point_count_ += std::max<size_t>(count, 1);
214 void EndContour(Point origin,
bool with_close)
override {
220 size_t GetPointCount()
const {
return point_count_; }
221 size_t GetContourCount()
const {
return contour_count_; }
224 size_t point_count_ = 0u;
225 size_t contour_count_ = 0u;
230class PathFillWriter :
public SegmentReceiver {
232 PathFillWriter(VertexWriter& writer, Scalar scale)
233 : writer_(writer), scale_(scale) {}
235 void BeginContour(Point origin,
bool will_be_closed)
override {
236 writer_.Write(origin);
239 void RecordLine(Point p1, Point p2)
override { writer_.Write(p2); }
241 void RecordQuad(Point p1, Point cp, Point p2)
override {
242 Quad quad{p1, cp, p2};
244 for (
size_t i = 1;
i < count;
i++) {
245 writer_.Write(quad.Solve(
i / count));
250 void RecordConic(Point p1, Point cp, Point p2, Scalar weight)
override {
251 Conic conic{p1, cp, p2, weight};
254 for (
size_t i = 1;
i < count;
i++) {
255 writer_.Write(conic.Solve(
i / count));
260 void RecordCubic(Point p1, Point cp1, Point cp2, Point p2)
override {
261 Cubic cubic{p1, cp1, cp2, p2};
264 for (
size_t i = 1;
i < count;
i++) {
265 writer_.Write(cubic.Solve(
i / count));
270 void EndContour(Point origin,
bool with_close)
override {
271 writer_.EndContour();
275 VertexWriter& writer_;
285 PathPruner pruner(receiver,
false);
292 PathPruner pruner(receiver,
true);
300 StorageCounter counter(scale);
301 PathPruner pruner(counter,
false);
304 return {counter.GetPointCount(), counter.GetContourCount()};
310 PathFillWriter path_writer(writer, scale);
311 PathPruner pruner(path_writer,
false);
Collection of functions to receive path segments from the underlying path representation via the DlPa...
virtual void CubicTo(const Point &cp1, const Point &cp2, const Point &p2)=0
virtual void LineTo(const Point &p2)=0
virtual void QuadTo(const Point &cp, const Point &p2)=0
virtual void MoveTo(const Point &p2, bool will_be_closed)=0
virtual bool ConicTo(const Point &cp, const Point &p2, Scalar weight)
virtual void Dispatch(PathReceiver &receiver) const =0
An interface for receiving pruned path segments.
An interface for generating a multi contour polyline as a triangle strip.
static void PathToFilledSegments(const PathSource &source, SegmentReceiver &receiver)
static void PathToStrokedSegments(const PathSource &source, SegmentReceiver &receiver)
static void PathToFilledVertices(const PathSource &source, VertexWriter &writer, Scalar scale)
static std::pair< size_t, size_t > CountFillStorage(const PathSource &source, Scalar scale)
#define FML_DCHECK(condition)
Scalar ComputeConicSubdivisions(Scalar scale_factor, Point p0, Point p1, Point p2, Scalar w)
std::array< Point, 4 > Quad
Scalar ComputeQuadradicSubdivisions(Scalar scale_factor, Point p0, Point p1, Point p2)
Scalar ComputeCubicSubdivisions(Scalar scale_factor, Point p0, Point p1, Point p2, Point p3)