From 586df25fe13fab6e5dc39dc014a94a22cd3c302f Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Tue, 23 Mar 2021 12:15:26 -0700 Subject: [PATCH] [web] Implement font features in the html renderer (flutter/engine#25088) --- .../flutter/lib/web_ui/dev/goldens_lock.yaml | 2 +- .../web_ui/lib/src/engine/text/paragraph.dart | 21 +++++++++ .../engine/canvas_paragraph/general_test.dart | 47 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/engine/src/flutter/lib/web_ui/dev/goldens_lock.yaml b/engine/src/flutter/lib/web_ui/dev/goldens_lock.yaml index 67d9c953557..5ea3b09d599 100644 --- a/engine/src/flutter/lib/web_ui/dev/goldens_lock.yaml +++ b/engine/src/flutter/lib/web_ui/dev/goldens_lock.yaml @@ -1,2 +1,2 @@ repository: https://github.com/flutter/goldens.git -revision: b86dc52ac1c8725ea17c50d9a7704687b5252833 +revision: c5f999871e83142afb82a636e97bd67a62789c6e diff --git a/engine/src/flutter/lib/web_ui/lib/src/engine/text/paragraph.dart b/engine/src/flutter/lib/web_ui/lib/src/engine/text/paragraph.dart index 463e763b8ee..1bce6463127 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/engine/text/paragraph.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/engine/text/paragraph.dart @@ -1825,6 +1825,11 @@ void _applyTextStyleToElement({ } } } + + final List? fontFeatures = style._fontFeatures; + if (fontFeatures != null && fontFeatures.isNotEmpty) { + cssStyle.fontFeatureSettings = _fontFeatureListToCss(fontFeatures); + } } html.Element _createPlaceholderElement({ @@ -1894,6 +1899,22 @@ String _shadowListToCss(List shadows) { return sb.toString(); } +String _fontFeatureListToCss(List fontFeatures) { + assert(fontFeatures.isNotEmpty); + + // For more details, see: + // * https://developer.mozilla.org/en-US/docs/Web/CSS/font-feature-settings + StringBuffer sb = new StringBuffer(); + for (int i = 0, len = fontFeatures.length; i < len; i++) { + if (i != 0) { + sb.write(','); + } + ui.FontFeature fontFeature = fontFeatures[i]; + sb.write('"${fontFeature.feature}" ${fontFeature.value}'); + } + return sb.toString(); +} + /// Applies background color properties in text style to paragraph or span /// elements. void _applyTextBackgroundToElement({ diff --git a/engine/src/flutter/lib/web_ui/test/golden_tests/engine/canvas_paragraph/general_test.dart b/engine/src/flutter/lib/web_ui/test/golden_tests/engine/canvas_paragraph/general_test.dart index c67462816cf..11190be2339 100644 --- a/engine/src/flutter/lib/web_ui/test/golden_tests/engine/canvas_paragraph/general_test.dart +++ b/engine/src/flutter/lib/web_ui/test/golden_tests/engine/canvas_paragraph/general_test.dart @@ -312,4 +312,51 @@ void testMain() async { canvas.drawParagraph(paragraph, Offset.zero); return takeScreenshot(canvas, bounds, 'canvas_paragraph_decoration'); }); + + void testFontFeatures(EngineCanvas canvas) { + final String text = 'Aa Bb Dd Ee Ff'; + final FontFeature enableSmallCaps = FontFeature('smcp'); + final FontFeature disableSmallCaps = FontFeature('smcp', 0); + final CanvasParagraph paragraph = rich( + ParagraphStyle(fontFamily: 'Roboto'), + (CanvasParagraphBuilder builder) { + builder.pushStyle(EngineTextStyle.only( + height: 2, + color: black, + fontSize: 32.0, + )); + builder.addText('Small Caps: '); + builder.pushStyle(EngineTextStyle.only( + color: blue, + fontFeatures: [enableSmallCaps], + )); + builder.addText('$text\n'); + // Make sure disabling a font feature also works. + builder.pushStyle(EngineTextStyle.only( + color: black, + fontFeatures: [disableSmallCaps], + )); + builder.addText('Normal Caps: '); + builder.pushStyle(EngineTextStyle.only( + color: blue, + )); + builder.addText(text); + }, + )..layout(constrain(double.infinity)); + canvas.drawParagraph(paragraph, Offset.zero); + } + + test('font features', () { + const Rect bounds = Rect.fromLTWH(0, 0, 500, 300); + final canvas = BitmapCanvas(bounds, RenderStrategy()); + testFontFeatures(canvas); + return takeScreenshot(canvas, bounds, 'canvas_paragraph_font_features'); + }); + + test('font features (DOM)', () { + const Rect bounds = Rect.fromLTWH(0, 0, 500, 300); + final canvas = DomCanvas(domRenderer.createElement('flt-picture')); + testFontFeatures(canvas); + return takeScreenshot(canvas, bounds, 'canvas_paragraph_font_features_dom'); + }); }