From a1b6142e18b65994dce9b370ef4b65d24aac98fa Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 26 Jun 2024 11:10:15 -0700 Subject: [PATCH 1/4] Issue #2538 - Part 1: Undo IsClusterExtender Change This partially reverts commit 49b7816286498e9ad5b48864847f0a2adabff318. So much for getting rid of the stupid constants... --- intl/unicharutil/util/nsUnicodeProperties.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/intl/unicharutil/util/nsUnicodeProperties.cpp b/intl/unicharutil/util/nsUnicodeProperties.cpp index b9c8b83fb2..3f273e1c1e 100644 --- a/intl/unicharutil/util/nsUnicodeProperties.cpp +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -152,8 +152,7 @@ IsClusterExtender(uint32_t aCh, uint8_t aCategory) { return ((aCategory >= HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK && aCategory <= HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) || - (GetEmojiPresentation(aCh) == EmojiComponent) || - (aCh == 0x200c) || // ZWNJ + (aCh >= 0x200c && aCh <= 0x200d) || // ZWJ, ZWNJ (aCh >= 0xff9e && aCh <= 0xff9f)); // katakana sound marks } From 68bcd4e61e69d9708df4b9f65c636580a1243ecc Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 26 Jun 2024 11:11:19 -0700 Subject: [PATCH 2/4] Issue #2538 - Part 2: Add IsEmojiClusterExtender Check specifically for Emoji-specific clusters only in Emoji-specific contexts. --- intl/unicharutil/util/nsUnicodeProperties.cpp | 13 ++++++++++++- intl/unicharutil/util/nsUnicodeProperties.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/intl/unicharutil/util/nsUnicodeProperties.cpp b/intl/unicharutil/util/nsUnicodeProperties.cpp index 3f273e1c1e..562013959a 100644 --- a/intl/unicharutil/util/nsUnicodeProperties.cpp +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -156,6 +156,15 @@ IsClusterExtender(uint32_t aCh, uint8_t aCategory) (aCh >= 0xff9e && aCh <= 0xff9f)); // katakana sound marks } +bool +IsEmojiClusterExtender(uint32_t aCh) +{ + return ((aCh == 0x200d) || (aCh == 0xfe0f) || // ZWJ, VS16 + (aCh >= 0x1f3fb && aCh <= 0x1f3ff) || // fitzpatrick skin tones + (aCh >= 0x1f9b0 && aCh <= 0x1f9b3) || // hair colors + (aCh >= 0xe0020 && aCh <= 0xe007f)); // TAGs +} + enum HSType { HST_NONE = U_HST_NOT_APPLICABLE, HST_L = U_HST_LEADING_JAMO, @@ -263,6 +272,7 @@ ClusterIterator::Next() } bool extendCluster = IsClusterExtender(ch) || + IsEmojiClusterExtender(ch) || (baseIsEmoji && prevWasZwj && ((GetEmojiPresentation(ch) == EmojiDefault) || (GetEmojiPresentation(ch) == EmojiComponent) || @@ -297,7 +307,8 @@ ClusterReverseIterator::Next() ch = SURROGATE_TO_UCS4(*--mPos, ch); } - if (!IsClusterExtender(ch)) { + // TODO: Full extendCluster support. + if (!(IsClusterExtender(ch) || IsEmojiClusterExtender(ch))) { break; } } while (mPos > mLimit); diff --git a/intl/unicharutil/util/nsUnicodeProperties.h b/intl/unicharutil/util/nsUnicodeProperties.h index 38fa230625..27b57f7383 100644 --- a/intl/unicharutil/util/nsUnicodeProperties.h +++ b/intl/unicharutil/util/nsUnicodeProperties.h @@ -219,6 +219,8 @@ inline bool IsClusterExtender(uint32_t aCh) { return IsClusterExtender(aCh, GetGeneralCategory(aCh)); } +bool IsEmojiClusterExtender(uint32_t aCh); + // A simple iterator for a string of char16_t codepoints that advances // by Unicode grapheme clusters class ClusterIterator From 44f81b46b69b012f7ebb3e8cb612e873f981f53f Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 27 Jun 2024 18:29:23 -0700 Subject: [PATCH 3/4] Issue #2538 - Part 3: Bring ZWJ Awareness to ClusterReverseIterator Additional patch to resolve a bug exposed while working on the Cluster issue. --- intl/unicharutil/util/nsUnicodeProperties.cpp | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/intl/unicharutil/util/nsUnicodeProperties.cpp b/intl/unicharutil/util/nsUnicodeProperties.cpp index 562013959a..5b9f5b9058 100644 --- a/intl/unicharutil/util/nsUnicodeProperties.cpp +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -180,6 +180,8 @@ GetHangulSyllableType(uint32_t aCh) return HSType(u_getIntPropertyValue(aCh, UCHAR_HANGUL_SYLLABLE_TYPE)); } +static const uint32_t kZWJ = 0x200d; + void ClusterIterator::Next() { @@ -233,7 +235,6 @@ ClusterIterator::Next() } } - const uint32_t kZWJ = 0x200d; uint32_t aNextCh = 0; if (mPos + 1 < mLimit) { aNextCh = *mPos; @@ -299,19 +300,55 @@ ClusterReverseIterator::Next() } uint32_t ch; - do { - ch = *--mPos; - if (NS_IS_LOW_SURROGATE(ch) && mPos > mLimit && - NS_IS_HIGH_SURROGATE(*(mPos - 1))) { - ch = SURROGATE_TO_UCS4(*--mPos, ch); + bool nextWasComponent = false; + size_t tRel = 0; + size_t tPos = 0; + size_t chLen = 0; + + do { + tRel++; + ch = *(mPos - tRel); + + if (NS_IS_LOW_SURROGATE(ch) && (mPos - tRel) > mLimit && + NS_IS_HIGH_SURROGATE(*(mPos - (tRel + 1)))) { + tRel++; + ch = SURROGATE_TO_UCS4(*(mPos - tRel), ch); + if (chLen == 0) { + chLen = 2; + } + } else if (chLen == 0) { + chLen = 1; } - // TODO: Full extendCluster support. - if (!(IsClusterExtender(ch) || IsEmojiClusterExtender(ch))) { + bool prevWillBeZwj = false; + bool validEmoji = + (GetEmojiPresentation(ch) == EmojiDefault) || + (GetEmojiPresentation(ch) == EmojiComponent) || + ((GetEmojiPresentation(ch) == TextDefault) && nextWasComponent); + if (validEmoji) { + tPos = tRel; + + uint32_t aPrevCh = *(mPos - (tRel + 1)); + if (NS_IS_LOW_SURROGATE(aPrevCh) && (mPos - (tRel + 1)) > mLimit) { + uint32_t aHighCh = *(mPos - (tRel + 2)); + if (NS_IS_HIGH_SURROGATE(aHighCh)) { + aPrevCh = SURROGATE_TO_UCS4(aHighCh, aPrevCh); + } + } + prevWillBeZwj = (aPrevCh == kZWJ); + } + if (!(IsClusterExtender(ch) || + IsEmojiClusterExtender(ch) || + prevWillBeZwj)) { + if (tPos == 0) { + tPos = chLen; + } break; } - } while (mPos > mLimit); + nextWasComponent = (GetEmojiPresentation(ch) == EmojiComponent); + } while ((mPos - tRel) > mLimit); + mPos -= tPos; // XXX May need to handle conjoining Jamo From 6525b2980c21a8dadfdab686e323f6689835fcf9 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 28 Jun 2024 14:55:06 +0200 Subject: [PATCH 4/4] Issue #2537 - Don't assume username fields appear before password fields in forms. --- toolkit/components/passwordmgr/LoginManagerContent.jsm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/toolkit/components/passwordmgr/LoginManagerContent.jsm b/toolkit/components/passwordmgr/LoginManagerContent.jsm index e8dcf8ad38..8a2f340a6b 100644 --- a/toolkit/components/passwordmgr/LoginManagerContent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm @@ -760,11 +760,10 @@ var LoginManagerContent = { } if (!usernameField) { - // Locate the username field in the form by searching backwards - // from the first password field, assume the first text field is the - // username. We might not find a username field if the user is + // Locate the username field in the form by searching. + // We might not find a username field if the user is // already logged in to the site. - for (var i = pwFields[0].index - 1; i >= 0; i--) { + for (var i = 0; i < form.elements.length; i++) { var element = form.elements[i]; if (!LoginHelper.isUsernameFieldType(element)) { continue;