38 explicit PathPruner(SegmentReceiver& receiver,
bool is_stroking =
false)
39 : receiver_(receiver), is_stroking_(is_stroking) {}
41 void MoveTo(
const Point& p2,
bool will_be_closed)
override {
43 if (contour_has_segments_ && !contour_has_points_) {
47 receiver_.RecordLine(contour_origin_, contour_origin_);
50 if (current_point_ != contour_origin_) {
55 FML_DCHECK(contour_has_segments_);
56 FML_DCHECK(contour_has_points_);
57 receiver_.RecordLine(current_point_, contour_origin_);
60 if (contour_has_segments_) {
63 receiver_.EndContour(contour_origin_,
false);
65 contour_origin_ = current_point_ = p2;
66 contour_has_segments_ = contour_has_points_ =
false;
67 contour_will_be_closed_ = will_be_closed;
75 if (p2 != current_point_) {
76 receiver_.RecordLine(current_point_, p2);
78 contour_has_points_ =
true;
83 if (cp == current_point_ || p2 == cp) {
88 receiver_.RecordQuad(current_point_, cp, p2);
90 contour_has_points_ =
true;
97 }
else if (cp == current_point_ || p2 == cp || weight == 0.0f) {
100 SegmentEncountered();
101 receiver_.RecordConic(current_point_, cp, p2, weight);
103 contour_has_points_ =
true;
109 SegmentEncountered();
110 if (cp1 != current_point_ ||
111 cp2 != current_point_ ||
112 p2 != current_point_) {
118 receiver_.RecordCubic(current_point_, cp1, cp2, p2);
120 contour_has_points_ =
true;
124 void Close()
override {
128 SegmentEncountered();
130 if (!contour_has_points_) {
131 FML_DCHECK(contour_has_segments_);
132 receiver_.RecordLine(current_point_, contour_origin_);
133 contour_has_points_ =
true;
136 if (current_point_ != contour_origin_) {
137 FML_DCHECK(contour_has_segments_);
138 FML_DCHECK(contour_has_points_);
139 receiver_.RecordLine(current_point_, contour_origin_);
142 receiver_.EndContour(contour_origin_,
true);
146 current_point_ = contour_origin_;
147 contour_has_segments_ = contour_has_points_ =
false;
154 if (!is_stroking_ && current_point_ != contour_origin_) {
155 FML_DCHECK(contour_has_segments_);
156 FML_DCHECK(contour_has_points_);
157 receiver_.RecordLine(current_point_, contour_origin_);
159 if (contour_has_segments_) {
160 receiver_.EndContour(contour_origin_,
false);
165 SegmentReceiver& receiver_;
166 const bool is_stroking_;
168 void SegmentEncountered() {
169 if (!contour_has_segments_) {
170 receiver_.BeginContour(contour_origin_, contour_will_be_closed_);
171 contour_has_segments_ =
true;
175 bool contour_has_segments_ =
false;
176 bool contour_has_points_ =
false;
177 bool contour_will_be_closed_ =
false;
178 Point contour_origin_;
179 Point current_point_;
182 class StorageCounter :
public SegmentReceiver {
186 void BeginContour(
Point origin,
bool will_be_closed)
override {
195 void RecordLine(
Point p1,
Point p2)
override { point_count_++; }
200 point_count_ += std::max<size_t>(count, 1);
206 point_count_ += std::max<size_t>(count, 1);
212 point_count_ += std::max<size_t>(count, 1);
215 void EndContour(
Point origin,
bool with_close)
override {
221 size_t GetPointCount()
const {
return point_count_; }
222 size_t GetContourCount()
const {
return contour_count_; }
225 size_t point_count_ = 0u;
226 size_t contour_count_ = 0u;
231 class PathFillWriter :
public SegmentReceiver {
233 PathFillWriter(VertexWriter& writer,
Scalar scale)
234 : writer_(writer), scale_(scale) {}
236 void BeginContour(
Point origin,
bool will_be_closed)
override {
237 writer_.Write(origin);
240 void RecordLine(
Point p1,
Point p2)
override { writer_.Write(p2); }
243 Quad quad{p1, cp, p2};
245 for (
size_t i = 1; i < count; i++) {
246 writer_.Write(quad.Solve(i / count));
252 Conic conic{p1, cp, p2, weight};
255 for (
size_t i = 1; i < count; i++) {
256 writer_.Write(conic.Solve(i / count));
262 Cubic cubic{p1, cp1, cp2, p2};
265 for (
size_t i = 1; i < count; i++) {
266 writer_.Write(cubic.Solve(i / count));
271 void EndContour(
Point origin,
bool with_close)
override {
272 writer_.EndContour();
276 VertexWriter& writer_;
286 PathPruner pruner(receiver,
false);
293 PathPruner pruner(receiver,
true);
301 StorageCounter counter(scale);
302 PathPruner pruner(counter,
false);
305 return {counter.GetPointCount(), counter.GetContourCount()};
311 PathFillWriter path_writer(writer, scale);
312 PathPruner pruner(path_writer,
false);
321 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 PathToTransformedFilledVertices(const PathSource &source, VertexWriter &writer, const Matrix &matrix)
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)
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)
A 4x4 matrix using column-major storage.
Scalar GetMaxBasisLengthXY() const
Return the maximum scale applied specifically to either the X axis or Y axis unit vectors (the bases)...