Skip to content

Add preferredLineHeightAtOffset to obtain measured metrics for full cursor height#24265

Closed
GaryQian wants to merge 15 commits intoflutter:masterfrom
GaryQian:cursorheight
Closed

Add preferredLineHeightAtOffset to obtain measured metrics for full cursor height#24265
GaryQian wants to merge 15 commits intoflutter:masterfrom
GaryQian:cursorheight

Conversation

@GaryQian
Copy link
Contributor

@GaryQian GaryQian commented Nov 13, 2018

This fixes #24182, #23934, #20694
This should also fix #20183 as well as other similar bugs reporting clipping of chinese and other tall-glyphed scripts.

Before, we were blindly using the height of a latin ' ' space character as the height of both the TextField as well as the cursor height. This PR calculates the actual height of the laid out text when it has been laid out and falls back to the old method before layout. I also track the max line height, and return the max height when there is a script taller than latin ' ' being used in the TextField.

This does introduce the possibility of the TextField height changing as taller glyphs are typed (for example, a string like ('Hello World 则没有这个问题' will cause the TextField to become taller when the Chinese is typed, as well as the overall text to shift slightly down), but it does seem consistent with some of the text editors in the wild.

There should be further work in the future to more consistently align the positions of ideographic/hanging script to alphabetic characters, as what we currently do seems slightly off in certain situations. (Tracked at #24317)

@GaryQian
Copy link
Contributor Author

cc @Hixie This adds API TextPainter.PreferredLineHeightAtOffset(int offset) to attempt to get the measured line height at the provided offset in the string.

@HansMuller
Copy link
Contributor

There should be further work in the future to more consistently align the positions of ideographic/hanging script to alphabetic characters, as what we currently do seems slightly off in certain situations.

There should be an issue that itemizes the additional work; refer to it in the description.

@xster
Copy link
Member

xster commented Nov 13, 2018

Might be helpful with #20694 too

@GaryQian
Copy link
Contributor Author

Might be helpful with #20694 too

This doesn't quite make it look like that in iOS. Without a taller script/glyph, we will still have the old heights of the cursor (at least with this patch).

There needs to be more work to obtain a cursor that matches something like the cursor in iOS.

@xster
Copy link
Member

xster commented Nov 14, 2018

Right, iOS would be closer to BoxHeightStyle.includeLineSpacingMiddle. Though are you sure the current PR is how it works on Android too?

On multi-line text fields with small glyphs, it seems like adjacent lines' cursors touch regardless.

@GaryQian
Copy link
Contributor Author

It looks like many android apps have similar behavior to iOS. What we currently do for the cursor is completely wrong and is just guessing at the potential height of a line.

This PR does not yet modify it such that we replicate iOS or Android, but rather just makes sure the cursor at least covers the full height of the glyph it is associated with.

I can make a separate patch that can accomplish this but it will likely be more complicated as we would have to rework the way we get the coordinates for the beginning of the cursor as well as the height.

@Hixie
Copy link
Contributor

Hixie commented Nov 14, 2018

This needs tests. The tests should check all the code here (there's lots of new code to test), including especially testing how the surrogate checking code handles low and high surrogates.

@xster
Copy link
Member

xster commented Nov 14, 2018

Doing OS fidelity in a separate PR is fine. As long as you're moving in a monotonic direction and aren't dismantling code or tests you're writing now to do it :)

@GaryQian
Copy link
Contributor Author

GaryQian commented Nov 15, 2018

Pushed new changes, The TextField now attempts to measure actual metrics before defaulting to the predicted metrics we used before in most places. This resolves the Chinese (and other languages) clipping issue, as well as the cursor height.

I removed the hard-coded caret height reduction of 2 pixels, as it better matches both Android as well as iOS.

I also exposed needsLayout as a getter in TextPainter, which is useful to check when certain methods dependent on layout are available for use.

Will add tests now.

// removed and replaced with a less biased alternative. We can choose what
// character to use based of the locale and the ScriptCategory field of
// MaterialLocalization.
builder.addText(' ');
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 wrong with the space character?

The code here doesn't know about Material, let alone localizations or anything like that.

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 space used in alphabetic scripts (0x0020) is not the same dimensions as the space used in ideographic scripts (0x3000). Alphabetic space is both shorter and narrower. This is causing our guess at line height to be too short when the user is expecting to type scripts like CJK, which impacts the height of the text field as well as the height of the cursor.

We have access to a Locale object from dart:ui here, I figured we might be able to do something with it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm. Really ideally we'd never change the caret size... it's a pity we don't have a way to just pick the "right" size for all text. Maybe we could measure the string U+0020 U+3000 ?

The locale from dart:ui isn't helpful here. We have no idea what the locale of the actual TextPainter's text is (it might have nothing to do with the locales in dart:ui).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Measuring a string with both U+0020 and U+3000 would make the height almost always be the height of U+3000 as it is consistently taller than U+0020. This is essentially the same as just defaulting to U+3000 which would cause fields with alphabetic text to behave strangely (box too tall, caret too tall, etc).

GaryQian added a commit to flutter/goldens that referenced this pull request Nov 16, 2018
@zoechi zoechi added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. labels Nov 28, 2018
caretRect = editable.getLocalRectForCaret(const TextPosition(offset: 4));
// TODO(garyq): Not a round number because of rounding in LibTxt height
// metrics. This rounding is slated to be removed as it is no longer
// needed. This test should be fixed when the rounding is removed.
Copy link
Contributor

Choose a reason for hiding this comment

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

please include a link to the relevant issue, so that audits of issue links will reveal this

@Hixie
Copy link
Contributor

Hixie commented Dec 13, 2018

cc @goderbauer for deeper review

@hahafather007
Copy link

When can this problem be solved?I still feel no change on the v1.1.2 version.

@GaryQian
Copy link
Contributor Author

So it turns out that the full solution to this requires additional work by supporting a paragraphStyle-level leading/height that functions as a min line height for the text. Since this patch would only be a temporary fix and introduces another significant bug, I will be pursuing the full proper fix instead. I will post more details about it soon.

@GaryQian
Copy link
Contributor Author

GaryQian commented Jan 4, 2019

#26085 Is a tracking issue that enumerates the work needed to implement "Strut" which will allow better defined line heights and ability to add "buffer zone" line padding that allows taller fonts to not impact line height.

@GaryQian
Copy link
Contributor Author

A modified version of this may be able to be implemented and landed after the strut features are added to LibTxt and the framework. Strut should be able to prevent the jumping text that this PR in its current state causes. The new changes will likely be done in a separate PR.

@GaryQian
Copy link
Contributor Author

Closing this PR for now, and a new strut-based fix will be written.

@GaryQian GaryQian closed this Jan 22, 2019
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cursor too high/short for non-alphabetic scripts such as Chinese, emojis, and others. TextField, Enter Chinese in android device ,The bottom is cut

7 participants