16using VS = SolidFillVertexShader;
23static constexpr Scalar kMinStrokeSizeMSAA = 0.5f;
25static constexpr Scalar kMinStrokeSize = 1.0f;
27template <
typename VertexWriter>
29 const Point& position,
34template <
typename VertexWriter>
36 const Point& position,
37 const Point& start_offset,
38 const Point& end_offset,
44 void AppendVertex(
const Point& point) {
45 data_.emplace_back(SolidFillVertexShader::PerVertexData{.position = point});
48 const std::vector<SolidFillVertexShader::PerVertexData>& GetData()
const {
53 std::vector<SolidFillVertexShader::PerVertexData> data_ = {};
56template <
typename VertexWriter>
57class StrokeGenerator {
60 const Scalar p_stroke_width,
61 const Scalar p_scaled_miter_limit,
62 const JoinProc<VertexWriter>& p_join_proc,
63 const CapProc<VertexWriter>& p_cap_proc,
73 for (
size_t contour_i = 0; contour_i <
polyline.contours.size();
76 size_t contour_start_point_i, contour_end_point_i;
77 std::tie(contour_start_point_i, contour_end_point_i) =
78 polyline.GetContourPointBounds(contour_i);
80 auto contour_delta = contour_end_point_i - contour_start_point_i;
81 if (contour_delta == 1) {
88 }
else if (contour_delta == 0) {
93 offset = ComputeOffset(contour_start_point_i, contour_start_point_i,
95 const Point contour_first_offset =
offset.GetVector();
105 vtx.position =
polyline.GetPoint(contour_start_point_i - 1);
109 vtx_builder.AppendVertex(
vtx.position);
110 vtx_builder.AppendVertex(
vtx.position);
112 vtx.position =
polyline.GetPoint(contour_start_point_i);
115 vtx_builder.AppendVertex(
vtx.position);
116 vtx_builder.AppendVertex(
vtx.position);
120 if (!
polyline.contours[contour_i].is_closed) {
125 cap_offset,
scale,
true);
128 for (
size_t contour_component_i = 0;
129 contour_component_i <
contour.components.size();
130 contour_component_i++) {
132 contour.components[contour_component_i];
133 bool is_last_component =
134 contour_component_i ==
contour.components.size() - 1;
137 size_t component_end_index =
138 is_last_component ? contour_end_point_i - 1
139 :
contour.components[contour_component_i + 1]
140 .component_start_index;
142 AddVerticesForCurveComponent(
143 vtx_builder, component_start_index, component_end_index,
144 contour_start_point_i, contour_end_point_i,
contour);
146 AddVerticesForLinearComponent(
147 vtx_builder, component_start_index, component_end_index,
148 contour_start_point_i, contour_end_point_i,
contour);
158 cap_offset,
scale,
false);
171 const size_t contour_start_point_i,
172 const size_t contour_end_point_i,
175 if (point_i >= contour_end_point_i) {
176 direction =
contour.end_direction;
177 }
else if (point_i <= contour_start_point_i) {
178 direction = -
contour.start_direction;
187 void AddVerticesForLinearComponent(
VertexWriter& vtx_builder,
188 const size_t component_start_index,
189 const size_t component_end_index,
190 const size_t contour_start_point_i,
191 const size_t contour_end_point_i,
193 bool is_last_component = component_start_index ==
194 contour.components.back().component_start_index;
196 for (
size_t point_i = component_start_index; point_i < component_end_index;
198 bool is_end_of_component = point_i == component_end_index - 1;
202 vtx.position =
polyline.GetPoint(point_i) + offset_vector;
203 vtx_builder.AppendVertex(
vtx.position);
204 vtx.position =
polyline.GetPoint(point_i) - offset_vector;
205 vtx_builder.AppendVertex(
vtx.position);
209 vtx.position =
polyline.GetPoint(point_i + 1) + offset_vector;
210 vtx_builder.AppendVertex(
vtx.position);
211 vtx.position =
polyline.GetPoint(point_i + 1) - offset_vector;
212 vtx_builder.AppendVertex(
vtx.position);
215 offset = ComputeOffset(point_i + 2, contour_start_point_i,
217 if (!is_last_component && is_end_of_component) {
226 void AddVerticesForCurveComponent(
VertexWriter& vtx_builder,
227 const size_t component_start_index,
228 const size_t component_end_index,
229 const size_t contour_start_point_i,
230 const size_t contour_end_point_i,
232 bool is_last_component = component_start_index ==
233 contour.components.back().component_start_index;
235 for (
size_t point_i = component_start_index; point_i < component_end_index;
237 bool is_end_of_component = point_i == component_end_index - 1;
240 vtx_builder.AppendVertex(
vtx.position);
242 vtx_builder.AppendVertex(
vtx.position);
245 offset = ComputeOffset(point_i + 2, contour_start_point_i,
249 if (!is_end_of_component) {
250 constexpr Scalar kAngleThreshold = 10 *
kPi / 180;
253 constexpr Scalar kAlignmentThreshold =
259 Scalar angle = kAngleThreshold;
263 while (angle <
std::abs(angle_total)) {
264 Scalar signed_angle = angle_total < 0 ? -angle : angle;
268 vtx_builder.AppendVertex(
vtx.position);
270 vtx_builder.AppendVertex(
vtx.position);
272 angle += kAngleThreshold;
279 if (is_end_of_component) {
286 Point last_component_offset = is_last_component
289 vtx.position =
polyline.GetPoint(point_i + 1) + last_component_offset;
290 vtx_builder.AppendVertex(
vtx.position);
291 vtx.position =
polyline.GetPoint(point_i + 1) - last_component_offset;
292 vtx_builder.AppendVertex(
vtx.position);
294 if (!is_last_component) {
312 SolidFillVertexShader::PerVertexData
vtx;
315template <
typename VertexWriter>
316void CreateButtCap(VertexWriter& vtx_builder,
317 const Point& position,
322 VS::PerVertexData
vtx;
323 vtx.position = position + orientation;
324 vtx_builder.AppendVertex(
vtx.position);
325 vtx.position = position - orientation;
326 vtx_builder.AppendVertex(
vtx.position);
329template <
typename VertexWriter>
330void CreateRoundCap(VertexWriter& vtx_builder,
331 const Point& position,
339 CubicPathComponent arc;
341 arc = CubicPathComponent(
346 arc = CubicPathComponent(
353 vtx_builder.AppendVertex(
vtx);
354 vtx = position - orientation;
355 vtx_builder.AppendVertex(
vtx);
357 arc.ToLinearPathComponents(
scale, [&vtx_builder, &
vtx, forward_normal,
358 position](
const Point& point) {
359 vtx = position + point;
360 vtx_builder.AppendVertex(
vtx);
361 vtx = position + (-point).Reflect(forward_normal);
362 vtx_builder.AppendVertex(
vtx);
366template <
typename VertexWriter>
367void CreateSquareCap(VertexWriter& vtx_builder,
368 const Point& position,
376 vtx_builder.AppendVertex(
vtx);
377 vtx = position - orientation;
378 vtx_builder.AppendVertex(
vtx);
379 vtx = position + orientation + forward;
380 vtx_builder.AppendVertex(
vtx);
381 vtx = position - orientation + forward;
382 vtx_builder.AppendVertex(
vtx);
385template <
typename VertexWriter>
386Scalar CreateBevelAndGetDirection(VertexWriter& vtx_builder,
387 const Point& position,
388 const Point& start_offset,
389 const Point& end_offset) {
391 vtx_builder.AppendVertex(
vtx);
393 Scalar dir = start_offset.Cross(end_offset) > 0 ? -1 : 1;
394 vtx = position + start_offset *
dir;
395 vtx_builder.AppendVertex(
vtx);
396 vtx = position + end_offset *
dir;
397 vtx_builder.AppendVertex(
vtx);
402template <
typename VertexWriter>
403void CreateMiterJoin(VertexWriter& vtx_builder,
404 const Point& position,
405 const Point& start_offset,
406 const Point& end_offset,
413 Scalar alignment = (start_normal.Dot(end_normal) + 1) / 2;
418 Scalar direction = CreateBevelAndGetDirection(vtx_builder, position,
419 start_offset, end_offset);
421 Point miter_point = (((start_offset + end_offset) / 2) / alignment);
422 if (miter_point.GetDistanceSquared({0, 0}) > miter_limit * miter_limit) {
427 VS::PerVertexData
vtx;
428 vtx.position = position + miter_point * direction;
429 vtx_builder.AppendVertex(
vtx.position);
432template <
typename VertexWriter>
433void CreateRoundJoin(VertexWriter& vtx_builder,
434 const Point& position,
435 const Point& start_offset,
436 const Point& end_offset,
443 Scalar alignment = 1 - (start_normal.Dot(end_normal) + 1) / 2;
448 Scalar direction = CreateBevelAndGetDirection(vtx_builder, position,
449 start_offset, end_offset);
452 (start_offset + end_offset).
Normalize() * start_offset.GetLength();
455 Point middle_handle = middle +
Point(-middle.y, middle.x) *
457 alignment * direction;
458 Point start_handle = start_offset +
Point(start_offset.y, -start_offset.x) *
460 alignment * direction;
462 VS::PerVertexData
vtx;
463 CubicPathComponent(start_offset, start_handle, middle_handle, middle)
464 .ToLinearPathComponents(
scale, [&vtx_builder, direction, &
vtx, position,
465 middle_normal](
const Point& point) {
466 vtx.position = position + point * direction;
467 vtx_builder.AppendVertex(
vtx.position);
468 vtx.position = position + (-point * direction).Reflect(middle_normal);
469 vtx_builder.AppendVertex(
vtx.position);
473template <
typename VertexWriter>
474void CreateBevelJoin(VertexWriter& vtx_builder,
475 const Point& position,
476 const Point& start_offset,
477 const Point& end_offset,
480 CreateBevelAndGetDirection(vtx_builder, position, start_offset, end_offset);
483template <
typename VertexWriter>
484void CreateSolidStrokeVertices(VertexWriter& vtx_builder,
489 const CapProc<VertexWriter>&
cap_proc,
493 stroke_generator.Generate(vtx_builder);
497template <
typename VertexWriter>
498JoinProc<VertexWriter> GetJoinProc(
Join stroke_join) {
499 switch (stroke_join) {
501 return &CreateBevelJoin<VertexWriter>;
503 return &CreateMiterJoin<VertexWriter>;
505 return &CreateRoundJoin<VertexWriter>;
509template <
typename VertexWriter>
510CapProc<VertexWriter> GetCapProc(
Cap stroke_cap) {
511 switch (stroke_cap) {
513 return &CreateButtCap<VertexWriter>;
515 return &CreateRoundCap<VertexWriter>;
517 return &CreateSquareCap<VertexWriter>;
522std::vector<SolidFillVertexShader::PerVertexData>
523StrokePathGeometry::GenerateSolidStrokeVertices(
const Path::Polyline&
polyline,
530 auto join_proc = GetJoinProc<PositionWriter>(stroke_join);
531 auto cap_proc = GetCapProc<PositionWriter>(stroke_cap);
534 PositionWriter vtx_builder;
535 stroke_generator.Generate(vtx_builder);
536 return vtx_builder.GetData();
539StrokePathGeometry::StrokePathGeometry(
const Path&
path,
546 miter_limit_(miter_limit),
547 stroke_cap_(stroke_cap),
548 stroke_join_(stroke_join) {}
553 return stroke_width_;
569 Scalar scaled_stroke_width =
573 if (scaled_stroke_width == 0.0 || scaled_stroke_width >= kMinStrokeSizeMSAA) {
577 return std::clamp(scaled_stroke_width * 20.0f, 0.f, 1.f);
584 if (stroke_width_ < 0.0) {
588 if (determinant == 0) {
598 auto& host_buffer =
renderer.GetTransientsBuffer();
601 PositionWriter position_writer;
604 miter_limit_ * stroke_width_ * 0.5f,
605 GetJoinProc<PositionWriter>(stroke_join_),
606 GetCapProc<PositionWriter>(stroke_cap_),
scale);
609 host_buffer.Emplace(position_writer.GetData().data(),
610 position_writer.GetData().size() *
611 sizeof(SolidFillVertexShader::PerVertexData),
612 alignof(SolidFillVertexShader::PerVertexData));
614 return GeometryResult{
619 .vertex_count = position_writer.GetData().size(),
630std::optional<Rect> StrokePathGeometry::GetCoverage(
633 if (!path_bounds.has_value()) {
639 max_radius = max_radius *
kSqrt2;
642 max_radius =
std::max(max_radius, miter_limit_ * 0.5f);
645 if (determinant == 0) {
650 max_radius *=
std::max(stroke_width_, min_size);
651 return path_bounds->Expand(max_radius).TransformBounds(
transform);
static unsigned clamp(SkFixed fx, int max)
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...
SampleCount GetSampleCount() const
The sample count of the attached render target.
Scalar ComputeAlphaCoverage(const Entity &entity) const override
Scalar GetMiterLimit() const
Scalar GetStrokeWidth() const
Join GetStrokeJoin() const
An interface for generating a multi contour polyline as a triangle strip.
Dart_NativeFunction function
static float max(float r, float g, float b)
static void Normalize(char *s)
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
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)
SK_API sk_sp< PrecompileColorFilter > Matrix()
SIN Vec< N, float > abs(const Vec< N, float > &x)
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
SeparatedVector2 previous_offset
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
constexpr Scalar GetMaxBasisLengthXY() const
Scalar GetMaxBasisLength() const
Scalar GetDeterminant() const
size_t component_start_index
A Vector2, broken down as a separate magnitude and direction. Assumes that the direction given is nor...
constexpr TPoint Normalize() const