Bug 2058356 - Use mozilla::Span for LineBreaker. r=TYLin
Currently, we are using pointer for text and break position state, but it is more safe to use Span. Differential Revision: https://phabricator.services.mozilla.com/D314550
This commit is contained in:
committed by
m_kato@ga2.so-net.ne.jp
parent
9f4bdbdd64
commit
c7ebb59cdc
@@ -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<uint8_t> saveWordStartBreakState(breakState[wordStart]);
|
||||
LineBreaker::ComputeBreakPositions(
|
||||
aText + wordStart, offset - wordStart, mWordBreak, mLineBreak,
|
||||
mScriptIsChineseOrJapanese, breakState.Elements() + wordStart);
|
||||
Span<const char16_t>(aText + wordStart, offset - wordStart),
|
||||
mWordBreak, mLineBreak, mScriptIsChineseOrJapanese,
|
||||
Span<uint8_t>(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<uint8_t> saveWordStartBreakState(breakState[wordStart]);
|
||||
LineBreaker::ComputeBreakPositions(
|
||||
aText + wordStart, offset - wordStart, mWordBreak, mLineBreak,
|
||||
mScriptIsChineseOrJapanese, breakState.Elements() + wordStart);
|
||||
Span<const uint8_t>(aText + wordStart, offset - wordStart),
|
||||
mWordBreak, mLineBreak, mScriptIsChineseOrJapanese,
|
||||
Span<uint8_t>(breakState.Elements() + wordStart,
|
||||
offset - wordStart));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<detail::LBCacheKey, detail::LBCacheEntry,
|
||||
}
|
||||
|
||||
static void CopyAndFill(const nsTArray<uint8_t>& aCachedBreakBefore,
|
||||
uint8_t* aBreakBefore, uint8_t* aEndBreakBefore) {
|
||||
auto* startFill = std::copy(aCachedBreakBefore.begin(),
|
||||
aCachedBreakBefore.end(), aBreakBefore);
|
||||
std::fill(startFill, aEndBreakBefore, false);
|
||||
Span<uint8_t> aBreakBefore) {
|
||||
auto startFill = std::copy(aCachedBreakBefore.begin(),
|
||||
aCachedBreakBefore.end(), aBreakBefore.begin());
|
||||
std::fill(startFill, aBreakBefore.end(), 0);
|
||||
}
|
||||
|
||||
class Observer final : public nsIObserver {
|
||||
|
||||
+36
-27
@@ -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<const char16_t> aText,
|
||||
WordBreakRule aWordBreak,
|
||||
LineBreakRule aLevel,
|
||||
bool aIsChineseOrJapanese,
|
||||
Span<uint8_t> 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<LineBreakCache::Entry> 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<int32_t> length = aLength;
|
||||
if (length.isValid()) {
|
||||
CheckedInt<int32_t> 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<uint8_t>(aBreakBefore, afterLastTrue - aBreakBefore),
|
||||
nsString(aText.Elements(), aText.Length()),
|
||||
nsTArray<uint8_t>(aBreakBefore.Elements(),
|
||||
afterLastTrue - aBreakBefore.Elements()),
|
||||
aWordBreak, aLevel, aIsChineseOrJapanese});
|
||||
}
|
||||
}
|
||||
|
||||
void LineBreaker::ComputeBreakPositions(const uint8_t* aChars, uint32_t aLength,
|
||||
void LineBreaker::ComputeBreakPositions(Span<const uint8_t> aText,
|
||||
WordBreakRule aWordBreak,
|
||||
LineBreakRule aLevel,
|
||||
bool aIsChineseOrJapanese,
|
||||
uint8_t* aBreakBefore) {
|
||||
if (aLength == 1) {
|
||||
Span<uint8_t> 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<int32_t> length = aLength;
|
||||
if (!length.isValid()) {
|
||||
CheckedInt<int32_t> 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<const uint8_t>{aChars, aLength});
|
||||
auto iterator = segmenter->segment_latin1(
|
||||
diplomat::span<const uint8_t>{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;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#ifndef mozilla_intl_LineBreaker_h_
|
||||
#define mozilla_intl_LineBreaker_h_
|
||||
|
||||
#include "mozilla/Span.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#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<const char16_t> aText,
|
||||
WordBreakRule aWordBreak,
|
||||
LineBreakRule aLevel,
|
||||
bool aIsChineseOrJapanese,
|
||||
uint8_t* aBreakBefore);
|
||||
static void ComputeBreakPositions(const uint8_t* aText, uint32_t aLength,
|
||||
Span<uint8_t> aBreakBefore);
|
||||
static void ComputeBreakPositions(Span<const uint8_t> aText,
|
||||
WordBreakRule aWordBreak,
|
||||
LineBreakRule aLevel,
|
||||
bool aIsChineseOrJapanese,
|
||||
uint8_t* aBreakBefore);
|
||||
Span<uint8_t> aBreakBefore);
|
||||
|
||||
static void Shutdown();
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user