Repository navigation
Closed
Labels
P1High-priority issues at the top of the work listHigh-priority issues at the top of the work listplatform-webWeb applications specificallyWeb applications specificallyteam-webOwned by Web platform teamOwned by Web platform teamtriaged-webTriaged by Web platform teamTriaged by Web platform team
Description
Steps to reproduce
Consider the following small app:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
const text = 'AAA AA AAA A A A';
final textPainter = TextPainter(
text: TextSpan(
text: text,
style: TextStyle(
color: Color(0xFFFFFFFF),
fontFamily: 'Arial',
fontSize: 24,
),
),
textDirection: TextDirection.ltr,
);
textPainter.layout(maxWidth: 184);
textPainter.computeLineMetrics();
final rangeAt0 = textPainter.getLineBoundary(TextPosition(offset: 0));
final rangeAt15 = textPainter.getLineBoundary(TextPosition(offset: 15));
return MaterialApp(
home: Scaffold(
body: Column(
children: [
Text('Range at 0 offset: S: ${rangeAt0.start} E: ${rangeAt0.end}'),
Text(
'Range at 15 offset: S: ${rangeAt15.start} E: ${rangeAt15.end}',
),
],
),
),
);
}
}Expected results
Although I understand that I can't exepect the same text range result between different platforms since font rendering and size calculation is affect by the platform, web is showing an inconsistent result compared to the other platforms since the range at offset 15 should start at 15, not end at 15 (unless I understood something wrongly, and if that is so, please let me know)
Actual results
When rendering on web, the range at the offeset 15 will result in a wrong value:
Range at 0 offset: Start 0 End: 15
Range at 15 offset: Start 0 End: 15
When running on MacOS for example we get instead
Range at 0 offset: Start 0 End: 15
Range at 15 offset: Start 15 End: 16
Code sample
Code sample
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
const text = 'AAA AA AAA A A A';
final textPainter = TextPainter(
text: TextSpan(
text: text,
style: TextStyle(
color: Color(0xFFFFFFFF),
fontFamily: 'Arial',
fontSize: 24,
),
),
textDirection: TextDirection.ltr,
);
textPainter.layout(maxWidth: 184);
textPainter.computeLineMetrics();
final rangeAt0 = textPainter.getLineBoundary(TextPosition(offset: 0));
final rangeAt15 = textPainter.getLineBoundary(TextPosition(offset: 15));
return MaterialApp(
home: Scaffold(
body: Column(
children: [
Text('Range at 0 offset: S: ${rangeAt0.start} E: ${rangeAt0.end}'),
Text(
'Range at 15 offset: S: ${rangeAt15.start} E: ${rangeAt15.end}',
),
],
),
),
);
}
}Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
[Paste your logs here]Flutter Doctor output
Doctor output
flutter doctor -v
[✓] Flutter (Channel stable, 3.44.4, on macOS 26.3.1 25D771280a darwin-arm64, locale en-BR) [1,884ms]
• Flutter version 3.44.4 on channel stable at /Users/erickzanardo/flutters/updated
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision ad70ec4617 (7 days ago), 2026-06-24 11:07:06 -0700
• Engine revision a10d8ac38d
• Dart version 3.12.2
• DevTools version 2.57.0
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android,
enable-ios, cli-animations, enable-native-assets, enable-swift-package-manager, omit-legacy-version-file,
enable-lldb-debugging, enable-uiscene-migration
[!] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [3.7s]
• Android SDK at /Users/erickzanardo/Library/Android/sdk
• Emulator version 35.2.10.0 (build_id 12414864) (CL:N/A)
• Platform android-36, build-tools 36.0.0
• ANDROID_HOME = /Users/erickzanardo/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 21.0.3+-79915917-b509.11)
! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses
[✓] Xcode - develop for iOS and macOS (Xcode 26.6) [2.8s]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 17F113
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [6ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Connected device (4 available) [8.1s]
• sdk gphone64 arm64 (mobile) • emulator-5554 • android-arm64 • Android 15 (API 35) (emulator)
• iPhone 17 Pro (mobile) • F720CF45-D57D-4431-B060-6BBF0F299F40 • ios •
com.apple.CoreSimulator.SimRuntime.iOS-26-0 (simulator)
• macOS (desktop) • macos • darwin-arm64 • macOS 26.3.1 25D771280a
darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 149.0.7827.201
! Error: Browsing on the local area network for iPhone de Erick. Ensure the device is unlocked and attached with a cable or
associated with the same local area network as this Mac.
The device must be opted into Developer Mode to connect wirelessly. (code -27)
[✓] Network resources [329ms]
• All expected network resources are available.
! Doctor found issues in 1 category.Note: I would be happy to work on a fix if we confirm this is a real issue!
Reacted by Jochum van der Ploeg, Lukas Klingsbo, Sophie King, John Weidner, Oscar, Dominik Šimoník, Juan, Marcos Sevilla, THARUN P and Kenzie Shimrock
Metadata
Metadata
Assignees
Labels
P1High-priority issues at the top of the work listHigh-priority issues at the top of the work listplatform-webWeb applications specificallyWeb applications specificallyteam-webOwned by Web platform teamOwned by Web platform teamtriaged-webTriaged by Web platform teamTriaged by Web platform team
Activity
fix: Workaround for the TextBoxComponent entering an endless loop (#3939
flutter-zl commentedon Jul 8, 2026
This issue was fixed by flame-engine/flame#3939.
erickzanardo commentedon Jul 8, 2026
@flutter-zl That PR didn't solved the issue on Flutter. What I did in that PR was to provide an workaround on the flame engine to avoid running in this issue. It still needs to be fixed in the flutter engine since the TextRange will still be reported wrongly.
GhagSagar23 commentedon Jul 15, 2026
I traced this down to a divergence between the native
dart:uibinding and the CanvasKit web implementation ofParagraph.getLineBoundary.Native (
engine/src/flutter/lib/ui/text.dart, L3322-L3343) explicitly handles the case where an offset sits exactly on the boundary between two lines: it queries both the current line andoffset + 1's line, and ifposition.affinity == TextAffinity.downstreamand the offset equals both the current line'sendand the next line'sstart, it returns the next line's range.TextPosition's default affinity isdownstream, soTextPosition(offset: 15)in the repro correctly resolves to line 2 on native platforms.CanvasKit's web implementation (
engine/src/flutter/lib/web_ui/lib/src/engine/canvaskit/text.dart, L974-L984) has no affinity handling at all — it's a plain first-match loop:flutter-triage-bot commentedon Aug 12, 2026
This issue is missing a priority label. Please set a priority label when adding the
triaged-weblabel.[web] Respect text affinity in getLineBoundary at a soft wrap (flutte…
github-actions commentedon Oct 14, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.[web] Respect text affinity in getLineBoundary at a soft wrap (flutte…