Bug 1011369 - Pass word-break and line-break properties to the line-breaker as two distinct enum class parameters. r=m_kato

Differential Revision: https://phabricator.services.mozilla.com/D30786

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jonathan Kew 2019-05-20 20:46:35 +00:00
parent 837368bc29
commit 9ac5b6c1af
5 changed files with 103 additions and 50 deletions

View File

@ -20,7 +20,8 @@ nsLineBreaker::nsLineBreaker()
mCurrentWordContainsComplexChar(false),
mAfterBreakableSpace(false),
mBreakHere(false),
mWordBreak(LineBreaker::kWordBreak_Normal) {}
mWordBreak(LineBreaker::WordBreak::Normal),
mStrictness(LineBreaker::Strictness::Auto) {}
nsLineBreaker::~nsLineBreaker() {
NS_ASSERTION(mCurrentWord.Length() == 0,
@ -57,22 +58,28 @@ static void SetupCapitalization(const char16_t* aWord, uint32_t aLength,
nsresult nsLineBreaker::FlushCurrentWord() {
uint32_t length = mCurrentWord.Length();
AutoTArray<uint8_t, 4000> breakState;
if (!breakState.AppendElements(length)) return NS_ERROR_OUT_OF_MEMORY;
if (!breakState.AppendElements(length)) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsTArray<bool> capitalizationState;
if (!mCurrentWordContainsComplexChar ||
mWordBreak == LineBreaker::kWordBreak_Anywhere) {
if (mStrictness == LineBreaker::Strictness::Anywhere) {
memset(breakState.Elements(),
gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL,
length * sizeof(uint8_t));
} else if (!mCurrentWordContainsComplexChar) {
// For break-strict set everything internal to "break", otherwise
// to "no break"!
memset(breakState.Elements(),
mWordBreak >= LineBreaker::kWordBreak_BreakAll
mWordBreak == LineBreaker::WordBreak::BreakAll
? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
: gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE,
length * sizeof(uint8_t));
} else {
nsContentUtils::LineBreaker()->GetJISx4051Breaks(
mCurrentWord.Elements(), length, mWordBreak, breakState.Elements());
mCurrentWord.Elements(), length, mWordBreak, mStrictness,
breakState.Elements());
}
bool autoHyphenate = mCurrentWordLanguage && !mCurrentWordContainsMixedLang;
@ -226,7 +233,8 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
if (aSink && !noBreaksNeeded) {
breakState[offset] =
mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
(mWordBreak >= LineBreaker::kWordBreak_BreakAll)
mWordBreak == LineBreaker::WordBreak::BreakAll ||
mStrictness == LineBreaker::Strictness::Anywhere
? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
: gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
}
@ -241,7 +249,7 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
// set it to false
uint8_t currentStart = breakState[wordStart];
nsContentUtils::LineBreaker()->GetJISx4051Breaks(
aText + wordStart, offset - wordStart, mWordBreak,
aText + wordStart, offset - wordStart, mWordBreak, mStrictness,
breakState.Elements() + wordStart);
breakState[wordStart] = currentStart;
}
@ -384,7 +392,8 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
// will be set by nsILineBreaker, we don't consider CJK at this point.
breakState[offset] =
mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ||
(mWordBreak >= LineBreaker::kWordBreak_BreakAll)
mWordBreak == LineBreaker::WordBreak::BreakAll ||
mStrictness == LineBreaker::Strictness::Anywhere
? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL
: gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE;
}
@ -398,7 +407,7 @@ nsresult nsLineBreaker::AppendText(nsAtom* aHyphenationLanguage,
// set it to false
uint8_t currentStart = breakState[wordStart];
nsContentUtils::LineBreaker()->GetJISx4051Breaks(
aText + wordStart, offset - wordStart, mWordBreak,
aText + wordStart, offset - wordStart, mWordBreak, mStrictness,
breakState.Elements() + wordStart);
breakState[wordStart] = currentStart;
}

View File

@ -175,9 +175,9 @@ class nsLineBreaker {
/*
* Set word-break mode for linebreaker. This is set by word-break property.
* @param aMode is LineBreaker::kWordBreak_* value.
* @param aMode is LineBreaker::WordBreak::* value.
*/
void SetWordBreak(uint8_t aMode) {
void SetWordBreak(mozilla::intl::LineBreaker::WordBreak aMode) {
// If current word is non-empty and mode is changing, flush the breaker.
if (aMode != mWordBreak && !mCurrentWord.IsEmpty()) {
nsresult rv = FlushCurrentWord();
@ -187,13 +187,32 @@ class nsLineBreaker {
// If previous mode was break-all, we should allow a break here.
// XXX (jfkthame) css-text spec seems unclear on this, raised question in
// https://github.com/w3c/csswg-drafts/issues/3897
if (mWordBreak == mozilla::intl::LineBreaker::kWordBreak_BreakAll) {
if (mWordBreak == mozilla::intl::LineBreaker::WordBreak::BreakAll) {
mBreakHere = true;
}
}
mWordBreak = aMode;
}
/*
* Set line-break rule strictness mode for linebreaker. This is set by the
* line-break property.
* @param aMode is LineBreaker::Strictness::* value.
*/
void SetStrictness(mozilla::intl::LineBreaker::Strictness aMode) {
if (aMode != mStrictness && !mCurrentWord.IsEmpty()) {
nsresult rv = FlushCurrentWord();
if (NS_FAILED(rv)) {
NS_WARNING("FlushCurrentWord failed, line-breaks may be wrong");
}
// If previous mode was anywhere, we should allow a break here.
if (mStrictness == mozilla::intl::LineBreaker::Strictness::Anywhere) {
mBreakHere = true;
}
}
mStrictness = aMode;
}
private:
// This is a list of text sources that make up the "current word" (i.e.,
// run of text which does not contain any whitespace). All the mLengths
@ -239,7 +258,9 @@ class nsLineBreaker {
// a run of breakable whitespace ends here
bool mBreakHere;
// line break mode by "word-break" style
uint8_t mWordBreak;
mozilla::intl::LineBreaker::WordBreak mWordBreak;
// strictness of break rules, from line-break property
mozilla::intl::LineBreaker::Strictness mStrictness;
};
#endif /*NSLINEBREAKER_H_*/

View File

@ -824,8 +824,8 @@ int32_t LineBreaker::WordMove(const char16_t* aText, uint32_t aLen,
ret = end;
}
} else {
GetJISx4051Breaks(aText + begin, end - begin,
LineBreaker::kWordBreak_Normal, breakState.Elements());
GetJISx4051Breaks(aText + begin, end - begin, WordBreak::Normal,
Strictness::Auto, breakState.Elements());
ret = aPos;
do {
@ -855,7 +855,8 @@ int32_t LineBreaker::Prev(const char16_t* aText, uint32_t aLen, uint32_t aPos) {
}
void LineBreaker::GetJISx4051Breaks(const char16_t* aChars, uint32_t aLength,
uint8_t aWordBreak, uint8_t* aBreakBefore) {
WordBreak aWordBreak, Strictness aLevel,
uint8_t* aBreakBefore) {
uint32_t cur;
int8_t lastClass = CLASS_NONE;
ContextState state(aChars, aLength);
@ -896,7 +897,7 @@ void LineBreaker::GetJISx4051Breaks(const char16_t* aChars, uint32_t aLength,
// CLASS_CLOSE by GetClass(), but those classes also include others that
// we don't want to touch here, so we re-check the Unicode line-break class
// to determine which ones to modify.
if (aWordBreak == LineBreaker::kWordBreak_BreakAll &&
if (aWordBreak == WordBreak::BreakAll &&
(cl == CLASS_CHARACTER || cl == CLASS_CLOSE)) {
auto cls = GetLineBreakClass(ch);
if (cls == U_LB_ALPHABETIC || cls == U_LB_NUMERIC ||
@ -914,8 +915,8 @@ void LineBreaker::GetJISx4051Breaks(const char16_t* aChars, uint32_t aLength,
if (cur > 0) {
NS_ASSERTION(CLASS_COMPLEX != lastClass || CLASS_COMPLEX != cl,
"Loop should have prevented adjacent complex chars here");
if (aWordBreak == LineBreaker::kWordBreak_Normal ||
aWordBreak == LineBreaker::kWordBreak_BreakAll) {
if (aWordBreak == WordBreak::Normal ||
aWordBreak == WordBreak::BreakAll) {
allowBreak = (state.UseConservativeBreaking())
? GetPairConservative(lastClass, cl)
: GetPair(lastClass, cl);
@ -938,7 +939,7 @@ void LineBreaker::GetJISx4051Breaks(const char16_t* aChars, uint32_t aLength,
}
}
if (aWordBreak == LineBreaker::kWordBreak_BreakAll) {
if (aWordBreak == WordBreak::BreakAll) {
// For break-all, we don't need to run a dictionary-based breaking
// algorithm, we just allow breaks between all grapheme clusters.
ClusterIterator ci(aChars + cur, end - cur);
@ -967,7 +968,8 @@ void LineBreaker::GetJISx4051Breaks(const char16_t* aChars, uint32_t aLength,
}
void LineBreaker::GetJISx4051Breaks(const uint8_t* aChars, uint32_t aLength,
uint8_t aWordBreak, uint8_t* aBreakBefore) {
WordBreak aWordBreak, Strictness aLevel,
uint8_t* aBreakBefore) {
uint32_t cur;
int8_t lastClass = CLASS_NONE;
ContextState state(aChars, aLength);
@ -985,7 +987,7 @@ void LineBreaker::GetJISx4051Breaks(const uint8_t* aChars, uint32_t aLength,
state.NotifyNonHyphenCharacter(ch);
cl = GetClass(ch);
}
if (aWordBreak == LineBreaker::kWordBreak_BreakAll &&
if (aWordBreak == WordBreak::BreakAll &&
(cl == CLASS_CHARACTER || cl == CLASS_CLOSE)) {
auto cls = GetLineBreakClass(ch);
// Don't need to check additional Japanese/Korean classes in 8-bit
@ -997,8 +999,8 @@ void LineBreaker::GetJISx4051Breaks(const uint8_t* aChars, uint32_t aLength,
bool allowBreak = false;
if (cur > 0) {
if (aWordBreak == LineBreaker::kWordBreak_Normal ||
aWordBreak == LineBreaker::kWordBreak_BreakAll) {
if (aWordBreak == WordBreak::Normal ||
aWordBreak == WordBreak::BreakAll) {
allowBreak = (state.UseConservativeBreaking())
? GetPairConservative(lastClass, cl)
: GetPair(lastClass, cl);

View File

@ -17,12 +17,18 @@ class LineBreaker {
public:
NS_INLINE_DECL_REFCOUNTING(LineBreaker)
enum {
// Order is important here, because of tests for value >= BreakAll
kWordBreak_Normal = 0, // default
kWordBreak_KeepAll = 1, // always keep
kWordBreak_BreakAll = 2, // break all
kWordBreak_Anywhere = 3 // line-break:anywhere
enum class WordBreak : uint8_t {
Normal = 0, // default
BreakAll = 1, // break all
KeepAll = 2 // always keep
};
enum class Strictness : uint8_t {
Auto = 0,
Loose = 1,
Normal = 2,
Strict = 3,
Anywhere = 4
};
static already_AddRefed<LineBreaker> Create();
@ -38,9 +44,11 @@ class LineBreaker {
// aLength is the length of the aText array and also the length of the
// aBreakBefore output array.
void GetJISx4051Breaks(const char16_t* aText, uint32_t aLength,
uint8_t aWordBreak, uint8_t* aBreakBefore);
WordBreak aWordBreak, Strictness aLevel,
uint8_t* aBreakBefore);
void GetJISx4051Breaks(const uint8_t* aText, uint32_t aLength,
uint8_t aWordBreak, uint8_t* aBreakBefore);
WordBreak aWordBreak, Strictness aLevel,
uint8_t* aBreakBefore);
private:
~LineBreaker() {}

View File

@ -2589,23 +2589,36 @@ void BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun,
// each MappedFlow. The line-breaker will flush its text if the property
// actually changes.
const auto* styleText = mappedFlow->mStartFrame->StyleText();
if (styleText->mLineBreak == StyleLineBreak::Anywhere) {
mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_Anywhere);
} else {
auto wordBreak = styleText->EffectiveWordBreak();
switch (wordBreak) {
case StyleWordBreak::BreakAll:
mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_BreakAll);
break;
case StyleWordBreak::KeepAll:
mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_KeepAll);
break;
case StyleWordBreak::Normal:
default:
MOZ_ASSERT(wordBreak == StyleWordBreak::Normal);
mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_Normal);
break;
}
auto wordBreak = styleText->EffectiveWordBreak();
switch (wordBreak) {
case StyleWordBreak::BreakAll:
mLineBreaker.SetWordBreak(LineBreaker::WordBreak::BreakAll);
break;
case StyleWordBreak::KeepAll:
mLineBreaker.SetWordBreak(LineBreaker::WordBreak::KeepAll);
break;
case StyleWordBreak::Normal:
default:
MOZ_ASSERT(wordBreak == StyleWordBreak::Normal);
mLineBreaker.SetWordBreak(LineBreaker::WordBreak::Normal);
break;
}
switch (styleText->mLineBreak) {
case StyleLineBreak::Auto:
mLineBreaker.SetStrictness(LineBreaker::Strictness::Auto);
break;
case StyleLineBreak::Normal:
mLineBreaker.SetStrictness(LineBreaker::Strictness::Normal);
break;
case StyleLineBreak::Loose:
mLineBreaker.SetStrictness(LineBreaker::Strictness::Loose);
break;
case StyleLineBreak::Strict:
mLineBreaker.SetStrictness(LineBreaker::Strictness::Strict);
break;
case StyleLineBreak::Anywhere:
mLineBreaker.SetStrictness(LineBreaker::Strictness::Anywhere);
break;
}
uint32_t offset = iter.GetSkippedOffset();