| Index: third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc
|
| diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc
|
| index 1954a5bc8b587a6365425c63065f3d3fb5d267a0..d0785764e780e61ef94319ab6a75a17070b18502 100644
|
| --- a/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc
|
| +++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_inline_items_builder.cc
|
| @@ -22,7 +22,7 @@ String NGLayoutInlineItemsBuilder::ToString() {
|
| // [1] https://drafts.csswg.org/css-text-3/#line-break-transform
|
| // [2] https://drafts.csswg.org/css-text-3/#white-space-phase-2
|
| unsigned next_start_offset = text_.length();
|
| - RemoveTrailingCollapsibleSpace(&next_start_offset);
|
| + RemoveTrailingCollapsibleSpaceIfExists(&next_start_offset);
|
|
|
| return text_.toString();
|
| }
|
| @@ -55,8 +55,9 @@ static bool ShouldRemoveNewlineSlow(const StringBuilder& before,
|
| const ComputedStyle* after_style) {
|
| // Remove if either before/after the newline is zeroWidthSpaceCharacter.
|
| UChar32 last = 0;
|
| - if (!before.isEmpty()) {
|
| - last = before[before.length() - 1];
|
| + DCHECK(!before.isEmpty() && before[before.length() - 1] == ' ');
|
| + if (before.length() >= 2) {
|
| + last = before[before.length() - 2];
|
| if (last == zeroWidthSpaceCharacter)
|
| return true;
|
| }
|
| @@ -111,15 +112,17 @@ static void AppendItem(Vector<NGLayoutInlineItem>* items,
|
| items->push_back(NGLayoutInlineItem(start, end, style, layout_object));
|
| }
|
|
|
| +static inline bool IsCollapsibleSpace(UChar c, bool preserve_newline) {
|
| + return c == spaceCharacter || c == tabulationCharacter ||
|
| + (!preserve_newline && c == newlineCharacter);
|
| +}
|
| +
|
| void NGLayoutInlineItemsBuilder::Append(const String& string,
|
| const ComputedStyle* style,
|
| LayoutObject* layout_object) {
|
| if (string.isEmpty())
|
| return;
|
|
|
| - if (has_pending_newline_)
|
| - ProcessPendingNewline(string, style);
|
| -
|
| EWhiteSpace whitespace = style->whiteSpace();
|
| bool preserve_newline =
|
| ComputedStyle::preserveNewline(whitespace) && !is_svgtext_;
|
| @@ -128,38 +131,49 @@ void NGLayoutInlineItemsBuilder::Append(const String& string,
|
|
|
| if (!collapse_whitespace) {
|
| text_.append(string);
|
| - is_last_collapsible_space_ = false;
|
| + last_collapsible_space_ = CollapsibleSpace::None;
|
| } else {
|
| text_.reserveCapacity(string.length());
|
| - for (unsigned i = 0; i < string.length(); i++) {
|
| + for (unsigned i = 0; i < string.length();) {
|
| UChar c = string[i];
|
| - bool is_collapsible_space;
|
| if (c == newlineCharacter) {
|
| - RemoveTrailingCollapsibleSpace(&start_offset);
|
| if (preserve_newline) {
|
| + RemoveTrailingCollapsibleSpaceIfExists(&start_offset);
|
| text_.append(c);
|
| // Remove collapsible spaces immediately following a newline.
|
| - is_last_collapsible_space_ = true;
|
| + last_collapsible_space_ = CollapsibleSpace::Space;
|
| + i++;
|
| continue;
|
| }
|
| - if (i + 1 == string.length()) {
|
| - // If at the end of string, process this newline on the next Append.
|
| - has_pending_newline_ = true;
|
| - break;
|
| +
|
| + if (last_collapsible_space_ == CollapsibleSpace::None)
|
| + text_.append(spaceCharacter);
|
| + last_collapsible_space_ = CollapsibleSpace::Newline;
|
| + i++;
|
| + continue;
|
| + }
|
| +
|
| + if (c == spaceCharacter || c == tabulationCharacter) {
|
| + if (last_collapsible_space_ == CollapsibleSpace::None) {
|
| + text_.append(spaceCharacter);
|
| + last_collapsible_space_ = CollapsibleSpace::Space;
|
| }
|
| - if (ShouldRemoveNewline(text_, style, string, i + 1, style))
|
| - continue;
|
| - is_collapsible_space = true;
|
| - } else {
|
| - is_collapsible_space = c == spaceCharacter || c == tabulationCharacter;
|
| + i++;
|
| + continue;
|
| + }
|
| +
|
| + if (last_collapsible_space_ == CollapsibleSpace::Newline) {
|
| + RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i,
|
| + style);
|
| }
|
| - if (!is_collapsible_space) {
|
| - text_.append(c);
|
| - is_last_collapsible_space_ = false;
|
| - } else if (!is_last_collapsible_space_) {
|
| - text_.append(spaceCharacter);
|
| - is_last_collapsible_space_ = true;
|
| +
|
| + unsigned start_of_non_space = i;
|
| + for (i++; i < string.length(); i++) {
|
| + if (IsCollapsibleSpace(string[i], false))
|
| + break;
|
| }
|
| + text_.append(string, start_of_non_space, i - start_of_non_space);
|
| + last_collapsible_space_ = CollapsibleSpace::None;
|
| }
|
| }
|
|
|
| @@ -172,49 +186,49 @@ void NGLayoutInlineItemsBuilder::Append(UChar character,
|
| LayoutObject* layout_object) {
|
| DCHECK(character != spaceCharacter && character != tabulationCharacter &&
|
| character != newlineCharacter && character != zeroWidthSpaceCharacter);
|
| - if (has_pending_newline_)
|
| - ProcessPendingNewline(emptyString, nullptr);
|
|
|
| text_.append(character);
|
| unsigned end_offset = text_.length();
|
| AppendItem(items_, end_offset - 1, end_offset, style, layout_object);
|
| - is_last_collapsible_space_ = false;
|
| + last_collapsible_space_ = CollapsibleSpace::None;
|
| }
|
|
|
| -void NGLayoutInlineItemsBuilder::AppendAsOpaqueToSpaceCollapsing(
|
| - UChar character) {
|
| - if (has_pending_newline_)
|
| - ProcessPendingNewline(emptyString, nullptr);
|
| +void NGLayoutInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded(
|
| + unsigned* next_start_offset,
|
| + const String& after,
|
| + unsigned after_index,
|
| + const ComputedStyle* after_style) {
|
| + DCHECK_EQ(last_collapsible_space_, CollapsibleSpace::Newline);
|
|
|
| - text_.append(character);
|
| - unsigned end_offset = text_.length();
|
| - AppendItem(items_, end_offset - 1, end_offset, nullptr);
|
| -}
|
| + if (text_.isEmpty() || text_[text_.length() - 1] != spaceCharacter)
|
| + return;
|
|
|
| -void NGLayoutInlineItemsBuilder::ProcessPendingNewline(
|
| - const String& string,
|
| - const ComputedStyle* style) {
|
| - DCHECK(has_pending_newline_);
|
| + const ComputedStyle* before_style = after_style;
|
| if (!items_->isEmpty()) {
|
| NGLayoutInlineItem& item = items_->back();
|
| - if (!ShouldRemoveNewline(text_, item.Style(), string, 0, style)) {
|
| - text_.append(spaceCharacter);
|
| - item.SetEndOffset(text_.length());
|
| - }
|
| + if (text_.length() < item.EndOffset() + 2)
|
| + before_style = item.Style();
|
| }
|
| - // Remove spaces following a newline even when the newline was removed.
|
| - is_last_collapsible_space_ = true;
|
| - has_pending_newline_ = false;
|
| +
|
| + if (ShouldRemoveNewline(text_, before_style, after, after_index, after_style))
|
| + RemoveTrailingCollapsibleSpace(next_start_offset);
|
| +}
|
| +
|
| +void NGLayoutInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists(
|
| + unsigned* next_start_offset) {
|
| + if (last_collapsible_space_ != CollapsibleSpace::None && !text_.isEmpty() &&
|
| + text_[text_.length() - 1] == spaceCharacter)
|
| + RemoveTrailingCollapsibleSpace(next_start_offset);
|
| }
|
|
|
| void NGLayoutInlineItemsBuilder::RemoveTrailingCollapsibleSpace(
|
| unsigned* next_start_offset) {
|
| - if (!is_last_collapsible_space_ || text_.isEmpty())
|
| - return;
|
| - DCHECK_EQ(spaceCharacter, text_[text_.length() - 1]);
|
| + DCHECK_NE(last_collapsible_space_, CollapsibleSpace::None);
|
| + DCHECK(!text_.isEmpty() && text_[text_.length() - 1] == spaceCharacter);
|
| +
|
| unsigned new_size = text_.length() - 1;
|
| text_.resize(new_size);
|
| - is_last_collapsible_space_ = false;
|
| + last_collapsible_space_ = CollapsibleSpace::None;
|
|
|
| // Adjust the last item if the removed space is already appended.
|
| if (*next_start_offset > new_size) {
|
| @@ -233,8 +247,7 @@ void NGLayoutInlineItemsBuilder::RemoveTrailingCollapsibleSpace(
|
| void NGLayoutInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style,
|
| UChar ltr,
|
| UChar rtl) {
|
| - AppendAsOpaqueToSpaceCollapsing(
|
| - style->direction() == TextDirection::kRtl ? rtl : ltr);
|
| + Append(style->direction() == TextDirection::kRtl ? rtl : ltr);
|
| }
|
|
|
| void NGLayoutInlineItemsBuilder::EnterBlock(const ComputedStyle* style) {
|
| @@ -273,11 +286,11 @@ void NGLayoutInlineItemsBuilder::EnterInline(LayoutObject* node) {
|
| Enter(node, popDirectionalIsolateCharacter);
|
| break;
|
| case UnicodeBidi::kPlaintext:
|
| - AppendAsOpaqueToSpaceCollapsing(firstStrongIsolateCharacter);
|
| + Append(firstStrongIsolateCharacter);
|
| Enter(node, popDirectionalIsolateCharacter);
|
| break;
|
| case UnicodeBidi::kIsolateOverride:
|
| - AppendAsOpaqueToSpaceCollapsing(firstStrongIsolateCharacter);
|
| + Append(firstStrongIsolateCharacter);
|
| AppendBidiControl(style, leftToRightOverrideCharacter,
|
| rightToLeftOverrideCharacter);
|
| Enter(node, popDirectionalIsolateCharacter);
|
| @@ -303,7 +316,7 @@ void NGLayoutInlineItemsBuilder::ExitInline(LayoutObject* node) {
|
|
|
| void NGLayoutInlineItemsBuilder::Exit(LayoutObject* node) {
|
| while (!exits_.isEmpty() && exits_.back().node == node) {
|
| - AppendAsOpaqueToSpaceCollapsing(exits_.back().character);
|
| + Append(exits_.back().character);
|
| exits_.pop_back();
|
| }
|
| }
|
|
|