Bug 1885702 - Fix initialization of masked text fragment in ClusterIterator. r=layout-reviewers,emilio

Differential Revision: https://phabricator.services.mozilla.com/D223050
This commit is contained in:
Jonathan Kew
2024-09-25 17:44:22 +00:00
parent ef48a336e6
commit 26ee40e65a

View File

@@ -8152,8 +8152,14 @@ ClusterIterator::ClusterIterator(nsTextFrame* aTextFrame, int32_t aPosition,
}
mFrag = aTextFrame->TextFragment();
const uint32_t textOffset =
AssertedCast<uint32_t>(aTextFrame->GetContentOffset());
const uint32_t textLen =
AssertedCast<uint32_t>(aTextFrame->GetContentLength());
// If we're in a password field, some characters may be masked. In such
// case, we need to treat each masked character is a mask character since
// case, we need to treat each masked character as a mask character since
// we shouldn't expose word boundary which is hidden by the masking.
if (aTextFrame->GetContent() && mFrag->GetLength() > 0 &&
aTextFrame->GetContent()->HasFlag(NS_MAYBE_MASKED) &&
@@ -8165,25 +8171,39 @@ ClusterIterator::ClusterIterator(nsTextFrame* aTextFrame, int32_t aPosition,
// can be just AddRefed in `mMaskedFrag`.
nsString maskedText;
maskedText.SetCapacity(mFrag->GetLength());
for (uint32_t i = 0; i < mFrag->GetLength(); ++i) {
mIterator.SetOriginalOffset(i);
uint32_t skippedOffset = mIterator.GetSkippedOffset();
// Note that aTextFrame may not cover the whole of mFrag (in cases with
// bidi continuations), so we cannot rely on its textrun (and associated
// styles) being available for the entire fragment.
uint32_t i = 0;
// Just copy any text that precedes what aTextFrame covers.
while (i < textOffset) {
maskedText.Append(mFrag->CharAt(i++));
}
// For the range covered by aTextFrame, mask chars if appropriate.
while (i < textOffset + textLen) {
uint32_t skippedOffset = mIterator.ConvertOriginalToSkipped(i);
bool mask =
skippedOffset < transformedTextRun->GetLength()
? transformedTextRun->mStyles[skippedOffset]->mMaskPassword
: false;
if (mFrag->IsHighSurrogateFollowedByLowSurrogateAt(i)) {
if (transformedTextRun->mStyles[skippedOffset]->mMaskPassword) {
if (mask) {
maskedText.Append(kPasswordMask);
maskedText.Append(kPasswordMask);
} else {
maskedText.Append(mFrag->CharAt(i));
maskedText.Append(mFrag->CharAt(i + 1));
}
++i;
i += 2;
} else {
maskedText.Append(
transformedTextRun->mStyles[skippedOffset]->mMaskPassword
? kPasswordMask
: mFrag->CharAt(i));
maskedText.Append(mask ? kPasswordMask : mFrag->CharAt(i));
++i;
}
}
// Copy any trailing text from the fragment.
while (i < mFrag->GetLength()) {
maskedText.Append(mFrag->CharAt(i++));
}
mMaskedFrag.SetTo(maskedText, mFrag->IsBidi(), true);
mFrag = &mMaskedFrag;
}
@@ -8194,11 +8214,6 @@ ClusterIterator::ClusterIterator(nsTextFrame* aTextFrame, int32_t aPosition,
: nsTextFrame::TrimmedOffsetFlags::NoTrimAfter |
nsTextFrame::TrimmedOffsetFlags::NoTrimBefore);
const uint32_t textOffset =
AssertedCast<uint32_t>(aTextFrame->GetContentOffset());
const uint32_t textLen =
AssertedCast<uint32_t>(aTextFrame->GetContentLength());
// Allocate an extra element to record the word break at the end of the line
// or text run in mWordBreak[textLen].
mWordBreaks.AppendElements(textLen + 1);