Commit 8a1b3565 authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

Merge the forked code in LazyLineBreakIterator and some cleanup

The word-break:keep-all code was forked in [1]. This patch merges it
back to single template function, in preparation of supporting
after-white-space in LayoutNG.

Includes some cleanup to make IsBreakable() inline function smaller
without increasing non-inline function calls.

[1] https://codereview.chromium.org/1094863007

BUG=636993

Change-Id: I6471b83437e29f5ee2fcb30473c8eb8d526abf35
Reviewed-on: https://chromium-review.googlesource.com/575799
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488146}
parent ee8ec000
...@@ -244,30 +244,48 @@ static inline bool ShouldBreakAfterBreakAll(ULineBreak last_line_break, ...@@ -244,30 +244,48 @@ static inline bool ShouldBreakAfterBreakAll(ULineBreak last_line_break,
return false; return false;
} }
// Computes if 'word-break:keep-all' should prevent line break.
// https://drafts.csswg.org/css-text-3/#valdef-word-break-keep-all
// The spec is not very verbose on how this should work. This logic prevents L/M
// general categories and complex line breaking since the spec says "except some
// south east aisans".
// https://github.com/w3c/csswg-drafts/issues/1619
static inline bool ShouldKeepAfterKeepAll(UChar last_ch,
UChar ch,
UChar next_ch) {
UChar pre_ch = U_MASK(u_charType(ch)) & U_GC_M_MASK ? last_ch : ch;
return U_MASK(u_charType(pre_ch)) & (U_GC_L_MASK | U_GC_N_MASK) &&
!WTF::Unicode::HasLineBreakingPropertyComplexContext(pre_ch) &&
U_MASK(u_charType(next_ch)) & (U_GC_L_MASK | U_GC_N_MASK) &&
!WTF::Unicode::HasLineBreakingPropertyComplexContext(next_ch);
}
inline bool NeedsLineBreakIterator(UChar ch) { inline bool NeedsLineBreakIterator(UChar ch) {
return ch > kAsciiLineBreakTableLastChar && ch != kNoBreakSpaceCharacter; return ch > kAsciiLineBreakTableLastChar && ch != kNoBreakSpaceCharacter;
} }
template <typename CharacterType, LineBreakType lineBreakType> template <typename CharacterType, LineBreakType lineBreakType>
static inline int NextBreakablePosition( inline int LazyLineBreakIterator::NextBreakablePosition(
const LazyLineBreakIterator& lazy_break_iterator, int pos,
const CharacterType* str, const CharacterType* str) const {
unsigned length, int len = static_cast<int>(string_.length());
int pos) {
int len = static_cast<int>(length);
int next_break = -1; int next_break = -1;
UChar last_last_ch = UChar last_last_ch = pos > 1 ? str[pos - 2] : SecondToLastCharacter();
pos > 1 ? str[pos - 2] : lazy_break_iterator.SecondToLastCharacter(); UChar last_ch = pos > 0 ? str[pos - 1] : LastCharacter();
UChar last_ch = pos > 0 ? str[pos - 1] : lazy_break_iterator.LastCharacter(); bool is_last_space = IsBreakableSpace(last_ch);
ULineBreak last_line_break; ULineBreak last_line_break;
if (lineBreakType == LineBreakType::kBreakAll) if (lineBreakType == LineBreakType::kBreakAll)
last_line_break = LineBreakPropertyValue(last_last_ch, last_ch); last_line_break = LineBreakPropertyValue(last_last_ch, last_ch);
unsigned prior_context_length = lazy_break_iterator.PriorContextLength(); unsigned prior_context_length = PriorContextLength();
for (int i = pos; i < len; i++) { CharacterType ch;
CharacterType ch = str[i]; bool is_space;
for (int i = pos; i < len;
if (IsBreakableSpace(ch) || ShouldBreakAfter(last_last_ch, last_ch, ch)) i++, last_last_ch = last_ch, last_ch = ch, is_last_space = is_space) {
ch = str[i];
is_space = IsBreakableSpace(ch);
if (is_space || ShouldBreakAfter(last_last_ch, last_ch, ch))
return i; return i;
if (lineBreakType == LineBreakType::kBreakAll && !U16_IS_LEAD(ch)) { if (lineBreakType == LineBreakType::kBreakAll && !U16_IS_LEAD(ch)) {
...@@ -278,70 +296,18 @@ static inline int NextBreakablePosition( ...@@ -278,70 +296,18 @@ static inline int NextBreakablePosition(
last_line_break = line_break; last_line_break = line_break;
} }
if (NeedsLineBreakIterator(ch) || NeedsLineBreakIterator(last_ch)) { if (lineBreakType == LineBreakType::kKeepAll &&
if (next_break < i) { ShouldKeepAfterKeepAll(last_last_ch, last_ch, ch)) {
// Don't break if positioned at start of primary context and there is no // word-break:keep-all prevents breaks between East Asian ideographic.
// prior context. continue;
if (i || prior_context_length) {
TextBreakIterator* break_iterator =
lazy_break_iterator.Get(prior_context_length);
if (break_iterator) {
next_break =
break_iterator->following(i - 1 + prior_context_length);
if (next_break >= 0) {
next_break -= prior_context_length;
}
}
}
}
if (i == next_break && !IsBreakableSpace(last_ch))
return i;
} }
last_last_ch = last_ch; if (NeedsLineBreakIterator(ch) || NeedsLineBreakIterator(last_ch)) {
last_ch = ch;
}
return len;
}
static inline bool ShouldKeepAfter(UChar last_ch, UChar ch, UChar next_ch) {
UChar pre_ch = U_MASK(u_charType(ch)) & U_GC_M_MASK ? last_ch : ch;
return U_MASK(u_charType(pre_ch)) & (U_GC_L_MASK | U_GC_N_MASK) &&
!WTF::Unicode::HasLineBreakingPropertyComplexContext(pre_ch) &&
U_MASK(u_charType(next_ch)) & (U_GC_L_MASK | U_GC_N_MASK) &&
!WTF::Unicode::HasLineBreakingPropertyComplexContext(next_ch);
}
static inline int NextBreakablePositionKeepAllInternal(
const LazyLineBreakIterator& lazy_break_iterator,
const UChar* str,
unsigned length,
int pos) {
int len = static_cast<int>(length);
int next_break = -1;
UChar last_last_ch =
pos > 1 ? str[pos - 2]
: static_cast<UChar>(lazy_break_iterator.SecondToLastCharacter());
UChar last_ch = pos > 0
? str[pos - 1]
: static_cast<UChar>(lazy_break_iterator.LastCharacter());
unsigned prior_context_length = lazy_break_iterator.PriorContextLength();
for (int i = pos; i < len; i++) {
UChar ch = str[i];
if (IsBreakableSpace(ch) || ShouldBreakAfter(last_last_ch, last_ch, ch))
return i;
if (!ShouldKeepAfter(last_last_ch, last_ch, ch) &&
(NeedsLineBreakIterator(ch) || NeedsLineBreakIterator(last_ch))) {
if (next_break < i) { if (next_break < i) {
// Don't break if positioned at start of primary context and there is no // Don't break if positioned at start of primary context and there is no
// prior context. // prior context.
if (i || prior_context_length) { if (i || prior_context_length) {
TextBreakIterator* break_iterator = TextBreakIterator* break_iterator = Get(prior_context_length);
lazy_break_iterator.Get(prior_context_length);
if (break_iterator) { if (break_iterator) {
next_break = next_break =
break_iterator->following(i - 1 + prior_context_length); break_iterator->following(i - 1 + prior_context_length);
...@@ -351,43 +317,22 @@ static inline int NextBreakablePositionKeepAllInternal( ...@@ -351,43 +317,22 @@ static inline int NextBreakablePositionKeepAllInternal(
} }
} }
} }
if (i == next_break && !IsBreakableSpace(last_ch)) if (i == next_break && !is_last_space)
return i; return i;
} }
last_last_ch = last_ch;
last_ch = ch;
} }
return len; return len;
} }
template <LineBreakType lineBreakType> template <LineBreakType lineBreakType>
static inline int NextBreakablePosition( inline int LazyLineBreakIterator::NextBreakablePosition(int pos) const {
const LazyLineBreakIterator& lazy_break_iterator, if (string_.Is8Bit()) {
const String& string, return NextBreakablePosition<LChar, lineBreakType>(pos,
int pos) { string_.Characters8());
if (string.Is8Bit()) }
return NextBreakablePosition<LChar, lineBreakType>( return NextBreakablePosition<UChar, lineBreakType>(pos,
lazy_break_iterator, string.Characters8(), string.length(), pos); string_.Characters16());
return NextBreakablePosition<UChar, lineBreakType>(
lazy_break_iterator, string.Characters16(), string.length(), pos);
}
int LazyLineBreakIterator::NextBreakablePositionIgnoringNBSP(int pos) const {
return NextBreakablePosition<LineBreakType::kNormal>(*this, string_, pos);
}
int LazyLineBreakIterator::NextBreakablePositionBreakAll(int pos) const {
return NextBreakablePosition<LineBreakType::kBreakAll>(*this, string_, pos);
}
int LazyLineBreakIterator::NextBreakablePositionKeepAll(int pos) const {
if (string_.Is8Bit())
return NextBreakablePosition<LChar, LineBreakType::kNormal>(
*this, string_.Characters8(), string_.length(), pos);
return NextBreakablePositionKeepAllInternal(*this, string_.Characters16(),
string_.length(), pos);
} }
int LazyLineBreakIterator::NextBreakablePositionBreakCharacter(int pos) const { int LazyLineBreakIterator::NextBreakablePositionBreakCharacter(int pos) const {
...@@ -396,6 +341,23 @@ int LazyLineBreakIterator::NextBreakablePositionBreakCharacter(int pos) const { ...@@ -396,6 +341,23 @@ int LazyLineBreakIterator::NextBreakablePositionBreakCharacter(int pos) const {
return next != kTextBreakDone ? next : string_.length(); return next != kTextBreakDone ? next : string_.length();
} }
int LazyLineBreakIterator::NextBreakablePosition(
int pos,
LineBreakType line_break_type) const {
switch (line_break_type) {
case LineBreakType::kNormal:
return NextBreakablePosition<LineBreakType::kNormal>(pos);
case LineBreakType::kBreakAll:
return NextBreakablePosition<LineBreakType::kBreakAll>(pos);
case LineBreakType::kKeepAll:
return NextBreakablePosition<LineBreakType::kKeepAll>(pos);
case LineBreakType::kBreakCharacter:
return NextBreakablePositionBreakCharacter(pos);
}
NOTREACHED();
return NextBreakablePosition(pos, LineBreakType::kNormal);
}
unsigned LazyLineBreakIterator::NextBreakOpportunity(unsigned offset) const { unsigned LazyLineBreakIterator::NextBreakOpportunity(unsigned offset) const {
int next_break = -1; int next_break = -1;
IsBreakable(offset, next_break); IsBreakable(offset, next_break);
......
...@@ -214,20 +214,7 @@ class PLATFORM_EXPORT LazyLineBreakIterator final { ...@@ -214,20 +214,7 @@ class PLATFORM_EXPORT LazyLineBreakIterator final {
int& next_breakable, int& next_breakable,
LineBreakType line_break_type) const { LineBreakType line_break_type) const {
if (pos > next_breakable) { if (pos > next_breakable) {
switch (line_break_type) { next_breakable = NextBreakablePosition(pos, line_break_type);
case LineBreakType::kBreakAll:
next_breakable = NextBreakablePositionBreakAll(pos);
break;
case LineBreakType::kKeepAll:
next_breakable = NextBreakablePositionKeepAll(pos);
break;
case LineBreakType::kNormal:
next_breakable = NextBreakablePositionIgnoringNBSP(pos);
break;
case LineBreakType::kBreakCharacter:
next_breakable = NextBreakablePositionBreakCharacter(pos);
break;
}
} }
return pos == next_breakable; return pos == next_breakable;
} }
...@@ -256,10 +243,12 @@ class PLATFORM_EXPORT LazyLineBreakIterator final { ...@@ -256,10 +243,12 @@ class PLATFORM_EXPORT LazyLineBreakIterator final {
cached_prior_context_length_ = 0; cached_prior_context_length_ = 0;
} }
int NextBreakablePositionIgnoringNBSP(int pos) const; template <typename CharacterType, LineBreakType>
int NextBreakablePositionBreakAll(int pos) const; int NextBreakablePosition(int pos, const CharacterType* str) const;
int NextBreakablePositionKeepAll(int pos) const; template <LineBreakType>
int NextBreakablePosition(int pos) const;
int NextBreakablePositionBreakCharacter(int pos) const; int NextBreakablePositionBreakCharacter(int pos) const;
int NextBreakablePosition(int pos, LineBreakType) const;
static const unsigned kPriorContextCapacity = 2; static const unsigned kPriorContextCapacity = 2;
String string_; String string_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment