| Flutter Impeller |

Public Member Functions | List of all members
impeller::StrokeRectGeometry Class Referencefinal

`#include <rect_geometry.h>`

Inheritance diagram for impeller::StrokeRectGeometry:

## 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< Rect > | GetCoverage (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`. More...
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< Geometry > | MakeFillPath (const flutter::DlPath &path, std::optional< Rect > inner_rect=std::nullopt)
static std::unique_ptr< Geometry > | MakeStrokePath (const flutter::DlPath &path, const StrokeParameters &stroke={})
static std::unique_ptr< Geometry > | MakeCover ()
static std::unique_ptr< Geometry > | MakeRect (const Rect &rect)
static std::unique_ptr< Geometry > | MakeOval (const Rect &rect)
static std::unique_ptr< Geometry > | MakeLine (const Point &p0, const Point &p1, const StrokeParameters &stroke)
static std::unique_ptr< Geometry > | MakeCircle (const Point &center, Scalar radius)
static std::unique_ptr< Geometry > | MakeStrokedCircle (const Point &center, Scalar radius, Scalar stroke_width)
static std::unique_ptr< Geometry > | MakeFilledArc (const Rect &oval_bounds, Degrees start, Degrees sweep, bool include_center)
static std::unique_ptr< Geometry > | MakeStrokedArc (const Rect &oval_bounds, Degrees start, Degrees sweep, const StrokeParameters &stroke)
static std::unique_ptr< Geometry > | MakeRoundRect (const Rect &rect, const Size &radii)
static std::unique_ptr< Geometry > | MakeRoundSuperellipse (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. More...
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 | ( |  | ) |
| override default

## Member Function Documentation

## ◆ GetCoverage()

std::optional< Rect > impeller::StrokeRectGeometry::GetCoverage | ( | const Matrix & | transform | ) | const
| override virtual

Implements impeller::Geometry.

Definition at line 337 of file rect_geometry.cc.

338 {
339 return rect_.TransformBounds(transform);
340 }
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:312
impeller::TRect::TransformBounds
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
| override virtual

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{
95 .type = PrimitiveType::kTriangleStrip,
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),
205 .mode = GeometryResult::Mode::kNormal,
206 };
207 }
208
209 case Join::kBevel: {
210 if (interior_filled) {
211 return GeometryResult{
212 .type = PrimitiveType::kTriangleStrip,
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),
236 .mode = GeometryResult::Mode::kNormal,
237 };
238 }
239 return GeometryResult{
240 .type = PrimitiveType::kTriangleStrip,
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),
273 .mode = GeometryResult::Mode::kNormal,
274 };
275 }
276
277 case Join::kMiter: {
278 if (interior_filled) {
279 return GeometryResult{
280 .type = PrimitiveType::kTriangleStrip,
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),
301 .mode = GeometryResult::Mode::kNormal,
302 };
303 }
304 return GeometryResult{
305 .type = PrimitiveType::kTriangleStrip,
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),
331 .mode = GeometryResult::Mode::kNormal,
332 };
333 }
334 }
335 }
impeller::Join::kRound
@ kRound
impeller::Join::kMiter
@ kMiter
impeller::Join::kBevel
@ kBevel
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:788
impeller::Point
TPoint< Scalar > Point
Definition: point.h:425
impeller::kMinStrokeSize
static constexpr Scalar kMinStrokeSize
Definition: geometry.h:19
impeller::GeometryResult::Mode::kNormal
@ kNormal
The geometry has no overlapping triangles.

References 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:

- impeller/entity/geometry/rect_geometry.h
- impeller/entity/geometry/rect_geometry.cc