Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2ac8552

Browse files
authored
[web] Fix crash on old versions of Chrome (Intl.Segmenter missing) (#41986)
`Chrome < v87` have the `v8BreakIterator` API but don't have `Intl.Segmenter`. This caused crashes for some apps (see b/281377168). This PR enhances our feature detection to take into account this API mismatch.
1 parent 3b9ff41 commit 2ac8552

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

lib/web_ui/lib/src/engine/browser_detection.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,5 @@ int _detectWebGLVersion() {
268268
}
269269

270270
/// Whether the current browser supports the Chromium variant of CanvasKit.
271-
bool get browserSupportsCanvaskitChromium => domIntl.v8BreakIterator != null;
271+
bool get browserSupportsCanvaskitChromium =>
272+
domIntl.v8BreakIterator != null && domIntl.Segmenter != null;

lib/web_ui/test/canvaskit/canvaskit_api_test.dart

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1826,17 +1826,22 @@ void _paragraphTests() {
18261826
}, skip: isFirefox); // Intended: Headless firefox has no webgl support https://github.com/flutter/flutter/issues/109265
18271827

18281828
group('getCanvasKitJsFileNames', () {
1829-
late dynamic oldV8BreakIterator = v8BreakIterator;
1829+
dynamic oldV8BreakIterator = v8BreakIterator;
1830+
dynamic oldIntlSegmenter = intlSegmenter;
1831+
18301832
setUp(() {
18311833
oldV8BreakIterator = v8BreakIterator;
1834+
oldIntlSegmenter = intlSegmenter;
18321835
});
18331836
tearDown(() {
18341837
v8BreakIterator = oldV8BreakIterator;
1838+
intlSegmenter = oldIntlSegmenter;
18351839
debugResetBrowserSupportsImageDecoder();
18361840
});
18371841

18381842
test('in Chromium-based browsers', () {
18391843
v8BreakIterator = Object(); // Any non-null value.
1844+
intlSegmenter = Object(); // Any non-null value.
18401845
browserSupportsImageDecoder = true;
18411846

18421847
expect(getCanvasKitJsFileNames(CanvasKitVariant.full), <String>['canvaskit.js']);
@@ -1847,7 +1852,19 @@ void _paragraphTests() {
18471852
]);
18481853
});
18491854

1855+
test('in older versions of Chromium-based browsers', () {
1856+
v8BreakIterator = Object(); // Any non-null value.
1857+
intlSegmenter = null; // Older versions of Chromium didn't have the Intl.Segmenter API.
1858+
browserSupportsImageDecoder = true;
1859+
1860+
expect(getCanvasKitJsFileNames(CanvasKitVariant.full), <String>['canvaskit.js']);
1861+
expect(getCanvasKitJsFileNames(CanvasKitVariant.chromium), <String>['chromium/canvaskit.js']);
1862+
expect(getCanvasKitJsFileNames(CanvasKitVariant.auto), <String>['canvaskit.js']);
1863+
});
1864+
18501865
test('in other browsers', () {
1866+
intlSegmenter = Object(); // Any non-null value.
1867+
18511868
v8BreakIterator = null;
18521869
browserSupportsImageDecoder = true;
18531870
expect(getCanvasKitJsFileNames(CanvasKitVariant.full), <String>['canvaskit.js']);
@@ -1901,3 +1918,9 @@ external dynamic get v8BreakIterator;
19011918

19021919
@JS('window.Intl.v8BreakIterator')
19031920
external set v8BreakIterator(dynamic x);
1921+
1922+
@JS('window.Intl.Segmenter')
1923+
external dynamic get intlSegmenter;
1924+
1925+
@JS('window.Intl.Segmenter')
1926+
external set intlSegmenter(dynamic x);

lib/web_ui/test/engine/browser_detect_test.dart

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,24 +157,30 @@ void testMain() {
157157
});
158158

159159
group('browserSupportsCanvasKitChromium', () {
160-
late dynamic oldV8BreakIterator = v8BreakIterator;
160+
dynamic oldV8BreakIterator = v8BreakIterator;
161+
dynamic oldIntlSegmenter = intlSegmenter;
162+
161163
setUp(() {
162164
oldV8BreakIterator = v8BreakIterator;
165+
oldIntlSegmenter = intlSegmenter;
163166
});
164167
tearDown(() {
165168
v8BreakIterator = oldV8BreakIterator;
169+
intlSegmenter = oldIntlSegmenter;
166170
debugResetBrowserSupportsImageDecoder();
167171
});
168172

169173
test('Detect browsers that support CanvasKit Chromium', () {
170174
v8BreakIterator = Object(); // Any non-null value.
175+
intlSegmenter = Object(); // Any non-null value.
171176
browserSupportsImageDecoder = true;
172177

173178
expect(browserSupportsCanvaskitChromium, isTrue);
174179
});
175180

176181
test('Detect browsers that do not support image codecs', () {
177182
v8BreakIterator = Object(); // Any non-null value.
183+
intlSegmenter = Object(); // Any non-null value.
178184
browserSupportsImageDecoder = false;
179185

180186
// TODO(mdebbar): we don't check image codecs for now.
@@ -184,17 +190,26 @@ void testMain() {
184190

185191
test('Detect browsers that do not support v8BreakIterator', () {
186192
v8BreakIterator = null;
193+
intlSegmenter = Object(); // Any non-null value.
187194
browserSupportsImageDecoder = true;
188195

189196
expect(browserSupportsCanvaskitChromium, isFalse);
190197
});
191198

192199
test('Detect browsers that support neither', () {
193200
v8BreakIterator = null;
201+
intlSegmenter = Object(); // Any non-null value.
194202
browserSupportsImageDecoder = false;
195203

196204
expect(browserSupportsCanvaskitChromium, isFalse);
197205
});
206+
207+
test('Detect browsers that support v8BreakIterator but no Intl.Segmenter', () {
208+
v8BreakIterator = Object(); // Any non-null value.
209+
intlSegmenter = null;
210+
211+
expect(browserSupportsCanvaskitChromium, isFalse);
212+
});
198213
});
199214

200215
group('OffscreenCanvas', () {
@@ -211,3 +226,9 @@ external dynamic get v8BreakIterator;
211226

212227
@JS('window.Intl.v8BreakIterator')
213228
external set v8BreakIterator(dynamic x);
229+
230+
@JS('window.Intl.Segmenter')
231+
external dynamic get intlSegmenter;
232+
233+
@JS('window.Intl.Segmenter')
234+
external set intlSegmenter(dynamic x);

0 commit comments

Comments
 (0)