flutter icon indicating copy to clipboard operation
flutter copied to clipboard

TextPainter.didExceedMaxLines method is always returning false on Web

Open george32451 opened this issue 5 years ago • 17 comments

Minimal Setup

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CustomPaint(
          size: Size(300, 25),
          painter: MyPainter(),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final textStyle = TextStyle(
      color: Colors.black,
      fontSize: 30,
    );
    final textSpan = TextSpan(
      text: 'Some long long long long long long long long text',
      style: textStyle,
    );
    final textPainter = TextPainter(
        text: textSpan,
        textDirection: TextDirection.ltr,
        maxLines: 1
    );
    textPainter.layout(
      minWidth: 0,
      maxWidth: size.width,
    );
    print(textPainter.didExceedMaxLines);
    final offset = Offset(0, 0);
    textPainter.paint(canvas, offset);
  }

  @override
  bool shouldRepaint(CustomPainter old) {
    return false;
  }
}

Problem

If i'm running this minimal app on iOS/Android the print(textPainter.didExceedMaxLines) method inside paint method of MyPainter class will print true, if the given text is actually long and isn't fit to the specified constraints, otherwise it will print false (Works as expected);

But if I'm building this app for the web, print(textPainter.didExceedMaxLines) method always prints false

Expected results: didExceedMaxLines should return true, if a text isn't fit to specified constraints (Flutter Web)

Actual results: didExceedMaxLines always returns false (Flutter Web)

Logs
[✓] Flutter (Channel beta, 1.21.0-9.2.pre, on Mac OS X 10.15.4 19E287, locale ru-RU)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.7)
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.0)
[✓] VS Code (version 1.48.1)
[✓] Connected device (3 available)

• No issues found!

george32451 avatar Sep 16 '20 13:09 george32451

code sample
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CustomPaint(
          size: Size(300, 25),
          painter: MyPainter(),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final textStyle = TextStyle(
      color: Colors.black,
      fontSize: 30,
    );
    final textSpan = TextSpan(
      text: 'Some long long long long long long long long text',
      style: textStyle,
    );
    final textPainter = TextPainter(
        text: textSpan, textDirection: TextDirection.ltr, maxLines: 1);
    textPainter.layout(
      minWidth: 0,
      maxWidth: size.width,
    );
    print(textPainter.didExceedMaxLines);
    final offset = Offset(0, 0);
    textPainter.paint(canvas, offset);
  }

  @override
  bool shouldRepaint(CustomPainter old) {
    return false;
  }
}

flutter doctor -v
[✓] Flutter (Channel master, 1.22.0-10.0.pre.204, on Mac OS X 10.15.6 19G2021,
    locale en-GB)
    • Flutter version 1.22.0-10.0.pre.204 at
      /Users/tahatesser/Code/flutter_master
    • Framework revision b2b5f2636a (7 minutes ago), 2020-09-16 08:02:06 -0700
    • Engine revision 1ef10b240e
    • Dart version 2.10.0 (build 2.10.0-124.0.dev)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at /Users/tahatesser/Code/sdk
    • Platform android-30, build-tools 30.0.2
    • ANDROID_HOME = /Users/tahatesser/Code/sdk
    • Java binary at: /Applications/Android
      Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.7)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.7, Build version 11E801a
    • CocoaPods version 1.9.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 49.0.2
    • Dart plugin version 193.7547
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6222593)

