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_) {
54 FML_DCHECK(contour_has_segments_);
55 FML_DCHECK(contour_has_points_);
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;
74 if (p2 != current_point_) {
75 receiver_.RecordLine(current_point_, p2);
77 contour_has_points_ =
true;
82 if (cp == current_point_ || p2 == cp) {
87 receiver_.RecordQuad(current_point_, cp, p2);
89 contour_has_points_ =
true;
96 }
else if (cp == current_point_ || p2 == cp || weight == 0.0f) {
100 receiver_.RecordConic(current_point_, cp, p2, weight);
102 contour_has_points_ =
true;
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_) {
130 FML_DCHECK(contour_has_segments_);
131 receiver_.RecordLine(current_point_, contour_origin_);
132 contour_has_points_ =
true;
135 if (current_point_ != contour_origin_) {
136 FML_DCHECK(contour_has_segments_);
137 FML_DCHECK(contour_has_points_);
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_) {
154 FML_DCHECK(contour_has_segments_);
155 FML_DCHECK(contour_has_points_);
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_;
181 class StorageCounter :
public SegmentReceiver {
185 void BeginContour(
Point origin,
bool will_be_closed)
override {
194 void RecordLine(
Point p1,
Point p2)
override { point_count_++; }
199 point_count_ += std::max<size_t>(count, 1);
205 point_count_ += std::max<size_t>(count, 1);
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;
230 class 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); }
242 Quad quad{p1, cp, p2};
244 for (
size_t i = 1; i < count; i++) {
245 writer_.Write(quad.Solve(i / count));
251 Conic conic{p1, cp, p2, weight};
254 for (
size_t i = 1; i < count; i++) {
255 writer_.Write(conic.Solve(i / count));
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)
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)