Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Width measures of Text components using a custom font are wrong #25481

Open
charpeni opened this issue Jul 3, 2019 · 35 comments
Open

Width measures of Text components using a custom font are wrong #25481

charpeni opened this issue Jul 3, 2019 · 35 comments
Labels
Bug Component: Text Contributor A React Native contributor. Platform: Android Android applications. Resolution: Backlog An issue that should be solved at some point, but it's not in the immediate roadmap.

Comments

@charpeni
Copy link
Contributor

charpeni commented Jul 3, 2019

React Native version:

System:
    OS: macOS 10.14.5
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    Memory: 1002.17 MB / 32.00 GB
    Shell: 5.3 - /bin/zsh
  Binaries:
    Node: 10.15.3 - ~/.nvm/versions/node/v10.15.3/bin/node
    Yarn: 1.16.0 - /usr/local/bin/yarn
    npm: 6.4.1 - ~/.nvm/versions/node/v10.15.3/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2
    Android SDK:
      API Levels: 23, 25, 26, 27, 28
      Build Tools: 27.0.3, 28.0.2, 28.0.3, 29.0.0
      System Images: android-28 | Google APIs Intel x86 Atom, android-28 | Google Play Intel x86 Atom, android-29 | Google Play Intel x86 Atom
      Android NDK: 17.2.4988734
  IDEs:
    Android Studio: 3.4 AI-183.6156.11.34.5522156
    Xcode: 10.2.1/10E1001 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.8.6 => 16.8.6
    react-native: 0.60.0 => 0.60.0

⚠️ This is not a regression from RN 0.60, can also be reproduced in RN 0.57.


On Android, some manufacturers — like Samsung, OnePlus, LG, HTC, and others — let you change the default font on your device without having a rooted device, and, of course, rooted devices can also do that.

The <Text> component provided by React Native doesn't seem to measure the layout correctly. Observed cases were when the default font is not Roboto and when a thick font weight is applied.

The result is that on these specifics devices, text components with a thicker font weight will be chopped off (seems to be wrapped in some cases?). It could be a dot missing, or even an entire word.

<Text style={{ fontWeight: 'bold' }}>
  This looks great!
</Text>
Roboto (Default font) OnePlus Slate

Repository to reproduce this.

Workaround

To influence the layout measures of the text component, we can set a border of at least 2 on it. By doing this, the layout will be properly measured, but the text won't be vertically centered.

From there, to vertically center the text, we can subtract the double of the border we previously set as a negative marginBottom. (As seen in the screenshots above).

@gnprice
Copy link
Contributor

gnprice commented Aug 10, 2019

Thanks @charpeni for the detailed report and debugging!

This issue has been around for a couple of years, as #15114. Some information that gradually accumulated there:

  • The issue goes back to RN v0.34.
  • It's not only users who change the default font who are affected -- on some models, the default font that comes with the device triggers this issue. This includes a number of Oppo and OnePlus models.
  • One workaround that seems 100% effective is to avoid setting fontWeight or using bold. This seems like a clue.
  • Some fascinating debugging in this comment finds that:
    • the font weight (and maybe other things) isn't taken into account to determine correct size for the text box.

    • In particular the box gets laid out with what looks to be exactly the right width for the non-bold, default-weight, version of the font. Then the actual text gets placed into it... and it's wider than that, so it doesn't fit.
    • In particular it gets line-wrapped based on the font's actual dimensions (but inside the box sized for its non-bold dimensions), so typically the last word of the line gets moved to the next line... which if it was a single-line box, means it just doesn't appear.

To influence the layout measures of the text component, we can set a border of at least 2 on it. By doing this, the layout will be properly measured

This is an interesting workaround! It would be especially interesting to know whether this workaround keeps working even when the text is long and the border is still small.

That is, does it somehow cause the layout code to go down the right path to use the correct font metrics to make the box as wide as it needs to be? Or does it just add the border itself to the width, and then the text is able to eat into that when it turns out to be wider?


... Looking closely at your screenshots, actually, I have a new observation.

The last three green boxes -- that is, each of the variations on a text box with bold text -- have exactly the same width in the OnePlus Slate case as the Roboto case.

OTOH the first box, with unstyled text, has less width for OnePlus Slate than for Roboto. And in the OnePlus Slate case, it has less width than the (first) bold box.

So it looks as if in the bold case, the size isn't getting based on the non-bold version of the same font... instead it seems to have the right dimensions for bold Roboto.

That would be interesting to confirm or disconfirm with more examples. If true, it may be a strong clue for whoever wants to go into the code to try to track down the actual cause.

@gaodeng
Copy link
Contributor

gaodeng commented Aug 14, 2019

this is duplicate of #15114 please reopen that issue

@stale
Copy link

stale bot commented Nov 12, 2019

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Nov 12, 2019
@carloscuesta
Copy link
Contributor

Not fixed AFAIK

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Nov 12, 2019
@treyp
Copy link

treyp commented Nov 12, 2019

Related, but I've noticed that because the wrapping calculation is wrong on custom fonts, sometimes you will get an extra line where the text renderer thinks the text will wrap but doesn't. There is no way to get rid of it.

Example:

Screen Shot 2019-11-12 at 1 56 35 PM

@YesSkyscrapers
Copy link

YesSkyscrapers commented Jan 21, 2020

Guys, I discovered workaround. You can use <TextInput /> to render texts instead of and this problem is gone.

