diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart index 2d8e8490dcb..74cd573f53f 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -2026,6 +2026,7 @@ extension SkTextStylePropertiesExtension on SkTextStyleProperties { external set fontStyle(SkFontStyle? value); external set shadows(List? value); external set fontFeatures(List? value); + external set fontVariations(List? value); } @JS() @@ -2075,6 +2076,16 @@ extension SkFontFeatureExtension on SkFontFeature { external set value(int? value); } +@JS() +@anonymous +@staticInterop +class SkFontVariation {} + +extension SkFontVariationExtension on SkFontVariation { + external set axis(String? value); + external set value(double? value); +} + @JS() @anonymous @staticInterop diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/renderer.dart index 0ebf6848e86..93f229fc783 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/renderer.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -303,6 +303,7 @@ class CanvasKitRenderer implements Renderer { foreground: foreground as CkPaint?, shadows: shadows, fontFeatures: fontFeatures, + fontVariations: fontVariations, ); @override diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart index 55da65bab6b..104ada6655f 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart @@ -220,6 +220,7 @@ class CkTextStyle implements ui.TextStyle { CkPaint? foreground, List? shadows, List? fontFeatures, + List? fontVariations, }) { return CkTextStyle._( color, @@ -242,6 +243,7 @@ class CkTextStyle implements ui.TextStyle { foreground, shadows, fontFeatures, + fontVariations, ); } @@ -266,6 +268,7 @@ class CkTextStyle implements ui.TextStyle { this.foreground, this.shadows, this.fontFeatures, + this.fontVariations, ); final ui.Color? color; @@ -288,6 +291,7 @@ class CkTextStyle implements ui.TextStyle { final CkPaint? foreground; final List? shadows; final List? fontFeatures; + final List? fontVariations; /// Merges this text style with [other] and returns the new text style. /// @@ -315,6 +319,7 @@ class CkTextStyle implements ui.TextStyle { foreground: other.foreground ?? foreground, shadows: other.shadows ?? shadows, fontFeatures: other.fontFeatures ?? fontFeatures, + fontVariations: other.fontVariations ?? fontVariations, ); } @@ -345,6 +350,7 @@ class CkTextStyle implements ui.TextStyle { final CkPaint? foreground = this.foreground; final List? shadows = this.shadows; final List? fontFeatures = this.fontFeatures; + final List? fontVariations = this.fontVariations; final SkTextStyleProperties properties = SkTextStyleProperties(); @@ -450,6 +456,17 @@ class CkTextStyle implements ui.TextStyle { properties.fontFeatures = skFontFeatures; } + if (fontVariations != null) { + final List skFontVariations = []; + for (final ui.FontVariation fontVariation in fontVariations) { + final SkFontVariation skFontVariation = SkFontVariation(); + skFontVariation.axis = fontVariation.axis; + skFontVariation.value = fontVariation.value; + skFontVariations.add(skFontVariation); + } + properties.fontVariations = skFontVariations; + } + return canvasKit.TextStyle(properties); }(); } diff --git a/engine/src/flutter/lib/web_ui/test/canvaskit/font_variation_golden_test.dart b/engine/src/flutter/lib/web_ui/test/canvaskit/font_variation_golden_test.dart new file mode 100644 index 00000000000..5f582f0be13 --- /dev/null +++ b/engine/src/flutter/lib/web_ui/test/canvaskit/font_variation_golden_test.dart @@ -0,0 +1,65 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; + +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; + +import 'common.dart'; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + setUpAll(() async { + await ui.webOnlyInitializePlatform(); + }); + + group('font variation', () { + test('is correctly rendered', () async { + const double testWidth = 300; + final CkPictureRecorder recorder = CkPictureRecorder(); + final CkCanvas canvas = recorder.beginRecording(ui.Rect.largest); + final CkParagraphBuilder builder = + CkParagraphBuilder(CkParagraphStyle( + fontSize: 40.0, + textDirection: ui.TextDirection.ltr, + )); + + builder.pushStyle(CkTextStyle( + fontFamily: 'RobotoVariable', + )); + builder.addText('Normal\n'); + builder.pop(); + + ui.FontVariation weight(double w) => ui.FontVariation('wght', w); + builder.pushStyle(CkTextStyle( + fontFamily: 'RobotoVariable', + fontVariations: [weight(900)], + )); + builder.addText('Heavy\n'); + builder.pop(); + + builder.pushStyle(CkTextStyle( + fontFamily: 'RobotoVariable', + fontVariations: [weight(100)], + )); + builder.addText('Light\n'); + builder.pop(); + + final CkParagraph paragraph = builder.build(); + paragraph.layout(const ui.ParagraphConstraints(width: testWidth - 20)); + canvas.drawParagraph(paragraph, const ui.Offset(10, 10)); + final CkPicture picture = recorder.endRecording(); + await matchPictureGolden( + 'font_variation.jpg', + picture, + region: ui.Rect.fromLTRB(0, 0, testWidth, paragraph.height + 20), + ); + }); + }); +}