Skip to content

Conversation

@LongCatIsLooong
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong commented Feb 11, 2024

The behavior largely remains the same, except:

  1. The EOT cursor (textLength, downstream) for text ending in the opposite writing direction as the paragraph is now placed at the visual end of the last line.
    For example, in a LTR paragraph, the EOT cursor for aA (lowercase for LTR and uppercase for RTL) is placed to the right of the line: aA| (it was a|A before).
    This matches the behavior of most applications that do logical order arrow key navigation instead of visual order navigation.
    And it makes the navigation order consistent for aA\naA:
  |aA    =>  aA|  => aA|  => aA  => aA   => aA 
   aA        aA      aA     |aA     aA|     aA|     
   (1)       (2)     (3)    (4)    (5)      (6)

This is indeed still pretty confusing as (2) and (3), as well as (5) and (6) are hard to distinguish (when the I beam has a large width they are actually visually distinguishable -- they use the same anchor but one gets painted to the left and the other to the right. I noticed that emacs does the same).
But logical order navigation will always be confusing in bidi text, in one way or another.

Interestingly there are 3 different behaviors I've observed in chrome:

  • the chrome download dialog (which I think uses GTK text widgets but not sure which version) gives me 2 cursors when navigating bidi text, and
  • its HTML fields only show one, and presumably they place the I beam at the trailing edge of the character (which makes more sense for backspacing I guess).
  • On the other hand, its (new) omnibar seems to use visual order arrow navigation

Side note: we may need to update the "tap to place the caret here" logic to handle the case where the tap lands outside of the text and the text ends in the opposite writing direction.

  1. Removed the logarithmic search. The same could be done using the characters package but when glyphInfo tells you about the baseline location in the future we probably don't need the getBoxesForRange call. This should fix Caret misplaced in bidi text #123424.

Internal Tests

This is going to change the image output of some internal golden tests. I'm planning to merge #143281 before this to avoid updating the same golden files twice for invalid selections.

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. f: cupertino flutter/packages/flutter/cupertino repository labels Feb 11, 2024
@github-actions github-actions bot added d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos labels Feb 11, 2024
@LongCatIsLooong LongCatIsLooong changed the title TextPainter.getOffsetForCaret Changing TextPainter.getOffsetForCaret implementation to remove the logarithmic search Feb 13, 2024
@LongCatIsLooong LongCatIsLooong marked this pull request as ready for review February 13, 2024 01:55
Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with nits 👍

0x000B || // Form Feed
0x000C || // Vertical Feed
0x2028 || // Line Separator
0x2029 => true, // Paragraph Separator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better, thanks!

assert(lastLineIndex >= 0);
final ui.LineMetrics lineMetrics = _paragraph.getLineMetricsAt(lastLineIndex)!;
// SkParagraph currently treats " " and "\t" as white spaces. Trailing white
// spaces don't contribute to the line width thus require special handling
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this say "and thus"?

Comment on lines +360 to +361
// TODO(LongCatIsLooong): handle the case where maxLine is set to non-null
// and the last line ends with trailing whitespaces.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to handle this in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I need to expose the text range from line metrics for this. Currently it only checks if textLength - 1 is a trailing space.

/// ligature component.
final class _LineCaretMetrics {
const _LineCaretMetrics({required this.offset, required this.writingDirection});
/// The offset from the top left corner of the paragraph to the the caret's
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate "the".

//
// For a TextPosition, typically when its TextAffinity is downstream, the
// corresponding I-beam caret is anchored to the leading edge of the
// `offset`-th character in the text. When the TextAffinity is upstream, the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe: "offset-th character" => "character at offset"

So for offset 1 and affinity downstream, it's anchored to the leading edge of the 2nd character (the character at index 1), right? If so, I think the above change is more clear. When I first read this paragraph, I think I incorrectly interpreted it to mean the 1st character.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right.

// too close to the right.
controller.dispose();
controller = TextEditingController(text: List<String>.filled(200, 'a').join());
controller = TextEditingController(text: 'a' * 200);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did Dart not always have the multiplying a String thing?

).topRight.dx;
inputWidth = editable.size.width;
expect(cursorRight, inputWidth - kCaretGap);
expect(cursorRight, inputWidth - kCaretGap - text.length * 10 - 2.0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the 2.0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

caret width

}

