flutter / flutter/flutter

[web] Android WebView textZoom makes lineHeightScaleFactorOverride report the ~624.9375 sentinel, rendering all Text invisible

Open
#190,350 3 comments 5 reactions 0 assignees View on GitHub
a: typography engine has reproducible steps P2 platform-web team-web triaged-web
Dominant language
Dart
Stars
179k
Forks
31.1k
PR merge metrics
PR metrics pending

Description

### Steps to reproduce

Regression variant of #178856, which was fixed by #178862 (2 Dec 2025). That fix is present in the versions below and this case still reproduces, so the sentinel-comparison problem was not fully closed.

The trigger here is an **Android WebView with `textZoom != 100`**, which is what Android's system font-size setting produces for any WebView-embedded Flutter web app. Unlike the runtime font-size change in #178856, this is wrong from first paint.

1. `flutter create mqprobe --platforms=web`, replace `lib/main.dart` with the sample below.
2. `flutter build web --release` and serve `build/web` (e.g. `python3 -m http.server 8085`).
3. On an Android emulator (Pixel_5, API 34): `adb shell settings put system font_scale 1.15`, then `adb reverse tcp:8085 tcp:8085`.
4. Load `http://localhost:8085/` in a plain Android `WebView` (`javaScriptEnabled = true`, `domStorageEnabled = true`). No `setTextZoom` call is needed — the WebView picks up the system font scale on its own.
5. Read the reported values, and note whether the red `Text` is visible.

### Expected results

`lineHeightScaleFactorOverride` should be `null`, exactly as it is at `textZoom == 100`. The user has changed their font size, not applied a text-spacing preference. `MediaQueryData.textScaler` already reports the font-size change correctly (1.15).

Per the dartdoc the value is "the system-reported height of the text, **as a multiple of the font size**", so ~625 is outside any meaningful range — WCAG 1.4.12 asks for 1.5.

### Actual results

`lineHeightScaleFactorOverride` is reported as **~624.937** at every zoom except exactly 100, and `Text` becomes unrenderable: `Text.build` multiplies its line height by that value, so an 18px line lays out ~12,936px tall and its glyphs paint thousands of pixels below the viewport. The app looks blank while icons, borders and images still draw. `RichText` is unaffected, because it never consults the override.

All measured on **Flutter 3.44.8 stable**, stock `flutter create` app, same device and build, varying only the system font scale:

| `font_scale` | `textZoom` | `lineHeightScaleFactorOverride` | `textScaler` | red `Text` visible |
|---|---|---|---|---|
| 0.85 | 85 | 624.9374824709756 | 0.85 | no |
| 1.0 | 100 | **null** | 1.0 | **yes** |
| 1.15 | 115 | 624.9347955648752 | 1.15 | no |
| 1.3 | 130 | 624.9375229225718 | 1.3 | no |

The value is a near-constant regardless of zoom direction or magnitude, which points straight at the sentinel rather than at any real measurement.

### Code sample

Code sample

```dart
import 'package:flutter/material.dart';

void main() => runApp(const ProbeApp());

class ProbeApp extends StatelessWidget {
const ProbeApp({super.key});

@override
Widget build(BuildContext context) =>
const MaterialApp(home: Scaffold(body: SafeArea(child: Probe())));
}

class Probe extends StatelessWidget {
const Probe({super.key});

@override
Widget build(BuildContext context) {
final mq = MediaQuery.of(context);
// RichText ignores the spacing overrides, so it stays readable even when
// the bug is active and every plain Text has been pushed off-screen.
final report = 'line=${mq.lineHeightScaleFactorOverride}\n'
'letter=${mq.letterSpacingOverride}\n'
'word=${mq.wordSpacingOverride}\n'
'para=${mq.paragraphSpacingOverride}\n'
'scale10=${mq.textScaler.scale(10)}\n'
'size=${mq.size.width.toStringAsFixed(0)}x${mq.size.height.toStringAsFixed(0)}';

return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: TextSpan(
text: report,
style: const TextStyle(fontSize: 15, color: Colors.black),
),
),
const SizedBox(height: 12),
const Text('PLAIN TEXT VISIBLE',
style: TextStyle(fontSize: 18, color: Colors.red)),
],
);
}
}
```

### Screenshots or Video

Screenshots / Video demonstration

Attached, one per row of the table above. Only `textZoom 100` renders the red `Text`.

Image
Image
Image
Image

### Logs

Logs

```console
[Paste your logs here]
```

### Flutter Doctor output

Doctor output

```
[!] Flutter (Channel stable, 3.44.8, on macOS 26.5.2 25F84 darwin-arm64, locale en-GB)
• Flutter version 3.44.8 on channel stable
• Framework revision 058e0af2c2, 2026-07-23 10:56:21 -0700
• Engine revision 0cd610717b
• Dart version 3.12.2
• DevTools version 2.57.0

[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
• Platform android-37.0, build-tools 36.0.0
• Java version OpenJDK Runtime Environment (build 21.0.10+-117844308-b1163.108)

[✓] Xcode - develop for iOS and macOS (Xcode 26.6)
[✓] Chrome - develop for the web
[✓] Network resources
```

Also reproduced on 3.41.7 and 3.44.2, both of which contain #178862.

Contributor guide

Open the contributing guide

Research direction

Start with the lib/main.dart reproduction and run the listed flutter build web and Android WebView steps at multiple font scales. Compare the current behavior with #178862; done means lineHeightScaleFactorOverride remains null for non-100 textZoom and plain Text remains visible, with regression coverage added where the relevant behavior is implemented.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, dart, flutter
Domain
frontend, mobile-dev, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.