Chromium Code Reviews| Index: third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc |
| diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc |
| index 1038485901038a4a211dbd51b71fa06440c5c91e..d61edeb8595624e7d437d622c16bee2e246a5391 100644 |
| --- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc |
| +++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_items_builder.cc |
| @@ -10,6 +10,15 @@ |
| namespace blink { |
| +NGInlineItemsBuilder::NGInlineItemsBuilder( |
| + Vector<NGInlineItem>* items, |
| + Vector<Vector<unsigned>>* removed_indexes) |
| + : items_(items), |
| + removed_indexes_(removed_indexes), |
| + input_strings_lengths_(Vector<unsigned>()) { |
| + DCHECK(removed_indexes); |
| +} |
| + |
| NGInlineItemsBuilder::~NGInlineItemsBuilder() { |
| DCHECK_EQ(0u, exits_.size()); |
| DCHECK_EQ(text_.length(), items_->IsEmpty() ? 0 : items_->back().EndOffset()); |
| @@ -22,7 +31,12 @@ String NGInlineItemsBuilder::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(); |
| - RemoveTrailingCollapsibleSpaceIfExists(&next_start_offset); |
| + bool trailing_space_removed = |
| + RemoveTrailingCollapsibleSpaceIfExists(&next_start_offset); |
| + if (trailing_space_removed && removed_indexes_) { |
| + DCHECK(input_strings_lengths_); |
| + AddLastTrailingSpaceToRemovedIndexes(input_strings_lengths_->back()); |
| + } |
| return text_.ToString(); |
| } |
| @@ -124,9 +138,34 @@ static inline bool IsControlItemCharacter(UChar c) { |
| return c == kTabulationCharacter || c == kNewlineCharacter; |
| } |
| +// Returns the largest integer in [0, |max|) that is absent in |integers|, or |
| +// kNotFound if such an integer does not exist. |
| +static size_t GetLargestAbsentInteger(const Vector<unsigned>& integers, |
| + unsigned max) { |
| + DCHECK(integers.IsEmpty() || integers.back() < max); |
| + if (!max || integers.size() == max) |
| + return kNotFound; |
| + if (integers.IsEmpty() || integers.back() + 1 < max) |
| + return max - 1; |
| + for (unsigned i = integers.size() - 1; i;) { |
| + DCHECK_LT(integers[i - 1], integers[i]); |
| + if (integers[i - 1] + 1 < integers[i] - 1) |
| + return integers[i] - 1; |
| + --i; |
| + } |
| + DCHECK_GT(integers[0], 0u); |
| + return integers[0] - 1; |
| +} |
| + |
| void NGInlineItemsBuilder::Append(const String& string, |
| const ComputedStyle* style, |
| LayoutObject* layout_object) { |
| + if (removed_indexes_) { |
| + DCHECK(input_strings_lengths_); |
| + input_strings_lengths_->push_back(string.length()); |
| + removed_indexes_->emplace_back(); |
| + } |
| + |
| if (string.IsEmpty()) |
| return; |
| text_.ReserveCapacity(string.length()); |
| @@ -153,12 +192,16 @@ void NGInlineItemsBuilder::AppendWithWhiteSpaceCollapsing( |
| if (c == kNewlineCharacter) { |
| // LayoutBR does not set preserve_newline, but should be preserved. |
| if (!i && end == 1 && layout_object && layout_object->IsBR()) { |
| - AppendForcedBreak(style, layout_object); |
| + bool trailing_space_removed = AppendForcedBreak(style, layout_object); |
| + if (trailing_space_removed && removed_indexes_) |
| + AddLastTrailingSpaceToRemovedIndexes(i); |
|
kojii
2017/06/19 05:56:33
Why don't we add to removed_indexes in RemoveTrail
Xiaocheng
2017/06/19 17:53:01
Updating |removed_indexes_| needs the number of ch
|
| return; |
| } |
| if (last_collapsible_space_ == CollapsibleSpace::kNone) |
| text_.Append(kSpaceCharacter); |
| + else if (removed_indexes_) |
| + removed_indexes_->back().push_back(i); |
| last_collapsible_space_ = CollapsibleSpace::kNewline; |
| i++; |
| continue; |
| @@ -168,13 +211,18 @@ void NGInlineItemsBuilder::AppendWithWhiteSpaceCollapsing( |
| if (last_collapsible_space_ == CollapsibleSpace::kNone) { |
| text_.Append(kSpaceCharacter); |
| last_collapsible_space_ = CollapsibleSpace::kSpace; |
| + } else if (removed_indexes_) { |
| + removed_indexes_->back().push_back(i); |
| } |
| i++; |
| continue; |
| } |
| if (last_collapsible_space_ == CollapsibleSpace::kNewline) { |
| - RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i, style); |
| + bool trailing_newline_removed = RemoveTrailingCollapsibleNewlineIfNeeded( |
| + &start_offset, string, i, style); |
| + if (trailing_newline_removed && removed_indexes_) |
| + AddLastTrailingSpaceToRemovedIndexes(i); |
| } |
| size_t end_of_non_space = string.Find(IsCollapsibleSpace, i + 1); |
| @@ -224,7 +272,9 @@ void NGInlineItemsBuilder::AppendWithPreservingNewlines( |
| LayoutObject* layout_object) { |
| for (unsigned start = 0; start < string.length();) { |
| if (string[start] == kNewlineCharacter) { |
| - AppendForcedBreak(style, layout_object); |
| + bool trailing_space_removed = AppendForcedBreak(style, layout_object); |
| + if (trailing_space_removed && removed_indexes_) |
| + AddLastTrailingSpaceToRemovedIndexes(start); |
| start++; |
| continue; |
| } |
| @@ -237,16 +287,18 @@ void NGInlineItemsBuilder::AppendWithPreservingNewlines( |
| } |
| } |
| -void NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style, |
| +bool NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style, |
| LayoutObject* layout_object) { |
| // Remove collapsible spaces immediately before a preserved newline. |
| unsigned start_offset = text_.length(); |
| - RemoveTrailingCollapsibleSpaceIfExists(&start_offset); |
| + bool trailing_space_removed = |
| + RemoveTrailingCollapsibleSpaceIfExists(&start_offset); |
| Append(NGInlineItem::kControl, kNewlineCharacter, style, layout_object); |
| // Remove collapsible spaces immediately after a preserved newline. |
| last_collapsible_space_ = CollapsibleSpace::kSpace; |
| + return trailing_space_removed; |
| } |
| void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type, |
| @@ -269,7 +321,7 @@ void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type, |
| AppendItem(items_, type, end_offset, end_offset, style, layout_object); |
| } |
| -void NGInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded( |
| +bool NGInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded( |
| unsigned* next_start_offset, |
| const String& after, |
| unsigned after_index, |
| @@ -277,7 +329,7 @@ void NGInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded( |
| DCHECK_EQ(last_collapsible_space_, CollapsibleSpace::kNewline); |
| if (text_.IsEmpty() || text_[text_.length() - 1] != kSpaceCharacter) |
| - return; |
| + return false; |
| const ComputedStyle* before_style = after_style; |
| if (!items_->IsEmpty()) { |
| @@ -286,15 +338,20 @@ void NGInlineItemsBuilder::RemoveTrailingCollapsibleNewlineIfNeeded( |
| before_style = item.Style(); |
| } |
| - if (ShouldRemoveNewline(text_, before_style, after, after_index, after_style)) |
| - RemoveTrailingCollapsibleSpace(next_start_offset); |
| + if (!ShouldRemoveNewline(text_, before_style, after, after_index, |
| + after_style)) |
| + return false; |
| + RemoveTrailingCollapsibleSpace(next_start_offset); |
| + return true; |
| } |
| -void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists( |
| +bool NGInlineItemsBuilder::RemoveTrailingCollapsibleSpaceIfExists( |
| unsigned* next_start_offset) { |
| - if (last_collapsible_space_ != CollapsibleSpace::kNone && !text_.IsEmpty() && |
| - text_[text_.length() - 1] == kSpaceCharacter) |
| - RemoveTrailingCollapsibleSpace(next_start_offset); |
| + if (last_collapsible_space_ == CollapsibleSpace::kNone || text_.IsEmpty() || |
| + text_[text_.length() - 1] != kSpaceCharacter) |
| + return false; |
| + RemoveTrailingCollapsibleSpace(next_start_offset); |
| + return true; |
| } |
| void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpace( |
| @@ -333,6 +390,29 @@ void NGInlineItemsBuilder::RemoveTrailingCollapsibleSpace( |
| } |
| } |
| +void NGInlineItemsBuilder::AddLastTrailingSpaceToRemovedIndexes( |
| + unsigned last_string_end) { |
| + DCHECK(removed_indexes_); |
| + DCHECK(input_strings_lengths_); |
| + DCHECK_EQ(removed_indexes_->size(), input_strings_lengths_->size()); |
| + for (unsigned i = removed_indexes_->size(); i;) { |
| + Vector<unsigned>& indexes = (*removed_indexes_)[--i]; |
| + size_t last_unremoved = |
| + GetLargestAbsentInteger(indexes, (i + 1) == removed_indexes_->size() |
| + ? last_string_end |
| + : (*input_strings_lengths_)[i]); |
| + if (last_unremoved == kNotFound) |
| + continue; |
| + |
| + indexes.insert( |
| + std::lower_bound(indexes.begin(), indexes.end(), last_unremoved) - |
| + indexes.begin(), |
| + last_unremoved); |
| + return; |
| + } |
| + NOTREACHED(); |
| +} |
| + |
| void NGInlineItemsBuilder::AppendBidiControl(const ComputedStyle* style, |
| UChar ltr, |
| UChar rtl) { |