Offset textOffsetToPosition(WidgetTester tester, int offset, {int index = 0}) {
assert(0 <= offset);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Yoda ordering.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the assert.

}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android }));


for (final TextDirection textDirection in TextDirection.values) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not run this for both TextDirections any more?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LTR variation is exactly the same test as the one above.

return _caretMetrics;
}

final ui.GlyphInfo? glyphInfo = cachedLayout.paragraph.getGlyphInfoAt(offset);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the secret to removing the logarithmic search? Are you able to get the bounds of the glyph using this getGlyphInfoAt method instead? What does it do internally if so?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getBoxForSelection doesn't include a multi-code-unit character if the input selection doesn't include the full range of it. Alternatively the same can be done using the characters package.

@LongCatIsLooong LongCatIsLooong added the autosubmit Merge PR when tree becomes green via auto submit App label Feb 20, 2024
@auto-submit auto-submit bot merged commit 3538e4c into flutter:master Feb 20, 2024
@LongCatIsLooong LongCatIsLooong deleted the text-painter-caret branch February 20, 2024 21:09
@LongCatIsLooong
Copy link
Contributor Author

Reason for revert: #143797

@LongCatIsLooong LongCatIsLooong added the revert Autorevert PR (with "Reason for revert:" comment) label Feb 21, 2024
auto-submit bot pushed a commit that referenced this pull request Feb 21, 2024
…move the logarithmic search (#143281)"

This reverts commit 3538e4c.
@auto-submit auto-submit bot removed the revert Autorevert PR (with "Reason for revert:" comment) label Feb 21, 2024
auto-submit bot added a commit that referenced this pull request Feb 21, 2024
…emove the logarithmic search (#143281)" (#143801)

Reverts #143281

Initiated by: LongCatIsLooong

Reason for reverting: #143797

Original PR Author: LongCatIsLooong

Reviewed By: {justinmc, jason-simmons}

This change reverts the following previous change:
Original Description:
The behavior largely remains the same, except:

1. The EOT cursor `(textLength, downstream)` for text ending in the opposite writing direction as the paragraph is now placed at the visual end of the last line. 
  For example, in a LTR paragraph, the EOT cursor for `aA` (lowercase for LTR and uppercase for RTL) is placed to the right of the line: `aA|` (it was `a|A` before). 
  This matches the behavior of most applications that do logical order arrow key navigation instead of visual order navigation. 
  And it makes the navigation order consistent for `aA\naA`:
```
  |aA    =>  aA|  => aA|  => aA  => aA   => aA 
   aA        aA      aA     |aA     aA|     aA|     
   (1)       (2)     (3)    (4)    (5)      (6)
```
This is indeed still pretty confusing as (2) and (3), as well as (5) and (6) are hard to distinguish (when the I beam has a large width they are actually visually distinguishable -- they use the same anchor but one gets painted to the left and the other to the right. I noticed that emacs does the same). 
But logical order navigation will always be confusing in bidi text, in one way or another.

Interestingly there are 3 different behaviors I've observed in chrome:
- the chrome download dialog (which I think uses GTK text widgets but not sure which version) gives me 2 cursors when navigating bidi text, and 
- its HTML fields only show one, and presumably they place the I beam at the **trailing edge** of the character (which makes more sense for backspacing I guess). 
- On the other hand, its (new) omnibar seems to use visual order arrow navigation

Side note: we may need to update the "tap to place the caret here" logic to handle the case where the tap lands outside of the text and the text ends in the opposite writing direction. 

2. Removed the logarithmic search. The same could be done using the characters package but when glyphInfo tells you about the baseline location in the future we probably don't need the `getBoxesForRange` call. This should fix #123424.

## Internal Tests

This is going to change the image output of some internal golden tests. I'm planning to merge #143281 before this to avoid updating the same golden files twice for invalid selections.
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 21, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 21, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 21, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 21, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 22, 2024
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Feb 22, 2024
Manual roll Flutter from 5129806 to efee280 (47 revisions)

Manual roll requested by [email protected]

flutter/flutter@5129806...efee280

2024-02-22 [email protected] Roll Flutter Engine from bf5c003085fd to 7eeb697687d5 (16 revisions) (flutter/flutter#143911)
2024-02-22 [email protected] Update PR template for dart fix (flutter/flutter#143879)
2024-02-22 [email protected] Re-use methods to calculate leading and trailing garbage in RenderSliverMultiBoxAdaptor (flutter/flutter#143884)
2024-02-21 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[Impeller] Make impeller goldens test blocking. (#143864)" (flutter/flutter#143896)
2024-02-21 [email protected] [Impeller] Make impeller goldens test blocking. (flutter/flutter#143864)
2024-02-21 [email protected] Disable color filter sepia test for Impeller. (flutter/flutter#143861)
2024-02-21 [email protected] Roll Flutter Engine from 52ffcaadea41 to bf5c003085fd (12 revisions) (flutter/flutter#143875)
2024-02-21 [email protected] Roll Flutter Engine from 4128895d79a1 to 52ffcaadea41 (1 revision) (flutter/flutter#143862)
2024-02-21 [email protected] Deprecate redundant itemExtent in RenderSliverFixedExtentBoxAdaptor methods (flutter/flutter#143412)
2024-02-21 [email protected] Add aab as alias for appbundle (flutter/flutter#143855)
2024-02-21 [email protected] Roll Flutter Engine from e16f43eeaaa4 to 4128895d79a1 (1 revision) (flutter/flutter#143856)
2024-02-21 [email protected] Roll Packages from 8bba41b to 48048f6 (2 revisions) (flutter/flutter#143853)
2024-02-21 [email protected] Update `hourMinuteTextStyle` defaults for Material 3 Time Picker (flutter/flutter#143749)
2024-02-21 [email protected] Roll Flutter Engine from 93063f61943a to e16f43eeaaa4 (2 revisions) (flutter/flutter#143827)
2024-02-21 [email protected] Roll Flutter Engine from ed49634486e9 to 93063f61943a (1 revision) (flutter/flutter#143826)
2024-02-21 [email protected] `CalendarDatePicker` doesn't announce selected date on desktop (flutter/flutter#143583)
2024-02-21 [email protected] Roll Flutter Engine from 9100d326475a to ed49634486e9 (2 revisions) (flutter/flutter#143824)
2024-02-21 [email protected] Add `timeSelectorSeparatorColor` and `timeSelectorSeparatorTextStyle`  for Material 3 Time Picker (flutter/flutter#143739)
2024-02-21 [email protected] Roll Flutter Engine from efc69946cb1e to 9100d326475a (2 revisions) (flutter/flutter#143820)
2024-02-21 [email protected] Roll Flutter Engine from 700250436e3f to efc69946cb1e (2 revisions) (flutter/flutter#143816)
2024-02-21 [email protected] Roll Flutter Engine from 3557277c575c to 700250436e3f (1 revision) (flutter/flutter#143814)
2024-02-21 [email protected] more fixes to unstable impeller goldens. (flutter/flutter#143811)
2024-02-21 [email protected] Roll Flutter Engine from cb12a8cc97a1 to 3557277c575c (2 revisions) (flutter/flutter#143807)
2024-02-21 [email protected] [flutter_tools] enable wasm compile on beta channel (flutter/flutter#143779)
2024-02-21 [email protected] Fix initialization of time in repeat on AnimationController (flutter/flutter#142887)
2024-02-21 [email protected] Disable debug banner to stabilize impeller goldens. (flutter/flutter#143794)
2024-02-21 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Changing `TextPainter.getOffsetForCaret` implementation to remove the logarithmic search (#143281)" (flutter/flutter#143801)
2024-02-20 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Add UI Benchmarks (#143542)" (flutter/flutter#143798)
2024-02-20 [email protected] Avoid applying partial dartfixes on CI (flutter/flutter#143551)
2024-02-20 [email protected] Add UI Benchmarks (flutter/flutter#143542)
2024-02-20 [email protected] Roll Flutter Engine from 1ae2c10e8071 to cb12a8cc97a1 (1 revision) (flutter/flutter#143791)
2024-02-20 [email protected] Implement `_suspendedNode` fix (flutter/flutter#143556)
2024-02-20 [email protected] Change `ItemExtentBuilder`'s return value nullable (flutter/flutter#142428)
2024-02-20 [email protected] Roll Flutter Engine from 27828054f07a to 1ae2c10e8071 (6 revisions) (flutter/flutter#143783)
2024-02-20 [email protected] Roll Flutter Engine from e16a260265ad to 27828054f07a (1 revision) (flutter/flutter#143769)
2024-02-20 [email protected] [gold] Always provide host ABI to gold config (flutter/flutter#143621)
2024-02-20 [email protected] instead of exiting the tool, print a warning when using --flavor with an incompatible device (flutter/flutter#143735)
2024-02-20 [email protected] Implementing `switch` expressions: everything in `flutter/lib/src/` (flutter/flutter#143634)
2024-02-20 [email protected] Changing `TextPainter.getOffsetForCaret` implementation to remove the logarithmic search (flutter/flutter#143281)
2024-02-20 [email protected] Delete local.properties that shouldn't have been pushed (flutter/flutter#143774)
2024-02-20 [email protected] Clean leaks. (flutter/flutter#142818)
2024-02-20 [email protected] Introduce tone-based surfaces and accent color add-ons - Part 2 (flutter/flutter#138521)
2024-02-20 [email protected] Explain when and why to use CrossAxisAlignment.baseline (flutter/flutter#143632)
2024-02-20 [email protected] Roll Flutter Engine from a41da3701923 to e16a260265ad (2 revisions) (flutter/flutter#143763)
...
LongCatIsLooong added a commit to LongCatIsLooong/flutter that referenced this pull request Feb 22, 2024
remove the logarithmic search (flutter#143281)" (reverted in flutter#143801)

This reverts commit f9b3b84.
auto-submit bot pushed a commit that referenced this pull request Feb 23, 2024
…emove the logarithmic search (#143281)" (reverted in #143801) (#143954)

The original PR was reverted because the new caret positioning callpath triggered a skparagraph assert. The assert has been removed. Relanding the PR with no changes applied.
LouiseHsu pushed a commit to LouiseHsu/packages that referenced this pull request Mar 7, 2024
)

Manual roll Flutter from 5129806 to efee280 (47 revisions)

Manual roll requested by [email protected]

flutter/flutter@5129806...efee280

2024-02-22 [email protected] Roll Flutter Engine from bf5c003085fd to 7eeb697687d5 (16 revisions) (flutter/flutter#143911)
2024-02-22 [email protected] Update PR template for dart fix (flutter/flutter#143879)
2024-02-22 [email protected] Re-use methods to calculate leading and trailing garbage in RenderSliverMultiBoxAdaptor (flutter/flutter#143884)
2024-02-21 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[Impeller] Make impeller goldens test blocking. (#143864)" (flutter/flutter#143896)
2024-02-21 [email protected] [Impeller] Make impeller goldens test blocking. (flutter/flutter#143864)
2024-02-21 [email protected] Disable color filter sepia test for Impeller. (flutter/flutter#143861)
2024-02-21 [email protected] Roll Flutter Engine from 52ffcaadea41 to bf5c003085fd (12 revisions) (flutter/flutter#143875)
2024-02-21 [email protected] Roll Flutter Engine from 4128895d79a1 to 52ffcaadea41 (1 revision) (flutter/flutter#143862)
2024-02-21 [email protected] Deprecate redundant itemExtent in RenderSliverFixedExtentBoxAdaptor methods (flutter/flutter#143412)
2024-02-21 [email protected] Add aab as alias for appbundle (flutter/flutter#143855)
2024-02-21 [email protected] Roll Flutter Engine from e16f43eeaaa4 to 4128895d79a1 (1 revision) (flutter/flutter#143856)
2024-02-21 [email protected] Roll Packages from 8bba41b to 48048f6 (2 revisions) (flutter/flutter#143853)
2024-02-21 [email protected] Update `hourMinuteTextStyle` defaults for Material 3 Time Picker (flutter/flutter#143749)
2024-02-21 [email protected] Roll Flutter Engine from 93063f61943a to e16f43eeaaa4 (2 revisions) (flutter/flutter#143827)
2024-02-21 [email protected] Roll Flutter Engine from ed49634486e9 to 93063f61943a (1 revision) (flutter/flutter#143826)
2024-02-21 [email protected] `CalendarDatePicker` doesn't announce selected date on desktop (flutter/flutter#143583)
2024-02-21 [email protected] Roll Flutter Engine from 9100d326475a to ed49634486e9 (2 revisions) (flutter/flutter#143824)
2024-02-21 [email protected] Add `timeSelectorSeparatorColor` and `timeSelectorSeparatorTextStyle`  for Material 3 Time Picker (flutter/flutter#143739)
2024-02-21 [email protected] Roll Flutter Engine from efc69946cb1e to 9100d326475a (2 revisions) (flutter/flutter#143820)
2024-02-21 [email protected] Roll Flutter Engine from 700250436e3f to efc69946cb1e (2 revisions) (flutter/flutter#143816)
2024-02-21 [email protected] Roll Flutter Engine from 3557277c575c to 700250436e3f (1 revision) (flutter/flutter#143814)
2024-02-21 [email protected] more fixes to unstable impeller goldens. (flutter/flutter#143811)
2024-02-21 [email protected] Roll Flutter Engine from cb12a8cc97a1 to 3557277c575c (2 revisions) (flutter/flutter#143807)
2024-02-21 [email protected] [flutter_tools] enable wasm compile on beta channel (flutter/flutter#143779)
2024-02-21 [email protected] Fix initialization of time in repeat on AnimationController (flutter/flutter#142887)
2024-02-21 [email protected] Disable debug banner to stabilize impeller goldens. (flutter/flutter#143794)
2024-02-21 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Changing `TextPainter.getOffsetForCaret` implementation to remove the logarithmic search (#143281)" (flutter/flutter#143801)
2024-02-20 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Add UI Benchmarks (#143542)" (flutter/flutter#143798)
2024-02-20 [email protected] Avoid applying partial dartfixes on CI (flutter/flutter#143551)
2024-02-20 [email protected] Add UI Benchmarks (flutter/flutter#143542)
2024-02-20 [email protected] Roll Flutter Engine from 1ae2c10e8071 to cb12a8cc97a1 (1 revision) (flutter/flutter#143791)
2024-02-20 [email protected] Implement `_suspendedNode` fix (flutter/flutter#143556)
2024-02-20 [email protected] Change `ItemExtentBuilder`'s return value nullable (flutter/flutter#142428)
2024-02-20 [email protected] Roll Flutter Engine from 27828054f07a to 1ae2c10e8071 (6 revisions) (flutter/flutter#143783)
2024-02-20 [email protected] Roll Flutter Engine from e16a260265ad to 27828054f07a (1 revision) (flutter/flutter#143769)
2024-02-20 [email protected] [gold] Always provide host ABI to gold config (flutter/flutter#143621)
2024-02-20 [email protected] instead of exiting the tool, print a warning when using --flavor with an incompatible device (flutter/flutter#143735)
2024-02-20 [email protected] Implementing `switch` expressions: everything in `flutter/lib/src/` (flutter/flutter#143634)
2024-02-20 [email protected] Changing `TextPainter.getOffsetForCaret` implementation to remove the logarithmic search (flutter/flutter#143281)
2024-02-20 [email protected] Delete local.properties that shouldn't have been pushed (flutter/flutter#143774)
2024-02-20 [email protected] Clean leaks. (flutter/flutter#142818)
2024-02-20 [email protected] Introduce tone-based surfaces and accent color add-ons - Part 2 (flutter/flutter#138521)
2024-02-20 [email protected] Explain when and why to use CrossAxisAlignment.baseline (flutter/flutter#143632)
2024-02-20 [email protected] Roll Flutter Engine from a41da3701923 to e16a260265ad (2 revisions) (flutter/flutter#143763)
...
justinmc added a commit to justinmc/flutter that referenced this pull request Apr 10, 2024
…ion to remove the logarithmic search (flutter#143281)" (reverted in flutter#143801) (flutter#143954)"

This reverts commit a0a854a.
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems autosubmit Merge PR when tree becomes green via auto submit App d: api docs Issues with https://api.flutter.dev/ d: examples Sample code and demos f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Caret misplaced in bidi text

3 participants