Skip to content

Commit 83d7a48

Browse files
bernhardojfacebook-github-bot
authored andcommitted
Resubmit D46501420 (#37790)
Summary: Multiline text in Android shows some extra space. It's easily noticeable when you set the text `alignSelf` to `flex-start`. This is because we are using `layout.getLineWidth` which will include trailing whitespace. <img width="300" alt="image" src="https://github.com/facebook/react-native/assets/50919443/8939092b-caef-4ad8-9b34-2ccef5d20968"> Based on Android doc, `getLineMax` exclude trailing whitespace. <img width="625" alt="image" src="https://github.com/facebook/react-native/assets/50919443/0b32e842-5fab-4fc7-8fd9-299877b9c553"> ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID] [FIXED] - Exclude trailing whitespace from newline character on measuring text line width For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [ANDROID] [FIXED] - Exclude trailing whitespace from newline character on measuring text line width Pull Request resolved: #37790 Test Plan: After applying the changes: <img width="300" alt="image" src="https://github.com/facebook/react-native/assets/50919443/bfbf52b0-7e7d-4c89-8958-6af38d8bc1c7"> Code snippet: ``` <Text style={{backgroundColor: 'red', alignSelf: 'flex-start', color: 'white'}}> 1{'\n'} </Text> ``` Reviewed By: cortinico Differential Revision: D46586516 Pulled By: NickGerleman fbshipit-source-id: 3ea9c150ad92082f9b4d1da453ba0ef04b09ce51
1 parent 1f45459 commit 83d7a48

File tree

5 files changed

+27
-7
lines changed

5 files changed

+27
-7
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/FontMetricsUtil.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,14 @@ public static WritableArray getFontMetrics(
4242
X_HEIGHT_MEASUREMENT_TEXT, 0, X_HEIGHT_MEASUREMENT_TEXT.length(), xHeightBounds);
4343
double xHeight = xHeightBounds.height() / AMPLIFICATION_FACTOR / dm.density;
4444
for (int i = 0; i < layout.getLineCount(); i++) {
45+
boolean endsWithNewLine = text.length() > 0 && text.charAt(layout.getLineEnd(i) - 1) == '\n';
46+
float lineWidth = endsWithNewLine ? layout.getLineMax(i) : layout.getLineWidth(i);
4547
Rect bounds = new Rect();
4648
layout.getLineBounds(i, bounds);
4749
WritableMap line = Arguments.createMap();
4850
line.putDouble("x", layout.getLineLeft(i) / dm.density);
4951
line.putDouble("y", bounds.top / dm.density);
50-
line.putDouble("width", layout.getLineWidth(i) / dm.density);
52+
line.putDouble("width", lineWidth / dm.density);
5153
line.putDouble("height", bounds.height() / dm.density);
5254
line.putDouble("descender", layout.getLineDescent(i) / dm.density);
5355
line.putDouble("ascender", -layout.getLineAscent(i) / dm.density);

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,10 @@ public long measure(
135135
layoutWidth = width;
136136
} else {
137137
for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) {
138-
float lineWidth = layout.getLineWidth(lineIndex);
138+
boolean endsWithNewLine =
139+
text.length() > 0 && text.charAt(layout.getLineEnd(lineIndex) - 1) == '\n';
140+
float lineWidth =
141+
endsWithNewLine ? layout.getLineMax(lineIndex) : layout.getLineWidth(lineIndex);
139142
if (lineWidth > layoutWidth) {
140143
layoutWidth = lineWidth;
141144
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,14 @@ protected void onLayout(
267267
// the last offset in the layout will result in an endless loop. Work around
268268
// this bug by avoiding getPrimaryHorizontal in that case.
269269
if (start == text.length() - 1) {
270+
boolean endsWithNewLine =
271+
text.length() > 0 && text.charAt(layout.getLineEnd(line) - 1) == '\n';
272+
float lineWidth = endsWithNewLine ? layout.getLineMax(line) : layout.getLineWidth(line);
270273
placeholderHorizontalPosition =
271274
isRtlParagraph
272275
// Equivalent to `layout.getLineLeft(line)` but `getLineLeft` returns incorrect
273276
// values when the paragraph is RTL and `setSingleLine(true)`.
274-
? textViewWidth - (int) layout.getLineWidth(line)
277+
? textViewWidth - (int) lineWidth
275278
: (int) layout.getLineRight(line) - width;
276279
} else {
277280
// The direction of the paragraph may not be exactly the direction the string is heading

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,10 @@ public static long measureText(
407407
calculatedWidth = width;
408408
} else {
409409
for (int lineIndex = 0; lineIndex < calculatedLineCount; lineIndex++) {
410-
float lineWidth = layout.getLineWidth(lineIndex);
410+
boolean endsWithNewLine =
411+
text.length() > 0 && text.charAt(layout.getLineEnd(lineIndex) - 1) == '\n';
412+
float lineWidth =
413+
endsWithNewLine ? layout.getLineMax(lineIndex) : layout.getLineWidth(lineIndex);
411414
if (lineWidth > calculatedWidth) {
412415
calculatedWidth = lineWidth;
413416
}
@@ -462,11 +465,14 @@ public static long measureText(
462465
// the last offset in the layout will result in an endless loop. Work around
463466
// this bug by avoiding getPrimaryHorizontal in that case.
464467
if (start == text.length() - 1) {
468+
boolean endsWithNewLine =
469+
text.length() > 0 && text.charAt(layout.getLineEnd(line) - 1) == '\n';
470+
float lineWidth = endsWithNewLine ? layout.getLineMax(line) : layout.getLineWidth(line);
465471
placeholderLeftPosition =
466472
isRtlParagraph
467473
// Equivalent to `layout.getLineLeft(line)` but `getLineLeft` returns incorrect
468474
// values when the paragraph is RTL and `setSingleLine(true)`.
469-
? calculatedWidth - layout.getLineWidth(line)
475+
? calculatedWidth - lineWidth
470476
: layout.getLineRight(line) - placeholderWidth;
471477
} else {
472478
// The direction of the paragraph may not be exactly the direction the string is heading

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,10 @@ public static long measureText(
429429
calculatedWidth = width;
430430
} else {
431431
for (int lineIndex = 0; lineIndex < calculatedLineCount; lineIndex++) {
432-
float lineWidth = layout.getLineWidth(lineIndex);
432+
boolean endsWithNewLine =
433+
text.length() > 0 && text.charAt(layout.getLineEnd(lineIndex) - 1) == '\n';
434+
float lineWidth =
435+
endsWithNewLine ? layout.getLineMax(lineIndex) : layout.getLineWidth(lineIndex);
433436
if (lineWidth > calculatedWidth) {
434437
calculatedWidth = lineWidth;
435438
}
@@ -484,12 +487,15 @@ public static long measureText(
484487
// the last offset in the layout will result in an endless loop. Work around
485488
// this bug by avoiding getPrimaryHorizontal in that case.
486489
if (start == text.length() - 1) {
490+
boolean endsWithNewLine =
491+
text.length() > 0 && text.charAt(layout.getLineEnd(line) - 1) == '\n';
492+
float lineWidth = endsWithNewLine ? layout.getLineMax(line) : layout.getLineWidth(line);
487493
placeholderLeftPosition =
488494
isRtlParagraph
489495
// Equivalent to `layout.getLineLeft(line)` but `getLineLeft` returns
490496
// incorrect
491497
// values when the paragraph is RTL and `setSingleLine(true)`.
492-
? calculatedWidth - layout.getLineWidth(line)
498+
? calculatedWidth - lineWidth
493499
: layout.getLineRight(line) - placeholderWidth;
494500
} else {
495501
// The direction of the paragraph may not be exactly the direction the string is

0 commit comments

Comments
 (0)