From 3d0cf8dcf88c529f262ab91af0e0c0b58839c4b5 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 27 Apr 2021 19:43:56 -0700 Subject: [PATCH] Fix IllegalArgumentException when creating layout with negative width Summary: This diff fixes an IllegalArgumentException that's thrown when creating layout with negative width. This is not a new bug, but it started firing recently (probably caused by a change in text being measured) stacktrace: ``` stack_trace: java.lang.IllegalArgumentException: Layout: -2 < 0 at android.text.Layout.(Layout.java:265) at android.text.Layout.(Layout.java:241) at android.text.BoringLayout.(BoringLayout.java:179) at android.text.BoringLayout.make(BoringLayout.java:61) at com.facebook.react.views.text.TextLayoutManager.createLayout(TextLayoutManager.java:290) at com.facebook.react.views.text.TextLayoutManager.measureText(TextLayoutManager.java:384) [inlined] at com.facebook.react.views.text.ReactTextViewManager.measure(ReactTextViewManager.java:172) [inlined] at com.facebook.react.fabric.mounting.MountingManager.measure(MountingManager.java:349) [inlined] at com.facebook.react.fabric.FabricUIManager.measure(FabricUIManager.java:461) at com.facebook.react.bridge.queue.NativeRunnable.run(Native Method) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923) ``` changelog: [internal] internal Reviewed By: JoshuaGross Differential Revision: D28015820 fbshipit-source-id: 129cd2a4c492d95d57fcdf3883b967a0b5df639a --- .../react/views/text/ReactTextShadowNode.java | 9 ++++++++- .../facebook/react/views/text/TextLayoutManager.java | 11 ++++++++++- .../react/views/text/TextLayoutManagerMapBuffer.java | 10 +++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java index 53111f41275..f350bccf872 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java @@ -231,7 +231,14 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode { // than the width of the text. layout = BoringLayout.make( - text, textPaint, boring.width, alignment, 1.f, 0.f, boring, mIncludeFontPadding); + text, + textPaint, + Math.max(boring.width, 0), + alignment, + 1.f, + 0.f, + boring, + mIncludeFontPadding); } else { // Is used for multiline, boring text and the width is known. diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java index cae80df050d..bbb57f87e88 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java @@ -24,6 +24,8 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; +import com.facebook.react.bridge.ReactNoCrashSoftException; +import com.facebook.react.bridge.ReactSoftException; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableNativeMap; @@ -284,13 +286,20 @@ public class TextLayoutManager { } } else if (boring != null && (unconstrainedWidth || boring.width <= width)) { + int boringLayoutWidth = boring.width; + if (boring.width < 0) { + ReactSoftException.logSoftException( + TAG, new ReactNoCrashSoftException("Text width is invalid: " + boring.width)); + boringLayoutWidth = 0; + } + // Is used for single-line, boring text when the width is either unknown or bigger // than the width of the text. layout = BoringLayout.make( text, textPaint, - boring.width, + boringLayoutWidth, Layout.Alignment.ALIGN_NORMAL, 1.f, 0.f, diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java index 7af9a540f86..422d986a636 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java @@ -24,6 +24,8 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; +import com.facebook.react.bridge.ReactNoCrashSoftException; +import com.facebook.react.bridge.ReactSoftException; import com.facebook.react.bridge.WritableArray; import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.common.mapbuffer.ReadableMapBuffer; @@ -298,13 +300,19 @@ public class TextLayoutManagerMapBuffer { } } else if (boring != null && (unconstrainedWidth || boring.width <= width)) { + int boringLayoutWidth = boring.width; + if (boring.width < 0) { + ReactSoftException.logSoftException( + TAG, new ReactNoCrashSoftException("Text width is invalid: " + boring.width)); + boringLayoutWidth = 0; + } // Is used for single-line, boring text when the width is either unknown or bigger // than the width of the text. layout = BoringLayout.make( text, textPaint, - boring.width, + boringLayoutWidth, Layout.Alignment.ALIGN_NORMAL, 1.f, 0.f,