Commit 99d504fd authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

Improve performance of PreviousBreakOpportunity

In the current layout engine, PreviousBreakOpportunity is used
only when mid-word break (break-all or break-word), but it is
much more heavily used in LayoutNG.

LazyLineBreakIterator is designed for forward only.
PreviousBreakOpportunity is implemented by repeatedly calling
NextBreakablePosition, but since NextBreakablePosition look
for the next break opportunity until the end of the string,
when a very long word without break opportunity is given,
PreviousBreakOpportunity is O(n!).

This patch changes it to O(n) by limiting the end position
NextBreakablePosition can look for.

blink/perf_tests/layout/word-break-break-word.html consumes
78% of the total time in LayoutNG. The average run is:
  Current engine:    469ms
  LayoutNG:       26,644ms
  This patch:      2,250ms

It's still 4-5 times slower, more improvements will be in
following patches.

Bug: 636993
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_layout_ng
Change-Id: I814e2c45c8030aa682c7f5e3a3b785b3c0733c84
Reviewed-on: https://chromium-review.googlesource.com/1095894
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567133}
parent 8c4bab31
......@@ -279,10 +279,9 @@ template <typename CharacterType,
BreakSpaceType break_space>
inline int LazyLineBreakIterator::NextBreakablePosition(
int pos,
const CharacterType* str) const {
int len = static_cast<int>(string_.length());
const CharacterType* str,
int len) const {
int next_break = -1;
UChar last_last_ch = pos > 1 ? str[pos - 2] : SecondToLastCharacter();
UChar last_ch = pos > 0 ? str[pos - 1] : LastCharacter();
bool is_last_space = IsBreakableSpace(last_ch);
......@@ -357,30 +356,35 @@ inline int LazyLineBreakIterator::NextBreakablePosition(
template <typename CharacterType, LineBreakType lineBreakType>
inline int LazyLineBreakIterator::NextBreakablePosition(
int pos,
const CharacterType* str) const {
const CharacterType* str,
int len) const {
switch (break_space_) {
case BreakSpaceType::kBeforeEverySpace:
return NextBreakablePosition<CharacterType, lineBreakType,
BreakSpaceType::kBeforeEverySpace>(pos, str);
BreakSpaceType::kBeforeEverySpace>(pos, str,
len);
case BreakSpaceType::kBeforeSpaceRun:
return NextBreakablePosition<CharacterType, lineBreakType,
BreakSpaceType::kBeforeSpaceRun>(pos, str);
BreakSpaceType::kBeforeSpaceRun>(pos, str,
len);
}
NOTREACHED();
return NextBreakablePosition<CharacterType, lineBreakType,
BreakSpaceType::kBeforeEverySpace>(pos, str);
BreakSpaceType::kBeforeEverySpace>(pos, str,
len);
}
template <LineBreakType lineBreakType>
inline int LazyLineBreakIterator::NextBreakablePosition(int pos) const {
inline int LazyLineBreakIterator::NextBreakablePosition(int pos,
int len) const {
if (UNLIKELY(string_.IsNull()))
return 0;
if (string_.Is8Bit()) {
return NextBreakablePosition<LChar, lineBreakType>(pos,
string_.Characters8());
return NextBreakablePosition<LChar, lineBreakType>(
pos, string_.Characters8(), len);
}
return NextBreakablePosition<UChar, lineBreakType>(pos,
string_.Characters16());
return NextBreakablePosition<UChar, lineBreakType>(
pos, string_.Characters16(), len);
}
int LazyLineBreakIterator::NextBreakablePositionBreakCharacter(int pos) const {
......@@ -389,16 +393,16 @@ int LazyLineBreakIterator::NextBreakablePositionBreakCharacter(int pos) const {
return next != kTextBreakDone ? next : string_.length();
}
int LazyLineBreakIterator::NextBreakablePosition(
int pos,
LineBreakType line_break_type) const {
int LazyLineBreakIterator::NextBreakablePosition(int pos,
LineBreakType line_break_type,
int len) const {
switch (line_break_type) {
case LineBreakType::kNormal:
return NextBreakablePosition<LineBreakType::kNormal>(pos);
return NextBreakablePosition<LineBreakType::kNormal>(pos, len);
case LineBreakType::kBreakAll:
return NextBreakablePosition<LineBreakType::kBreakAll>(pos);
return NextBreakablePosition<LineBreakType::kBreakAll>(pos, len);
case LineBreakType::kKeepAll:
return NextBreakablePosition<LineBreakType::kKeepAll>(pos);
return NextBreakablePosition<LineBreakType::kKeepAll>(pos, len);
case LineBreakType::kBreakCharacter:
return NextBreakablePositionBreakCharacter(pos);
}
......@@ -406,9 +410,15 @@ int LazyLineBreakIterator::NextBreakablePosition(
return NextBreakablePosition(pos, LineBreakType::kNormal);
}
int LazyLineBreakIterator::NextBreakablePosition(
int pos,
LineBreakType line_break_type) const {
return NextBreakablePosition(pos, line_break_type,
static_cast<int>(string_.length()));
}
unsigned LazyLineBreakIterator::NextBreakOpportunity(unsigned offset) const {
int next_break = -1;
IsBreakable(offset, next_break);
int next_break = NextBreakablePosition(offset, break_type_);
DCHECK_GE(next_break, 0);
return next_break;
}
......@@ -416,9 +426,20 @@ unsigned LazyLineBreakIterator::NextBreakOpportunity(unsigned offset) const {
unsigned LazyLineBreakIterator::PreviousBreakOpportunity(unsigned offset,
unsigned min) const {
unsigned pos = std::min(offset, string_.length());
for (; pos > min; pos--) {
if (IsBreakable(pos))
return pos;
// +2 to ensure at least one code point is included.
unsigned end = std::min(pos + 2, string_.length());
while (pos > min) {
int next_break = NextBreakablePosition(pos, break_type_, end);
DCHECK_GE(next_break, 0);
if (static_cast<unsigned>(next_break) == pos)
return next_break;
// There's no break opportunities at |pos| or after.
end = pos;
if (string_.Is8Bit())
--pos;
else
U16_BACK_1(string_.Characters16(), 0, pos);
}
return min;
}
......
......@@ -279,12 +279,13 @@ class PLATFORM_EXPORT LazyLineBreakIterator final {
}
template <typename CharacterType, LineBreakType, BreakSpaceType>
int NextBreakablePosition(int pos, const CharacterType* str) const;
int NextBreakablePosition(int pos, const CharacterType* str, int len) const;
template <typename CharacterType, LineBreakType>
int NextBreakablePosition(int pos, const CharacterType* str) const;
int NextBreakablePosition(int pos, const CharacterType* str, int len) const;
template <LineBreakType>
int NextBreakablePosition(int pos) const;
int NextBreakablePosition(int pos, int len) const;
int NextBreakablePositionBreakCharacter(int pos) const;
int NextBreakablePosition(int pos, LineBreakType, int len) const;
int NextBreakablePosition(int pos, LineBreakType) const;
static const unsigned kPriorContextCapacity = 2;
......
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