Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions lib/web_ui/lib/src/engine/web_experiments.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -47,6 +62,9 @@ class WebExperiments {
case 'useCanvasText':
useCanvasText = enabled;
break;
case 'useCanvasRichText':
useCanvasRichText = enabled;
break;
}
}
}
2 changes: 2 additions & 0 deletions lib/web_ui/lib/src/ui/text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
20 changes: 20 additions & 0 deletions lib/web_ui/test/engine/web_experiments_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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', () {
Expand Down