| Flutter Impeller |

arc_geometry.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/impeller/entity/geometry/arc_geometry.h"
6
7 #include "flutter/impeller/entity/geometry/line_geometry.h"
8 #include "fml/logging.h"
9
10 namespace impeller {
11
12 ArcGeometry::ArcGeometry(const Arc& arc)
13 : arc_(arc), stroke_width_(-1.0f), cap_(Cap::kButt) {}
14
15 ArcGeometry::ArcGeometry(const Arc& arc, const StrokeParameters& stroke)
16 : arc_(arc), stroke_width_(stroke.width), cap_(stroke.cap) {
17 FML_DCHECK(arc.IsPerfectCircle());
18 FML_DCHECK(!arc.IncludeCenter());
19 }
20
21 ArcGeometry::~ArcGeometry() = default;
22
23 // |Geometry|
24 Scalar ArcGeometry::ComputeAlphaCoverage(const Matrix& transform) const {
25 if (stroke_width_ < 0) {
26 return 1;
27 }
28 return Geometry::ComputeStrokeAlphaCoverage(transform, stroke_width_);
29 }
30
31 GeometryResult ArcGeometry::GetPositionBuffer(const ContentContext& renderer,
32 const Entity& entity,
33 RenderPass& pass) const {
34 auto& transform = entity.GetTransform();
35
36 if (stroke_width_ < 0) {
37 auto generator = renderer.GetTessellator().FilledArc(
38 transform, arc_,
39 renderer.GetDeviceCapabilities().SupportsTriangleFan());
40
41 return ComputePositionGeometry(renderer, generator, entity, pass);
42 } else {
43 FML_DCHECK(arc_.IsPerfectCircle());
44 FML_DCHECK(!arc_.IncludeCenter());
45 Scalar half_width =
46 LineGeometry::ComputePixelHalfWidth(transform, stroke_width_);
47
48 auto generator =
49 renderer.GetTessellator().StrokedArc(transform, arc_, cap_, half_width);
50
51 auto result = ComputePositionGeometry(renderer, generator, entity, pass);
52 if (CapsOverlap()) {
53 result.mode = GeometryResult::Mode::kPreventOverdraw;
54 }
55 return result;
56 }
57 }
58
59 std::optional<Rect> ArcGeometry::GetCoverage(const Matrix& transform) const {
60 Scalar padding = //
61 stroke_width_ < 0
62 ? 0.0
63 : LineGeometry::ComputePixelHalfWidth(transform, stroke_width_);
64
65 if (arc_.IsFullCircle()) {
66 // Simpler calculation than below and we don't pad by the extra distance
67 // that square caps take up because we aren't going to use caps.
68 return arc_.GetOvalBounds().Expand(padding).TransformAndClipBounds(
69 transform);
70 }
71
72 if (cap_ == Cap::kSquare) {
73 padding = padding * kSqrt2;
74 }
75
76 return arc_.GetTightArcBounds().Expand(padding).TransformAndClipBounds(
77 transform);
78 }
79
80 bool ArcGeometry::CoversArea(const Matrix& transform, const Rect& rect) const {
81 return false;
82 }
83
84 bool ArcGeometry::IsAxisAlignedRect() const {
85 return false;
86 }
87
88 bool ArcGeometry::CapsOverlap() const {
89 FML_DCHECK(arc_.GetSweep().degrees >= 0.0f);
90 FML_DCHECK(arc_.GetSweep().degrees <= 360.0f);
91
92 if (stroke_width_ < 0 || cap_ == Cap::kButt ||
93 arc_.GetSweep().degrees <= 180) {
94 return false;
95 }
96
97 switch (cap_) {
98 case Cap::kSquare: {
99 // Square caps overlap if the inner corner of the ending cap extends
100 // inside the inner edge of the start cap. For a visualization of when
101 // this occurs, see
102 // https://github.com/flutter/flutter/issues/178746#issuecomment-3554526727
103 // Note that testing for overlap is completely independent of the arc's
104 // start angle. To simplify the overlap test, we treat the arc as if its
105 // start angle is 0. This allows the test to only require checking the x
106 // coordinate of the ending cap, rather than needing to calculate overlap
107 // based on both x and y positions of both caps.
108 auto radius = arc_.GetOvalSize().width * 0.5f;
109 auto half_width = stroke_width_ * 0.5f;
110 auto inner_radius = radius - half_width;
111 auto inner_arc_end_x =
112 cos(Radians(arc_.GetSweep()).radians) * inner_radius;
113 auto inner_square_cap_end_x =
114 inner_arc_end_x +
115 cos(Radians(arc_.GetSweep() + Degrees(90)).radians) * half_width;
116 return inner_square_cap_end_x > inner_radius;
117 }
118 case Cap::kRound: {
119 // Round caps overlap if the distance between the arc's start and end
120 // points is less than the stroke width.
121 // https://github.com/flutter/flutter/issues/178746#issuecomment-3554526727
122 // Note that testing for overlap is completely independent of the arc's
123 // start angle. To simplify the overlap test, we treat the arc as if its
124 // start angle is 0.
125 auto radius = arc_.GetOvalSize().width / 2.0f;
126 auto start_point = Point(radius, 0);
127 auto sweep_radians = Radians(arc_.GetSweep()).radians;
128 auto end_point = Point(cos(sweep_radians), sin(sweep_radians)) * radius;
129 return start_point.GetDistanceSquared(end_point) <
130 stroke_width_ * stroke_width_;
131 }
132 case Cap::kButt:
133 FML_UNREACHABLE()
134 }
135 }
136
137 } // namespace impeller
arc_geometry.h
impeller::ArcGeometry::~ArcGeometry
~ArcGeometry() override
impeller::ArcGeometry::IsAxisAlignedRect
bool IsAxisAlignedRect() const override
Definition: arc_geometry.cc:84
impeller::ArcGeometry::ComputeAlphaCoverage
Scalar ComputeAlphaCoverage(const Matrix &transform) const override
Definition: arc_geometry.cc:24
impeller::ArcGeometry::CoversArea
bool CoversArea(const Matrix &transform, const Rect &rect) const override
Determines if this geometry, transformed by the given transform, will completely cover all surface ar...
Definition: arc_geometry.cc:80
impeller::ArcGeometry::ArcGeometry
ArcGeometry(const Arc &arc)
Definition: arc_geometry.cc:12
impeller::Capabilities::SupportsTriangleFan
virtual bool SupportsTriangleFan() const =0
Whether the primitive type TriangleFan is supported by the backend.
impeller::ContentContext
Definition: content_context.h:122
impeller::ContentContext::GetDeviceCapabilities
const Capabilities & GetDeviceCapabilities() const
Definition: content_context.cc:973
impeller::ContentContext::GetTessellator
Tessellator & GetTessellator() const
Definition: content_context.cc:965
impeller::Entity
Definition: entity.h:26
impeller::Entity::GetTransform
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:46
impeller::Geometry::ComputeStrokeAlphaCoverage
static Scalar ComputeStrokeAlphaCoverage(const Matrix &entity, Scalar stroke_width)
Compute an alpha value to simulate lower coverage of fractional pixel strokes.
Definition: geometry.cc:149
impeller::Geometry::ComputePositionGeometry
static GeometryResult ComputePositionGeometry(const ContentContext &renderer, const Tessellator::VertexGenerator &generator, const Entity &entity, RenderPass &pass)
Definition: geometry.cc:26
impeller::LineGeometry::ComputePixelHalfWidth
static Scalar ComputePixelHalfWidth(const Matrix &transform, Scalar width)
Definition: line_geometry.cc:18
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
impeller::Tessellator::StrokedArc
ArcVertexGenerator StrokedArc(const Matrix &view_transform, const Arc &arc, Cap cap, Scalar half_width)
Create a |VertexGenerator| that can produce vertices for a stroked arc inscribed within the given ova...
Definition: tessellator.cc:623
impeller::Tessellator::FilledArc
ArcVertexGenerator FilledArc(const Matrix &view_transform, const Arc &arc, bool supports_triangle_fans)
Create a |VertexGenerator| that can produce vertices for a stroked arc inscribed within the given ova...
Definition: tessellator.cc:612
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:312
padding
Vector2 padding
The halo padding in source space.
Definition: gaussian_blur_filter_contents.cc:87
line_geometry.h
impeller
Definition: allocation.cc:12
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::Point
TPoint< Scalar > Point
Definition: point.h:425
impeller::Cap
Cap
An enum that describes ways to decorate the end of a path contour.
Definition: stroke_parameters.h:13
impeller::Cap::kRound
@ kRound
impeller::Cap::kButt
@ kButt
impeller::Cap::kSquare
@ kSquare
impeller::kSqrt2
constexpr float kSqrt2
Definition: constants.h:47
impeller::Arc
Definition: arc.h:13
impeller::Arc::GetTightArcBounds
Rect GetTightArcBounds() const
Definition: arc.cc:59
impeller::Arc::IncludeCenter
constexpr bool IncludeCenter() const
Definition: arc.h:110
impeller::Arc::IsFullCircle
constexpr bool IsFullCircle() const
Definition: arc.h:114
impeller::Arc::GetOvalSize
const Size GetOvalSize() const
Returns the size of the oval bounds.
Definition: arc.h:100
impeller::Arc::IsPerfectCircle
constexpr bool IsPerfectCircle() const
Definition: arc.h:112
impeller::Arc::GetOvalBounds
const Rect & GetOvalBounds() const
Return the bounds of the oval in which this arc is inscribed.
Definition: arc.h:94
impeller::Arc::GetSweep
constexpr Degrees GetSweep() const
Definition: arc.h:108
impeller::Degrees::degrees
Scalar degrees
Definition: scalar.h:67
impeller::GeometryResult
Definition: geometry.h:21
impeller::GeometryResult::Mode::kPreventOverdraw
@ kPreventOverdraw
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::StrokeParameters
A structure to store all of the parameters related to stroking a path or basic geometry object.
Definition: stroke_parameters.h:28
impeller::TPoint::GetDistanceSquared
constexpr Type GetDistanceSquared(const TPoint &p) const
Definition: point.h:181
impeller::TRect< Scalar >
impeller::TRect::Expand
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition: rect.h:618
impeller::TRect::TransformAndClipBounds
constexpr TRect TransformAndClipBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle, clipped against the near clippin...
Definition: rect.h:438
impeller::TSize::width
Type width
Definition: size.h:28