14using VS = SolidFillVertexShader;
18template <
typename VertexWriter>
19using CapProc = std::function<void(VertexWriter& vtx_builder,
20 const Point& position,
25template <
typename VertexWriter>
26using JoinProc = std::function<void(VertexWriter& vtx_builder,
27 const Point& position,
28 const Point& start_offset,
29 const Point& end_offset,
35 void AppendVertex(
const Point& point) {
36 data_.emplace_back(SolidFillVertexShader::PerVertexData{.position = point});
39 const std::vector<SolidFillVertexShader::PerVertexData>& GetData()
const {
44 std::vector<SolidFillVertexShader::PerVertexData> data_ = {};
47template <
typename VertexWriter>
48class StrokeGenerator {
51 const Scalar p_stroke_width,
52 const Scalar p_scaled_miter_limit,
53 const JoinProc<VertexWriter>& p_join_proc,
54 const CapProc<VertexWriter>& p_cap_proc,
63 void Generate(VertexWriter& vtx_builder) {
64 for (
size_t contour_i = 0; contour_i <
polyline.contours.size();
67 size_t contour_start_point_i, contour_end_point_i;
68 std::tie(contour_start_point_i, contour_end_point_i) =
69 polyline.GetContourPointBounds(contour_i);
71 auto contour_delta = contour_end_point_i - contour_start_point_i;
72 if (contour_delta == 1) {
79 }
else if (contour_delta == 0) {
84 offset = ComputeOffset(contour_start_point_i, contour_start_point_i,
96 vtx.position =
polyline.GetPoint(contour_start_point_i - 1);
100 vtx_builder.AppendVertex(
vtx.position);
101 vtx_builder.AppendVertex(
vtx.position);
103 vtx.position =
polyline.GetPoint(contour_start_point_i);
106 vtx_builder.AppendVertex(
vtx.position);
107 vtx_builder.AppendVertex(
vtx.position);
111 if (!
polyline.contours[contour_i].is_closed) {
116 cap_offset,
scale,
true);
119 for (
size_t contour_component_i = 0;
120 contour_component_i <
contour.components.size();
121 contour_component_i++) {
123 contour.components[contour_component_i];
124 bool is_last_component =
125 contour_component_i ==
contour.components.size() - 1;
128 size_t component_end_index =
129 is_last_component ? contour_end_point_i - 1
130 :
contour.components[contour_component_i + 1]
131 .component_start_index;
133 AddVerticesForCurveComponent(
134 vtx_builder, component_start_index, component_end_index,
135 contour_start_point_i, contour_end_point_i,
contour);
137 AddVerticesForLinearComponent(
138 vtx_builder, component_start_index, component_end_index,
139 contour_start_point_i, contour_end_point_i,
contour);
149 cap_offset,
scale,
false);
160 Point ComputeOffset(
const size_t point_i,
161 const size_t contour_start_point_i,
162 const size_t contour_end_point_i,
165 if (point_i >= contour_end_point_i) {
166 direction =
contour.end_direction;
167 }
else if (point_i <= contour_start_point_i) {
168 direction = -
contour.start_direction;
176 void AddVerticesForLinearComponent(VertexWriter& vtx_builder,
177 const size_t component_start_index,
178 const size_t component_end_index,
179 const size_t contour_start_point_i,
180 const size_t contour_end_point_i,
182 bool is_last_component = component_start_index ==
183 contour.components.back().component_start_index;
185 for (
size_t point_i = component_start_index; point_i < component_end_index;
187 bool is_end_of_component = point_i == component_end_index - 1;
189 vtx_builder.AppendVertex(
vtx.position);
191 vtx_builder.AppendVertex(
vtx.position);
196 vtx_builder.AppendVertex(
vtx.position);
198 vtx_builder.AppendVertex(
vtx.position);
201 offset = ComputeOffset(point_i + 2, contour_start_point_i,
203 if (!is_last_component && is_end_of_component) {
211 void AddVerticesForCurveComponent(VertexWriter& vtx_builder,
212 const size_t component_start_index,
213 const size_t component_end_index,
214 const size_t contour_start_point_i,
215 const size_t contour_end_point_i,
217 bool is_last_component = component_start_index ==
218 contour.components.back().component_start_index;
220 for (
size_t point_i = component_start_index; point_i < component_end_index;
222 bool is_end_of_component = point_i == component_end_index - 1;
225 vtx_builder.AppendVertex(
vtx.position);
227 vtx_builder.AppendVertex(
vtx.position);
230 offset = ComputeOffset(point_i + 2, contour_start_point_i,
234 if (is_end_of_component) {
236 vtx_builder.AppendVertex(
vtx.position);
238 vtx_builder.AppendVertex(
vtx.position);
240 if (!is_last_component) {
257 SolidFillVertexShader::PerVertexData
vtx;
260template <
typename VertexWriter>
261void CreateButtCap(VertexWriter& vtx_builder,
262 const Point& position,
267 VS::PerVertexData
vtx;
268 vtx.position = position + orientation;
269 vtx_builder.AppendVertex(
vtx.position);
270 vtx.position = position - orientation;
271 vtx_builder.AppendVertex(
vtx.position);
274template <
typename VertexWriter>
275void CreateRoundCap(VertexWriter& vtx_builder,
276 const Point& position,
284 CubicPathComponent arc;
286 arc = CubicPathComponent(
291 arc = CubicPathComponent(
298 vtx_builder.AppendVertex(
vtx);
299 vtx = position - orientation;
300 vtx_builder.AppendVertex(
vtx);
302 arc.ToLinearPathComponents(
scale, [&vtx_builder, &
vtx, forward_normal,
303 position](
const Point& point) {
304 vtx = position + point;
305 vtx_builder.AppendVertex(
vtx);
306 vtx = position + (-point).Reflect(forward_normal);
307 vtx_builder.AppendVertex(
vtx);
311template <
typename VertexWriter>
312void CreateSquareCap(VertexWriter& vtx_builder,
313 const Point& position,
321 vtx_builder.AppendVertex(
vtx);
322 vtx = position - orientation;
323 vtx_builder.AppendVertex(
vtx);
324 vtx = position + orientation + forward;
325 vtx_builder.AppendVertex(
vtx);
326 vtx = position - orientation + forward;
327 vtx_builder.AppendVertex(
vtx);
330template <
typename VertexWriter>
331Scalar CreateBevelAndGetDirection(VertexWriter& vtx_builder,
332 const Point& position,
333 const Point& start_offset,
334 const Point& end_offset) {
336 vtx_builder.AppendVertex(
vtx);
338 Scalar dir = start_offset.Cross(end_offset) > 0 ? -1 : 1;
339 vtx = position + start_offset *
dir;
340 vtx_builder.AppendVertex(
vtx);
341 vtx = position + end_offset *
dir;
342 vtx_builder.AppendVertex(
vtx);
347template <
typename VertexWriter>
348void CreateMiterJoin(VertexWriter& vtx_builder,
349 const Point& position,
350 const Point& start_offset,
351 const Point& end_offset,
358 Scalar alignment = (start_normal.Dot(end_normal) + 1) / 2;
363 Scalar direction = CreateBevelAndGetDirection(vtx_builder, position,
364 start_offset, end_offset);
366 Point miter_point = (((start_offset + end_offset) / 2) / alignment);
367 if (miter_point.GetDistanceSquared({0, 0}) > miter_limit * miter_limit) {
372 VS::PerVertexData
vtx;
373 vtx.position = position + miter_point * direction;
374 vtx_builder.AppendVertex(
vtx.position);
377template <
typename VertexWriter>
378void CreateRoundJoin(VertexWriter& vtx_builder,
379 const Point& position,
380 const Point& start_offset,
381 const Point& end_offset,
388 Scalar alignment = 1 - (start_normal.Dot(end_normal) + 1) / 2;
393 Scalar direction = CreateBevelAndGetDirection(vtx_builder, position,
394 start_offset, end_offset);
397 (start_offset + end_offset).Normalize() * start_offset.
GetLength();
400 Point middle_handle = middle +
Point(-middle.y, middle.x) *
402 alignment * direction;
403 Point start_handle = start_offset +
Point(start_offset.y, -start_offset.x) *
405 alignment * direction;
407 VS::PerVertexData
vtx;
408 CubicPathComponent(start_offset, start_handle, middle_handle, middle)
409 .ToLinearPathComponents(
scale, [&vtx_builder, direction, &
vtx, position,
410 middle_normal](
const Point& point) {
411 vtx.position = position + point * direction;
412 vtx_builder.AppendVertex(
vtx.position);
413 vtx.position = position + (-point * direction).Reflect(middle_normal);
414 vtx_builder.AppendVertex(
vtx.position);
418template <
typename VertexWriter>
419void CreateBevelJoin(VertexWriter& vtx_builder,
420 const Point& position,
421 const Point& start_offset,
422 const Point& end_offset,
425 CreateBevelAndGetDirection(vtx_builder, position, start_offset, end_offset);
428template <
typename VertexWriter>
429void CreateSolidStrokeVertices(VertexWriter& vtx_builder,
434 const CapProc<VertexWriter>&
cap_proc,
438 stroke_generator.Generate(vtx_builder);
442template <
typename VertexWriter>
443JoinProc<VertexWriter> GetJoinProc(
Join stroke_join) {
444 switch (stroke_join) {
446 return &CreateBevelJoin<VertexWriter>;
448 return &CreateMiterJoin<VertexWriter>;
450 return &CreateRoundJoin<VertexWriter>;
454template <
typename VertexWriter>
455CapProc<VertexWriter> GetCapProc(
Cap stroke_cap) {
456 switch (stroke_cap) {
458 return &CreateButtCap<VertexWriter>;
460 return &CreateRoundCap<VertexWriter>;
462 return &CreateSquareCap<VertexWriter>;
467std::vector<SolidFillVertexShader::PerVertexData>
468StrokePathGeometry::GenerateSolidStrokeVertices(
const Path::Polyline&
polyline,
475 auto join_proc = GetJoinProc<PositionWriter>(stroke_join);
476 auto cap_proc = GetCapProc<PositionWriter>(stroke_cap);
479 PositionWriter vtx_builder;
480 stroke_generator.Generate(vtx_builder);
481 return vtx_builder.GetData();
484StrokePathGeometry::StrokePathGeometry(
const Path& path,
491 miter_limit_(miter_limit),
492 stroke_cap_(stroke_cap),
493 stroke_join_(stroke_join) {}
498 return stroke_width_;
517 if (stroke_width_ < 0.0) {
521 if (determinant == 0) {
525 Scalar min_size = 1.0f / sqrt(std::abs(determinant));
528 auto& host_buffer = renderer.GetTransientsBuffer();
531 PositionWriter position_writer;
532 auto polyline = renderer.GetTessellator()->CreateTempPolyline(path_,
scale);
534 miter_limit_ * stroke_width_ * 0.5f,
535 GetJoinProc<PositionWriter>(stroke_join_),
536 GetCapProc<PositionWriter>(stroke_cap_),
scale);
539 host_buffer.Emplace(position_writer.GetData().data(),
540 position_writer.GetData().size() *
541 sizeof(SolidFillVertexShader::PerVertexData),
542 alignof(SolidFillVertexShader::PerVertexData));
548 .vertex_buffer = buffer_view,
549 .vertex_count = position_writer.GetData().size(),
564 if (!path_bounds.has_value()) {
570 max_radius = max_radius *
kSqrt2;
573 max_radius = std::max(max_radius, miter_limit_ * 0.5f);
576 if (determinant == 0) {
579 Scalar min_size = 1.0f / sqrt(std::abs(determinant));
580 max_radius *= std::max(stroke_width_, min_size);
581 return path_bounds->Expand(max_radius).TransformBounds(
transform);
Matrix GetShaderTransform(const RenderPass &pass) const
Get the vertex shader transform used for drawing this Entity.
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
static constexpr const Scalar kArcApproximationMagic
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
std::optional< Rect > GetBoundingBox() const
Render passes encode render commands directed as one specific render target into an underlying comman...
GeometryResult::Mode GetResultMode() const override
Scalar GetMiterLimit() const
std::optional< Rect > GetCoverage(const Matrix &transform) const override
Scalar GetStrokeWidth() const
GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const override
Join GetStrokeJoin() const
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 vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
@ kNone
Does not use the index buffer.
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
SolidFillVertexShader::PerVertexData vtx
const CapProc< VertexWriter > & cap_proc
const Scalar scaled_miter_limit
const Scalar stroke_width
const JoinProc< VertexWriter > & join_proc
const Path::Polyline & polyline
A 4x4 matrix using column-major storage.
Scalar GetMaxBasisLength() const
Scalar GetDeterminant() const
size_t component_start_index
constexpr Type GetLength() const
constexpr TPoint Normalize() const