diff --git a/lib/web_ui/lib/src/engine/text/paragraph.dart b/lib/web_ui/lib/src/engine/text/paragraph.dart index c41a6b6cf51f8..3214fb897d0df 100644 --- a/lib/web_ui/lib/src/engine/text/paragraph.dart +++ b/lib/web_ui/lib/src/engine/text/paragraph.dart @@ -1072,7 +1072,7 @@ void _applyParagraphStyleToElement({ style._fontStyle == ui.FontStyle.normal ? 'normal' : 'italic'; } if (style._effectiveFontFamily != null) { - cssStyle.fontFamily = "'${style._effectiveFontFamily}'"; + cssStyle.fontFamily = quoteFontFamily(style._effectiveFontFamily); } } else { if (style._textAlign != previousStyle._textAlign) { @@ -1098,7 +1098,7 @@ void _applyParagraphStyleToElement({ : null; } if (style._fontFamily != previousStyle._fontFamily) { - cssStyle.fontFamily = "'${style._fontFamily}'"; + cssStyle.fontFamily = quoteFontFamily(style._fontFamily); } } } @@ -1138,11 +1138,11 @@ void _applyTextStyleToElement({ // consistently use Ahem font. if (isSpan && !ui.debugEmulateFlutterTesterEnvironment) { if (style._fontFamily != null) { - cssStyle.fontFamily = "'${style._fontFamily}'"; + cssStyle.fontFamily = quoteFontFamily(style._fontFamily); } } else { if (style._effectiveFontFamily != null) { - cssStyle.fontFamily = "'${style._effectiveFontFamily}'"; + cssStyle.fontFamily = quoteFontFamily(style._effectiveFontFamily); } } if (style._letterSpacing != null) { @@ -1176,7 +1176,7 @@ void _applyTextStyleToElement({ : null; } if (style._fontFamily != previousStyle._fontFamily) { - cssStyle.fontFamily = "'${style._fontFamily}'"; + cssStyle.fontFamily = quoteFontFamily(style._fontFamily); } if (style._letterSpacing != previousStyle._letterSpacing) { cssStyle.letterSpacing = '${style._letterSpacing}px'; diff --git a/lib/web_ui/lib/src/engine/text/ruler.dart b/lib/web_ui/lib/src/engine/text/ruler.dart index 0bfe215469820..41cbdf0dcb78f 100644 --- a/lib/web_ui/lib/src/engine/text/ruler.dart +++ b/lib/web_ui/lib/src/engine/text/ruler.dart @@ -86,7 +86,7 @@ class ParagraphGeometricStyle { result.write(DomRenderer.defaultFontSize); } result.write(' '); - result.write("'$effectiveFontFamily'"); + result.write(quoteFontFamily(effectiveFontFamily)); return result.toString(); } @@ -227,7 +227,7 @@ class TextDimensions { void applyStyle(ParagraphGeometricStyle style) { _element.style ..fontSize = style.fontSize != null ? '${style.fontSize.floor()}px' : null - ..fontFamily = "'${style.effectiveFontFamily}'" + ..fontFamily = quoteFontFamily(style.effectiveFontFamily) ..fontWeight = style.fontWeight != null ? fontWeightToCss(style.fontWeight) : null ..fontStyle = style.fontStyle != null diff --git a/lib/web_ui/lib/src/engine/util.dart b/lib/web_ui/lib/src/engine/util.dart index b0ec8422d8947..715d6a30ea3e1 100644 --- a/lib/web_ui/lib/src/engine/util.dart +++ b/lib/web_ui/lib/src/engine/util.dart @@ -238,3 +238,30 @@ String _pathToSvgClipPath(ui.Path path, bool _isNsErrorFailureException(dynamic e) { return js_util.getProperty(e, 'name') == 'NS_ERROR_FAILURE'; } + +/// From: https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#Syntax +/// +/// Generic font families are a fallback mechanism, a means of preserving some +/// of the style sheet author's intent when none of the specified fonts are +/// available. Generic family names are keywords and must not be quoted. A +/// generic font family should be the last item in the list of font family +/// names. +const Set _genericFontFamilies = { + 'serif', + 'sans-serif', + 'monospace', + 'cursive', + 'fantasy', + 'system-ui', + 'math', + 'emoji', + 'fangsong', +}; + +/// Wraps a font family in quotes unless it is a generic font family. +String quoteFontFamily(String fontFamily) { + if (_genericFontFamilies.contains(fontFamily)) { + return fontFamily; + } + return '"$fontFamily"'; +} diff --git a/lib/web_ui/test/text_test.dart b/lib/web_ui/test/text_test.dart index eab005177c5fc..16dfa4c64fd6d 100644 --- a/lib/web_ui/test/text_test.dart +++ b/lib/web_ui/test/text_test.dart @@ -245,4 +245,21 @@ void main() async { // The nested span here should not set it's family to default sans-serif. expect(spans[1].style.fontFamily, 'Ahem'); }); + + test('can set font families that need to be quoted', () { + // Set this to false so it doesn't default to 'Ahem' font. + debugEmulateFlutterTesterEnvironment = false; + + final ParagraphBuilder builder = ParagraphBuilder(ParagraphStyle( + fontFamily: 'MyFont 2000', + fontSize: 12.0, + )); + + builder.addText('Hello'); + + final EngineParagraph paragraph = builder.build(); + expect(paragraph.paragraphElement.style.fontFamily, '"MyFont 2000"'); + + debugEmulateFlutterTesterEnvironment = true; + }); }