@YesSkyscrapers
Copy link

New solution
#15114 (comment)
Just change textBreakStrategy to simple fix it

@stale
Copy link

stale bot commented May 31, 2020

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label May 31, 2020
@saadibrahim
Copy link

Still an issue.

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Jun 2, 2020
@stale
Copy link

stale bot commented Aug 31, 2020

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Aug 31, 2020
@gnprice
Copy link
Contributor

gnprice commented Aug 31, 2020 via email

@stale stale bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Aug 31, 2020
@charpeni charpeni added the Resolution: Backlog An issue that should be solved at some point, but it's not in the immediate roadmap. label Sep 2, 2020
@MoOx
Copy link
Contributor

MoOx commented Sep 23, 2020

Is it correct to assume that the bug is located in TextLayoutManager.java inside measureText function ?

public static long measureText(
Context context,
ReadableMap attributedString,
ReadableMap paragraphAttributes,
float width,
YogaMeasureMode widthYogaMeasureMode,
float height,
YogaMeasureMode heightYogaMeasureMode,
ReactTextViewManagerCallback reactTextViewManagerCallback,
@Nullable float[] attachmentsPositions) {
// TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic)
TextPaint textPaint = sTextPaintInstance;
Spannable text;
if (attributedString.hasKey("cacheId")) {
int cacheId = attributedString.getInt("cacheId");
if (sTagToSpannableCache.containsKey(cacheId)) {
text = sTagToSpannableCache.get(cacheId);
} else {
return 0;
}
} else {
text = getOrCreateSpannableForText(context, attributedString, reactTextViewManagerCallback);
}
int textBreakStrategy =
TextAttributeProps.getTextBreakStrategy(
paragraphAttributes.getString(TEXT_BREAK_STRATEGY_KEY));
boolean includeFontPadding =
paragraphAttributes.hasKey(INCLUDE_FONT_PADDING_KEY)
? paragraphAttributes.getBoolean(INCLUDE_FONT_PADDING_KEY)
: DEFAULT_INCLUDE_FONT_PADDING;
if (text == null) {
throw new IllegalStateException("Spannable element has not been prepared in onBeforeLayout");
}
BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint);
float desiredWidth = boring == null ? Layout.getDesiredWidth(text, textPaint) : Float.NaN;
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthYogaMeasureMode == YogaMeasureMode.UNDEFINED || width < 0;
Layout layout =
createLayout(
text, boring, width, widthYogaMeasureMode, includeFontPadding, textBreakStrategy);
int maximumNumberOfLines =
paragraphAttributes.hasKey(MAXIMUM_NUMBER_OF_LINES_KEY)
? paragraphAttributes.getInt(MAXIMUM_NUMBER_OF_LINES_KEY)
: UNSET;
int calculatedLineCount =
maximumNumberOfLines == UNSET || maximumNumberOfLines == 0
? layout.getLineCount()
: Math.min(maximumNumberOfLines, layout.getLineCount());
// Instead of using `layout.getWidth()` (which may yield a significantly larger width for
// text that is wrapping), compute width using the longest line.
float calculatedWidth = 0;
if (widthYogaMeasureMode == YogaMeasureMode.EXACTLY) {
calculatedWidth = width;
} else {
for (int lineIndex = 0; lineIndex < calculatedLineCount; lineIndex++) {
float lineWidth = layout.getLineWidth(lineIndex);
if (lineWidth > calculatedWidth) {
calculatedWidth = lineWidth;
}
}
if (widthYogaMeasureMode == YogaMeasureMode.AT_MOST && calculatedWidth > width) {
calculatedWidth = width;
}
}
float calculatedHeight = height;
if (heightYogaMeasureMode != YogaMeasureMode.EXACTLY) {
calculatedHeight = layout.getLineBottom(calculatedLineCount - 1);
if (heightYogaMeasureMode == YogaMeasureMode.AT_MOST && calculatedHeight > height) {
calculatedHeight = height;
}
}
// Calculate the positions of the attachments (views) that will be rendered inside the Spanned
// Text. The following logic is only executed when a text contains views inside. This
// follows a similar logic than used in pre-fabric (see ReactTextView.onLayout method).
int attachmentIndex = 0;
int lastAttachmentFoundInSpan;
for (int i = 0; i < text.length(); i = lastAttachmentFoundInSpan) {
lastAttachmentFoundInSpan =
text.nextSpanTransition(i, text.length(), TextInlineViewPlaceholderSpan.class);
TextInlineViewPlaceholderSpan[] placeholders =
text.getSpans(i, lastAttachmentFoundInSpan, TextInlineViewPlaceholderSpan.class);
for (TextInlineViewPlaceholderSpan placeholder : placeholders) {
int start = text.getSpanStart(placeholder);
int line = layout.getLineForOffset(start);
boolean isLineTruncated = layout.getEllipsisCount(line) > 0;
// This truncation check works well on recent versions of Android (tested on 5.1.1 and
// 6.0.1) but not on Android 4.4.4. The reason is that getEllipsisCount is buggy on
// Android 4.4.4. Specifically, it incorrectly returns 0 if an inline view is the first
// thing to be truncated.
if (!(isLineTruncated && start >= layout.getLineStart(line) + layout.getEllipsisStart(line))
|| start >= layout.getLineEnd(line)) {
float placeholderWidth = placeholder.getWidth();
float placeholderHeight = placeholder.getHeight();
// Calculate if the direction of the placeholder character is Right-To-Left.
boolean isRtlChar = layout.isRtlCharAt(start);
boolean isRtlParagraph = layout.getParagraphDirection(line) == Layout.DIR_RIGHT_TO_LEFT;
float placeholderLeftPosition;
// There's a bug on Samsung devices where calling getPrimaryHorizontal on
// the last offset in the layout will result in an endless loop. Work around
// this bug by avoiding getPrimaryHorizontal in that case.
if (start == text.length() - 1) {
placeholderLeftPosition =
isRtlParagraph
// Equivalent to `layout.getLineLeft(line)` but `getLineLeft` returns incorrect
// values when the paragraph is RTL and `setSingleLine(true)`.
? calculatedWidth - layout.getLineWidth(line)
: layout.getLineRight(line) - placeholderWidth;
} else {
// The direction of the paragraph may not be exactly the direction the string is heading
// in at the
// position of the placeholder. So, if the direction of the character is the same as the
// paragraph
// use primary, secondary otherwise.
boolean characterAndParagraphDirectionMatch = isRtlParagraph == isRtlChar;
placeholderLeftPosition =
characterAndParagraphDirectionMatch
? layout.getPrimaryHorizontal(start)
: layout.getSecondaryHorizontal(start);
if (isRtlParagraph) {
// Adjust `placeholderLeftPosition` to work around an Android bug.
// The bug is when the paragraph is RTL and `setSingleLine(true)`, some layout
// methods such as `getPrimaryHorizontal`, `getSecondaryHorizontal`, and
// `getLineRight` return incorrect values. Their return values seem to be off
// by the same number of pixels so subtracting these values cancels out the error.
//
// The result is equivalent to bugless versions of
// `getPrimaryHorizontal`/`getSecondaryHorizontal`.
placeholderLeftPosition =
calculatedWidth - (layout.getLineRight(line) - placeholderLeftPosition);
}
if (isRtlChar) {
placeholderLeftPosition -= placeholderWidth;
}
}
// Vertically align the inline view to the baseline of the line of text.
float placeholderTopPosition = layout.getLineBaseline(line) - placeholderHeight;
int attachmentPosition = attachmentIndex * 2;
// The attachment array returns the positions of each of the attachments as
attachmentsPositions[attachmentPosition] =
PixelUtil.toSPFromPixel(placeholderTopPosition);
attachmentsPositions[attachmentPosition + 1] =
PixelUtil.toSPFromPixel(placeholderLeftPosition);
attachmentIndex++;
}
}
}

