diff --git a/lib/web_ui/lib/src/engine/web_experiments.dart b/lib/web_ui/lib/src/engine/web_experiments.dart index ecc53cb70be3f..fb5f1a40b637c 100644 --- a/lib/web_ui/lib/src/engine/web_experiments.dart +++ b/lib/web_ui/lib/src/engine/web_experiments.dart @@ -36,9 +36,24 @@ class WebExperiments { bool _useCanvasText = _defaultUseCanvasText; + // TODO(mdebbar): Clean up https://github.com/flutter/flutter/issues/71952 + /// Experiment flag for using canvas-based measurement for rich text. + bool get useCanvasRichText => _useCanvasRichText; + set useCanvasRichText(bool? enabled) { + _useCanvasRichText = enabled ?? _defaultUseCanvasRichText; + } + + static const bool _defaultUseCanvasRichText = const bool.fromEnvironment( + 'FLUTTER_WEB_USE_EXPERIMENTAL_CANVAS_RICH_TEXT', + defaultValue: false, + ); + + bool _useCanvasRichText = _defaultUseCanvasRichText; + /// Reset all experimental flags to their default values. void reset() { _useCanvasText = _defaultUseCanvasText; + _useCanvasRichText = _defaultUseCanvasRichText; } /// Used to enable/disable experimental flags in the web engine. @@ -47,6 +62,9 @@ class WebExperiments { case 'useCanvasText': useCanvasText = enabled; break; + case 'useCanvasRichText': + useCanvasRichText = enabled; + break; } } } diff --git a/lib/web_ui/lib/src/ui/text.dart b/lib/web_ui/lib/src/ui/text.dart index 2d9ef7d3b9ee1..43c54c4e9b6d2 100644 --- a/lib/web_ui/lib/src/ui/text.dart +++ b/lib/web_ui/lib/src/ui/text.dart @@ -587,6 +587,8 @@ abstract class ParagraphBuilder { factory ParagraphBuilder(ParagraphStyle style) { if (engine.useCanvasKit) { return engine.CkParagraphBuilder(style); + } else if (engine.WebExperiments.instance!.useCanvasRichText) { + return engine.CanvasParagraphBuilder(style as engine.EngineParagraphStyle); } else { return engine.DomParagraphBuilder(style as engine.EngineParagraphStyle); } diff --git a/lib/web_ui/test/engine/web_experiments_test.dart b/lib/web_ui/test/engine/web_experiments_test.dart index c0f0a4f7f05f2..5102846e5c84e 100644 --- a/lib/web_ui/test/engine/web_experiments_test.dart +++ b/lib/web_ui/test/engine/web_experiments_test.dart @@ -11,6 +11,7 @@ import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; const bool _defaultUseCanvasText = true; +const bool _defaultUseCanvasRichText = false; void main() { internalBootstrapBrowserTest(() => testMain); @@ -27,47 +28,66 @@ void testMain() { test('default web experiment values', () { expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); }); test('can turn on/off web experiments', () { WebExperiments.instance.updateExperiment('useCanvasText', true); + WebExperiments.instance.updateExperiment('useCanvasRichText', true); expect(WebExperiments.instance.useCanvasText, true); + expect(WebExperiments.instance.useCanvasRichText, true); WebExperiments.instance.updateExperiment('useCanvasText', false); + WebExperiments.instance.updateExperiment('useCanvasRichText', false); expect(WebExperiments.instance.useCanvasText, false); + expect(WebExperiments.instance.useCanvasRichText, false); WebExperiments.instance.updateExperiment('useCanvasText', null); + WebExperiments.instance.updateExperiment('useCanvasRichText', null); // Goes back to default value. expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); }); test('ignores unknown experiments', () { expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); WebExperiments.instance.updateExperiment('foobarbazqux', true); expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); WebExperiments.instance.updateExperiment('foobarbazqux', false); expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); }); test('can reset web experiments', () { WebExperiments.instance.updateExperiment('useCanvasText', false); + WebExperiments.instance.updateExperiment('useCanvasRichText', false); WebExperiments.instance.reset(); expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); WebExperiments.instance.updateExperiment('useCanvasText', false); + WebExperiments.instance.updateExperiment('useCanvasRichText', false); WebExperiments.instance.updateExperiment('foobarbazqux', true); WebExperiments.instance.reset(); expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); }); test('js interop also works', () { expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); expect(() => jsUpdateExperiment('useCanvasText', true), returnsNormally); + expect(() => jsUpdateExperiment('useCanvasRichText', true), returnsNormally); expect(WebExperiments.instance.useCanvasText, true); + expect(WebExperiments.instance.useCanvasRichText, true); expect(() => jsUpdateExperiment('useCanvasText', null), returnsNormally); + expect(() => jsUpdateExperiment('useCanvasRichText', null), returnsNormally); expect(WebExperiments.instance.useCanvasText, _defaultUseCanvasText); + expect(WebExperiments.instance.useCanvasRichText, _defaultUseCanvasRichText); }); test('js interop throws on wrong type', () {