Index: third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc |
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc |
index d464a038527e453fe395bcae591ee9444b65ff27..4656455ad8dca35170336bde27cd74b2a8b99a5b 100644 |
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc |
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc |
@@ -17,7 +17,6 @@ |
#include "core/style/ComputedStyle.h" |
#include "platform/fonts/shaping/HarfBuzzShaper.h" |
#include "platform/fonts/shaping/ShapingLineBreaker.h" |
-#include "platform/text/TextBreakIterator.h" |
namespace blink { |
@@ -28,19 +27,7 @@ namespace { |
#if defined(MOCK_SHAPE_LINE) |
// The mock for ShapingLineBreaker::ShapeLine(). |
-// Given the design of ShapingLineBreaker, expected semantics are: |
-// - The returned offset is always > item.StartOffset(). |
-// - offset < item.EndOffset(): |
-// - width <= available_width: the break opportunity to fit is found. |
-// - width > available_width: the first break opportunity did not fit. |
-// - offset == item.EndOffset(): |
-// - width <= available_width: the break opportunity at the end of the item |
-// fits. |
-// - width > available_width: the first break opportunity is at the end of |
-// the item and it does not fit. |
-// - offset > item.EndOffset():, the first break opportunity is beyond the |
-// end of item and thus cannot measure. In this case, inline_size shows the |
-// width until the end of the item. It may fit or may not. |
+// See BreakText() for the expected semantics. |
std::pair<unsigned, LayoutUnit> ShapeLineMock( |
const NGInlineItem& item, |
unsigned offset, |
@@ -67,23 +54,16 @@ std::pair<unsigned, LayoutUnit> ShapeLineMock( |
} |
#endif |
-LineBreakType GetLineBreakType(const ComputedStyle& style) { |
- if (style.AutoWrap()) { |
- if (style.WordBreak() == EWordBreak::kBreakAll || |
- style.WordBreak() == EWordBreak::kBreakWord) |
- return LineBreakType::kBreakAll; |
- if (style.WordBreak() == EWordBreak::kKeepAll) |
- return LineBreakType::kKeepAll; |
- } |
- return LineBreakType::kNormal; |
-} |
- |
} // namespace |
NGLineBreaker::NGLineBreaker(NGInlineNode* node, |
const NGConstraintSpace* space, |
NGInlineBreakToken* break_token) |
- : node_(node), constraint_space_(space), item_index_(0), offset_(0) { |
+ : node_(node), |
+ constraint_space_(space), |
+ item_index_(0), |
+ offset_(0), |
+ break_iterator_(node->Text()) { |
if (break_token) { |
item_index_ = break_token->ItemIndex(); |
offset_ = break_token->TextOffset(); |
@@ -106,130 +86,169 @@ void NGLineBreaker::BreakLine(NGInlineItemResults* item_results, |
NGInlineLayoutAlgorithm* algorithm) { |
DCHECK(item_results->IsEmpty()); |
const Vector<NGInlineItem>& items = node_->Items(); |
- const String& text = node_->Text(); |
const ComputedStyle& style = node_->Style(); |
- LazyLineBreakIterator break_iterator(text, style.LocaleForLineBreakIterator(), |
- GetLineBreakType(style)); |
+ UpdateBreakIterator(style); |
#if !defined(MOCK_SHAPE_LINE) |
+ // TODO(kojii): Instantiate in the constructor. |
HarfBuzzShaper shaper(text.Characters16(), text.length()); |
#endif |
- LayoutUnit available_width = algorithm->AvailableWidth(); |
- LayoutUnit position; |
+ available_width_ = algorithm->AvailableWidth(); |
+ position_ = LayoutUnit(0); |
+ LineBreakState state = LineBreakState::kNotBreakable; |
+ |
while (item_index_ < items.size()) { |
+ // CloseTag prohibits to break before. |
const NGInlineItem& item = items[item_index_]; |
+ if (item.Type() == NGInlineItem::kCloseTag) { |
+ item_results->push_back( |
+ NGInlineItemResult(item_index_, offset_, item.EndOffset())); |
+ HandleCloseTag(item, &item_results->back()); |
+ continue; |
+ } |
+ |
+ if (state == LineBreakState::kBreakAfterTrailings) |
+ return; |
+ if (state == LineBreakState::kIsBreakable && position_ > available_width_) |
+ return HandleOverflow(item_results); |
+ |
item_results->push_back( |
NGInlineItemResult(item_index_, offset_, item.EndOffset())); |
NGInlineItemResult* item_result = &item_results->back(); |
+ if (item.Type() == NGInlineItem::kText) { |
+ state = HandleText(item, item_result); |
+ } else if (item.Type() == NGInlineItem::kAtomicInline) { |
+ state = HandleAtomicInline(item, item_result); |
+ } else if (item.Type() == NGInlineItem::kControl) { |
+ state = HandleControlItem(item, item_result); |
+ if (state == LineBreakState::kForcedBreak) |
+ return; |
+ } else if (item.Type() == NGInlineItem::kOpenTag) { |
+ HandleOpenTag(item, item_result); |
+ state = LineBreakState::kNotBreakable; |
+ } else if (item.Type() == NGInlineItem::kFloating) { |
+ HandleFloat(item, item_results, algorithm); |
+ } else { |
+ MoveToNextOf(item); |
+ } |
+ } |
+ if (state == LineBreakState::kIsBreakable && position_ > available_width_) |
+ return HandleOverflow(item_results); |
+} |
- // If the start offset is at the item boundary, try to add the entire item. |
- if (offset_ == item.StartOffset()) { |
- if (item.Type() == NGInlineItem::kText) { |
- item_result->inline_size = item.InlineSize(); |
- } else if (item.Type() == NGInlineItem::kAtomicInline) { |
- LayoutAtomicInline(item, item_result); |
- } else if (item.Type() == NGInlineItem::kControl) { |
- if (HandleControlItem(item, text, item_result, position)) { |
- MoveToNextOf(item); |
- break; |
- } |
- } else if (item.Type() == NGInlineItem::kFloating) { |
- algorithm->LayoutAndPositionFloat(position, item.GetLayoutObject()); |
- // Floats may change the available width if they fit. |
- available_width = algorithm->AvailableWidth(); |
- // Floats are already positioned in the container_builder. |
- item_results->pop_back(); |
- MoveToNextOf(item); |
- continue; |
- } else { |
- MoveToNextOf(item); |
- continue; |
- } |
- LayoutUnit next_position = position + item_result->inline_size; |
- if (next_position <= available_width) { |
- MoveToNextOf(item); |
- position = next_position; |
- continue; |
- } |
+NGLineBreaker::LineBreakState NGLineBreaker::HandleText( |
+ const NGInlineItem& item, |
+ NGInlineItemResult* item_result) { |
+ DCHECK_EQ(item.Type(), NGInlineItem::kText); |
+ |
+ // If the start offset is at the item boundary, try to add the entire item. |
+ if (offset_ == item.StartOffset()) { |
+ item_result->inline_size = item.InlineSize(); |
+ LayoutUnit next_position = position_ + item_result->inline_size; |
+ if (!auto_wrap_ || next_position <= available_width_) { |
+ position_ = next_position; |
+ MoveToNextOf(item); |
+ if (auto_wrap_ && break_iterator_.IsBreakable(item.EndOffset())) |
+ return LineBreakState::kIsBreakable; |
+ item_result->prohibit_break_after = true; |
+ return LineBreakState::kNotBreakable; |
+ } |
+ } |
- // The entire item does not fit. Handle non-text items as overflow, |
- // since only text item is breakable. |
- if (item.Type() != NGInlineItem::kText) { |
- MoveToNextOf(item); |
- return HandleOverflow(item_results, break_iterator); |
- } |
+ if (auto_wrap_) { |
+ // Try to break inside of this text item. |
+ BreakText(item_result, item, available_width_ - position_); |
+ position_ += item_result->inline_size; |
+ |
+ bool is_overflow = position_ > available_width_; |
+ item_result->no_break_opportunities_inside = is_overflow; |
+ if (item_result->end_offset < item.EndOffset()) { |
+ offset_ = item_result->end_offset; |
+ return is_overflow ? LineBreakState::kIsBreakable |
+ : LineBreakState::kBreakAfterTrailings; |
} |
+ MoveToNextOf(item); |
+ return item_result->prohibit_break_after ? LineBreakState::kNotBreakable |
+ : LineBreakState::kIsBreakable; |
+ } |
+ |
+ // Add the rest of the item if !auto_wrap. |
+ // Because the start position may need to reshape, run ShapingLineBreaker |
+ // with max available width. |
+ DCHECK_NE(offset_, item.StartOffset()); |
+ BreakText(item_result, item, LayoutUnit::Max()); |
+ DCHECK_EQ(item_result->end_offset, item.EndOffset()); |
+ item_result->no_break_opportunities_inside = true; |
+ item_result->prohibit_break_after = true; |
+ position_ += item_result->inline_size; |
+ MoveToNextOf(item); |
+ return LineBreakState::kNotBreakable; |
+} |
+ |
+void NGLineBreaker::BreakText(NGInlineItemResult* item_result, |
+ const NGInlineItem& item, |
+ LayoutUnit available_width) { |
+ DCHECK_EQ(item.Type(), NGInlineItem::kText); |
+ item.AssertOffset(item_result->start_offset); |
- // Either the start or the break is in the mid of a text item. |
- DCHECK_EQ(item.Type(), NGInlineItem::kText); |
- DCHECK_LT(offset_, item.EndOffset()); |
- break_iterator.SetLocale(item.Style()->LocaleForLineBreakIterator()); |
- break_iterator.SetBreakType(GetLineBreakType(*item.Style())); |
#if defined(MOCK_SHAPE_LINE) |
- unsigned break_offset; |
- std::tie(break_offset, item_result->inline_size) = ShapeLineMock( |
- item, offset_, available_width - position, break_iterator); |
+ std::tie(item_result->end_offset, item_result->inline_size) = ShapeLineMock( |
+ item, item_result->start_offset, available_width, break_iterator_); |
#else |
- // TODO(kojii): We need to instantiate ShapingLineBreaker here because it |
- // has item-specific info as context. Should they be part of ShapeLine() to |
- // instantiate once, or is this just fine since instatiation is not |
- // expensive? |
- DCHECK_EQ(item.TextShapeResult()->StartIndexForResult(), |
- item.StartOffset()); |
- DCHECK_EQ(item.TextShapeResult()->EndIndexForResult(), item.EndOffset()); |
- ShapingLineBreaker breaker(&shaper, &item.Style()->GetFont(), |
- item.TextShapeResult(), &break_iterator); |
- unsigned break_offset; |
- item_result->shape_result = |
- breaker.ShapeLine(offset_, available_width - position, &break_offset); |
- item_result->inline_size = item_result->shape_result->SnappedWidth(); |
+ // TODO(kojii): We need to instantiate ShapingLineBreaker here because it |
+ // has item-specific info as context. Should they be part of ShapeLine() to |
+ // instantiate once, or is this just fine since instatiation is not |
+ // expensive? |
+ DCHECK_EQ(item.TextShapeResult()->StartIndexForResult(), item.StartOffset()); |
+ DCHECK_EQ(item.TextShapeResult()->EndIndexForResult(), item.EndOffset()); |
+ ShapingLineBreaker breaker(&shaper, &item.Style()->GetFont(), |
+ item.TextShapeResult(), break_iterator_); |
+ item_result->shape_result = breaker.ShapeLine( |
+ item_result->start_offset, available_width, &item_result->end_offset); |
+ item_result->inline_size = item_result->shape_result->SnappedWidth(); |
#endif |
- DCHECK_GT(break_offset, offset_); |
- position += item_result->inline_size; |
- |
- // If the break found within the item, break here. |
- if (break_offset < item.EndOffset()) { |
- offset_ = item_result->end_offset = break_offset; |
- if (position <= available_width) |
- break; |
- // The first break opportunity of the item does not fit. |
- } else { |
- // No break opporunity in the item, or the first break opportunity is at |
- // the end of the item. If it fits, continue to the next item. |
- item_result->end_offset = item.EndOffset(); |
- MoveToNextOf(item); |
- if (position <= available_width) |
- continue; |
- } |
- |
- // We need to look at next item if we're overflowing, and the break |
- // opportunity is beyond this item. |
- if (break_offset > item.EndOffset()) |
- continue; |
- return HandleOverflow(item_results, break_iterator); |
+ DCHECK_GT(item_result->end_offset, item_result->start_offset); |
+ // * If width <= available_width: |
+ // * If offset < item.EndOffset(): the break opportunity to fit is found. |
+ // * If offset == item.EndOffset(): the break opportunity at the end fits. |
+ // There may be room for more characters. |
+ // * If offset > item.EndOffset(): the first break opportunity is beyond |
+ // the end. There may be room for more characters. |
+ // * If width > available_width: The first break opporunity does not fit. |
+ // offset is the first break opportunity, either inside, at the end, or |
+ // beyond the end. |
+ if (item_result->end_offset <= item.EndOffset()) { |
+ item_result->prohibit_break_after = false; |
+ } else { |
+ item_result->prohibit_break_after = true; |
+ item_result->end_offset = item.EndOffset(); |
} |
} |
// Measure control items; new lines and tab, that are similar to text, affect |
// layout, but do not need shaping/painting. |
-bool NGLineBreaker::HandleControlItem(const NGInlineItem& item, |
- const String& text, |
- NGInlineItemResult* item_result, |
- LayoutUnit position) { |
+NGLineBreaker::LineBreakState NGLineBreaker::HandleControlItem( |
+ const NGInlineItem& item, |
+ NGInlineItemResult* item_result) { |
DCHECK_EQ(item.Length(), 1u); |
- UChar character = text[item.StartOffset()]; |
- if (character == kNewlineCharacter) |
- return true; |
- |
+ UChar character = node_->Text()[item.StartOffset()]; |
+ if (character == kNewlineCharacter) { |
+ MoveToNextOf(item); |
+ return LineBreakState::kForcedBreak; |
+ } |
DCHECK_EQ(character, kTabulationCharacter); |
DCHECK(item.Style()); |
const ComputedStyle& style = *item.Style(); |
const Font& font = style.GetFont(); |
- item_result->inline_size = font.TabWidth(style.GetTabSize(), position); |
- return false; |
+ item_result->inline_size = font.TabWidth(style.GetTabSize(), position_); |
+ position_ += item_result->inline_size; |
+ MoveToNextOf(item); |
+ // TODO(kojii): Implement break around the tab character. |
+ return LineBreakState::kIsBreakable; |
} |
-void NGLineBreaker::LayoutAtomicInline(const NGInlineItem& item, |
- NGInlineItemResult* item_result) { |
+NGLineBreaker::LineBreakState NGLineBreaker::HandleAtomicInline( |
+ const NGInlineItem& item, |
+ NGInlineItemResult* item_result) { |
DCHECK_EQ(item.Type(), NGInlineItem::kAtomicInline); |
NGBlockNode* node = new NGBlockNode(item.GetLayoutObject()); |
const ComputedStyle& style = node->Style(); |
@@ -251,65 +270,158 @@ void NGLineBreaker::LayoutAtomicInline(const NGInlineItem& item, |
ComputeMargins(*constraint_space_, style, |
constraint_space_->WritingMode(), style.Direction()); |
item_result->inline_size += item_result->margins.InlineSum(); |
+ |
+ position_ += item_result->inline_size; |
+ MoveToNextOf(item); |
+ if (auto_wrap_) |
+ return LineBreakState::kIsBreakable; |
+ item_result->prohibit_break_after = true; |
+ return LineBreakState::kNotBreakable; |
+} |
+ |
+void NGLineBreaker::HandleFloat(const NGInlineItem& item, |
+ NGInlineItemResults* item_results, |
+ NGInlineLayoutAlgorithm* algorithm) { |
+ algorithm->LayoutAndPositionFloat(position_, item.GetLayoutObject()); |
+ // Floats may change the available width if they fit. |
+ available_width_ = algorithm->AvailableWidth(); |
+ // Floats are already positioned in the container_builder. |
+ item_results->pop_back(); |
+ MoveToNextOf(item); |
+} |
+ |
+void NGLineBreaker::HandleOpenTag(const NGInlineItem& item, |
+ NGInlineItemResult* item_result) { |
+ if (item.HasStartEdge()) { |
+ DCHECK(item.Style()); |
+ // TODO(kojii): We compute 16 values and discard 12 out of that, and do it 3 |
+ // times per element. We may want to cache this. crrev.com/2865903002/#msg14 |
+ NGBoxStrut margins = ComputeMargins(*constraint_space_, *item.Style(), |
+ constraint_space_->WritingMode(), |
+ constraint_space_->Direction()); |
+ NGBoxStrut borders = ComputeBorders(*constraint_space_, *item.Style()); |
+ NGBoxStrut paddings = ComputePadding(*constraint_space_, *item.Style()); |
+ item_result->inline_size = |
+ margins.inline_start + borders.inline_start + paddings.inline_start; |
+ position_ += item_result->inline_size; |
+ } |
+ UpdateBreakIterator(*item.Style()); |
+ MoveToNextOf(item); |
+} |
+ |
+void NGLineBreaker::HandleCloseTag(const NGInlineItem& item, |
+ NGInlineItemResult* item_result) { |
+ if (item.HasEndEdge()) { |
+ DCHECK(item.Style()); |
+ NGBoxStrut margins = ComputeMargins(*constraint_space_, *item.Style(), |
+ constraint_space_->WritingMode(), |
+ constraint_space_->Direction()); |
+ NGBoxStrut borders = ComputeBorders(*constraint_space_, *item.Style()); |
+ NGBoxStrut paddings = ComputePadding(*constraint_space_, *item.Style()); |
+ item_result->inline_size = |
+ margins.inline_end + borders.inline_end + paddings.inline_end; |
+ position_ += item_result->inline_size; |
+ } |
+ DCHECK(item.GetLayoutObject() && item.GetLayoutObject()->Parent()); |
+ UpdateBreakIterator(item.GetLayoutObject()->Parent()->StyleRef()); |
+ MoveToNextOf(item); |
} |
// Handles when the last item overflows. |
// At this point, item_results does not fit into the current line, and there |
// are no break opportunities in item_results.back(). |
-void NGLineBreaker::HandleOverflow( |
- NGInlineItemResults* item_results, |
- const LazyLineBreakIterator& break_iterator) { |
- DCHECK_GT(offset_, 0u); |
- |
- // Find the last break opportunity. If none, let this line overflow. |
- unsigned line_start_offset = item_results->front().start_offset; |
- unsigned break_offset = |
- break_iterator.PreviousBreakOpportunity(offset_ - 1, line_start_offset); |
- if (!break_offset || break_offset <= line_start_offset) { |
- AppendCloseTags(item_results); |
- return; |
- } |
- |
- // Truncate the end of the line to the break opportunity. |
+void NGLineBreaker::HandleOverflow(NGInlineItemResults* item_results) { |
const Vector<NGInlineItem>& items = node_->Items(); |
- unsigned new_end = item_results->size(); |
- while (true) { |
- NGInlineItemResult* item_result = &(*item_results)[--new_end]; |
- if (item_result->start_offset < break_offset) { |
- // The break is at the mid of the item. Adjust the end_offset to the new |
- // break offset. |
- const NGInlineItem& item = items[item_result->item_index]; |
- item.AssertEndOffset(break_offset); |
- DCHECK_EQ(item.Type(), NGInlineItem::kText); |
- DCHECK_NE(item_result->end_offset, break_offset); |
- item_result->end_offset = break_offset; |
- item_result->inline_size = |
- item.InlineSize(item_result->start_offset, item_result->end_offset); |
- // TODO(kojii): May need to reshape. Add to ShapingLineBreaker? |
- new_end++; |
- break; |
- } |
- if (item_result->start_offset == break_offset) { |
- // The new break offset is at the item boundary. Remove items up to the |
- // new break offset. |
- // TODO(kojii): Remove open tags as well. |
- break; |
+ LayoutUnit rewind_width = available_width_ - position_; |
+ DCHECK_LT(rewind_width, 0); |
+ |
+ // Search for a break opportunity that can fit. |
+ // Also keep track of the first break opportunity in case of overflow. |
+ unsigned break_before = 0; |
+ unsigned break_before_if_before_allow = 0; |
+ LayoutUnit rewind_width_if_before_allow; |
+ bool last_item_prohibits_break_before = true; |
+ for (unsigned i = item_results->size(); i;) { |
+ NGInlineItemResult* item_result = &(*item_results)[--i]; |
+ const NGInlineItem& item = items[item_result->item_index]; |
+ rewind_width += item_result->inline_size; |
+ if (item.Type() == NGInlineItem::kText || |
+ item.Type() == NGInlineItem::kAtomicInline) { |
+ // Try to break inside of this item. |
+ if (item.Type() == NGInlineItem::kText && rewind_width >= 0 && |
+ !item_result->no_break_opportunities_inside) { |
+ // When the text fits but its right margin does not, the break point |
+ // must not be at the end. |
+ LayoutUnit item_available_width = |
+ std::min(rewind_width, item_result->inline_size - 1); |
+ BreakText(item_result, item, item_available_width); |
+ if (item_result->inline_size <= item_available_width) { |
+ DCHECK_LT(item_result->end_offset, item.EndOffset()); |
+ DCHECK(!item_result->prohibit_break_after); |
+ return Rewind(item_results, i + 1); |
+ } |
+ if (!item_result->prohibit_break_after && |
+ !last_item_prohibits_break_before) { |
+ break_before = i + 1; |
+ } |
+ } |
+ |
+ // Try to break after this item. |
+ if (break_before_if_before_allow && !item_result->prohibit_break_after) { |
+ if (rewind_width_if_before_allow >= 0) |
+ return Rewind(item_results, break_before_if_before_allow); |
+ break_before = break_before_if_before_allow; |
+ } |
+ |
+ // Otherwise, before this item is a possible break point. |
+ break_before_if_before_allow = i; |
+ rewind_width_if_before_allow = rewind_width; |
+ last_item_prohibits_break_before = false; |
+ } else if (item.Type() == NGInlineItem::kCloseTag) { |
+ last_item_prohibits_break_before = true; |
+ } else { |
+ if (i + 1 == break_before_if_before_allow) { |
+ break_before_if_before_allow = i; |
+ rewind_width_if_before_allow = rewind_width; |
+ } |
+ last_item_prohibits_break_before = false; |
} |
} |
- DCHECK_GT(new_end, 0u); |
+ // The rewind point did not found, let this line overflow. |
+ // If there was a break opporunity, the overflow should stop there. |
+ if (break_before) |
+ Rewind(item_results, break_before); |
+} |
+ |
+void NGLineBreaker::Rewind(NGInlineItemResults* item_results, |
+ unsigned new_end) { |
// TODO(kojii): Should we keep results for the next line? We don't need to |
// re-layout atomic inlines. |
// TODO(kojii): Removing processed floats is likely a problematic. Keep |
// floats in this line, or keep it for the next line. |
item_results->Shrink(new_end); |
- // Update the current item index and offset to the new break point. |
- const NGInlineItemResult& last_item_result = item_results->back(); |
- offset_ = last_item_result.end_offset; |
- item_index_ = last_item_result.item_index; |
- if (items[item_index_].EndOffset() == offset_) |
- item_index_++; |
+ MoveToNextOf(item_results->back()); |
+} |
+ |
+void NGLineBreaker::UpdateBreakIterator(const ComputedStyle& style) { |
+ auto_wrap_ = style.AutoWrap(); |
+ |
+ if (auto_wrap_) { |
+ break_iterator_.SetLocale(style.LocaleForLineBreakIterator()); |
+ |
+ if (style.WordBreak() == EWordBreak::kBreakAll || |
+ style.WordBreak() == EWordBreak::kBreakWord) { |
+ break_iterator_.SetBreakType(LineBreakType::kBreakAll); |
+ } else if (style.WordBreak() == EWordBreak::kKeepAll) { |
+ break_iterator_.SetBreakType(LineBreakType::kKeepAll); |
+ } else { |
+ break_iterator_.SetBreakType(LineBreakType::kNormal); |
+ } |
+ |
+ // TODO(kojii): Implement word-wrap/overflow-wrap property |
+ } |
} |
void NGLineBreaker::MoveToNextOf(const NGInlineItem& item) { |
@@ -318,6 +430,14 @@ void NGLineBreaker::MoveToNextOf(const NGInlineItem& item) { |
item_index_++; |
} |
+void NGLineBreaker::MoveToNextOf(const NGInlineItemResult& item_result) { |
+ offset_ = item_result.end_offset; |
+ item_index_ = item_result.item_index; |
+ const NGInlineItem& item = node_->Items()[item_result.item_index]; |
+ if (offset_ == item.EndOffset()) |
+ item_index_++; |
+} |
+ |
void NGLineBreaker::SkipCollapsibleWhitespaces() { |
const Vector<NGInlineItem>& items = node_->Items(); |
if (item_index_ >= items.size()) |
@@ -336,17 +456,6 @@ void NGLineBreaker::SkipCollapsibleWhitespaces() { |
} |
} |
-void NGLineBreaker::AppendCloseTags(NGInlineItemResults* item_results) { |
- const Vector<NGInlineItem>& items = node_->Items(); |
- for (; item_index_ < items.size(); item_index_++) { |
- const NGInlineItem& item = items[item_index_]; |
- if (item.Type() != NGInlineItem::kCloseTag) |
- break; |
- DCHECK_EQ(offset_, item.EndOffset()); |
- item_results->push_back(NGInlineItemResult(item_index_, offset_, offset_)); |
- } |
-} |
- |
RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const { |
const Vector<NGInlineItem>& items = node_->Items(); |
if (item_index_ >= items.size()) |