@@ -1497,6 +1497,101 @@ TEST_P(AiksTest, SolidStrokesRenderCorrectly) {
14971497 ASSERT_TRUE (OpenPlaygroundHere (callback));
14981498}
14991499
1500+ TEST_P (AiksTest, GradientStrokesRenderCorrectly) {
1501+ // Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2
1502+ bool first_frame = true ;
1503+ auto callback = [&](AiksContext& renderer, RenderTarget& render_target) {
1504+ if (first_frame) {
1505+ first_frame = false ;
1506+ ImGui::SetNextWindowSize ({480 , 100 });
1507+ ImGui::SetNextWindowPos ({100 , 550 });
1508+ }
1509+
1510+ static float scale = 3 ;
1511+ static bool add_circle_clip = true ;
1512+ const char * tile_mode_names[] = {" Clamp" , " Repeat" , " Mirror" , " Decal" };
1513+ const Entity::TileMode tile_modes[] = {
1514+ Entity::TileMode::kClamp , Entity::TileMode::kRepeat ,
1515+ Entity::TileMode::kMirror , Entity::TileMode::kDecal };
1516+ static int selected_tile_mode = 0 ;
1517+ static float alpha = 1 ;
1518+
1519+ ImGui::Begin (" Controls" );
1520+ ImGui::SliderFloat (" Scale" , &scale, 0 , 6 );
1521+ ImGui::Checkbox (" Circle clip" , &add_circle_clip);
1522+ ImGui::SliderFloat (" Alpha" , &alpha, 0 , 1 );
1523+ ImGui::Combo (" Tile mode" , &selected_tile_mode, tile_mode_names,
1524+ sizeof (tile_mode_names) / sizeof (char *));
1525+ ImGui::End ();
1526+
1527+ Canvas canvas;
1528+ canvas.Scale (GetContentScale ());
1529+ Paint paint;
1530+ paint.color = Color::White ();
1531+ canvas.DrawPaint (paint);
1532+
1533+ paint.style = Paint::Style::kStroke ;
1534+ paint.color = Color (1.0 , 1.0 , 1.0 , alpha);
1535+ paint.stroke_width = 10 ;
1536+ auto tile_mode = tile_modes[selected_tile_mode];
1537+ paint.color_source = [tile_mode]() {
1538+ std::vector<Color> colors = {Color{0.9568 , 0.2627 , 0.2118 , 1.0 },
1539+ Color{0.1294 , 0.5882 , 0.9529 , 1.0 }};
1540+ std::vector<Scalar> stops = {0.0 , 1.0 };
1541+ Matrix matrix = {
1542+ 1 , 0 , 0 , 0 , //
1543+ 0 , 1 , 0 , 0 , //
1544+ 0 , 0 , 1 , 0 , //
1545+ 0 , 0 , 0 , 1 //
1546+ };
1547+ auto contents = std::make_shared<LinearGradientContents>();
1548+ contents->SetEndPoints ({0 , 0 }, {50 , 50 });
1549+ contents->SetColors (std::move (colors));
1550+ contents->SetStops (std::move (stops));
1551+ contents->SetTileMode (tile_mode);
1552+ contents->SetMatrix (matrix);
1553+ return contents;
1554+ };
1555+
1556+ Path path = PathBuilder{}
1557+ .MoveTo ({20 , 20 })
1558+ .QuadraticCurveTo ({60 , 20 }, {60 , 60 })
1559+ .Close ()
1560+ .MoveTo ({60 , 20 })
1561+ .QuadraticCurveTo ({60 , 60 }, {20 , 60 })
1562+ .TakePath ();
1563+
1564+ canvas.Scale (Vector2 (scale, scale));
1565+
1566+ if (add_circle_clip) {
1567+ auto [handle_a, handle_b] = IMPELLER_PLAYGROUND_LINE (
1568+ Point (60 , 300 ), Point (600 , 300 ), 20 , Color::Red (), Color::Red ());
1569+
1570+ auto screen_to_canvas = canvas.GetCurrentTransformation ().Invert ();
1571+ Point point_a = screen_to_canvas * handle_a * GetContentScale ();
1572+ Point point_b = screen_to_canvas * handle_b * GetContentScale ();
1573+
1574+ Point middle = (point_a + point_b) / 2 ;
1575+ auto radius = point_a.GetDistance (middle);
1576+ canvas.ClipPath (PathBuilder{}.AddCircle (middle, radius).TakePath ());
1577+ }
1578+
1579+ for (auto join : {Join::kBevel , Join::kRound , Join::kMiter }) {
1580+ paint.stroke_join = join;
1581+ for (auto cap : {Cap::kButt , Cap::kSquare , Cap::kRound }) {
1582+ paint.stroke_cap = cap;
1583+ canvas.DrawPath (path, paint);
1584+ canvas.Translate ({80 , 0 });
1585+ }
1586+ canvas.Translate ({-240 , 60 });
1587+ }
1588+
1589+ return renderer.Render (canvas.EndRecordingAsPicture (), render_target);
1590+ };
1591+
1592+ ASSERT_TRUE (OpenPlaygroundHere (callback));
1593+ }
1594+
15001595TEST_P (AiksTest, CoverageOriginShouldBeAccountedForInSubpasses) {
15011596 auto callback = [&](AiksContext& renderer, RenderTarget& render_target) {
15021597 Canvas canvas;
0 commit comments