| 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 2aec0936902d03f51dcafc4d9a3dd54523d28f61..1038485901038a4a211dbd51b71fa06440c5c91e 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
|
| @@ -113,9 +113,15 @@ static void AppendItem(Vector<NGInlineItem>* items,
|
| items->push_back(NGInlineItem(type, start, end, style, layout_object));
|
| }
|
|
|
| -static inline bool IsCollapsibleSpace(UChar c, bool preserve_newline) {
|
| +static inline bool IsCollapsibleSpace(UChar c) {
|
| return c == kSpaceCharacter || c == kTabulationCharacter ||
|
| - (!preserve_newline && c == kNewlineCharacter);
|
| + c == kNewlineCharacter;
|
| +}
|
| +
|
| +// Characters needing a separate control item than other text items.
|
| +// It makes the line breaker easier to handle.
|
| +static inline bool IsControlItemCharacter(UChar c) {
|
| + return c == kTabulationCharacter || c == kNewlineCharacter;
|
| }
|
|
|
| void NGInlineItemsBuilder::Append(const String& string,
|
| @@ -123,59 +129,60 @@ void NGInlineItemsBuilder::Append(const String& string,
|
| LayoutObject* layout_object) {
|
| if (string.IsEmpty())
|
| return;
|
| + text_.ReserveCapacity(string.length());
|
|
|
| EWhiteSpace whitespace = style->WhiteSpace();
|
| - bool preserve_newline =
|
| - ComputedStyle::PreserveNewline(whitespace) && !is_svgtext_;
|
| - bool collapse_whitespace = ComputedStyle::CollapseWhiteSpace(whitespace);
|
| - unsigned start_offset = text_.length();
|
| + if (!ComputedStyle::CollapseWhiteSpace(whitespace))
|
| + return AppendWithoutWhiteSpaceCollapsing(string, style, layout_object);
|
| + if (ComputedStyle::PreserveNewline(whitespace) && !is_svgtext_)
|
| + return AppendWithPreservingNewlines(string, style, layout_object);
|
|
|
| - if (!collapse_whitespace) {
|
| - text_.Append(string);
|
| - last_collapsible_space_ = CollapsibleSpace::kNone;
|
| - } else {
|
| - text_.ReserveCapacity(string.length());
|
| - for (unsigned i = 0; i < string.length();) {
|
| - UChar c = string[i];
|
| - if (c == kNewlineCharacter) {
|
| - if (preserve_newline) {
|
| - RemoveTrailingCollapsibleSpaceIfExists(&start_offset);
|
| - text_.Append(c);
|
| - // Remove collapsible spaces immediately following a newline.
|
| - last_collapsible_space_ = CollapsibleSpace::kSpace;
|
| - i++;
|
| - continue;
|
| - }
|
| -
|
| - if (last_collapsible_space_ == CollapsibleSpace::kNone)
|
| - text_.Append(kSpaceCharacter);
|
| - last_collapsible_space_ = CollapsibleSpace::kNewline;
|
| - i++;
|
| - continue;
|
| - }
|
| + AppendWithWhiteSpaceCollapsing(string, 0, string.length(), style,
|
| + layout_object);
|
| +}
|
|
|
| - if (c == kSpaceCharacter || c == kTabulationCharacter) {
|
| - if (last_collapsible_space_ == CollapsibleSpace::kNone) {
|
| - text_.Append(kSpaceCharacter);
|
| - last_collapsible_space_ = CollapsibleSpace::kSpace;
|
| - }
|
| - i++;
|
| - continue;
|
| +void NGInlineItemsBuilder::AppendWithWhiteSpaceCollapsing(
|
| + const String& string,
|
| + unsigned start,
|
| + unsigned end,
|
| + const ComputedStyle* style,
|
| + LayoutObject* layout_object) {
|
| + unsigned start_offset = text_.length();
|
| + for (unsigned i = start; i < end;) {
|
| + UChar c = string[i];
|
| + 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);
|
| + return;
|
| }
|
|
|
| - if (last_collapsible_space_ == CollapsibleSpace::kNewline) {
|
| - RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i,
|
| - style);
|
| - }
|
| + if (last_collapsible_space_ == CollapsibleSpace::kNone)
|
| + text_.Append(kSpaceCharacter);
|
| + last_collapsible_space_ = CollapsibleSpace::kNewline;
|
| + i++;
|
| + continue;
|
| + }
|
|
|
| - unsigned start_of_non_space = i;
|
| - for (i++; i < string.length(); i++) {
|
| - if (IsCollapsibleSpace(string[i], false))
|
| - break;
|
| + if (c == kSpaceCharacter || c == kTabulationCharacter) {
|
| + if (last_collapsible_space_ == CollapsibleSpace::kNone) {
|
| + text_.Append(kSpaceCharacter);
|
| + last_collapsible_space_ = CollapsibleSpace::kSpace;
|
| }
|
| - text_.Append(string, start_of_non_space, i - start_of_non_space);
|
| - last_collapsible_space_ = CollapsibleSpace::kNone;
|
| + i++;
|
| + continue;
|
| }
|
| +
|
| + if (last_collapsible_space_ == CollapsibleSpace::kNewline) {
|
| + RemoveTrailingCollapsibleNewlineIfNeeded(&start_offset, string, i, style);
|
| + }
|
| +
|
| + size_t end_of_non_space = string.Find(IsCollapsibleSpace, i + 1);
|
| + if (end_of_non_space == kNotFound)
|
| + end_of_non_space = string.length();
|
| + text_.Append(string, i, end_of_non_space - i);
|
| + i = end_of_non_space;
|
| + last_collapsible_space_ = CollapsibleSpace::kNone;
|
| }
|
|
|
| if (text_.length() > start_offset) {
|
| @@ -184,13 +191,69 @@ void NGInlineItemsBuilder::Append(const String& string,
|
| }
|
| }
|
|
|
| +// Even when without whitespace collapsing, control characters (newlines and
|
| +// tabs) are in their own control items to make the line breaker easier.
|
| +void NGInlineItemsBuilder::AppendWithoutWhiteSpaceCollapsing(
|
| + const String& string,
|
| + const ComputedStyle* style,
|
| + LayoutObject* layout_object) {
|
| + for (unsigned start = 0; start < string.length();) {
|
| + UChar c = string[start];
|
| + if (IsControlItemCharacter(c)) {
|
| + Append(NGInlineItem::kControl, c, style, layout_object);
|
| + start++;
|
| + continue;
|
| + }
|
| +
|
| + size_t end = string.Find(IsControlItemCharacter, start + 1);
|
| + if (end == kNotFound)
|
| + end = string.length();
|
| + unsigned start_offset = text_.length();
|
| + text_.Append(string, start, end - start);
|
| + AppendItem(items_, NGInlineItem::kText, start_offset, text_.length(), style,
|
| + layout_object);
|
| + start = end;
|
| + }
|
| +
|
| + last_collapsible_space_ = CollapsibleSpace::kNone;
|
| +}
|
| +
|
| +void NGInlineItemsBuilder::AppendWithPreservingNewlines(
|
| + const String& string,
|
| + const ComputedStyle* style,
|
| + LayoutObject* layout_object) {
|
| + for (unsigned start = 0; start < string.length();) {
|
| + if (string[start] == kNewlineCharacter) {
|
| + AppendForcedBreak(style, layout_object);
|
| + start++;
|
| + continue;
|
| + }
|
| +
|
| + size_t end = string.find(kNewlineCharacter, start + 1);
|
| + if (end == kNotFound)
|
| + end = string.length();
|
| + AppendWithWhiteSpaceCollapsing(string, start, end, style, layout_object);
|
| + start = end;
|
| + }
|
| +}
|
| +
|
| +void NGInlineItemsBuilder::AppendForcedBreak(const ComputedStyle* style,
|
| + LayoutObject* layout_object) {
|
| + // Remove collapsible spaces immediately before a preserved newline.
|
| + unsigned start_offset = text_.length();
|
| + RemoveTrailingCollapsibleSpaceIfExists(&start_offset);
|
| +
|
| + Append(NGInlineItem::kControl, kNewlineCharacter, style, layout_object);
|
| +
|
| + // Remove collapsible spaces immediately after a preserved newline.
|
| + last_collapsible_space_ = CollapsibleSpace::kSpace;
|
| +}
|
| +
|
| void NGInlineItemsBuilder::Append(NGInlineItem::NGInlineItemType type,
|
| UChar character,
|
| const ComputedStyle* style,
|
| LayoutObject* layout_object) {
|
| DCHECK_NE(character, kSpaceCharacter);
|
| - DCHECK_NE(character, kTabulationCharacter);
|
| - DCHECK_NE(character, kNewlineCharacter);
|
| DCHECK_NE(character, kZeroWidthSpaceCharacter);
|
|
|
| text_.Append(character);
|
|
|