[✓] VS Code (version 1.49.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.14.1

 
[✓] Connected device (4 available)            
    • iPhone 11 (mobile) • 73130414-6DF8-4E37-B9AF-F81FA0F9068B • ios
      • com.apple.CoreSimulator.SimRuntime.iOS-13-7 (simulator)
    • macOS (desktop)    • macos                                • darwin-x64
      • Mac OS X 10.15.6 19G2021
    • Web Server (web)   • web-server                           • web-javascript
      • Flutter Tools
    • Chrome (web)       • chrome                               • web-javascript
      • Google Chrome 85.0.4183.102

• No issues found!

TahaTesser avatar Sep 16 '20 15:09 TahaTesser

@mdebbar can you please triage this?

yjbanov avatar Sep 16 '20 23:09 yjbanov

lineCount here https://github.com/flutter/engine/blob/87eff25909559e86f1e9f87de1516cbdc2ca82ab/lib/web_ui/lib/src/engine/text/measurement.dart#L590 gets capped at maxLines if set, so height and naturalHeight always end up being equal which causes didExceedMaxLines to always be false. https://github.com/flutter/engine/blob/7bda396b0f4778a2364f43f3951ef42f7bce6228/lib/web_ui/lib/src/engine/text/paragraph.dart#L308

muhleder avatar Sep 21 '20 09:09 muhleder

It looks like LinesCalculator stops measuring when it hits the maxLines limit (would make sense for performance) which could be why lineCount gets capped. https://github.com/flutter/engine/blob/87eff25909559e86f1e9f87de1516cbdc2ca82ab/lib/web_ui/lib/src/engine/text/measurement.dart#L842

muhleder avatar Sep 21 '20 09:09 muhleder

Incidentally DomTextMeasurementService does provide the correct naturalHeight so a quick fix for anyone who needs it and is comfortable compiling their own engine is to add a style.maxLines == null condition to _canUseCanvasMeasurement https://github.com/flutter/engine/blob/87eff25909559e86f1e9f87de1516cbdc2ca82ab/lib/web_ui/lib/src/engine/text/measurement.dart#L217-L226

muhleder avatar Sep 21 '20 09:09 muhleder

What's the correct fix here? This is breaking the popular auto_size_text package for web on mobile.

My current workaround is to always use CanvasKit, but this comes with other issues on mobile.

doppio avatar Apr 29 '21 22:04 doppio

I'd also like to see this fixed as I use auto_size_text extensively and this is a headache

MyBuzzTechnologies avatar May 18 '21 07:05 MyBuzzTechnologies

I am running into this problem. auto_size_text is broken for web.

sgalway00 avatar May 22 '21 16:05 sgalway00

I'm using this to check if my RichText widget will overflow, and I'm running into the same issue, does anyone know of any alternative way to do it?

Piotrekqwe avatar Oct 06 '21 15:10 Piotrekqwe

I am having the same problem as Piotrekqwe. Is there any update or workaround to this ?

ngthailam avatar Oct 12 '21 14:10 ngthailam

I am running into this problem. auto_size_text is broken for web on mobile

kipouras avatar Jan 04 '22 09:01 kipouras

Same problem. Only occurs when web-renderer is html but that's the renderer I want to use.

jpiabrantes avatar Mar 10 '22 08:03 jpiabrantes

Same problem for me

nazdream avatar Mar 31 '22 06:03 nazdream

Same problem here (also when using auto_size_text). I added a temporary and incomplete work-around in https://github.com/leisim/auto_size_text/issues/126

MarcVanDaele90 avatar Oct 27 '22 07:10 MarcVanDaele90

It seems flutter/engine#34085 PR did fix the issue it is also available in Flutter framework since #113652 is merged.

Earliest prebuilt Beta SDK version that supports it is 3.6.0-0.1.pre.

maRci002 avatar Dec 29 '22 22:12 maRci002

Thanks for checking @maRci002!

I would like to close this issue if others can also confirm it's fixed (cc @george32451).

mdebbar avatar Jan 09 '23 15:01 mdebbar

FYI: Flutter 3.7.0 Stable now handles TextPainter.didExceedMaxLines properly both html / canvasKit renderer.

maRci002 avatar Jan 26 '23 15:01 maRci002

Closing. Thanks everyone for confirming!

mdebbar avatar Feb 01 '23 14:02 mdebbar

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 -v and a minimal reproduction of the issue.

github-actions[bot] avatar Mar 03 '23 18:03 github-actions[bot]