Skip to content

Paragraph.getLineBoundary doesn't consider TextAffinity #87970

Closed
flutter-team-archive/engine
#28008

Description

@justinmc

ui.Paragraph.getLineBoundary gives an incorrect response when passed TextAffinity.downstream at a line wrap.

Example

Imagine we're rendering the string "123456789" and our field is very narrow and so the "9" wraps:

|12345678|
|9       |

There are now two TextPositions between the 8 and the 9, one on the first line and one on the second line:

First line: TextPosition(offset: 8, affinity: TextAffinity.upstream)
Second line: TextPosition(offset: 8, affinity: TextAffinity.downstream)

The problem is that getLineBoundary will return a TextRange of 0-8 regardless of which of the above two TextPositions are passed to it. It doesn't use the TextAffinity, only the index, which you can see in the code here.

Activity

  1. justinmc commented on Aug 9, 2021

    @justinmc
    ContributorAuthor

    CC @GaryQian Do you have any idea if there was a reason for this, or is this something that we should fix?

  2. TahaTesser commented on Aug 10, 2021

    @TahaTesser
    Contributor

    I think I've reproduced the issue correctly, let me know if it is missing something

    Used the following minimal code sample

    complete minimal runnable code sample
    import 'dart:async';
    import 'dart:typed_data';
    import 'dart:ui' as ui;
    import 'dart:io';
    
    import 'package:flutter/painting.dart';
    
    Future<ui.Image> getScreenshot() async {
      final screenshotbytes = File('locations.jpg').readAsBytes();
    
      final Completer<ui.Image> completer = Completer<ui.Image>();
      ui.decodeImageFromList(await screenshotbytes, completer.complete);
      return completer.future;
    }
    
    Future<ui.Picture?> paint(ui.Rect paintBounds) async {
      final ui.PictureRecorder recorder = ui.PictureRecorder();
    
      final ui.Canvas canvas = ui.Canvas(recorder, paintBounds);
    
      final ui.ParagraphBuilder paragraphBuilder =
          ui.ParagraphBuilder(ui.ParagraphStyle(
        fontSize: 150,
        fontFamily: 'Montserrat-Bold',
        textAlign: TextAlign.center,
      ))
            ..addText('123456789');
    
      final ui.Paragraph paragraph = paragraphBuilder.build()
        ..layout(ui.ParagraphConstraints(width: paintBounds.size.width - 100));
      canvas.drawParagraph(
          paragraph, Offset(paintBounds.left + 50, paintBounds.top + 100));
    
      final range1 = paragraph.getLineBoundary(
          TextPosition(offset: 8, affinity: TextAffinity.upstream));
    
      print(range1);
    
      final range2 = paragraph.getLineBoundary(
          TextPosition(offset: 8, affinity: TextAffinity.downstream));
      print(range2);
    
      return recorder.endRecording();
    }
    
    ui.Scene composite(ui.Picture picture, ui.Rect bounds) {
      final double devicePixelRatio = ui.window.devicePixelRatio;
      final Float64List deviceTransform = Float64List(16)
        ..[0] = devicePixelRatio
        ..[5] = devicePixelRatio
        ..[10] = 1.0
        ..[15] = 1.0;
      final ui.SceneBuilder sceneBuilder = ui.SceneBuilder()
        ..pushTransform(deviceTransform)
        ..addPicture(ui.Offset.zero, picture)
        ..pop();
      return sceneBuilder.build();
    }
    
    void beginFrame(Duration timeStamp) async {
      final ui.Rect paintBounds = ui.Offset.zero & const ui.Size(800, 1920);
      final ui.Picture? picture = await paint(paintBounds);
      final ui.Scene scene = composite(picture!, paintBounds);
      ui.window.render(scene);
    
      final image = await picture.toImage(1080, 1920);
      final data = await image.toByteData(format: ui.ImageByteFormat.png);
      if (data != null) {
        final buffer = data.buffer;
        File('screenshot_3.png').writeAsBytes(
            buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
      }
    }
    
    void main() {
      ui.window.onBeginFrame = beginFrame;
      ui.window.scheduleFrame();
    }
    
    [  +16 ms] flutter: TextRange(start: 0, end: 8)
    [        ] flutter: TextRange(start: 0, end: 8)
    preview

    image

    stable master
    ❌ ❌

    Check flutter doctor -v outputs for each channel below

    flutter doctor -v
    [✓] Flutter (Channel stable, 2.2.3, on Microsoft Windows [Version 10.0.22000.120], locale en-US)
        • Flutter version 2.2.3 at C:\Users\Taha\Code\flutter_stable
        • Framework revision f4abaa0735 (6 weeks ago), 2021-07-01 12:46:11 -0700
        • Engine revision 241c87ad80
        • Dart version 2.13.4
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
        • Android SDK at C:\Users\Taha\Code\android-sdk
        • Platform android-30, build-tools 30.0.3
        • ANDROID_SDK_ROOT = C:\Users\Taha\Code\android-sdk
        • Java binary at: C:\Users\Taha\Code\android-studio\jre\bin\java
        • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)
        • All Android licenses accepted.
    
    [✓] Chrome - develop for the web
        • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe
    
    [✓] Visual Studio - develop for Windows (Visual Studio Community 2019 16.10.4)
        • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
        • Visual Studio Community 2019 version 16.10.31515.178
        • Windows 10 SDK version 10.0.19041.0
    
    [!] 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/windows#android-setup for detailed instructions).
    
    [✓] VS Code (version 1.59.0)
        • VS Code at C:\Users\Taha\AppData\Local\Programs\Microsoft VS Code
        • Flutter extension version 3.25.0
    
    [✓] Connected device (3 available)
        • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22000.120]
        • Chrome (web)      • chrome  • web-javascript • Google Chrome 92.0.4515.131
        • Edge (web)        • edge    • web-javascript • Microsoft Edge 92.0.902.67
    
    ! Doctor found issues in 1 category.
    [✓] Flutter (Channel master, 2.5.0-6.0.pre.40, on Microsoft Windows [Version 10.0.22000.120], locale en-US)
        • Flutter version 2.5.0-6.0.pre.40 at C:\Users\Taha\Code\flutter_master
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 7d76a827c0 (14 hours ago), 2021-08-09 15:21:17 -0700
        • Engine revision 4fef55db10
        • Dart version 2.14.0 (build 2.14.0-385.0.dev)
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
        • Android SDK at C:\Users\Taha\Code\android-sdk
        • Platform android-30, build-tools 30.0.3
        • ANDROID_SDK_ROOT = C:\Users\Taha\Code\android-sdk
        • Java binary at: C:\Users\Taha\Code\android-studio\jre\bin\java
        • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)
        • All Android licenses accepted.
    
    [✓] Chrome - develop for the web
        • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe
    
    [✓] Visual Studio - develop for Windows (Visual Studio Community 2019 16.10.4)
        • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
        • Visual Studio Community 2019 version 16.10.31515.178
        • Windows 10 SDK version 10.0.19041.0
    
    [✓] Android Studio (version 2020.3)
        • Android Studio at C:\Users\Taha\Code\android-studio
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)
    
    [✓] VS Code (version 1.59.0)
        • VS Code at C:\Users\Taha\AppData\Local\Programs\Microsoft VS Code
        • Flutter extension version 3.25.0
    
    [✓] Connected device (4 available)
        • Windows (desktop)       • windows • windows-x64     • Microsoft Windows [Version 10.0.22000.120]
        • Windows (UWP) (desktop) • winuwp  • windows-uwp-x64 •
        • Chrome (web)            • chrome  • web-javascript  • Google Chrome 92.0.4515.131
        • Edge (web)              • edge    • web-javascript  • Microsoft Edge 92.0.902.67
    
    • No issues found!

    ✅: No Issue ❌: Issue reproduced

  3. added
    engineflutter/engine related. See also e: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    a: typographyText rendering, possibly libtxt
    and removed
    in triagePresently being triaged by the triage team
    on Aug 10, 2021
  4. justinmc commented on Aug 10, 2021

    @justinmc
    ContributorAuthor

    @TahaTesser Yes thank you for the great repro! I ashamed to say that I assumed it wasn't reproducible without putting print statements in the framework code 😞

  5. added
    r: fixedIssue is closed as already fixed in a newer version
    on Aug 17, 2021
  6. github-actions commented on Aug 31, 2021

    @github-actions

    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.

  7. locked as resolved and limited conversation to collaborators on Aug 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: typographyText rendering, possibly libtxtdependency: dartDart team may need to help usengineflutter/engine related. See also e: labels.found in release: 2.2Found to occur in 2.2found in release: 2.5Found to occur in 2.5has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer version

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions