Skip to content

Parse textDecorationLine without compiling a regex on Android - #59733

Merged
Abbondanzo merged 1 commit into
react:mainfrom
hryhoriiK97:android-text-decoration-line-split
Nov 2, 2026
Merged

Abbondanzo merged 1 commit into
react:mainfrom
hryhoriiK97:android-text-decoration-line-split

Conversation

@hryhoriiK97

Copy link
Copy Markdown
Contributor

Summary:

On Android, TextAttributeProps.setTextDecorationLine splits the textDecorationLine value with "-".toRegex(). That compiles a new java.util.regex.Pattern on every call. The call happens for every text fragment that has a textDecorationLine (underlines, strikethroughs, links), each time its text is laid out on the JS thread.

The serialized value is none, underline, strikethrough or underline-strikethrough, so splitting on the '-' character gives the same parts without a regex. The old code also dropped trailing empty parts, but the loop only compares against underline and strikethrough, so they make no difference.

This adds no state or cache. It only helps text with a textDecorationLine.

Changelog:

[ANDROID] [CHANGED] - Parse textDecorationLine without compiling a regex

Test Plan:

Unit test: TextAttributePropsTest gets mapBufferSetsTextDecorationLine, which checks none, underline, strikethrough and underline-strikethrough through TextAttributeProps.fromMapBuffer. It also passes without this change, because the behavior is the same.

./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest --tests 'com.facebook.react.views.text.*'

102 tests, 0 failures. ktfmt reports no changes in the two files.

Measurements: two release RNTester APKs built from this commit's base, one with and one without this change, on a Galaxy A16 and a Pixel 9a (both Android 16), compiled with cmd package compile -m speed. Both APKs have the same temporary benchmark edits. A Playground screen shows the rows and changes some of them every 100 ms for 20 s (10 of 60 underlined rows, 20 of 100 rows with no textDecorationLine), with new strings each time so the measure cache doesn't hide the work. Each run is a fresh process, in A/B/B/A order, twice, so 4 runs per APK. JS thread CPU comes from /proc/<pid>/task/<tid>/stat. The table shows the median per changed row, with the range in brackets.

Row Phone Without this change With this change Change
7 text fragments, one an underlined link Galaxy A16 1840 µs (1820–1845) 1772 µs (1755–1805) −3.7%
7 text fragments, one an underlined link Pixel 9a 2432 µs (2310–2545) 2330 µs (2265–2375) −4.2%
About 4 fragments, no textDecorationLine Galaxy A16 940 µs (932–948) 942 µs (940–960) no change
About 4 fragments, no textDecorationLine Pixel 9a 1256 µs (1220–1278) 1230 µs (1225–1232) no clear change

The ranges for the underlined row overlap on the Pixel 9a. The row with no textDecorationLine never reaches this code, so it serves as a control.

The row measurements above are all from this commit's base. On an older base, a simpleperf profile of a similar rich text list on a moto g57 power showed Pattern.compile and Pattern.matcher under TextAttributeProps.fromMapBuffer at 2.9% of the JS thread.

Not measured: the main thread, because this code runs on the JS thread when text is laid out.

🤖 Generated with Claude Code

TextAttributeProps.setTextDecorationLine split the value with
"-".toRegex(), which compiles a java.util.regex.Pattern for every text
fragment that has a textDecorationLine, each time the text is laid out.
Splitting on the '-' character gives the same parts without a regex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 1, 2026
@facebook-github-tools facebook-github-tools Bot added p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels Nov 1, 2026
@meta-codesync

meta-codesync Bot commented Nov 1, 2026

Copy link
Copy Markdown

@Abbondanzo has imported this pull request. If you are a Meta employee, you can view this in D128941371.

@Abbondanzo
Abbondanzo merged commit 47a9917 into react:main Nov 2, 2026
63 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants