Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[engine] WebUI engine's TextLayoutService doesn't handle TextAlign.justify correctly for Chinese text #148486

Open
laishere opened this issue May 16, 2024 · 5 comments
Labels
a: internationalization Supporting other languages or locales. (aka i18n) a: typography Text rendering, possibly libtxt engine flutter/engine repository. See also e: labels. P2 Important issues not at the top of the work list platform-web Web applications specifically team-web Owned by Web platform team triaged-web Triaged by Web platform team

Comments

@laishere
Copy link

laishere commented May 16, 2024

Steps to reproduce

Test this widget:

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // return CustomPaint(painter: _TestPainter(), child: Container());
    final str = '你好世界你好世界你好世界你好世界啦啦啦啦哈哈哈哈哈哈';
    return Padding(
        padding: EdgeInsets.symmetric(horizontal: 20, vertical: 30),
        child: Container(
          decoration: BoxDecoration(border: Border.all(color: Colors.red)),
          child: Text(str,
              style: TextStyle(fontSize: 50), textAlign: TextAlign.justify),
        ));
  }
}

And I just checked the webui engine.
I think the problem is because of:

https://github.com/flutter/engine/blob/a1994d326c83751b504481f0399d5f3622faf7e5/lib/web_ui/lib/src/engine/text/layout_service.dart#L184
and
https://github.com/flutter/engine/blob/dd8840d74d8b713549949861f8b3ec6a02787e14/lib/web_ui/lib/src/engine/text/layout_fragmenter.dart#L339
Quote:

  /// Adjust the width of this fragment for paragraph justification.
  void justifyTo({required double paragraphWidth}) {
    // Only justify this fragment if it's not a trailing space in the line.
    if (end > line.endIndex - line.trailingSpaces) {
      // Don't justify fragments that are part of trailing spaces of the line.
      return;
    }

    if (trailingSpaces == 0) {
      // If this fragment has no spaces, there's nothing to justify.
      return;
    }

    final double justificationTotal = paragraphWidth - line.width;
    final double justificationPerSpace = justificationTotal / line.nonTrailingSpaces;
    _extraWidthForJustification = justificationPerSpace * trailingSpaces;
  }

The above codes adjust the spaces between fragments, which is correct for English words which are separated by spaces.
However, Chinese words in sentences are rarely separated by spaces, so the code ends here:

    if (trailingSpaces == 0) {
      // If this fragment has no spaces, there's nothing to justify.
      return;
    }

So when laying out Chinese paragraph, TextAlign.justify is the same as TextAlign.left in ltr direction. Please check the image below.

And I think there's a simple solution to this: every fragment should be treated as having at least one traling space except for the last fragment in each lines.

Expected results

macOS result:
截屏2024-05-16 22 46 51

Actual results

Chrome result:
截屏2024-05-16 22 44 28

Code sample

Test this widget:

class Test extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // return CustomPaint(painter: _TestPainter(), child: Container());
    final str = '你好世界你好世界你好世界你好世界啦啦啦啦哈哈哈哈哈哈';
    return Padding(
        padding: EdgeInsets.symmetric(horizontal: 20, vertical: 30),
        child: Container(
          decoration: BoxDecoration(border: Border.all(color: Colors.red)),
          child: Text(str,
              style: TextStyle(fontSize: 50), textAlign: TextAlign.justify),
        ));
  }
}

Screenshots or Video

No response

Logs

No response

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.19.6, on macOS 14.4.1 23E224 darwin-x64, locale
    zh-Hans-CN)
    • Flutter version 3.19.6 on channel stable at /Users/lai/sdk/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 54e66469a9 (4 weeks ago), 2024-04-17 13:08:03 -0700
    • Engine revision c4cd48e186
    • Dart version 3.3.4
    • DevTools version 2.31.1

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from:
      https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK
      components.
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup
      for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.


[✓] Xcode - develop for iOS and macOS (Xcode 15.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15C500b
    • CocoaPods version 1.14.3

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

[!] Android Studio (not installed)
    • Android Studio not found; download from
      https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup
      for detailed instructions).

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

[✓] Proxy Configuration
    • HTTP_PROXY is set
    • NO_PROXY is
      192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,127.0.0.1,localhost,*.local,::1,ti
      mestamp.apple.com,sequoia.apple.com,seed-sequoia.siri.apple.com
    • NO_PROXY contains localhost
    • NO_PROXY contains 127.0.0.1
    • NO_PROXY contains ::1

[✓] Connected device (3 available)
    • la iPhone (mobile) • 00008110-000C5C893A00401E • ios            • iOS
      17.2.1 21C66
    • macOS (desktop)    • macos                     • darwin-x64     • macOS
      14.4.1 23E224 darwin-x64
    • Chrome (web)       • chrome                    • web-javascript • Google
      Chrome 124.0.6367.209

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.
@laishere laishere changed the title WebUI engine's TextLayoutService doesn't handle TextAlign.justify correctly for Chinese text. [engine] WebUI engine's TextLayoutService doesn't handle TextAlign.justify correctly for Chinese text May 16, 2024
@darshankawar darshankawar added the in triage Presently being triaged by the triage team label May 17, 2024
@darshankawar
Copy link
Member

Thanks for the report @laishere
Can you check if your issue resembles #140572 or not ?

@darshankawar darshankawar added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 17, 2024
@laishere
Copy link
Author

Thanks for reply. No, it's not the same issue.

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 17, 2024
@darshankawar
Copy link
Member

@laishere
Running the code using latest stable on web and macos gives me below that you can check and let us know what should be the expected behavior:

  1. Web:
Screenshot 2024-05-20 at 11 23 30 AM
  1. macOS:
Screenshot 2024-05-20 at 11 24 28 AM

@darshankawar darshankawar added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 20, 2024
@laishere
Copy link
Author

For each lines except the last, the last word's end should be aligned with the container's end. The web: "哈" word in first line has a gap between its end and container's end, which is incorrect for TextAlign.justify. You can use larger font size to see it more clearly.

MacOS behaves fine.

By the way, you can insert a space to the sentence when running on web, which will make it look fine. Just like the spaces between english words.

As I said before, it's because of the text layout logic for web engine handle TextAlign.justify by adding extra width to the trailing spaces after each words. So it will not behave normally when the words do not have any trailing spaces for languages like Chinese, Japanese, etc.

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 20, 2024
@darshankawar
Copy link
Member

Thanks for the update. Keeping the issue open and labeling for team's input / attention.

@darshankawar darshankawar added a: internationalization Supporting other languages or locales. (aka i18n) platform-web Web applications specifically team-web Owned by Web platform team a: typography Text rendering, possibly libtxt engine flutter/engine repository. See also e: labels. and removed in triage Presently being triaged by the triage team labels May 20, 2024
@yjbanov yjbanov added P2 Important issues not at the top of the work list triaged-web Triaged by Web platform team labels May 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: internationalization Supporting other languages or locales. (aka i18n) a: typography Text rendering, possibly libtxt engine flutter/engine repository. See also e: labels. P2 Important issues not at the top of the work list platform-web Web applications specifically team-web Owned by Web platform team triaged-web Triaged by Web platform team
Projects
None yet
Development

No branches or pull requests

3 participants