Fix Android text descender clipping with tight lineHeight#57115
Fix Android text descender clipping with tight lineHeight#57115TorinAsakura wants to merge 3 commits into
Conversation
|
Hi @TorinAsakura! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
|
Can you show examples before/after? |
|
@javache Sure. I re-ran the RNTester repro on Android with fontSize: 24, lineHeight: 24, and gjpqy. |
|
@javache has imported this pull request. If you are a Meta employee, you can view this in D108406457. |
cortinico
left a comment
There was a problem hiding this comment.
Review automatically exported from Phabricator review in Meta.
|
Thanks, this is a good catch. I reproduced the mechanism behind the screenshots. The current patch preserves the original font top/bottom in CustomLineHeightSpan. That fixes the single-line descender repro, but with Android’s default includeFontPadding=true those same top/bottom values are consumed by StaticLayout as first/last-line padding, so the measured paragraph height grows. That explains the multiline change. I don’t think CustomLineHeightSpan is the right boundary for fixing both constraints. We need to keep the line box at the requested lineHeight and handle glyph ink overflow separately. The existing ReactTextView path still goes through Android TextView drawing and its internal clipRect, so this probably belongs around the prepared text layout / overflow inset boundary instead. I’ll rework this around preserving the current line-height layout contract first. If that scope is too broad for this PR, I can split or re-scope before pushing another patch. |
|
Reworked in 459c205. The PR no longer uses CustomLineHeightSpan top/bottom to carry font bounds, so tight multiline lineHeight stays at the requested layout height. The unclipped drawing is now handled in ReactTextView for ordinary non-selectable text when overflow is visible, which avoids TextView's internal clipRect. Selectable/linkify text and non-visible overflow stay on the regular TextView drawing path. I also added coverage for both sides of the issue: StaticLayout height regression tests for tight lineHeight, and a ReactTextView pixel test for ink drawn outside the line bounds with visible overflow. Local checks passed with stable Hermes selected for Gradle: ReactAndroid targeted unit tests, ktfmtCheck, git diff --check, Prettier and ESLint for the RNTester repro file. |




Summary:
Fixes #49886.
Close torin-asakura/workspace#115.
Android TextView clips text drawing to the view bounds in its default onDraw path. For explicit lineHeight, CustomLineHeightSpan should keep paragraph layout bounds tied to the requested lineHeight; using font top/bottom to avoid clipping fixes the single-line repro but expands multiline text.
This keeps the line-height layout contract intact and draws ordinary non-selectable ReactTextView text directly when overflow is visible, avoiding TextView's internal clipRect. Selectable/linkify text and non-visible overflow continue to use the regular TextView drawing path.
Changelog:
[ANDROID] [FIXED] - Prevent descenders from being clipped when Android text lineHeight matches fontSize
Test Plan:
Command:
Result:
Command:
Result:
Command:
Result: no output.
Command:
Result:
Command:
Result: no output.
RNTester visual repro with fontSize: 24, lineHeight: 24, and gjpqy.
Visual evidence:
Before this PR
After this PR