diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 4d45116f5d73..eb721b3e6a8f 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -578,24 +578,26 @@ void gfxFontShaper::MergeFontFeatures( void gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, const char16_t* aString, uint32_t aLength) { - CompressedGlyph* glyphs = GetCharacterGlyphs() + aOffset; + if (aLength == 0) { + return; + } + CompressedGlyph* const glyphs = GetCharacterGlyphs() + aOffset; CompressedGlyph extendCluster = CompressedGlyph::MakeComplex(false, true); - const char16_t* const stringStart = aString; - intl::GraphemeClusterBreakIteratorUtf16 iter(aString, aLength); - // GraphemeClusterBreakIteratorUtf16 won't be able to tell us if the string // _begins_ with a cluster-extender, so we handle that here - if (aLength) { - uint32_t ch = *aString; - if (aLength > 1 && NS_IS_SURROGATE_PAIR(ch, aString[1])) { - ch = SURROGATE_TO_UCS4(ch, aString[1]); - } - if (IsClusterExtender(ch)) { - *glyphs = extendCluster; - } + uint32_t ch = aString[0]; + if (aLength > 1 && NS_IS_SURROGATE_PAIR(ch, aString[1])) { + ch = SURROGATE_TO_UCS4(ch, aString[1]); } + if (IsClusterExtender(ch)) { + glyphs[0] = extendCluster; + } + + intl::GraphemeClusterBreakIteratorUtf16 iter( + Span(aString, aLength)); + uint32_t pos = 0; const char16_t kIdeographicSpace = 0x3000; // Special case for Bengali: although Virama normally clusters with the @@ -604,25 +606,23 @@ void gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, // preceding letter by any letter-spacing or justification. const char16_t kBengaliVirama = 0x09CD; const char16_t kBengaliYa = 0x09AF; - while (!iter.AtEnd()) { - if (*iter == char16_t(' ') || *iter == kIdeographicSpace) { - glyphs->SetIsSpace(); - } else if (*iter == kBengaliYa) { + while (pos < aLength) { + const char16_t ch = aString[pos]; + if (ch == char16_t(' ') || ch == kIdeographicSpace) { + glyphs[pos].SetIsSpace(); + } else if (ch == kBengaliYa) { // Unless we're at the start, check for a preceding virama. - if (aString > stringStart && *(aString - 1) == kBengaliVirama) { - *glyphs = extendCluster; + if (pos > 0 && aString[pos - 1] == kBengaliVirama) { + glyphs[pos] = extendCluster; } } // advance iter to the next cluster-start (or end of text) - iter.Next(); + const uint32_t nextPos = *iter.Next(); // step past the first char of the cluster - aString++; - glyphs++; + ++pos; // mark all the rest as cluster-continuations - while (aString < iter) { - *glyphs = extendCluster; - glyphs++; - aString++; + for (; pos < nextPos; ++pos) { + glyphs[pos] = extendCluster; } } } diff --git a/intl/lwbrk/LineBreaker.cpp b/intl/lwbrk/LineBreaker.cpp index 61beef408e68..e278d774323f 100644 --- a/intl/lwbrk/LineBreaker.cpp +++ b/intl/lwbrk/LineBreaker.cpp @@ -1090,10 +1090,10 @@ void LineBreaker::ComputeBreakPositions( if (aWordBreak == WordBreakRule::BreakAll) { // For break-all, we don't need to run a dictionary-based breaking // algorithm, we just allow breaks between all grapheme clusters. - GraphemeClusterBreakIteratorUtf16 ci(aChars + cur, end - cur); - while (!ci.AtEnd()) { - ci.Next(); - aBreakBefore[ci - aChars] = true; + GraphemeClusterBreakIteratorUtf16 ci( + Span(aChars + cur, end - cur)); + while (Maybe pos = ci.Next()) { + aBreakBefore[cur + *pos] = true; } } else { ComplexBreaker::GetBreaks(aChars + cur, end - cur, aBreakBefore + cur); diff --git a/intl/lwbrk/Segmenter.cpp b/intl/lwbrk/Segmenter.cpp index 427f67b415b9..d7c07095acbd 100644 --- a/intl/lwbrk/Segmenter.cpp +++ b/intl/lwbrk/Segmenter.cpp @@ -55,6 +55,10 @@ Maybe WordBreakIteratorUtf16::Next() { return Some(mPos); } +GraphemeClusterBreakIteratorUtf16::GraphemeClusterBreakIteratorUtf16( + Span aText) + : SegmentIteratorUtf16(aText) {} + enum HSType { HST_NONE = U_HST_NOT_APPLICABLE, HST_L = U_HST_LEADING_JAMO, @@ -69,22 +73,23 @@ static HSType GetHangulSyllableType(uint32_t aCh) { aCh, UnicodeProperties::IntProperty::HangulSyllableType)); } -void GraphemeClusterBreakIteratorUtf16::Next() { - if (AtEnd()) { - NS_WARNING("ClusterIterator has already reached the end"); - return; +Maybe GraphemeClusterBreakIteratorUtf16::Next() { + const auto len = mText.Length(); + if (mPos >= len) { + // The iterator has already reached the end. + return Nothing(); } - uint32_t ch = *mPos++; + uint32_t ch = mText[mPos++]; - if (mPos < mLimit && NS_IS_SURROGATE_PAIR(ch, *mPos)) { - ch = SURROGATE_TO_UCS4(ch, *mPos++); + if (mPos < len && NS_IS_SURROGATE_PAIR(ch, mText[mPos])) { + ch = SURROGATE_TO_UCS4(ch, mText[mPos++]); } else if ((ch & ~0xff) == 0x1100 || (ch >= 0xa960 && ch <= 0xa97f) || (ch >= 0xac00 && ch <= 0xd7ff)) { // Handle conjoining Jamo that make Hangul syllables HSType hangulState = GetHangulSyllableType(ch); - while (mPos < mLimit) { - ch = *mPos; + while (mPos < len) { + ch = mText[mPos]; HSType hangulType = GetHangulSyllableType(ch); switch (hangulType) { case HST_L: @@ -127,21 +132,21 @@ void GraphemeClusterBreakIteratorUtf16::Next() { bool baseIsEmoji = (GetEmojiPresentation(ch) == EmojiDefault) || (GetEmojiPresentation(ch) == TextDefault && - ((mPos < mLimit && *mPos == kVS16) || - (mPos + 1 < mLimit && *mPos == kFitzpatrickHigh && - *(mPos + 1) >= kFitzpatrickLowFirst && - *(mPos + 1) <= kFitzpatrickLowLast))); + ((mPos < len && mText[mPos] == kVS16) || + (mPos + 1 < len && mText[mPos] == kFitzpatrickHigh && + mText[mPos + 1] >= kFitzpatrickLowFirst && + mText[mPos + 1] <= kFitzpatrickLowLast))); bool prevWasZwj = false; - while (mPos < mLimit) { - ch = *mPos; + while (mPos < len) { + ch = mText[mPos]; size_t chLen = 1; // Check for surrogate pairs; note that isolated surrogates will just // be treated as generic (non-cluster-extending) characters here, // which is fine for cluster-iterating purposes - if (mPos < mLimit - 1 && NS_IS_SURROGATE_PAIR(ch, *(mPos + 1))) { - ch = SURROGATE_TO_UCS4(ch, *(mPos + 1)); + if (mPos < len - 1 && NS_IS_SURROGATE_PAIR(ch, mText[mPos + 1])) { + ch = SURROGATE_TO_UCS4(ch, mText[mPos + 1]); chLen = 2; } @@ -149,8 +154,8 @@ void GraphemeClusterBreakIteratorUtf16::Next() { IsClusterExtender(ch) || (baseIsEmoji && prevWasZwj && ((GetEmojiPresentation(ch) == EmojiDefault) || - (GetEmojiPresentation(ch) == TextDefault && mPos + chLen < mLimit && - *(mPos + chLen) == kVS16))); + (GetEmojiPresentation(ch) == TextDefault && mPos + chLen < len && + mText[mPos + chLen] == kVS16))); if (!extendCluster) { break; } @@ -159,39 +164,49 @@ void GraphemeClusterBreakIteratorUtf16::Next() { mPos += chLen; } - NS_ASSERTION(mText < mPos && mPos <= mLimit, - "ClusterIterator::Next has overshot the string!"); + MOZ_ASSERT(mPos <= len, "Next() has overshot the string!"); + return Some(mPos); } -void GraphemeClusterBreakReverseIteratorUtf16::Next() { - if (AtEnd()) { - NS_WARNING("ClusterReverseIterator has already reached the end"); - return; +GraphemeClusterBreakReverseIteratorUtf16:: + GraphemeClusterBreakReverseIteratorUtf16(Span aText) + : SegmentIteratorUtf16(aText) { + mPos = mText.Length(); +} + +Maybe GraphemeClusterBreakReverseIteratorUtf16::Next() { + if (mPos == 0) { + return Nothing(); } uint32_t ch; do { - ch = *--mPos; + ch = mText[--mPos]; - if (mPos > mLimit && NS_IS_SURROGATE_PAIR(*(mPos - 1), ch)) { - ch = SURROGATE_TO_UCS4(*--mPos, ch); + if (mPos > 0 && NS_IS_SURROGATE_PAIR(mText[mPos - 1], ch)) { + ch = SURROGATE_TO_UCS4(mText[--mPos], ch); } if (!IsClusterExtender(ch)) { break; } - } while (mPos > mLimit); + } while (mPos > 0); // XXX May need to handle conjoining Jamo - NS_ASSERTION(mPos >= mLimit, - "ClusterReverseIterator::Next has overshot the string!"); + return Some(mPos); +} + +Maybe GraphemeClusterBreakReverseIteratorUtf16::Seek(uint32_t aPos) { + if (mPos > aPos) { + mPos = aPos; + } + return Next(); } Result, ICUError> Segmenter::TryCreate( Span aLocale, const SegmenterOptions& aOptions) { - if (aOptions.mGranularity == SegmenterGranularity::Grapheme || - aOptions.mGranularity == SegmenterGranularity::Sentence) { + if (aOptions.mGranularity == SegmenterGranularity::Sentence) { // Grapheme and Sentence iterator are not yet implemented. return Err(ICUError::InternalError); } @@ -202,6 +217,7 @@ UniquePtr Segmenter::Segment( Span aText) const { switch (mOptions.mGranularity) { case SegmenterGranularity::Grapheme: + return MakeUnique(aText); case SegmenterGranularity::Sentence: MOZ_ASSERT_UNREACHABLE("Unimplemented yet!"); return nullptr; diff --git a/intl/lwbrk/Segmenter.h b/intl/lwbrk/Segmenter.h index 8f6512cb2534..647adb6faba4 100644 --- a/intl/lwbrk/Segmenter.h +++ b/intl/lwbrk/Segmenter.h @@ -124,30 +124,11 @@ class WordBreakIteratorUtf16 final : public SegmentIteratorUtf16 { /** * Grapheme cluster break iterator for UTF-16 text. */ -class GraphemeClusterBreakIteratorUtf16 { +class GraphemeClusterBreakIteratorUtf16 final : public SegmentIteratorUtf16 { public: - GraphemeClusterBreakIteratorUtf16(const char16_t* aText, uint32_t aLength) - : mPos(aText), - mLimit(aText + aLength) -#ifdef DEBUG - , - mText(aText) -#endif - { - } + explicit GraphemeClusterBreakIteratorUtf16(Span aText); - operator const char16_t*() const { return mPos; } - - bool AtEnd() const { return mPos >= mLimit; } - - void Next(); - - private: - const char16_t* mPos; - const char16_t* mLimit; -#ifdef DEBUG - const char16_t* mText; -#endif + Maybe Next() override; }; /** @@ -156,21 +137,13 @@ class GraphemeClusterBreakIteratorUtf16 { * Note: The reverse iterator doesn't handle conjoining Jamo and emoji. Use it * at your own risk. */ -class GraphemeClusterBreakReverseIteratorUtf16 { +class GraphemeClusterBreakReverseIteratorUtf16 final + : public SegmentIteratorUtf16 { public: - GraphemeClusterBreakReverseIteratorUtf16(const char16_t* aText, - uint32_t aLength) - : mPos(aText + aLength), mLimit(aText) {} + explicit GraphemeClusterBreakReverseIteratorUtf16(Span aText); - operator const char16_t*() const { return mPos; } - - bool AtEnd() const { return mPos <= mLimit; } - - void Next(); - - private: - const char16_t* mPos; - const char16_t* mLimit; + Maybe Next() override; + Maybe Seek(uint32_t aPos) override; }; /** diff --git a/intl/lwbrk/gtest/TestSegmenter.cpp b/intl/lwbrk/gtest/TestSegmenter.cpp index 0b9919ab9136..21c44a078f92 100644 --- a/intl/lwbrk/gtest/TestSegmenter.cpp +++ b/intl/lwbrk/gtest/TestSegmenter.cpp @@ -51,11 +51,48 @@ TEST(IntlSegmenter, TestWordBreakIteratorUtf16) ASSERT_EQ(segIter->Seek(0u), Nothing()); } -TEST(IntlSegmenter, TestGraphemeBreakIteratorUtf16) +TEST(IntlSegmenter, TestGraphemeClusterBreakIteratorUtf16) { SegmenterOptions options{SegmenterGranularity::Grapheme}; auto result = Segmenter::TryCreate("en", options); - ASSERT_TRUE(result.isErr()); + ASSERT_TRUE(result.isOk()); + auto graphemeClusterSegmenter = result.unwrap(); + + const char16_t text[] = u"hello world"; + UniquePtr segIter = + graphemeClusterSegmenter->Segment(MakeStringSpan(text)); + + // Seek to the space between "hello" and "world" + ASSERT_EQ(segIter->Seek(5u), Some(6u)); + + ASSERT_EQ(segIter->Next(), Some(7u)); + ASSERT_EQ(segIter->Next(), Some(8u)); + ASSERT_EQ(segIter->Next(), Some(9u)); + ASSERT_EQ(segIter->Next(), Some(10u)); + ASSERT_EQ(segIter->Next(), Some(11u)); + ASSERT_EQ(segIter->Next(), Nothing()); + + // Same as calling Next(). + ASSERT_EQ(segIter->Seek(0u), Nothing()); +} + +TEST(IntlSegmenter, TestGraphemeClusterBreakReverseIteratorUtf16) +{ + const char16_t text[] = u"hello world"; + GraphemeClusterBreakReverseIteratorUtf16 segIter(MakeStringSpan(text)); + + // Seek to the space between "hello" and "world" + ASSERT_EQ(segIter.Seek(6u), Some(5u)); + + ASSERT_EQ(segIter.Next(), Some(4u)); + ASSERT_EQ(segIter.Next(), Some(3u)); + ASSERT_EQ(segIter.Next(), Some(2u)); + ASSERT_EQ(segIter.Next(), Some(1u)); + ASSERT_EQ(segIter.Next(), Some(0u)); + ASSERT_EQ(segIter.Next(), Nothing()); + + // Same as calling Next(). + ASSERT_EQ(segIter.Seek(0u), Nothing()); } TEST(IntlSegmenter, TestSentenceBreakIteratorUtf16) diff --git a/intl/unicharutil/util/nsUnicodeProperties.cpp b/intl/unicharutil/util/nsUnicodeProperties.cpp index 5118959033bd..7f5029765cc4 100644 --- a/intl/unicharutil/util/nsUnicodeProperties.cpp +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -168,12 +168,10 @@ bool IsClusterExtender(uint32_t aCh, uint8_t aCategory) { } uint32_t CountGraphemeClusters(Span aText) { - intl::GraphemeClusterBreakIteratorUtf16 iter(aText.Elements(), - aText.Length()); + intl::GraphemeClusterBreakIteratorUtf16 iter(aText); uint32_t result = 0; - while (!iter.AtEnd()) { + while (iter.Next()) { ++result; - iter.Next(); } return result; } diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp index 528d1ce43553..8c78bbf7b8a2 100644 --- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -69,9 +69,9 @@ bool nsFileControlFrame::CropTextToWidth(gfxContext& aRenderingContext, nsLayoutUtils::GetFontMetricsForFrame(aFrame, 1.0f); // see if the text will completely fit in the width given - nscoord textWidth = nsLayoutUtils::AppUnitWidthOfStringBidi( - aText, aFrame, *fm, aRenderingContext); - if (textWidth <= aWidth) { + if (const nscoord textWidth = nsLayoutUtils::AppUnitWidthOfStringBidi( + aText, aFrame, *fm, aRenderingContext); + textWidth <= aWidth) { return false; } @@ -80,54 +80,49 @@ bool nsFileControlFrame::CropTextToWidth(gfxContext& aRenderingContext, // see if the width is even smaller than the ellipsis fm->SetTextRunRTL(false); - textWidth = nsLayoutUtils::AppUnitWidthOfString(kEllipsis, *fm, drawTarget); - if (textWidth >= aWidth) { + const nscoord ellipsisWidth = + nsLayoutUtils::AppUnitWidthOfString(kEllipsis, *fm, drawTarget); + if (ellipsisWidth >= aWidth) { aText = kEllipsis; return true; } // determine how much of the string will fit in the max width - nscoord totalWidth = textWidth; - intl::GraphemeClusterBreakIteratorUtf16 leftIter(aText.Data(), - aText.Length()); - intl::GraphemeClusterBreakReverseIteratorUtf16 rightIter(aText.Data(), - aText.Length()); - const char16_t* leftPos = leftIter; - const char16_t* rightPos = rightIter; - const char16_t* pos; - ptrdiff_t length; + nscoord totalWidth = ellipsisWidth; + const Span text(aText); + intl::GraphemeClusterBreakIteratorUtf16 leftIter(text); + intl::GraphemeClusterBreakReverseIteratorUtf16 rightIter(text); + uint32_t leftPos = 0; + uint32_t rightPos = aText.Length(); nsAutoString leftString, rightString; while (leftPos < rightPos) { - leftIter.Next(); - pos = leftIter; - length = pos - leftPos; - textWidth = - nsLayoutUtils::AppUnitWidthOfString(leftPos, length, *fm, drawTarget); - if (totalWidth + textWidth > aWidth) { + Maybe pos = leftIter.Next(); + Span chars = text.FromTo(leftPos, *pos); + nscoord charWidth = + nsLayoutUtils::AppUnitWidthOfString(chars, *fm, drawTarget); + if (totalWidth + charWidth > aWidth) { break; } - leftString.Append(leftPos, length); - leftPos = pos; - totalWidth += textWidth; + leftString.Append(chars); + leftPos = *pos; + totalWidth += charWidth; if (leftPos >= rightPos) { break; } - rightIter.Next(); - pos = rightIter; - length = rightPos - pos; - textWidth = - nsLayoutUtils::AppUnitWidthOfString(pos, length, *fm, drawTarget); - if (totalWidth + textWidth > aWidth) { + pos = rightIter.Next(); + chars = text.FromTo(*pos, rightPos); + charWidth = nsLayoutUtils::AppUnitWidthOfString(chars, *fm, drawTarget); + if (totalWidth + charWidth > aWidth) { break; } - rightString.Insert(pos, 0, length); - rightPos = pos; - totalWidth += textWidth; + rightString.Insert(chars, 0); + rightPos = *pos; + totalWidth += charWidth; } aText = leftString + kEllipsis + rightString; diff --git a/layout/xul/nsTextBoxFrame.cpp b/layout/xul/nsTextBoxFrame.cpp index 3d15eed8f3df..fe04e4c65d50 100644 --- a/layout/xul/nsTextBoxFrame.cpp +++ b/layout/xul/nsTextBoxFrame.cpp @@ -622,71 +622,59 @@ nscoord nsTextBoxFrame::CalculateTitleForWidth(gfxContext& aRenderingContext, case CropAuto: case CropNone: case CropRight: { - GraphemeClusterBreakIteratorUtf16 iter(mTitle.Data(), mTitle.Length()); - const char16_t* dataBegin = iter; - const char16_t* pos = dataBegin; - nscoord charWidth; + const Span title(mTitle); + GraphemeClusterBreakIteratorUtf16 iter(title); + uint32_t pos = 0; nscoord totalWidth = 0; - while (!iter.AtEnd()) { - iter.Next(); - const char16_t* nextPos = iter; - ptrdiff_t length = nextPos - pos; - charWidth = - nsLayoutUtils::AppUnitWidthOfString(pos, length, *fm, drawTarget); + while (Maybe nextPos = iter.Next()) { + const nscoord charWidth = nsLayoutUtils::AppUnitWidthOfString( + title.FromTo(pos, *nextPos), *fm, drawTarget); if (totalWidth + charWidth > aWidth) { break; } - if (UTF16_CODE_UNIT_IS_BIDI(*pos)) { + if (UTF16_CODE_UNIT_IS_BIDI(mTitle[pos])) { AddStateBits(NS_FRAME_IS_BIDI); } - pos = nextPos; + pos = *nextPos; totalWidth += charWidth; } - if (pos == dataBegin) { + if (pos == 0) { return titleWidth; } // insert what character we can in. - nsAutoString title(mTitle); - title.Truncate(pos - dataBegin); - mCroppedTitle.Insert(title, 0); + mCroppedTitle.Insert(title.To(pos), 0); } break; case CropLeft: { - GraphemeClusterBreakReverseIteratorUtf16 iter(mTitle.Data(), - mTitle.Length()); - const char16_t* dataEnd = iter; - const char16_t* prevPos = dataEnd; - nscoord charWidth; + const Span title(mTitle); + GraphemeClusterBreakReverseIteratorUtf16 iter(title); + uint32_t pos = title.Length(); nscoord totalWidth = 0; - while (!iter.AtEnd()) { - iter.Next(); - const char16_t* pos = iter; - ptrdiff_t length = prevPos - pos; - charWidth = - nsLayoutUtils::AppUnitWidthOfString(pos, length, *fm, drawTarget); + // nextPos is decreasing since we use a reverse iterator. + while (Maybe nextPos = iter.Next()) { + const nscoord charWidth = nsLayoutUtils::AppUnitWidthOfString( + title.FromTo(*nextPos, pos), *fm, drawTarget); if (totalWidth + charWidth > aWidth) { break; } - if (UTF16_CODE_UNIT_IS_BIDI(*pos)) { + if (UTF16_CODE_UNIT_IS_BIDI(mTitle[*nextPos])) { AddStateBits(NS_FRAME_IS_BIDI); } - prevPos = pos; + pos = *nextPos; totalWidth += charWidth; } - if (prevPos == dataEnd) { + if (pos == title.Length()) { return titleWidth; } - nsAutoString copy; - mTitle.Right(copy, dataEnd - prevPos); - mCroppedTitle += copy; + mCroppedTitle.Append(title.From(pos)); } break; case CropCenter: { @@ -699,57 +687,48 @@ nscoord nsTextBoxFrame::CalculateTitleForWidth(gfxContext& aRenderingContext, } // determine how much of the string will fit in the max width - nscoord charWidth = 0; + const Span title(mTitle); nscoord totalWidth = 0; - GraphemeClusterBreakIteratorUtf16 leftIter(mTitle.Data(), - mTitle.Length()); - GraphemeClusterBreakReverseIteratorUtf16 rightIter(mTitle.Data(), - mTitle.Length()); - const char16_t* dataBegin = leftIter; - const char16_t* dataEnd = rightIter; - const char16_t* leftPos = dataBegin; - const char16_t* rightPos = dataEnd; - const char16_t* pos; - ptrdiff_t length; + GraphemeClusterBreakIteratorUtf16 leftIter(title); + GraphemeClusterBreakReverseIteratorUtf16 rightIter(title); + uint32_t leftPos = 0; + uint32_t rightPos = title.Length(); nsAutoString leftString, rightString; while (leftPos < rightPos) { - leftIter.Next(); - pos = leftIter; - length = pos - leftPos; - charWidth = nsLayoutUtils::AppUnitWidthOfString(leftPos, length, *fm, - drawTarget); + Maybe nextPos = leftIter.Next(); + Span chars = title.FromTo(leftPos, *nextPos); + nscoord charWidth = + nsLayoutUtils::AppUnitWidthOfString(chars, *fm, drawTarget); if (totalWidth + charWidth > aWidth) { break; } - if (UTF16_CODE_UNIT_IS_BIDI(*leftPos)) { + if (UTF16_CODE_UNIT_IS_BIDI(mTitle[leftPos])) { AddStateBits(NS_FRAME_IS_BIDI); } - leftString.Append(leftPos, length); - leftPos = pos; + leftString.Append(chars); + leftPos = *nextPos; totalWidth += charWidth; if (leftPos >= rightPos) { break; } - rightIter.Next(); - pos = rightIter; - length = rightPos - pos; - charWidth = - nsLayoutUtils::AppUnitWidthOfString(pos, length, *fm, drawTarget); + nextPos = rightIter.Next(); + chars = title.FromTo(*nextPos, rightPos); + charWidth = nsLayoutUtils::AppUnitWidthOfString(chars, *fm, drawTarget); if (totalWidth + charWidth > aWidth) { break; } - if (UTF16_CODE_UNIT_IS_BIDI(*pos)) { + if (UTF16_CODE_UNIT_IS_BIDI(mTitle[*nextPos])) { AddStateBits(NS_FRAME_IS_BIDI); } - rightString.Insert(pos, 0, length); - rightPos = pos; + rightString.Insert(chars, 0); + rightPos = *nextPos; totalWidth += charWidth; } diff --git a/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp b/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp index 3d01aa5421a2..5a4f7acbef03 100644 --- a/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp +++ b/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp @@ -6,6 +6,7 @@ #include "mozilla/TextUtils.h" #include "mozTXTToHTMLConv.h" #include "mozilla/intl/Segmenter.h" +#include "mozilla/Maybe.h" #include "nsNetUtil.h" #include "nsUnicharUtils.h" #include "nsUnicodeProperties.h" @@ -23,6 +24,9 @@ using mozilla::IsAscii; using mozilla::IsAsciiAlpha; using mozilla::IsAsciiDigit; +using mozilla::Maybe; +using mozilla::Some; +using mozilla::Span; using mozilla::intl::GraphemeClusterBreakIteratorUtf16; using mozilla::intl::GraphemeClusterBreakReverseIteratorUtf16; @@ -560,9 +564,9 @@ bool mozTXTToHTMLConv::ItMatchesDelimited(const char16_t* aInString, // find length of the char/cluster to be ignored int32_t ignoreLen = before == LT_IGNORE ? 0 : 1; if (ignoreLen) { - GraphemeClusterBreakIteratorUtf16 ci(aInString, aInLength); - ci.Next(); - ignoreLen = ci - aInString; + GraphemeClusterBreakIteratorUtf16 ci( + Span(aInString, aInLength)); + ignoreLen = *ci.Next(); } int32_t afterIndex = aRepLen + ignoreLen; @@ -593,10 +597,11 @@ uint32_t mozTXTToHTMLConv::NumberOfMatches(const char16_t* aInString, LIMTYPE before, LIMTYPE after) { uint32_t result = 0; - const char16_t* end = aInString + aInStringLength; - for (GraphemeClusterBreakIteratorUtf16 ci(aInString, aInStringLength); - !ci.AtEnd(); ci.Next()) { - if (ItMatchesDelimited(ci, end - ci, rep, aRepLen, before, after)) { + const uint32_t len = mozilla::AssertedCast(aInStringLength); + GraphemeClusterBreakIteratorUtf16 ci(Span(aInString, len)); + for (uint32_t pos = 0; pos < len; pos = *ci.Next()) { + if (ItMatchesDelimited(aInString + pos, aInStringLength - pos, rep, aRepLen, + before, after)) { result++; } } @@ -982,17 +987,15 @@ mozTXTToHTMLConv::ScanTXT(const nsAString& aInString, uint32_t whattodo, const char16_t* rawInputString = aInString.BeginReading(); uint32_t inLength = aInString.Length(); - for (GraphemeClusterBreakIteratorUtf16 ci(rawInputString, inLength); - !ci.AtEnd();) { - uint32_t i = ci - rawInputString; + const Span inString(aInString); + GraphemeClusterBreakIteratorUtf16 ci(inString); + uint32_t i = 0; + while (i < inLength) { if (doGlyphSubstitution) { int32_t glyphTextLen; if (GlyphHit(&rawInputString[i], inLength - i, i == 0, aOutString, glyphTextLen)) { - i += glyphTextLen; - while (ci < rawInputString + i) { - ci.Next(); - } + i = *ci.Seek(i + glyphTextLen - 1); continue; } } @@ -1002,10 +1005,11 @@ mozTXTToHTMLConv::ScanTXT(const nsAString& aInString, uint32_t whattodo, int32_t newLength = aInString.Length(); if (i > 0) // skip the first element? { - GraphemeClusterBreakReverseIteratorUtf16 ri(rawInputString, i); - ri.Next(); - newOffset = ri; - newLength = aInString.Length() - (ri - rawInputString); + GraphemeClusterBreakReverseIteratorUtf16 ri( + Span(rawInputString, i)); + Maybe nextPos = ri.Next(); + newOffset += *nextPos; + newLength -= *nextPos; } switch (aInString[i]) // Performance increase @@ -1014,7 +1018,7 @@ mozTXTToHTMLConv::ScanTXT(const nsAString& aInString, uint32_t whattodo, if (StructPhraseHit(newOffset, newLength, i == 0, u"*", 1, "b", "class=\"moz-txt-star\"", aOutString, structPhrase_strong)) { - ci.Next(); + i = *ci.Next(); continue; } break; @@ -1022,7 +1026,7 @@ mozTXTToHTMLConv::ScanTXT(const nsAString& aInString, uint32_t whattodo, if (StructPhraseHit(newOffset, newLength, i == 0, u"/", 1, "i", "class=\"moz-txt-slash\"", aOutString, structPhrase_italic)) { - ci.Next(); + i = *ci.Next(); continue; } break; @@ -1031,7 +1035,7 @@ mozTXTToHTMLConv::ScanTXT(const nsAString& aInString, uint32_t whattodo, "span" /* is deprecated */, "class=\"moz-txt-underscore\"", aOutString, structPhrase_underline)) { - ci.Next(); + i = *ci.Next(); continue; } break; @@ -1039,7 +1043,7 @@ mozTXTToHTMLConv::ScanTXT(const nsAString& aInString, uint32_t whattodo, if (StructPhraseHit(newOffset, newLength, i == 0, u"|", 1, "code", "class=\"moz-txt-verticalline\"", aOutString, structPhrase_code)) { - ci.Next(); + i = *ci.Next(); continue; } break; @@ -1071,10 +1075,7 @@ mozTXTToHTMLConv::ScanTXT(const nsAString& aInString, uint32_t whattodo, replaceBefore); aOutString += outputHTML; endOfLastURLOutput = aOutString.Length(); - i += replaceAfter + 1; - while (ci < rawInputString + i) { - ci.Next(); - } + i = *ci.Seek(i + replaceAfter); continue; } } @@ -1088,13 +1089,13 @@ mozTXTToHTMLConv::ScanTXT(const nsAString& aInString, uint32_t whattodo, case '>': case '&': EscapeChar(aInString[i], aOutString, false); - ci.Next(); + i = *ci.Next(); break; // Normal characters default: { - const char16_t* start = ci; - ci.Next(); - aOutString += Substring(start, (const char16_t*)ci); + const uint32_t oldIdx = i; + i = *ci.Next(); + aOutString.Append(inString.FromTo(oldIdx, i)); break; } }