Flutter Engine
 
Loading...
Searching...
No Matches
impeller::StrokeRectGeometry Class Referencefinal

#include <rect_geometry.h>

Inheritance diagram for impeller::StrokeRectGeometry:
impeller::Geometry

Public Member Functions

 StrokeRectGeometry (const Rect &rect, const StrokeParameters &stroke)
 
 ~StrokeRectGeometry () override
 
GeometryResult GetPositionBuffer (const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
 
std::optional< RectGetCoverage (const Matrix &transform) const override
 
- Public Member Functions inherited from impeller::Geometry
virtual ~Geometry ()
 
virtual GeometryResult::Mode GetResultMode () const
 
virtual bool CoversArea (const Matrix &transform, const Rect &rect) const
 Determines if this geometry, transformed by the given transform, will completely cover all surface area of the given rect.
 
virtual bool IsAxisAlignedRect () const
 
virtual bool CanApplyMaskFilter () const
 
virtual Scalar ComputeAlphaCoverage (const Matrix &transform) const
 

Additional Inherited Members

- Static Public Member Functions inherited from impeller::Geometry
static std::unique_ptr< GeometryMakeFillPath (const flutter::DlPath &path, std::optional< Rect > inner_rect=std::nullopt)
 
static std::unique_ptr< GeometryMakeStrokePath (const flutter::DlPath &path, const StrokeParameters &stroke={})
 
static std::unique_ptr< GeometryMakeCover ()
 
static std::unique_ptr< GeometryMakeRect (const Rect &rect)
 
static std::unique_ptr< GeometryMakeOval (const Rect &rect)
 
static std::unique_ptr< GeometryMakeLine (const Point &p0, const Point &p1, const StrokeParameters &stroke)
 
static std::unique_ptr< GeometryMakeCircle (const Point &center, Scalar radius)
 
static std::unique_ptr< GeometryMakeStrokedCircle (const Point &center, Scalar radius, Scalar stroke_width)
 
static std::unique_ptr< GeometryMakeFilledArc (const Rect &oval_bounds, Degrees start, Degrees sweep, bool include_center)
 
static std::unique_ptr< GeometryMakeStrokedArc (const Rect &oval_bounds, Degrees start, Degrees sweep, const StrokeParameters &stroke)
 
static std::unique_ptr< GeometryMakeRoundRect (const Rect &rect, const Size &radii)
 
static std::unique_ptr< GeometryMakeRoundSuperellipse (const Rect &rect, Scalar corner_radius)
 
static Scalar ComputeStrokeAlphaCoverage (const Matrix &entity, Scalar stroke_width)
 Compute an alpha value to simulate lower coverage of fractional pixel strokes.
 
static GeometryResult ComputePositionGeometry (const ContentContext &renderer, const Tessellator::VertexGenerator &generator, const Entity &entity, RenderPass &pass)
 

Detailed Description

Definition at line 37 of file rect_geometry.h.

Constructor & Destructor Documentation

◆ StrokeRectGeometry()

impeller::StrokeRectGeometry::StrokeRectGeometry ( const Rect rect,
const StrokeParameters stroke 
)
explicit

Definition at line 50 of file rect_geometry.cc.

52 : rect_(rect),
53 stroke_width_(stroke.width),
54 stroke_join_(AdjustStrokeJoin(stroke)) {}

◆ ~StrokeRectGeometry()

impeller::StrokeRectGeometry::~StrokeRectGeometry ( )
overridedefault

Member Function Documentation

◆ GetCoverage()

std::optional< Rect > impeller::StrokeRectGeometry::GetCoverage ( const Matrix transform) const
overridevirtual

Implements impeller::Geometry.

Definition at line 337 of file rect_geometry.cc.

338 {
339 return rect_.TransformBounds(transform);
340}
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition rect.h:472

References transform, and impeller::TRect< T >::TransformBounds().

◆ GetPositionBuffer()

GeometryResult impeller::StrokeRectGeometry::GetPositionBuffer ( const ContentContext renderer,
const Entity entity,
RenderPass pass 
) const
overridevirtual

Implements impeller::Geometry.

Definition at line 58 of file rect_geometry.cc.

61 {
62 if (stroke_width_ < 0.0) {
63 return {};
64 }
65 Scalar max_basis = entity.GetTransform().GetMaxBasisLengthXY();
66 if (max_basis == 0) {
67 return {};
68 }
69
70 Scalar min_size = kMinStrokeSize / max_basis;
71 Scalar stroke_width = std::max(stroke_width_, min_size);
72 Scalar half_stroke_width = stroke_width * 0.5f;
73
74 auto& data_host_buffer = renderer.GetTransientsDataBuffer();
75 const Rect& rect = rect_;
76 bool interior_filled = (stroke_width >= rect.GetSize().MinDimension());
77
78 switch (stroke_join_) {
79 case Join::kRound: {
80 Tessellator::Trigs trigs =
81 renderer.GetTessellator().GetTrigsForDeviceRadius(half_stroke_width *
82 max_basis);
83
84 FML_DCHECK(trigs.size() >= 2u);
85
86 auto vertex_count = trigs.size() * 4;
87 if (!interior_filled) {
88 // If there is a hole in the interior (as with most stroked rects
89 // unless the stroke width is really really wide) then we need
90 // to perform some surgery to generate the hollowed-out interior.
91 vertex_count += 12;
92 }
93
94 return GeometryResult{
96 .vertex_buffer =
97 {
98 .vertex_buffer = data_host_buffer.Emplace(
99 vertex_count * sizeof(Point), alignof(Point),
100 [hsw = half_stroke_width, &rect, vertex_count, &trigs,
101 interior_filled](uint8_t* buffer) {
102 Scalar left = rect.GetLeft();
103 Scalar top = rect.GetTop();
104 Scalar right = rect.GetRight();
105 Scalar bottom = rect.GetBottom();
106
107 auto vertices = reinterpret_cast<Point*>(buffer);
108 [[maybe_unused]]
109 auto vertices_end = vertices + vertex_count;
110
111 // Traverse top down, left to right across slices.
112
113 // Slice 1: Draw across between top pair of round joins.
114 for (auto trig : trigs) {
115 // trig.sin goes from 0 to 1
116 // trig.cos goes from 1 to 0
117 *vertices++ = Point(left - trig.sin * hsw,
118 top - trig.cos * hsw);
119 *vertices++ = Point(right + trig.sin * hsw,
120 top - trig.cos * hsw);
121 }
122 // Ends up with vertices that draw across the bottom
123 // of the top curved section (left - hsw, top) to
124 // (right + hsw, top). This is the starting pair of
125 // vertices for the following square section.
126
127 if (interior_filled) {
128 // If interior is filled, we can just let the bottom
129 // pair of vertices of the top edge connect to the
130 // top pair of vertices of the bottom edge generated
131 // in slice 5 below. They both go left-right so they
132 // will create a proper zig-zag box to connect the
133 // 2 sections.
134 } else {
135 // Slice 2: Draw the inner part of the top stroke.
136 // Simply extend down from the last horizontal pair
137 // of vertices to (top + hsw).
138 *vertices++ = Point(left - hsw, top + hsw);
139 *vertices++ = Point(right + hsw, top + hsw);
140
141 // Slice 3: Draw the left and right edges.
142
143 // Slice 3a: Draw the right edge first.
144 // Since we are already at the right edge from the
145 // previous slice, we just have to add 2 vertices
146 // to get to the bottom of that right edge, but we
147 // have to start with an additional vertex that
148 // connects to (right - hsw) instead of the left
149 // side of the rectangle to avoid a big triangle
150 // through the hollow interior section.
151 *vertices++ = Point(right - hsw, top + hsw);
152 *vertices++ = Point(right + hsw, bottom - hsw);
153 *vertices++ = Point(right - hsw, bottom - hsw);
154
155 // Now we need to jump up for the left edge, but we
156 // need to dupliate the last point and the next point
157 // to avoid drawing anything connecting them. These
158 // 2 vertices end up generating 2 empty triangles.
159 *vertices++ = Point(right - hsw, bottom - hsw);
160 *vertices++ = Point(left + hsw, top + hsw);
161
162 // Slice 3b: Now draw the left edge.
163 // We draw this in a specific zig zag order so that
164 // we end up at (left - hsw, bottom - hsw) to connect
165 // properly to the next section.
166 *vertices++ = Point(left + hsw, top + hsw);
167 *vertices++ = Point(left - hsw, top + hsw);
168 *vertices++ = Point(left + hsw, bottom - hsw);
169 *vertices++ = Point(left - hsw, bottom - hsw);
170
171 // Slice 4: Draw the inner part of the bottom stroke.
172 // Since the next section starts by drawing across
173 // the width of the rect at Y=bottom, we simple have
174 // to make sure that we presently have a pair of
175 // vertices that span the top of that section. The
176 // last point was (left - hsw, bottom - hsw), so we
177 // just have to add its right side partner which
178 // is not the same as the vertex before that. This
179 // extra vertex ends up defining an empty triangle,
180 // but sets us up for the final slice to complete
181 // this interior part of the bottom stroke.
182 *vertices++ = Point(right + hsw, bottom - hsw);
183 // Now the first pair of vertices below will
184 // "complete the zig-zag box" for the inner part
185 // of the bottom stroke.
186 }
187
188 // Slice 5: Draw between bottom pair of round joins.
189 for (auto trig : trigs) {
190 // trig.sin goes from 0 to 1
191 // trig.cos goes from 1 to 0
192 *vertices++ = Point(left - trig.cos * hsw,
193 bottom + trig.sin * hsw);
194 *vertices++ = Point(right + trig.cos * hsw,
195 bottom + trig.sin * hsw);
196 }
197
198 // Make sure our estimate is always up to date.
199 FML_DCHECK(vertices == vertices_end);
200 }),
201 .vertex_count = vertex_count,
202 .index_type = IndexType::kNone,
203 },
204 .transform = entity.GetShaderTransform(pass),
206 };
207 }
208
209 case Join::kBevel: {
210 if (interior_filled) {
211 return GeometryResult{
213 .vertex_buffer =
214 {
215 .vertex_buffer = data_host_buffer.Emplace(
216 8 * sizeof(Point), alignof(Point),
217 [hsw = half_stroke_width, &rect](uint8_t* buffer) {
218 Scalar left = rect.GetLeft();
219 Scalar top = rect.GetTop();
220 Scalar right = rect.GetRight();
221 Scalar bottom = rect.GetBottom();
222 auto vertices = reinterpret_cast<Point*>(buffer);
223 vertices[0] = Point(left, top - hsw);
224 vertices[1] = Point(right, top - hsw);
225 vertices[2] = Point(left - hsw, top);
226 vertices[3] = Point(right + hsw, top);
227 vertices[4] = Point(left - hsw, bottom);
228 vertices[5] = Point(right + hsw, bottom);
229 vertices[6] = Point(left, bottom + hsw);
230 vertices[7] = Point(right, bottom + hsw);
231 }),
232 .vertex_count = 8u,
233 .index_type = IndexType::kNone,
234 },
235 .transform = entity.GetShaderTransform(pass),
237 };
238 }
239 return GeometryResult{
241 .vertex_buffer =
242 {
243 .vertex_buffer = data_host_buffer.Emplace(
244 17 * sizeof(Point), alignof(Point),
245 [hsw = half_stroke_width, &rect](uint8_t* buffer) {
246 Scalar left = rect.GetLeft();
247 Scalar top = rect.GetTop();
248 Scalar right = rect.GetRight();
249 Scalar bottom = rect.GetBottom();
250 auto vertices = reinterpret_cast<Point*>(buffer);
251 vertices[0] = Point(left - hsw, top);
252 vertices[1] = Point(left + hsw, top + hsw);
253 vertices[2] = Point(left, top - hsw);
254 vertices[3] = Point(right - hsw, top + hsw);
255 vertices[4] = Point(right, top - hsw);
256 vertices[5] = Point(right - hsw, top + hsw);
257 vertices[6] = Point(right + hsw, top);
258 vertices[7] = Point(right - hsw, bottom - hsw);
259 vertices[8] = Point(right + hsw, bottom);
260 vertices[9] = Point(right - hsw, bottom - hsw);
261 vertices[10] = Point(right, bottom + hsw);
262 vertices[11] = Point(left + hsw, bottom - hsw);
263 vertices[12] = Point(left, bottom + hsw);
264 vertices[13] = Point(left + hsw, bottom - hsw);
265 vertices[14] = Point(left - hsw, bottom);
266 vertices[15] = Point(left + hsw, top + hsw);
267 vertices[16] = Point(left - hsw, top);
268 }),
269 .vertex_count = 17u,
270 .index_type = IndexType::kNone,
271 },
272 .transform = entity.GetShaderTransform(pass),
274 };
275 }
276
277 case Join::kMiter: {
278 if (interior_filled) {
279 return GeometryResult{
281 .vertex_buffer =
282 {
283 .vertex_buffer = data_host_buffer.Emplace(
284 4 * sizeof(Point), alignof(Point),
285 [hsw = half_stroke_width, &rect](uint8_t* buffer) {
286 Scalar left = rect.GetLeft();
287 Scalar top = rect.GetTop();
288 Scalar right = rect.GetRight();
289 Scalar bottom = rect.GetBottom();
290 auto vertices = reinterpret_cast<Point*>(buffer);
291
292 vertices[0] = Point(left - hsw, top - hsw);
293 vertices[1] = Point(right + hsw, top - hsw);
294 vertices[2] = Point(left - hsw, bottom + hsw);
295 vertices[3] = Point(right + hsw, bottom + hsw);
296 }),
297 .vertex_count = 4u,
298 .index_type = IndexType::kNone,
299 },
300 .transform = entity.GetShaderTransform(pass),
302 };
303 }
304 return GeometryResult{
306 .vertex_buffer =
307 {
308 .vertex_buffer = data_host_buffer.Emplace(
309 10 * sizeof(Point), alignof(Point),
310 [hsw = half_stroke_width, &rect](uint8_t* buffer) {
311 Scalar left = rect.GetLeft();
312 Scalar top = rect.GetTop();
313 Scalar right = rect.GetRight();
314 Scalar bottom = rect.GetBottom();
315 auto vertices = reinterpret_cast<Point*>(buffer);
316 vertices[0] = Point(left - hsw, top - hsw);
317 vertices[1] = Point(left + hsw, top + hsw);
318 vertices[2] = Point(right + hsw, top - hsw);
319 vertices[3] = Point(right - hsw, top + hsw);
320 vertices[4] = Point(right + hsw, bottom + hsw);
321 vertices[5] = Point(right - hsw, bottom - hsw);
322 vertices[6] = Point(left - hsw, bottom + hsw);
323 vertices[7] = Point(left + hsw, bottom - hsw);
324 vertices[8] = Point(left - hsw, top - hsw);
325 vertices[9] = Point(left + hsw, top + hsw);
326 }),
327 .vertex_count = 10u,
328 .index_type = IndexType::kNone,
329 },
330 .transform = entity.GetShaderTransform(pass),
332 };
333 }
334 }
335}
#define FML_DCHECK(condition)
Definition logging.h:122
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
float Scalar
Definition scalar.h:19
@ kNone
Does not use the index buffer.
TRect< Scalar > Rect
Definition rect.h:788
TPoint< Scalar > Point
Definition point.h:327
static constexpr Scalar kMinStrokeSize
Definition geometry.h:19
@ kNormal
The geometry has no overlapping triangles.

References FML_DCHECK, impeller::TRect< T >::GetBottom(), impeller::TRect< T >::GetLeft(), impeller::Matrix::GetMaxBasisLengthXY(), impeller::TRect< T >::GetRight(), impeller::Entity::GetShaderTransform(), impeller::TRect< T >::GetSize(), impeller::ContentContext::GetTessellator(), impeller::TRect< T >::GetTop(), impeller::Entity::GetTransform(), impeller::ContentContext::GetTransientsDataBuffer(), impeller::Tessellator::GetTrigsForDeviceRadius(), impeller::kBevel, impeller::kMinStrokeSize, impeller::kMiter, impeller::kNone, impeller::GeometryResult::kNormal, impeller::kRound, impeller::kTriangleStrip, impeller::Tessellator::Trigs::size(), and impeller::GeometryResult::type.


The documentation for this class was generated from the following files: