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

Commit 8758e37

Browse files
authored
[web] Add support for textScaleFactor (#29028)
1 parent 9830def commit 8758e37

File tree

4 files changed

+120
-2
lines changed

4 files changed

+120
-2
lines changed

lib/web_ui/lib/src/engine/platform_dispatcher.dart

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'dart:async';
66
import 'dart:convert';
77
import 'dart:html' as html;
8+
import 'dart:js_util' as js_util;
89
import 'dart:typed_data';
910

1011
import 'package:meta/meta.dart';
@@ -53,8 +54,10 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
5354
/// The current platform configuration.
5455
@override
5556
ui.PlatformConfiguration get configuration => _configuration;
56-
ui.PlatformConfiguration _configuration =
57-
ui.PlatformConfiguration(locales: parseBrowserLanguages());
57+
ui.PlatformConfiguration _configuration = ui.PlatformConfiguration(
58+
locales: parseBrowserLanguages(),
59+
textScaleFactor: findBrowserTextScaleFactor(),
60+
);
5861

5962
/// Receives all events related to platform configuration changes.
6063
@override
@@ -1076,3 +1079,41 @@ void invoke3<A1, A2, A3>(void Function(A1 a1, A2 a2, A3 a3)? callback,
10761079
});
10771080
}
10781081
}
1082+
1083+
const double _defaultRootFontSize = 16.0;
1084+
1085+
/// Finds the text scale factor of the browser by looking at the computed style
1086+
/// of the browser's <html> element.
1087+
double findBrowserTextScaleFactor() {
1088+
final num fontSize = _parseFontSize(html.document.documentElement!) ?? _defaultRootFontSize;
1089+
return fontSize / _defaultRootFontSize;
1090+
}
1091+
1092+
/// Parses the font size of [element] and returns the value without a unit.
1093+
num? _parseFontSize(html.Element element) {
1094+
num? fontSize;
1095+
1096+
if (js_util.hasProperty(element, 'computedStyleMap')) {
1097+
// Use the newer `computedStyleMap` API available on some browsers.
1098+
final dynamic computedStyleMap =
1099+
// ignore: implicit_dynamic_function
1100+
js_util.callMethod(element, 'computedStyleMap', <Object?>[]);
1101+
if (computedStyleMap is Object) {
1102+
final dynamic fontSizeObject =
1103+
// ignore: implicit_dynamic_function
1104+
js_util.callMethod(computedStyleMap, 'get', <Object?>['font-size']);
1105+
if (fontSizeObject is Object) {
1106+
// ignore: implicit_dynamic_function
1107+
fontSize = js_util.getProperty(fontSizeObject, 'value') as num;
1108+
}
1109+
}
1110+
}
1111+
1112+
if (fontSize == null) {
1113+
// Fallback to `getComputedStyle`.
1114+
final String fontSizeString = element.getComputedStyle().fontSize;
1115+
fontSize = parseFloat(fontSizeString);
1116+
}
1117+
1118+
return fontSize;
1119+
}

lib/web_ui/lib/src/engine/util.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
@JS()
6+
library util;
7+
58
import 'dart:async';
69
import 'dart:html' as html;
710
import 'dart:js_util' as js_util;
811
import 'dart:math' as math;
912
import 'dart:typed_data';
1013

14+
import 'package:js/js.dart';
1115
import 'package:ui/ui.dart' as ui;
1216

1317
import 'browser_detection.dart';
@@ -653,3 +657,25 @@ extension JsonExtensions on Map<dynamic, dynamic> {
653657
return this[propertyName] as double?;
654658
}
655659
}
660+
661+
typedef JsParseFloat = num? Function(String source);
662+
663+
@JS('parseFloat')
664+
external JsParseFloat get _jsParseFloat;
665+
666+
/// Parses a string [source] into a double.
667+
///
668+
/// Uses the JavaScript `parseFloat` function instead of Dart's [double.parse]
669+
/// because the latter can't parse strings like "20px".
670+
///
671+
/// Returns null if it fails to parse.
672+
num? parseFloat(String source) {
673+
// Using JavaScript's `parseFloat` here because it can parse values
674+
// like "20px", while Dart's `double.tryParse` fails.
675+
final num? result = _jsParseFloat(source);
676+
677+
if (result == null || result.isNaN) {
678+
return null;
679+
}
680+
return result;
681+
}

lib/web_ui/test/engine/platform_dispatcher_test.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,34 @@ void testMain() {
8383
js_util.setProperty(
8484
html.window.navigator, 'clipboard', originalClipboard);
8585
});
86+
87+
test('can find text scale factor', () async {
88+
const double deltaTolerance = 1e-5;
89+
90+
final html.Element root = html.document.documentElement!;
91+
final String oldFontSize = root.style.fontSize;
92+
93+
addTearDown(() {
94+
root.style.fontSize = oldFontSize;
95+
});
96+
97+
root.style.fontSize = '16px';
98+
expect(findBrowserTextScaleFactor(), 1.0);
99+
100+
root.style.fontSize = '20px';
101+
expect(findBrowserTextScaleFactor(), 1.25);
102+
103+
root.style.fontSize = '24px';
104+
expect(findBrowserTextScaleFactor(), 1.5);
105+
106+
root.style.fontSize = '14.4px';
107+
expect(findBrowserTextScaleFactor(), closeTo(0.9, deltaTolerance));
108+
109+
root.style.fontSize = '12.8px';
110+
expect(findBrowserTextScaleFactor(), closeTo(0.8, deltaTolerance));
111+
112+
root.style.fontSize = null;
113+
expect(findBrowserTextScaleFactor(), 1.0);
114+
});
86115
});
87116
}

lib/web_ui/test/engine/util_test.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,26 @@ void testMain() {
7979
debugOperatingSystemOverride = null;
8080
debugIsIOS15 = null;
8181
});
82+
83+
test('parseFloat basic tests', () {
84+
// Simple integers and doubles.
85+
expect(parseFloat('108'), 108.0);
86+
expect(parseFloat('.34'), 0.34);
87+
expect(parseFloat('108.34'), 108.34);
88+
89+
// Number followed by text.
90+
expect(parseFloat('108.34px'), 108.34);
91+
expect(parseFloat('108.34px29'), 108.34);
92+
expect(parseFloat('108.34px 29'), 108.34);
93+
94+
// Number followed by space and text.
95+
expect(parseFloat('108.34 px29'), 108.34);
96+
expect(parseFloat('108.34 px 29'), 108.34);
97+
98+
// Invalid numbers.
99+
expect(parseFloat('text'), isNull);
100+
expect(parseFloat('text108'), isNull);
101+
expect(parseFloat('text 108'), isNull);
102+
expect(parseFloat('another text 108'), isNull);
103+
});
82104
}

0 commit comments

Comments
 (0)