1111#include " impeller/entity/content_context.h"
1212#include " impeller/entity/entity.h"
1313#include " impeller/geometry/path_builder.h"
14+ #include " impeller/geometry/scalar.h"
1415#include " impeller/geometry/vector.h"
1516#include " impeller/renderer/render_pass.h"
1617#include " impeller/renderer/sampler_library.h"
@@ -284,8 +285,7 @@ const IRect& TextureContents::GetSourceRect() const {
284285
285286SolidStrokeContents::SolidStrokeContents () {
286287 SetStrokeCap (Cap::kButt );
287- // TODO(99089): Change this to kMiter once implemented.
288- SetStrokeJoin (Join::kBevel );
288+ SetStrokeJoin (Join::kMiter );
289289}
290290
291291SolidStrokeContents::~SolidStrokeContents () = default ;
@@ -302,7 +302,8 @@ static VertexBuffer CreateSolidStrokeVertices(
302302 const Path& path,
303303 HostBuffer& buffer,
304304 const SolidStrokeContents::CapProc& cap_proc,
305- const SolidStrokeContents::JoinProc& join_proc) {
305+ const SolidStrokeContents::JoinProc& join_proc,
306+ Scalar miter_limit) {
306307 using VS = SolidStrokeVertexShader;
307308
308309 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
@@ -380,7 +381,7 @@ static VertexBuffer CreateSolidStrokeVertices(
380381
381382 // Generate join from the current line to the next line.
382383 join_proc (vtx_builder, polyline.points [point_i], previous_normal,
383- normal);
384+ normal, miter_limit );
384385 }
385386 }
386387 }
@@ -390,7 +391,7 @@ static VertexBuffer CreateSolidStrokeVertices(
390391 cap_proc (vtx_builder, polyline.points [contour_end_point_i - 1 ], normal);
391392 } else {
392393 join_proc (vtx_builder, polyline.points [contour_start_point_i], normal,
393- contour_first_normal);
394+ contour_first_normal, miter_limit );
394395 }
395396 }
396397
@@ -419,8 +420,9 @@ bool SolidStrokeContents::Render(const ContentContext& renderer,
419420 cmd.label = " SolidStroke" ;
420421 cmd.pipeline = renderer.GetSolidStrokePipeline (OptionsFromPass (pass));
421422 cmd.stencil_reference = entity.GetStencilDepth ();
422- cmd.BindVertices (CreateSolidStrokeVertices (
423- entity.GetPath (), pass.GetTransientsBuffer (), cap_proc_, join_proc_));
423+ cmd.BindVertices (
424+ CreateSolidStrokeVertices (entity.GetPath (), pass.GetTransientsBuffer (),
425+ cap_proc_, join_proc_, miter_limit_));
424426 VS::BindFrameInfo (cmd, pass.GetTransientsBuffer ().EmplaceUniform (frame_info));
425427 VS::BindStrokeInfo (cmd,
426428 pass.GetTransientsBuffer ().EmplaceUniform (stroke_info));
@@ -438,12 +440,15 @@ Scalar SolidStrokeContents::GetStrokeSize() const {
438440 return stroke_size_;
439441}
440442
441- void SolidStrokeContents::SetStrokeMiter (Scalar miter) {
442- miter_ = miter;
443+ void SolidStrokeContents::SetStrokeMiter (Scalar miter_limit) {
444+ if (miter_limit < 0 ) {
445+ return ; // Skia behaves like this.
446+ }
447+ miter_limit_ = miter_limit;
443448}
444449
445- Scalar SolidStrokeContents::GetStrokeMiter (Scalar miter ) {
446- return miter_ ;
450+ Scalar SolidStrokeContents::GetStrokeMiter () {
451+ return miter_limit_ ;
447452}
448453
449454void SolidStrokeContents::SetStrokeCap (Cap cap) {
@@ -484,6 +489,26 @@ SolidStrokeContents::Cap SolidStrokeContents::GetStrokeCap() {
484489 return cap_;
485490}
486491
492+ static Scalar CreateBevelAndGetDirection (
493+ VertexBufferBuilder<SolidStrokeVertexShader::PerVertexData>& vtx_builder,
494+ const Point& position,
495+ const Point& start_normal,
496+ const Point& end_normal) {
497+ SolidStrokeVertexShader::PerVertexData vtx;
498+ vtx.vertex_position = position;
499+ vtx.pen_down = 1.0 ;
500+ vtx.vertex_normal = {};
501+ vtx_builder.AppendVertex (vtx);
502+
503+ Scalar dir = start_normal.Cross (end_normal) > 0 ? -1 : 1 ;
504+ vtx.vertex_normal = start_normal * dir;
505+ vtx_builder.AppendVertex (vtx);
506+ vtx.vertex_normal = end_normal * dir;
507+ vtx_builder.AppendVertex (vtx);
508+
509+ return dir;
510+ }
511+
487512void SolidStrokeContents::SetStrokeJoin (Join join) {
488513 join_ = join;
489514
@@ -492,23 +517,37 @@ void SolidStrokeContents::SetStrokeJoin(Join join) {
492517 case Join::kBevel :
493518 join_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
494519 const Point& position, const Point& start_normal,
495- const Point& end_normal) {
520+ const Point& end_normal, Scalar miter_limit) {
521+ CreateBevelAndGetDirection (vtx_builder, position, start_normal, end_normal);
522+ };
523+ break ;
524+ case Join::kMiter :
525+ join_proc_ = [](VertexBufferBuilder<VS::PerVertexData>& vtx_builder,
526+ const Point& position, const Point& start_normal,
527+ const Point& end_normal, Scalar miter_limit) {
528+ // 1 for no joint (straight line), 0 for max joint (180 degrees).
529+ Scalar alignment = (start_normal.Dot (end_normal) + 1 ) / 2 ;
530+ if (ScalarNearlyEqual (alignment, 1 )) {
531+ return ;
532+ }
533+
534+ Scalar dir =
535+ CreateBevelAndGetDirection (vtx_builder, position, start_normal, end_normal);
536+
537+ Point miter_point = (start_normal + end_normal) / 2 / alignment;
538+ if (miter_point.GetDistanceSquared ({0 , 0 }) >
539+ miter_limit * miter_limit) {
540+ return ; // Convert to bevel when we exceed the miter limit.
541+ }
542+
543+ // Outer miter point.
496544 SolidStrokeVertexShader::PerVertexData vtx;
497545 vtx.vertex_position = position;
498546 vtx.pen_down = 1.0 ;
499- vtx.vertex_normal = {};
500- vtx_builder.AppendVertex (vtx);
501-
502- Scalar dir = start_normal.Cross (end_normal) > 0 ? -1 : 1 ;
503- vtx.vertex_normal = start_normal * dir;
504- vtx_builder.AppendVertex (vtx);
505- vtx.vertex_normal = end_normal * dir;
547+ vtx.vertex_normal = miter_point * dir;
506548 vtx_builder.AppendVertex (vtx);
507549 };
508550 break ;
509- case Join::kMiter :
510- FML_DLOG (ERROR) << " Unimplemented." ;
511- break ;
512551 case Join::kRound :
513552 FML_DLOG (ERROR) << " Unimplemented." ;
514553 break ;
0 commit comments