From 66f69854cff25062f0730984333c4eb34faef8bc Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Tue, 7 Apr 2026 16:33:43 +0000 Subject: [PATCH] Expand whitespace character detection in StringUtil.isVisuallyEmpty. Fixes #14470 --- .../java/org/signal/core/util/StringUtil.kt | 27 ++++++++++++++++--- .../StringUtilTest_whitespace_handling.java | 21 +++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/core/util/src/main/java/org/signal/core/util/StringUtil.kt b/core/util/src/main/java/org/signal/core/util/StringUtil.kt index 15e583e822..1d4157766f 100644 --- a/core/util/src/main/java/org/signal/core/util/StringUtil.kt +++ b/core/util/src/main/java/org/signal/core/util/StringUtil.kt @@ -10,11 +10,29 @@ import java.nio.charset.StandardCharsets object StringUtil { private val WHITESPACE: Set = setOf( + '\u00AD', // soft hyphen + '\u034F', // combining grapheme joiner + '\u061C', // arabic letter mark + '\u115F', // hangul choseong filler + '\u1160', // hangul jungseong filler + '\u17B4', // khmer vowel inherent aq + '\u17B5', // khmer vowel inherent aa + '\u180E', // mongolian vowel separator + '\u200B', // zero-width space + '\u200C', // zero-width non-joiner + '\u200D', // zero-width joiner '\u200E', // left-to-right mark '\u200F', // right-to-left mark '\u2007', // figure space - '\u200B', // zero-width space - '\u2800' // braille blank + '\u2060', // word joiner + '\u2061', // function application + '\u2062', // invisible times + '\u2063', // invisible separator + '\u2064', // invisible plus + '\u2800', // braille pattern blank + '\u3164', // hangul filler + '\uFEFF', // zero-width no-break space (BOM) + '\uFFA0' // halfwidth hangul filler ) /** @@ -133,10 +151,11 @@ object StringUtil { /** * @return True if the character is invisible or whitespace. Accounts for various unicode - * whitespace characters. + * whitespace characters including format characters, non-breaking spaces, and other + * invisible code points. */ fun isVisuallyEmpty(c: Char): Boolean { - return Character.isWhitespace(c) || WHITESPACE.contains(c) + return Character.isWhitespace(c) || Character.isSpaceChar(c) || Character.getType(c) == Character.FORMAT.toInt() || WHITESPACE.contains(c) } /** diff --git a/core/util/src/test/java/org/signal/core/util/StringUtilTest_whitespace_handling.java b/core/util/src/test/java/org/signal/core/util/StringUtilTest_whitespace_handling.java index fd4b8967b9..920f491408 100644 --- a/core/util/src/test/java/org/signal/core/util/StringUtilTest_whitespace_handling.java +++ b/core/util/src/test/java/org/signal/core/util/StringUtilTest_whitespace_handling.java @@ -34,6 +34,27 @@ public final class StringUtilTest_whitespace_handling { { "\u2800", "", true }, { "\u2007\u200FA\tB\u200EC\u200E\u200F", "A\tB\u200EC", false }, + /* No-break spaces */ + { "\u00A0", "", true }, + { "\u202F", "", true }, + + /* Format characters */ + { "\u200C", "", true }, + { "\u200D", "", true }, + { "\u2060", "", true }, + { "\uFEFF", "", true }, + + /* Additional invisible characters */ + { "\u034F", "", true }, + { "\u2800", "", true }, + { "\u3164", "", true }, + { "\uFFA0", "", true }, + { "\u115F", "", true }, + { "\u1160", "", true }, + + /* Mixed invisible characters should still be empty */ + { "\u00A0\u200D\u2060\uFEFF", "", true }, + }); }