7 #include "flutter/display_list/geometry/dl_path.h" 
   22 class PositionWriter {
 
   24   explicit PositionWriter(std::vector<Point>& 
points)
 
   25       : points_(
points), oversized_() {
 
   29   void AppendVertex(
const Point& point) {
 
   31       oversized_.push_back(point);
 
   33       points_[offset_++] = point;
 
   39   std::pair<size_t, size_t> GetUsedSize()
 const {
 
   40     return std::make_pair(offset_, oversized_.size());
 
   43   bool HasOversizedBuffer()
 const { 
return !oversized_.empty(); }
 
   45   const std::vector<Point>& GetOversizedBuffer()
 const { 
return oversized_; }
 
   48   std::vector<Point>& points_;
 
   49   std::vector<Point> oversized_;
 
  134                             PositionWriter& vtx_builder,
 
  137       : tessellator_(tessellator),
 
  138         vtx_builder_(vtx_builder),
 
  139         half_stroke_width_(stroke.width * 0.5f),
 
  140         maximum_join_cosine_(
 
  141             ComputeMaximumJoinCosine(scale, half_stroke_width_)),
 
  142         minimum_miter_cosine_(ComputeMinimumMiterCosine(stroke.miter_limit)),
 
  146         trigs_(MakeTrigs(tessellator, scale, half_stroke_width_)) {
 
  148     FML_DCHECK(trigs_.
size() >= 2);
 
  149     FML_DCHECK(trigs_[0].cos == 1.0f);  
 
  150     FML_DCHECK(trigs_[0].sin == 0.0f);
 
  151     FML_DCHECK(trigs_.
end()[-1].cos == 0.0f);  
 
  152     FML_DCHECK(trigs_.
end()[-1].sin == 1.0f);
 
  158     if (has_prior_contour_ && origin != last_point_) {
 
  160       vtx_builder_.AppendVertex(last_point_);
 
  161       vtx_builder_.AppendVertex(last_point_);
 
  162       vtx_builder_.AppendVertex(origin);
 
  163       vtx_builder_.AppendVertex(origin);
 
  165     has_prior_contour_ = 
true;
 
  166     has_prior_segment_ = 
false;
 
  167     contour_needs_cap_ = !will_be_closed;
 
  168     last_point_ = origin;
 
  169     origin_point_ = origin;
 
  177       HandlePreviousJoin(current_perpendicular);
 
  178       AppendVertices(p2, current_perpendicular);
 
  180       last_perpendicular_ = current_perpendicular;
 
  187     RecordCurve<PathTessellator::Quad>({p1, cp, p2});
 
  192     RecordCurve<PathTessellator::Conic>({p1, cp, p2, weight});
 
  197     RecordCurve<PathTessellator::Cubic>({p1, cp1, cp2, p2});
 
  201   template <
typename Curve>
 
  203     std::optional<Point> start_direction = curve.GetStartDirection();
 
  204     std::optional<Point> end_direction = curve.GetEndDirection();
 
  208     FML_DCHECK(start_direction.has_value() && end_direction.has_value());
 
  211     if (start_direction.has_value() && end_direction.has_value()) {
 
  214           PerpendicularFromUnitDirection(-start_direction.value());
 
  216           PerpendicularFromUnitDirection(end_direction.value());
 
  221       HandlePreviousJoin(start_perpendicular);
 
  224           std::ceilf(curve.SubdivisionCount(scale_ * half_stroke_width_));
 
  226       Point prev = curve.p1;
 
  230       for (
int i = 1; i < count; i++) {
 
  231         Point cur = curve.Solve(i / count);
 
  235         prev_perpendicular = cur_perpendicular;
 
  240       last_perpendicular_ = end_perpendicular;
 
  241       last_point_ = curve.p2;
 
  248     if (prev_perpendicular.
GetAlignment(cur_perpendicular) < trigs_[1].cos) {
 
  251       AppendVertices(cur, prev_perpendicular);
 
  252       AddJoin(
Join::kRound, cur, prev_perpendicular, cur_perpendicular);
 
  254     AppendVertices(cur, cur_perpendicular);
 
  259     FML_DCHECK(origin == origin_point_);
 
  260     if (!has_prior_segment_) {
 
  262       FML_DCHECK(last_point_ == origin);
 
  265       Vector2 perpendicular = {-half_stroke_width_, 0};
 
  266       AddCap(cap, origin, perpendicular, 
true);
 
  269         AppendVertices(origin, perpendicular);
 
  271       AddCap(cap, origin, perpendicular, 
false);
 
  272     } 
else if (with_close) {
 
  274       FML_DCHECK(origin == origin_point_);
 
  275       FML_DCHECK(last_point_ == origin);
 
  276       AddJoin(join_, origin, last_perpendicular_, origin_perpendicular_);
 
  278       last_perpendicular_ = origin_perpendicular_;
 
  279       last_point_ = origin;
 
  281       AddCap(cap_, last_point_, last_perpendicular_.
GetVector(), 
false);
 
  283     has_prior_segment_ = 
false;
 
  289                  const Size radii)
 override {
 
  295         PerpendicularFromUnitDirection({-iterator.
start.
y, iterator.
start.
x});
 
  296     HandlePreviousJoin(prev_perpendicular);
 
  302         Point cur = center + direction * radii;
 
  304             PerpendicularFromUnitDirection({-direction.
y, direction.
x});
 
  306         prev_perpendicular = cur_perpendicular;
 
  311         PerpendicularFromUnitDirection({-iterator.
end.
y, iterator.
end.
x});
 
  315     last_perpendicular_ = end_perpendicular;
 
  321   PositionWriter& vtx_builder_;
 
  322   const Scalar half_stroke_width_;
 
  323   const Scalar maximum_join_cosine_;
 
  324   const Scalar minimum_miter_cosine_;
 
  334   bool has_prior_contour_ = 
false;
 
  335   bool has_prior_segment_ = 
false;
 
  336   bool contour_needs_cap_ = 
false;
 
  340                                       Scalar half_stroke_width) {
 
  345   static constexpr 
Scalar kJoinPixelThreshold = 0.25f;
 
  356                                          Scalar half_stroke_width) {
 
  378     Scalar hypotenuse = scale * half_stroke_width;
 
  379     if (hypotenuse <= kJoinPixelThreshold) {
 
  384     Scalar bisector = std::sqrt(hypotenuse * hypotenuse -
 
  385                                 kJoinPixelThreshold * kJoinPixelThreshold);
 
  386     Scalar half_cosine = bisector / hypotenuse;
 
  387     Scalar cosine = 2.0f * half_cosine * half_cosine - 1;
 
  403   static Scalar ComputeMinimumMiterCosine(
Scalar miter_limit) {
 
  404     if (miter_limit <= 1.0f) {
 
  429     Scalar half_cosine = 1 / miter_limit;
 
  430     Scalar cosine = 2.0f * half_cosine * half_cosine - 1;
 
  434   inline SeparatedVector2 PerpendicularFromPoints(
const Point from,
 
  435                                                   const Point to)
 const {
 
  436     return PerpendicularFromUnitDirection((to - from).Normalize());
 
  439   inline SeparatedVector2 PerpendicularFromUnitDirection(
 
  440       const Vector2 direction)
 const {
 
  441     return SeparatedVector2(
Vector2{-direction.
y, direction.x},
 
  445   inline void AppendVertices(
const Point curve_point, 
Vector2 offset) {
 
  446     vtx_builder_.AppendVertex(curve_point + offset);
 
  447     vtx_builder_.AppendVertex(curve_point - offset);
 
  450   inline void AppendVertices(
const Point curve_point,
 
  451                              SeparatedVector2 perpendicular) {
 
  452     return AppendVertices(curve_point, perpendicular.GetVector());
 
  455   inline void HandlePreviousJoin(SeparatedVector2 new_perpendicular) {
 
  456     FML_DCHECK(has_prior_contour_);
 
  457     if (has_prior_segment_) {
 
  458       AddJoin(join_, last_point_, last_perpendicular_, new_perpendicular);
 
  460       has_prior_segment_ = 
true;
 
  461       Vector2 perpendicular_vector = new_perpendicular.GetVector();
 
  462       if (contour_needs_cap_) {
 
  463         AddCap(cap_, last_point_, perpendicular_vector, 
true);
 
  467       AppendVertices(last_point_, perpendicular_vector);
 
  468       origin_perpendicular_ = new_perpendicular;
 
  489               bool contour_start) {
 
  494         Point along(perpendicular.y, -perpendicular.x);
 
  497           vtx_builder_.AppendVertex(path_point - along);
 
  502           for (
size_t i = trigs_.
size() - 2u; i > 0u; --i) {
 
  503             Point center = path_point - along * trigs_[i].sin;
 
  504             Vector2 offset = perpendicular * trigs_[i].cos;
 
  506             AppendVertices(center, offset);
 
  512           size_t end = trigs_.
size() - 1u;
 
  513           for (
size_t i = 1u; i < 
end; ++i) {
 
  514             Point center = path_point + along * trigs_[i].sin;
 
  515             Vector2 offset = perpendicular * trigs_[i].cos;
 
  517             AppendVertices(center, offset);
 
  521           vtx_builder_.AppendVertex(path_point + along);
 
  526         Point along(perpendicular.y, -perpendicular.x);
 
  527         Point square_center = contour_start             
 
  529                                   : path_point + along;
 
  530         AppendVertices(square_center, perpendicular);
 
  536   void AddJoin(
Join join,
 
  538                SeparatedVector2 old_perpendicular,
 
  539                SeparatedVector2 new_perpendicular) {
 
  540     Scalar cosine = old_perpendicular.GetAlignment(new_perpendicular);
 
  541     if (cosine >= maximum_join_cosine_) {
 
  558         if (cosine >= minimum_miter_cosine_) {
 
  560               (old_perpendicular.GetVector() + new_perpendicular.GetVector()) /
 
  562           if (old_perpendicular.Cross(new_perpendicular) < 0) {
 
  563             vtx_builder_.AppendVertex(path_point + miter_vector);
 
  565             vtx_builder_.AppendVertex(path_point - miter_vector);
 
  573         if (cosine >= trigs_[1].cos) {
 
  579         if (cosine < -trigs_[1].cos) {
 
  587           AddCap(
Cap::kRound, path_point, old_perpendicular.GetVector(), 
false);
 
  599         Vector2 from_vector, to_vector;
 
  600         bool begin_end_crossed;
 
  601         Scalar turning = old_perpendicular.Cross(new_perpendicular);
 
  607           from_vector = -old_perpendicular.GetVector();
 
  608           to_vector = -new_perpendicular.GetVector();
 
  612           begin_end_crossed = 
false;
 
  618           from_vector = new_perpendicular.GetVector();
 
  619           to_vector = old_perpendicular.GetVector();
 
  623           begin_end_crossed = 
true;
 
  625         FML_DCHECK(from_vector.Cross(to_vector) > 0);
 
  627         if (begin_end_crossed) {
 
  628           vtx_builder_.AppendVertex(path_point + from_vector);
 
  634         bool visit_center = 
false;
 
  640         Point middle_vector = (from_vector + to_vector);
 
  649         size_t end = trigs_.
size() - 1u;
 
  650         for (
size_t i = 1u; i < 
end; ++i) {
 
  651           Point p = trigs_[i] * from_vector;
 
  652           if (p.Cross(middle_vector) <= 0) {
 
  661             vtx_builder_.AppendVertex(path_point);
 
  662             visit_center = 
false;
 
  666           vtx_builder_.AppendVertex(path_point + p);
 
  676             vtx_builder_.AppendVertex(path_point);
 
  677             visit_center = 
false;
 
  681           vtx_builder_.AppendVertex(path_point + p);
 
  684         if (begin_end_crossed) {
 
  685           vtx_builder_.AppendVertex(path_point + to_vector);
 
  694     AppendVertices(path_point, new_perpendicular);
 
  699 std::vector<Point> StrokeSegmentsGeometry::GenerateSolidStrokeVertices(
 
  700     Tessellator& tessellator,
 
  701     const PathSource& source,
 
  702     const StrokeParameters& stroke,
 
  704   std::vector<Point> 
points(4096);
 
  705   PositionWriter vtx_builder(
points);
 
  706   StrokePathSegmentReceiver receiver(tessellator, vtx_builder, stroke, scale);
 
  708   auto [arena, extra] = vtx_builder.GetUsedSize();
 
  709   FML_DCHECK(extra == 0u);
 
  720   return stroke_.
width;
 
  744   if (stroke_.
width < 0.0) {
 
  748   if (max_basis == 0) {
 
  753   StrokeParameters adjusted_stroke = stroke_;
 
  754   adjusted_stroke.
width = std::max(stroke_.
width, min_size);
 
  760   PositionWriter position_writer(tessellator.GetStrokePointCache());
 
  761   StrokePathSegmentReceiver receiver(tessellator, position_writer,
 
  762                                      adjusted_stroke, scale);
 
  763   Dispatch(receiver, tessellator, scale);
 
  765   const auto [arena_length, oversized_length] = position_writer.GetUsedSize();
 
  766   if (!position_writer.HasOversizedBuffer()) {
 
  768         host_buffer.Emplace(tessellator.GetStrokePointCache().data(),
 
  769                             arena_length * 
sizeof(
Point), 
alignof(
Point));
 
  775                                   .vertex_count = arena_length,
 
  781   const std::vector<Point>& oversized_data =
 
  782       position_writer.GetOversizedBuffer();
 
  785       (arena_length + oversized_length) * 
sizeof(
Point),  
 
  790          tessellator.GetStrokePointCache().data(),  
 
  791          arena_length * 
sizeof(
Point)               
 
  795          oversized_data.data(),                                             
 
  796          oversized_data.size() * 
sizeof(
Point)                              
 
  804                                 .vertex_count = arena_length + oversized_length,
 
  817     const Rect& path_bounds)
 const {
 
  824     max_radius = max_radius * 
kSqrt2;
 
  827     max_radius = std::max(max_radius, stroke_.
miter_limit * 0.5f);
 
  830   if (max_basis == 0) {
 
  835   max_radius *= std::max(stroke_.
width, min_size);
 
  886   if (include_center) {
 
  911       source_(p0, p1, on_length, off_length) {}
 
void Dispatch(PathAndArcSegmentReceiver &receiver, Tessellator &tessellator, Scalar scale) const override
ArcStrokeGeometry(const Arc &arc, const StrokeParameters ¶meters)
std::optional< Rect > GetCoverage(const Matrix &transform) const override
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Tessellator & GetTessellator() const
Matrix GetShaderTransform(const RenderPass &pass) const
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
static Scalar ComputeStrokeAlphaCoverage(const Matrix &entity, Scalar stroke_width)
Compute an alpha value to simulate lower coverage of fractional pixel strokes.
A |SegmentReceiver| that also accepts Arc segments for optimal handling. A path or |PathSource| will ...
virtual void RecordArc(const Arc &arc, const Point center, const Size radii)=0
virtual void RecordLine(Point p1, Point p2)=0
virtual void EndContour(Point origin, bool with_close)=0
virtual void BeginContour(Point origin, bool will_be_closed)=0
static void PathToStrokedSegments(const PathSource &source, SegmentReceiver &receiver)
Render passes encode render commands directed as one specific render target into an underlying comman...
const PathSource & GetSource() const override
StrokeDashedLineGeometry(Point p0, Point p1, Scalar on_length, Scalar off_length, const StrokeParameters ¶meters)
StrokeDiffRoundRectGeometry(const RoundRect &outer, const RoundRect &inner, const StrokeParameters ¶meters)
const PathSource & GetSource() const override
StrokePathGeometry(const flutter::DlPath &path, const StrokeParameters ¶meters)
const PathSource & GetSource() const override
void RecordCurve(const Curve &curve)
void BeginContour(Point origin, bool will_be_closed) override
void RecordArc(const Arc &arc, const Point center, const Size radii) override
void EndContour(Point origin, bool with_close) override
void RecordQuad(Point p1, Point cp, Point p2) override
StrokePathSegmentReceiver(Tessellator &tessellator, PositionWriter &vtx_builder, const StrokeParameters &stroke, const Scalar scale)
void RecordConic(Point p1, Point cp, Point p2, Scalar weight) override
void RecordCubic(Point p1, Point cp1, Point cp2, Point p2) override
void RecordCurveSegment(const SeparatedVector2 &prev_perpendicular, const Point cur, const SeparatedVector2 &cur_perpendicular)
void RecordLine(Point p1, Point p2) override
An abstract Geometry base class that produces fillable vertices representing the stroked outline from...
virtual const PathSource & GetSource() const =0
std::optional< Rect > GetCoverage(const Matrix &transform) const override
StrokePathSourceGeometry(const StrokeParameters ¶meters)
void Dispatch(PathAndArcSegmentReceiver &receiver, Tessellator &tessellator, Scalar scale) const override
An abstract Geometry base class that produces fillable vertices representing the stroked outline of t...
virtual void Dispatch(PathAndArcSegmentReceiver &receiver, Tessellator &tessellator, Scalar scale) const =0
Join GetStrokeJoin() const
Scalar GetStrokeWidth() const
Scalar GetMiterLimit() const
Scalar ComputeAlphaCoverage(const Matrix &transform) const override
std::optional< Rect > GetStrokeCoverage(const Matrix &transform, const Rect &segment_bounds) const
StrokeSegmentsGeometry(const StrokeParameters ¶meters)
~StrokeSegmentsGeometry() override
std::vector< Trig >::iterator end() const
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
Trigs GetTrigsForDeviceRadius(Scalar pixel_radius)
@ kNone
Does not use the index buffer.
Join
An enum that describes ways to join two segments of a path.
Cap
An enum that describes ways to decorate the end of a path contour.
static constexpr size_t kPointArenaSize
The size of the point arena buffer stored on the tessellator.
static constexpr Scalar kMinStrokeSize
Iteration ComputeIterations(size_t step_count, bool simplify_360=true) const
Rect GetTightArcBounds() const
constexpr bool IncludeCenter() const
const Size GetOvalSize() const
Returns the size of the oval bounds.
const Point GetOvalCenter() const
Returns the center of the oval bounds.
A 4x4 matrix using column-major storage.
Scalar GetMaxBasisLengthXY() const
A Vector2, broken down as a separate magnitude and direction. Assumes that the direction given is nor...
Scalar GetAlignment(const SeparatedVector2 &other) const
Vector2 GetVector() const
Returns the vector representation of the vector.
A structure to store all of the parameters related to stroking a path or basic geometry object.
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
constexpr Type MaxDimension() const
std::vector< Point > points