MoOx added a commit to MoOx/LifeTime that referenced this issue Feb 1, 2021
Trick is: DONT rely on fontWeight... (like in 1ac5a99)
Instead use fontFamily. It seems fontWeight on android without an explicit fontFamily just sucks.

Ref facebook/react-native#25481

Closes #27
@MoOx
Copy link
Contributor

MoOx commented Feb 1, 2021

I discovered a "trick" to avoid this kind of issue: don't rely on fontWeight on Android alone! Instead use fontFamily.
Android Roboto have only 6 variants, same for OnePlus Slate.
I have spend a few hours trying to find an acceptable combo on stock Android (using a Pixel 3), ColorsOS (Oppo) and OxygenOS (OnePlus)

You can safely (on Android) use the following name instead of weight

  • sans-serif-thin (= 100/200 depending on android custom font)
  • sans-serif-light (=300)
  • sans-serif / sans-serif-regular (400) (note that OnePlus Slate doesn't handle sans-serif like sans-serif-regular, when used with a weight)
  • sans-serif-medium (500)
  • sans-serif-bold (600/700)
  • sans-serif-black (800/900)

Note that fontWeight coupled with a fontFamily give better result on Android, if you want to rely on OS font.

Here is a stylesheet you can use safely to think about "weight" and forget about the trick

  // iOS: no comment, weight are perfect
  // Android: only has 100/300/400/500/700/900
  // it's a total mess depanding on brands...
  // more details here https://github.com/MoOx/LifeTime/blob/5ce54e13096642da02e46bf54b48548f7b5b1890/src/components/shareable/Theme.res#L120-L168
  // ios | st. and. | oppo | 1+
  // 100 | 100 | 100 | 200
  // 200 | 300 | 300 | 300
  // 300 | 300 | 300 | 300
  // 400 | 400 | 400 | 400
  // 500 | 500 | 500 | 500
  // 600 | 500 | 500 | 500
  // 700 | 700 | 700 | 700
  // 800 | 700 | 700 | 900
  // 900 | 800 | 800 | 900
const weightStyles = StyleSheet.create({
  "weight100": Platform.OS === "android"
    ? {fontFamily: "sans-serif-thin", fontWeight: "100"}
    : {fontWeight: "100"},
  "weight200": Platform.OS === "android"
    ? {fontFamily: "sans-serif-light", fontWeight: "200"}
    : {fontWeight: "200"},
  "weight300": Platform.OS === "android"
    ? {fontFamily: "sans-serif-light", fontWeight: "300"}
    : {fontWeight: "300"},
  "weight400": Platform.OS === "android"
    ? {fontFamily: "sans-serif", fontWeight: "400"}
    : {fontWeight: "400"},
  "weight500": Platform.OS === "android"
    ? {fontFamily: "sans-serif-medium", fontWeight: "500"}
    : {fontWeight: "500"},
  "weight600": Platform.OS === "android"
    ? {fontFamily: "sans-serif-medium", fontWeight: "600"}
    : {fontWeight: "600"},
  // reminder: oneplus handle sans-serif-regular / 700 != sans-serif / 700 !!
  "weight700": Platform.OS === "android"
    ? {fontFamily: "sans-serif-regular", fontWeight: "700"}
    : {fontWeight: "700"},
  "weight800": Platform.OS === "android"
    ? {fontFamily: "sans-serif-bold", fontWeight: "700"}
    : {fontWeight: "800"},
  "weight900": Platform.OS === "android"
    ? {fontFamily: "sans-serif-black", fontWeight: "900"}
    : {fontWeight: "900"},
})

Just to tag issues so people would find the workaround: #15114 #25258 #29259 #18258 #17629 #21729

@dumathane
Copy link

Still an issue. Any updates?

@dumathane
Copy link

Hi there! Hoping someone can give me some direction on a potential solution to this one. 'numberOfLines' property is basically useless for android.

Thanks for reviewing!

@dumathane
Copy link

Has anyone had a chance to look at this yet? An update would be appreciated! Thank you!

@dumathane
Copy link

Hello again! Any update on this still reproducible issue?

Thanks!

@danilobuerger
Copy link
Contributor

Hi @dumathane, it looks like this issue is clearly important to you. You could think about sponsoring / paying someone to fix it for you as nobody else is going to fix it apparently (this issue is already more than 2 years old).

@JoniVR
Copy link

JoniVR commented Jun 24, 2022

For anyone running into this, I can reproduce this issue on any recent android emulator by enabling "Bold text" under Accessibility > Text and display, which seems like this is not just an issue for some brands, but an accessibility issue in general..

The theory of the box around the text being incorrectly calculated seems pretty accurate to me.

facebook-github-bot pushed a commit that referenced this issue Oct 17, 2022
Summary:
- **[9fb581c7c](facebook/react@9fb581c7c )**: Refactor: merge duplicate imports ([#25489](facebook/react#25489)) //<c0dedance>//
- **[bc358362a](facebook/react@bc358362a )**: [Flight] Improve Error Messages when Invalid Object is Passed to Client/Host Components ([#25492](facebook/react#25492)) //<Sebastian Markbåge>//
- **[780eacd40](facebook/react@780eacd40 )**: Flow upgrade to 0.190 ([#25483](facebook/react#25483)) //<Jan Kassens>//
- **[54f0e0f73](facebook/react@54f0e0f73 )**: Scaffolding for react-dom/unstable_external-server-runtime ([#25482](facebook/react#25482)) //<Andrew Clark>//
- **[0eaca3756](facebook/react@0eaca3756 )**: Add script to generate inline Fizz runtime ([#25481](facebook/react#25481)) //<Andrew Clark>//
- **[69c7246d9](facebook/react@69c7246d9 )**: Initialize useMemoCache with sentinel values ([#25465](facebook/react#25465)) //<Joseph Savona>//
- **[3b814327e](facebook/react@3b814327e )**: Allow Async Functions to be used in Server Components ([#25479](facebook/react#25479)) //<Sebastian Markbåge>//
- **[a6bf46689](facebook/react@a6bf46689 )**: Extract Fizz instruction set to build macro ([#25457](facebook/react#25457)) //<Andrew Clark>//
- **[ea5bc6bac](facebook/react@ea5bc6bac )**: [React Native FB] dynamic feature flag for ref access warning ([#25471](facebook/react#25471)) //<Jan Kassens>//
- **[08d035bc8](facebook/react@08d035bc8 )**: Remove Shallow Renderer Tests ([#25475](facebook/react#25475)) //<Sebastian Markbåge>//
- **[a8c16a004](facebook/react@a8c16a004 )**: Split Cache into its own Dispatcher ([#25474](facebook/react#25474)) //<Sebastian Markbåge>//
- **[2cf4352e1](facebook/react@2cf4352e1 )**: Implement HostSingleton Fiber type ([#25426](facebook/react#25426)) //<Josh Story>//
- **[aa9988e5e](facebook/react@aa9988e5e )**: Server render fork for react-dom ([#25436](facebook/react#25436)) //<Josh Story>//
- **[513417d69](facebook/react@513417d69 )**: Return lastNonHostInstance in getInspectorDataForInstance for devtools ([#25441](facebook/react#25441)) //<Tianyu Yao>//
- **[5d60a0b84](facebook/react@5d60a0b84 )**: Bugfix: LegacyHidden shouldn't defer effects ([#25442](facebook/react#25442)) //<Andrew Clark>//
- **[618388bc3](facebook/react@618388bc3 )**: [Float] Support script preloads ([#25432](facebook/react#25432)) //<Josh Story>//
- **[2872a26e1](facebook/react@2872a26e1 )**: track resources in different roots separately ([#25388](facebook/react#25388)) //<Josh Story>//
- **[ea04a486a](facebook/react@ea04a486a )**: Flow: remove unused suppressions ([#25424](facebook/react#25424)) //<Jan Kassens>//
- **[9813edef2](facebook/react@9813edef2 )**: Flow upgrade to 0.188 //<Jan Kassens>//
- **[3b6826ed9](facebook/react@3b6826ed9 )**: Flow: inference_mode=constrain_writes //<Jan Kassens>//
- **[aed33a49c](facebook/react@aed33a49c )**: Flow upgrade to 0.185 //<Jan Kassens>//
- **[f02a5f5c7](facebook/react@f02a5f5c7 )**: Flow upgrade to 0.182 //<Jan Kassens>//
- **[72593f008](facebook/react@72593f008 )**: Flow upgrade to 0.176 //<Jan Kassens>//
- **[46d40f306](facebook/react@46d40f306 )**: Flow upgrade to 0.175 //<Jan Kassens>//
- **[1089faf0d](facebook/react@1089faf0d )**: Flow: run codemod to remove existential type //<Jan Kassens>//
- **[3fd9bd8e7](facebook/react@3fd9bd8e7 )**: Add RulesOfHooks support for `use` //<Lauren Tan>//
- **[338e6a967](facebook/react@338e6a967 )**: Flow upgrade to 0.155 //<Jan Kassens>//
- **[8bc95bb3c](facebook/react@8bc95bb3c )**: Flow upgrade to 0.154 //<Jan Kassens>//
- **[9f8a98a39](facebook/react@9f8a98a39 )**: Flow upgrade to 0.153 //<Jan Kassens>//
- **[64fe791be](facebook/react@64fe791be )**: Flow upgrade to 0.146 //<Jan Kassens>//
- **[d3c6c16a0](facebook/react@d3c6c16a0 )**: Flow upgrade to 0.145 //<Jan Kassens>//
- **[00a2f8150](facebook/react@00a2f8150 )**: Flow upgrade to 0.143 //<Jan Kassens>//
- **[0a3072278](facebook/react@0a3072278 )**: Flow: complete types first migration ([#25389](facebook/react#25389)) //<Jan Kassens>//
- **[bcc05671f](facebook/react@bcc05671f )**: Flow: types first in shared ([#25343](facebook/react#25343)) //<Jan Kassens>//
- **[b1f34aa30](facebook/react@b1f34aa30 )**: Flow: types first in react-native-renderer ([#25363](facebook/react#25363)) //<Jan Kassens>//
- **[9143864ae](facebook/react@9143864ae )**: Flow: well formed exports for smaller packages ([#25361](facebook/react#25361)) //<Jan Kassens>//
- **[21a851e03](facebook/react@21a851e03 )**: Fix devtools typos and grammar ([#24587](facebook/react#24587)) //<Alexandru Tasica>//
- **[cfafeb685](facebook/react@cfafeb685 )**: Remove extra space in Wedge.js ([#24611](facebook/react#24611)) //<Kerim Büyükakyüz>//
- **[9c3de25e1](facebook/react@9c3de25e1 )**: Flow: types first in reconciler ([#25362](facebook/react#25362)) //<Jan Kassens>//
- **[7b25b961d](facebook/react@7b25b961d )**: [Fizz/Float] Float for stylesheet resources ([#25243](facebook/react#25243)) //<Josh Story>//
- **[4c016e7aa](facebook/react@4c016e7aa )**: Refactor: use  property shorthand ([#25366](facebook/react#25366)) //<zhangrenyang>//
- **[06066c1a5](facebook/react@06066c1a5 )**: Make RulesOfHooks-test more consistent with ExhaustiveDeps-test //<Lauren Tan>//
- **[49ae0fad8](facebook/react@49ae0fad8 )**: Fix RulesOfHooks test case indentation //<Lauren Tan>//
- **[abbbdf4ce](facebook/react@abbbdf4ce )**: Put modern StrictMode behind a feature flag ([#25365](facebook/react#25365)) //<Samuel Susla>//
- **[434110390](facebook/react@434110390 )**: ReactHooks.js - delete emptyObject ([#25031](facebook/react#25031)) //<Igor Berlenko>//
- **[31400ce29](facebook/react@31400ce29 )**: Refactor: merge duplicate imports ([#25364](facebook/react#25364)) //<jerry-lllman>//
- **[3517bd9f7](facebook/react@3517bd9f7 )**: Refactor useEvent ([#25336](facebook/react#25336)) //<Lauren Tan>//
- **[6cf06a929](facebook/react@6cf06a929 )**: Remove outdated comments. ([#24464](facebook/react#24464)) //<zhangenming>//
- **[20a257c25](facebook/react@20a257c25 )**: Refactor: more word doubles removed ([#25352](facebook/react#25352)) //<Vic Graf>//
- **[8cadcffd5](facebook/react@8cadcffd5 )**: Fix typo: reconcilation -> reconciliation ([#25355](facebook/react#25355)) //<zhangrenyang>//
- **[ebbe599a2](facebook/react@ebbe599a2 )**: Fix EventListener fork ([#25347](facebook/react#25347)) //<Sebastian Markbåge>//
- **[97d75c9c8](facebook/react@97d75c9c8 )**: Move react-dom implementation files to react-dom-bindings ([#25345](facebook/react#25345)) //<Sebastian Markbåge>//
- **[3de926449](facebook/react@3de926449 )**: [Fizz] experimental_useEvent ([#25325](facebook/react#25325)) //<dan>//
- **[5b59dd640](facebook/react@5b59dd640 )**: Fix duplicate words tests ([#25333](facebook/react#25333)) //<Vic Graf>//
- **[cb5084d1c](facebook/react@cb5084d1c )**: [ESLint] Check useEvent references instead ([#25319](facebook/react#25319)) //<Lauren Tan>//
- **[c89a83695](facebook/react@c89a83695 )**: Update RulesOfHooks with useEvent rules ([#25285](facebook/react#25285)) //<Lauren Tan>//
- **[efc6a08e9](facebook/react@efc6a08e9 )**: [Flight] Implement error digests for Flight runtime and expose errorInfo in getDerivedStateFromError ([#25302](facebook/react#25302)) //<Josh Story>//
- **[c1d414d75](facebook/react@c1d414d75 )**: Add ref to Offscreen component ([#25254](facebook/react#25254)) //<Samuel Susla>//
- **[135e33c95](facebook/react@135e33c95 )**: Flow: typing of Scheduler ([#25317](facebook/react#25317)) //<Jan Kassens>//
- **[cc8cb145f](facebook/react@cc8cb145f )**: Flow: add some missing types in react-reconciler ([#25316](facebook/react#25316)) //<Jan Kassens>//
- **[112d0498c](facebook/react@112d0498c )**: [Fizz] Move digest from errorInfo to Error instance ([#25313](facebook/react#25313)) //<Josh Story>//
- **[d1bb1c586](facebook/react@d1bb1c586 )**: Fix memory leak after repeated setState bailouts ([#25309](facebook/react#25309)) //<Andrew Clark>//

Changelog:
[General][Changed] - React Native sync for revisions 0cac4d5...9fb581c

jest_e2e[run_all_tests]

Reviewed By: yungsters

Differential Revision: D40383219

fbshipit-source-id: dc2a44bd05df041e0c7f2e1060640b1d2c372187
@paulolp7
Copy link

Is there any update on this problem?
I had the same problem on a MOTOROLA EDGE 20 PRO with Android 12

@jcdhlzq
Copy link
Contributor

jcdhlzq commented May 10, 2023

This issue has been reproduced and verified to be fixed in the pr #37271.

OlimpiaZurek pushed a commit to OlimpiaZurek/react-native that referenced this issue May 22, 2023
Summary:
- **[9fb581c7c](facebook/react@9fb581c7c )**: Refactor: merge duplicate imports ([facebook#25489](facebook/react#25489)) //<c0dedance>//
- **[bc358362a](facebook/react@bc358362a )**: [Flight] Improve Error Messages when Invalid Object is Passed to Client/Host Components ([facebook#25492](facebook/react#25492)) //<Sebastian Markbåge>//
- **[780eacd40](facebook/react@780eacd40 )**: Flow upgrade to 0.190 ([facebook#25483](facebook/react#25483)) //<Jan Kassens>//
- **[54f0e0f73](facebook/react@54f0e0f73 )**: Scaffolding for react-dom/unstable_external-server-runtime ([facebook#25482](facebook/react#25482)) //<Andrew Clark>//
- **[0eaca3756](facebook/react@0eaca3756 )**: Add script to generate inline Fizz runtime ([facebook#25481](facebook/react#25481)) //<Andrew Clark>//
- **[69c7246d9](facebook/react@69c7246d9 )**: Initialize useMemoCache with sentinel values ([facebook#25465](facebook/react#25465)) //<Joseph Savona>//
- **[3b814327e](facebook/react@3b814327e )**: Allow Async Functions to be used in Server Components ([facebook#25479](facebook/react#25479)) //<Sebastian Markbåge>//
- **[a6bf46689](facebook/react@a6bf46689 )**: Extract Fizz instruction set to build macro ([facebook#25457](facebook/react#25457)) //<Andrew Clark>//
- **[ea5bc6bac](facebook/react@ea5bc6bac )**: [React Native FB] dynamic feature flag for ref access warning ([facebook#25471](facebook/react#25471)) //<Jan Kassens>//
- **[08d035bc8](facebook/react@08d035bc8 )**: Remove Shallow Renderer Tests ([facebook#25475](facebook/react#25475)) //<Sebastian Markbåge>//
- **[a8c16a004](facebook/react@a8c16a004 )**: Split Cache into its own Dispatcher ([facebook#25474](facebook/react#25474)) //<Sebastian Markbåge>//
- **[2cf4352e1](facebook/react@2cf4352e1 )**: Implement HostSingleton Fiber type ([facebook#25426](facebook/react#25426)) //<Josh Story>//
- **[aa9988e5e](facebook/react@aa9988e5e )**: Server render fork for react-dom ([facebook#25436](facebook/react#25436)) //<Josh Story>//
- **[513417d69](facebook/react@513417d69 )**: Return lastNonHostInstance in getInspectorDataForInstance for devtools ([facebook#25441](facebook/react#25441)) //<Tianyu Yao>//
- **[5d60a0b84](facebook/react@5d60a0b84 )**: Bugfix: LegacyHidden shouldn't defer effects ([facebook#25442](facebook/react#25442)) //<Andrew Clark>//
- **[618388bc3](facebook/react@618388bc3 )**: [Float] Support script preloads ([facebook#25432](facebook/react#25432)) //<Josh Story>//
- **[2872a26e1](facebook/react@2872a26e1 )**: track resources in different roots separately ([facebook#25388](facebook/react#25388)) //<Josh Story>//
- **[ea04a486a](facebook/react@ea04a486a )**: Flow: remove unused suppressions ([facebook#25424](facebook/react#25424)) //<Jan Kassens>//
- **[9813edef2](facebook/react@9813edef2 )**: Flow upgrade to 0.188 //<Jan Kassens>//
- **[3b6826ed9](facebook/react@3b6826ed9 )**: Flow: inference_mode=constrain_writes //<Jan Kassens>//
- **[aed33a49c](facebook/react@aed33a49c )**: Flow upgrade to 0.185 //<Jan Kassens>//
- **[f02a5f5c7](facebook/react@f02a5f5c7 )**: Flow upgrade to 0.182 //<Jan Kassens>//
- **[72593f008](facebook/react@72593f008 )**: Flow upgrade to 0.176 //<Jan Kassens>//
- **[46d40f306](facebook/react@46d40f306 )**: Flow upgrade to 0.175 //<Jan Kassens>//
- **[1089faf0d](facebook/react@1089faf0d )**: Flow: run codemod to remove existential type //<Jan Kassens>//
- **[3fd9bd8e7](facebook/react@3fd9bd8e7 )**: Add RulesOfHooks support for `use` //<Lauren Tan>//
- **[338e6a967](facebook/react@338e6a967 )**: Flow upgrade to 0.155 //<Jan Kassens>//
- **[8bc95bb3c](facebook/react@8bc95bb3c )**: Flow upgrade to 0.154 //<Jan Kassens>//
- **[9f8a98a39](facebook/react@9f8a98a39 )**: Flow upgrade to 0.153 //<Jan Kassens>//
- **[64fe791be](facebook/react@64fe791be )**: Flow upgrade to 0.146 //<Jan Kassens>//
- **[d3c6c16a0](facebook/react@d3c6c16a0 )**: Flow upgrade to 0.145 //<Jan Kassens>//
- **[00a2f8150](facebook/react@00a2f8150 )**: Flow upgrade to 0.143 //<Jan Kassens>//
- **[0a3072278](facebook/react@0a3072278 )**: Flow: complete types first migration ([facebook#25389](facebook/react#25389)) //<Jan Kassens>//
- **[bcc05671f](facebook/react@bcc05671f )**: Flow: types first in shared ([facebook#25343](facebook/react#25343)) //<Jan Kassens>//
- **[b1f34aa30](facebook/react@b1f34aa30 )**: Flow: types first in react-native-renderer ([facebook#25363](facebook/react#25363)) //<Jan Kassens>//
- **[9143864ae](facebook/react@9143864ae )**: Flow: well formed exports for smaller packages ([facebook#25361](facebook/react#25361)) //<Jan Kassens>//
- **[21a851e03](facebook/react@21a851e03 )**: Fix devtools typos and grammar ([facebook#24587](facebook/react#24587)) //<Alexandru Tasica>//
- **[cfafeb685](facebook/react@cfafeb685 )**: Remove extra space in Wedge.js ([facebook#24611](facebook/react#24611)) //<Kerim Büyükakyüz>//
- **[9c3de25e1](facebook/react@9c3de25e1 )**: Flow: types first in reconciler ([facebook#25362](facebook/react#25362)) //<Jan Kassens>//
- **[7b25b961d](facebook/react@7b25b961d )**: [Fizz/Float] Float for stylesheet resources ([facebook#25243](facebook/react#25243)) //<Josh Story>//
- **[4c016e7aa](facebook/react@4c016e7aa )**: Refactor: use  property shorthand ([facebook#25366](facebook/react#25366)) //<zhangrenyang>//
- **[06066c1a5](facebook/react@06066c1a5 )**: Make RulesOfHooks-test more consistent with ExhaustiveDeps-test //<Lauren Tan>//
- **[49ae0fad8](facebook/react@49ae0fad8 )**: Fix RulesOfHooks test case indentation //<Lauren Tan>//
- **[abbbdf4ce](facebook/react@abbbdf4ce )**: Put modern StrictMode behind a feature flag ([facebook#25365](facebook/react#25365)) //<Samuel Susla>//
- **[434110390](facebook/react@434110390 )**: ReactHooks.js - delete emptyObject ([facebook#25031](facebook/react#25031)) //<Igor Berlenko>//
- **[31400ce29](facebook/react@31400ce29 )**: Refactor: merge duplicate imports ([facebook#25364](facebook/react#25364)) //<jerry-lllman>//
- **[3517bd9f7](facebook/react@3517bd9f7 )**: Refactor useEvent ([facebook#25336](facebook/react#25336)) //<Lauren Tan>//
- **[6cf06a929](facebook/react@6cf06a929 )**: Remove outdated comments. ([facebook#24464](facebook/react#24464)) //<zhangenming>//
- **[20a257c25](facebook/react@20a257c25 )**: Refactor: more word doubles removed ([facebook#25352](facebook/react#25352)) //<Vic Graf>//
- **[8cadcffd5](facebook/react@8cadcffd5 )**: Fix typo: reconcilation -> reconciliation ([facebook#25355](facebook/react#25355)) //<zhangrenyang>//
- **[ebbe599a2](facebook/react@ebbe599a2 )**: Fix EventListener fork ([facebook#25347](facebook/react#25347)) //<Sebastian Markbåge>//
- **[97d75c9c8](facebook/react@97d75c9c8 )**: Move react-dom implementation files to react-dom-bindings ([facebook#25345](facebook/react#25345)) //<Sebastian Markbåge>//
- **[3de926449](facebook/react@3de926449 )**: [Fizz] experimental_useEvent ([facebook#25325](facebook/react#25325)) //<dan>//
- **[5b59dd640](facebook/react@5b59dd640 )**: Fix duplicate words tests ([facebook#25333](facebook/react#25333)) //<Vic Graf>//
- **[cb5084d1c](facebook/react@cb5084d1c )**: [ESLint] Check useEvent references instead ([facebook#25319](facebook/react#25319)) //<Lauren Tan>//
- **[c89a83695](facebook/react@c89a83695 )**: Update RulesOfHooks with useEvent rules ([facebook#25285](facebook/react#25285)) //<Lauren Tan>//
- **[efc6a08e9](facebook/react@efc6a08e9 )**: [Flight] Implement error digests for Flight runtime and expose errorInfo in getDerivedStateFromError ([facebook#25302](facebook/react#25302)) //<Josh Story>//
- **[c1d414d75](facebook/react@c1d414d75 )**: Add ref to Offscreen component ([facebook#25254](facebook/react#25254)) //<Samuel Susla>//
- **[135e33c95](facebook/react@135e33c95 )**: Flow: typing of Scheduler ([facebook#25317](facebook/react#25317)) //<Jan Kassens>//
- **[cc8cb145f](facebook/react@cc8cb145f )**: Flow: add some missing types in react-reconciler ([facebook#25316](facebook/react#25316)) //<Jan Kassens>//
- **[112d0498c](facebook/react@112d0498c )**: [Fizz] Move digest from errorInfo to Error instance ([facebook#25313](facebook/react#25313)) //<Josh Story>//
- **[d1bb1c586](facebook/react@d1bb1c586 )**: Fix memory leak after repeated setState bailouts ([facebook#25309](facebook/react#25309)) //<Andrew Clark>//

Changelog:
[General][Changed] - React Native sync for revisions 0cac4d5...9fb581c

jest_e2e[run_all_tests]

Reviewed By: yungsters

Differential Revision: D40383219

fbshipit-source-id: dc2a44bd05df041e0c7f2e1060640b1d2c372187
Copy link

github-actions bot commented Nov 6, 2023

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Nov 6, 2023
@lexicalninja
Copy link

PR for fix is still open, waiting on merge of that PR to check solution. Do not close

@github-actions github-actions bot removed the Stale There has been a lack of activity on this issue and it may be closed soon. label Nov 7, 2023
@fabOnReact
Copy link
Contributor

it is a similar issue to #41770. The measure logic which uses Static or Boring Layout, probably does not take in consideration that you are using custom fonts. Custom Fonts will render with different ascent,descent and maybe event width than normal font.. So measure calculates the wrong width and maybe even height.

@fabOnReact
Copy link
Contributor

Hello,

Thanks for the issue. I have been contributing to facebook/react-native for 4 years and specialize in the Text/TextInput components. I currently have 58 facebook/react-native PRs:

https://github.com/facebook/react-native/pulls?q=is%3Apr+author%3Afabriziobertoglio1987+

This is the suggested approach from the react-native core team (see this discussion):

I'm publishing several fixes for Text and TextInput component in a separate library react-native-improved.

  • The Component is based on ReactTextView, it is the same implementation from react-native.
  • It will include several bug fixes.
  • You can use the library until the PR is merged and released with react-native.
  • You can use side by side both components from react-native and react-native-improved, depending on where you need the fix.
  • I will also publish the PR to facebook/react-native (daily fixes and releases).

The advantages would be:

  • Increased engagement with the community, issues are quickly fixed.
  • No limitations when merging PRs (react-native main branch is used on facebook marketplace).
  • Only Meta employees can merge and review facebook/react-native PRs.
  • Allows us to further experiment and develop react-native.

What do you think about this? Should I keep working on this? Thanks

@fabOnReact
Copy link
Contributor

I believe this issue is fixed with #41770

@fabOnReact
Copy link
Contributor

fabOnReact commented Feb 1, 2024

I tested the example on the main branch using custom font one plus slate. I don't have the OnePlus Device, but I installed OneSlate Plus as custom font and applied the fix for #42116 to use fontWeight: "bold" with the custom font.

As you can see from the below screenshot, I can not reproduce the issue on main branch.

The last text uses fontFamily harry potter, to prove that font-family works.

CLICK TO OPEN TESTS RESULTS

Screenshot 2024-02-01 at 5 04 41 PM Screenshot 2024-02-01 at 5 10 23 PM Screenshot 2024-02-01 at 5 11 06 PM

cc @cortinico

@BuddhaNag12
Copy link

Related, but I've noticed that because the wrapping calculation is wrong on custom fonts, sometimes you will get an extra line where the text renderer thinks the text will wrap but doesn't. There is no way to get rid of it.

Example:

Screen Shot 2019-11-12 at 1 56 35 PM

is this issue resolved?

@react-native-bot
Copy link
Collaborator

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@react-native-bot react-native-bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Aug 13, 2024
@gnprice
Copy link
Contributor

gnprice commented Aug 13, 2024

Stale-bot please go away; there's no reason to believe the bug has been fixed.

@react-native-bot react-native-bot removed Stale There has been a lack of activity on this issue and it may be closed soon. labels Aug 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Component: Text Contributor A React Native contributor. Platform: Android Android applications. Resolution: Backlog An issue that should be solved at some point, but it's not in the immediate roadmap.
Projects
None yet
Development

No branches or pull requests