diff --git a/dom/base/nsLineBreaker.cpp b/dom/base/nsLineBreaker.cpp index 5a69eb9dba45..136899ab826a 100644 --- a/dom/base/nsLineBreaker.cpp +++ b/dom/base/nsLineBreaker.cpp @@ -17,6 +17,7 @@ #include "nsHyphenator.h" using mozilla::AutoRestore; +using mozilla::Span; using mozilla::intl::LineBreaker; using mozilla::intl::LineBreakRule; using mozilla::intl::Locale; @@ -158,9 +159,8 @@ nsresult nsLineBreaker::FlushCurrentWord() { gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE, length * sizeof(uint8_t)); } else { - LineBreaker::ComputeBreakPositions( - mCurrentWord.Elements(), length, mWordBreak, mLineBreak, - mScriptIsChineseOrJapanese, breakState.Elements()); + LineBreaker::ComputeBreakPositions(mCurrentWord, mWordBreak, mLineBreak, + mScriptIsChineseOrJapanese, breakState); } bool autoHyphenate = mCurrentWordLanguage && !mCurrentWordContainsMixedLang; @@ -341,8 +341,10 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage, // will set it to false. AutoRestore saveWordStartBreakState(breakState[wordStart]); LineBreaker::ComputeBreakPositions( - aText + wordStart, offset - wordStart, mWordBreak, mLineBreak, - mScriptIsChineseOrJapanese, breakState.Elements() + wordStart); + Span(aText + wordStart, offset - wordStart), + mWordBreak, mLineBreak, mScriptIsChineseOrJapanese, + Span(breakState.Elements() + wordStart, + offset - wordStart)); } if (hyphenator) { FindHyphenationPoints(hyphenator, aText + wordStart, aText + offset, @@ -601,8 +603,10 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage, // will set it to false. AutoRestore saveWordStartBreakState(breakState[wordStart]); LineBreaker::ComputeBreakPositions( - aText + wordStart, offset - wordStart, mWordBreak, mLineBreak, - mScriptIsChineseOrJapanese, breakState.Elements() + wordStart); + Span(aText + wordStart, offset - wordStart), + mWordBreak, mLineBreak, mScriptIsChineseOrJapanese, + Span(breakState.Elements() + wordStart, + offset - wordStart)); } } diff --git a/intl/lwbrk/LineBreakCache.h b/intl/lwbrk/LineBreakCache.h index 224e1ae605c5..c794b07cfd06 100644 --- a/intl/lwbrk/LineBreakCache.h +++ b/intl/lwbrk/LineBreakCache.h @@ -11,6 +11,7 @@ #include "nsThreadUtils.h" #include "mozilla/HashFunctions.h" #include "mozilla/MruCache.h" +#include "mozilla/Span.h" #include "mozilla/StaticPtr.h" #include "mozilla/intl/Segmenter.h" @@ -20,7 +21,7 @@ namespace intl { namespace detail { struct LBCacheKey { const char16_t* mText; - uint32_t mLength; + size_t mLength; // ICU4X segmenter results depend on these flags, so they need to be part // of the cache key. (Legacy ComplexBreaker just leaves them as default.) WordBreakRule mWordBreak = WordBreakRule::Normal; @@ -74,10 +75,10 @@ class LineBreakCache : public MruCache& aCachedBreakBefore, - uint8_t* aBreakBefore, uint8_t* aEndBreakBefore) { - auto* startFill = std::copy(aCachedBreakBefore.begin(), - aCachedBreakBefore.end(), aBreakBefore); - std::fill(startFill, aEndBreakBefore, false); + Span aBreakBefore) { + auto startFill = std::copy(aCachedBreakBefore.begin(), + aCachedBreakBefore.end(), aBreakBefore.begin()); + std::fill(startFill, aBreakBefore.end(), 0); } class Observer final : public nsIObserver { diff --git a/intl/lwbrk/LineBreaker.cpp b/intl/lwbrk/LineBreaker.cpp index 6c906a0b78ab..36dbf2b63f2f 100644 --- a/intl/lwbrk/LineBreaker.cpp +++ b/intl/lwbrk/LineBreaker.cpp @@ -109,10 +109,15 @@ static capi::LineSegmenter* GetLineSegmenter(bool aUseDefault, locale, options.AsFFI()); } -void LineBreaker::ComputeBreakPositions( - const char16_t* aChars, uint32_t aLength, WordBreakRule aWordBreak, - LineBreakRule aLevel, bool aIsChineseOrJapanese, uint8_t* aBreakBefore) { - if (aLength == 1) { +void LineBreaker::ComputeBreakPositions(Span aText, + WordBreakRule aWordBreak, + LineBreakRule aLevel, + bool aIsChineseOrJapanese, + Span aBreakBefore) { + MOZ_ASSERT(aText.Length() == aBreakBefore.Length()); + + const size_t length = aText.Length(); + if (length == 1) { // Although UAX#14 LB2 rule requires never breaking at the start of text // (SOT), ICU4X line segmenter API is designed to match other segmenter in // UAX#29 to always break at the start of text. Hence the optimization @@ -126,8 +131,8 @@ void LineBreaker::ComputeBreakPositions( // to make that decision, we probe every /kStride/ characters. bool useCache = [=]() { const uint32_t kStride = 8; - for (uint32_t i = 0; i < aLength; i += kStride) { - if (intl::UnicodeProperties::IsScriptioContinua(aChars[i])) { + for (uint32_t i = 0; i < length; i += kStride) { + if (intl::UnicodeProperties::IsScriptioContinua(aText[i])) { return true; } } @@ -135,31 +140,31 @@ void LineBreaker::ComputeBreakPositions( }(); Maybe entry; if (useCache) { - LineBreakCache::KeyType key{aChars, aLength, aWordBreak, aLevel, + LineBreakCache::KeyType key{aText.Elements(), length, aWordBreak, aLevel, aIsChineseOrJapanese}; entry.emplace(LineBreakCache::Cache()->Lookup(key)); if (*entry) { auto& breakBefore = entry->Data().mBreaks; - LineBreakCache::CopyAndFill(breakBefore, aBreakBefore, - aBreakBefore + aLength); + LineBreakCache::CopyAndFill(breakBefore, aBreakBefore); return; } } - memset(aBreakBefore, 0, aLength); + std::fill(aBreakBefore.begin(), aBreakBefore.end(), 0); - CheckedInt length = aLength; - if (length.isValid()) { + CheckedInt checkedLength = length; + if (checkedLength.isValid()) { const bool useDefault = UseDefaultLineSegmenter(aWordBreak, aLevel, aIsChineseOrJapanese); auto lineSegmenter = GetLineSegmenter(useDefault, aWordBreak, aLevel, aIsChineseOrJapanese); auto segmenter = LineSegmenter::FromFFI(lineSegmenter); - auto iterator = segmenter->segment16(std::u16string_view{aChars, aLength}); + auto iterator = + segmenter->segment16(std::u16string_view{aText.Elements(), length}); while (true) { const int32_t nextPos = iterator->next(); - if (nextPos < 0 || nextPos >= length.value()) { + if (nextPos < 0 || nextPos >= checkedLength.value()) { break; } aBreakBefore[nextPos] = 1; @@ -173,26 +178,30 @@ void LineBreaker::ComputeBreakPositions( if (useCache) { // As a very simple memory saving measure we trim off trailing elements // that are false before caching. - auto* afterLastTrue = aBreakBefore + aLength; + auto* afterLastTrue = aBreakBefore.Elements() + length; while (!*(afterLastTrue - 1)) { - if (--afterLastTrue == aBreakBefore) { + if (--afterLastTrue == aBreakBefore.Elements()) { break; } } entry->Set(LineBreakCache::EntryType{ - nsString(aChars, aLength), - nsTArray(aBreakBefore, afterLastTrue - aBreakBefore), + nsString(aText.Elements(), aText.Length()), + nsTArray(aBreakBefore.Elements(), + afterLastTrue - aBreakBefore.Elements()), aWordBreak, aLevel, aIsChineseOrJapanese}); } } -void LineBreaker::ComputeBreakPositions(const uint8_t* aChars, uint32_t aLength, +void LineBreaker::ComputeBreakPositions(Span aText, WordBreakRule aWordBreak, LineBreakRule aLevel, bool aIsChineseOrJapanese, - uint8_t* aBreakBefore) { - if (aLength == 1) { + Span aBreakBefore) { + MOZ_ASSERT(aText.Length() == aBreakBefore.Length()); + + const size_t length = aText.Length(); + if (length == 1) { // Although UAX#14 LB2 rule requires never breaking at the start of text // (SOT), ICU4X line segmenter API is designed to match other segmenter in // UAX#29 to always break at the start of text. Hence the optimization @@ -201,10 +210,10 @@ void LineBreaker::ComputeBreakPositions(const uint8_t* aChars, uint32_t aLength, return; } - memset(aBreakBefore, 0, aLength); + std::fill(aBreakBefore.begin(), aBreakBefore.end(), 0); - CheckedInt length = aLength; - if (!length.isValid()) { + CheckedInt checkedLength = length; + if (!checkedLength.isValid()) { return; } @@ -213,12 +222,12 @@ void LineBreaker::ComputeBreakPositions(const uint8_t* aChars, uint32_t aLength, auto lineSegmenter = GetLineSegmenter(useDefault, aWordBreak, aLevel, aIsChineseOrJapanese); auto segmenter = icu4x::LineSegmenter::FromFFI(lineSegmenter); - auto iterator = - segmenter->segment_latin1(diplomat::span{aChars, aLength}); + auto iterator = segmenter->segment_latin1( + diplomat::span{aText.Elements(), length}); while (true) { const int32_t nextPos = iterator->next(); - if (nextPos < 0 || nextPos >= length.value()) { + if (nextPos < 0 || nextPos >= checkedLength.value()) { break; } aBreakBefore[nextPos] = 1; diff --git a/intl/lwbrk/LineBreaker.h b/intl/lwbrk/LineBreaker.h index d2c2a71706d0..719d91be7032 100644 --- a/intl/lwbrk/LineBreaker.h +++ b/intl/lwbrk/LineBreaker.h @@ -4,6 +4,8 @@ #ifndef mozilla_intl_LineBreaker_h_ #define mozilla_intl_LineBreaker_h_ +#include "mozilla/Span.h" + #include #define NS_LINEBREAKER_NEED_MORE_TEXT -1 @@ -24,18 +26,17 @@ class LineBreaker final { // rules to find breaks inside the word. aBreakBefore is set to the break- // before status of each character; aBreakBefore[0] will always be false // because we never return a break before the first character. - // aLength is the length of the aText array and also the length of the - // aBreakBefore output array. - static void ComputeBreakPositions(const char16_t* aText, uint32_t aLength, + // The aBreakBefore output array must have the same length as aText. + static void ComputeBreakPositions(Span aText, WordBreakRule aWordBreak, LineBreakRule aLevel, bool aIsChineseOrJapanese, - uint8_t* aBreakBefore); - static void ComputeBreakPositions(const uint8_t* aText, uint32_t aLength, + Span aBreakBefore); + static void ComputeBreakPositions(Span aText, WordBreakRule aWordBreak, LineBreakRule aLevel, bool aIsChineseOrJapanese, - uint8_t* aBreakBefore); + Span aBreakBefore); static void Shutdown(); }; diff --git a/intl/lwbrk/gtest/TestSegmenterPerf.cpp b/intl/lwbrk/gtest/TestSegmenterPerf.cpp index 1cfd18ecb02a..cf938437ba1f 100644 --- a/intl/lwbrk/gtest/TestSegmenterPerf.cpp +++ b/intl/lwbrk/gtest/TestSegmenterPerf.cpp @@ -88,9 +88,9 @@ static void TestSegmenterBench(const nsString& aStr, bool aIsJaOrZh, breakState.SetLength(aStr.Length()); for (size_t i = 0; i < aCount; i++) { - LineBreaker::ComputeBreakPositions( - aStr.get(), aStr.Length(), WordBreakRule::Normal, LineBreakRule::Strict, - aIsJaOrZh, breakState.Elements()); + LineBreaker::ComputeBreakPositions(aStr, WordBreakRule::Normal, + LineBreakRule::Strict, aIsJaOrZh, + breakState); } }