Chromium Code Reviews| 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()) { |
|
ikilpatrick
2017/05/30 16:05:26
If i get time this week i'll play with pulling thi
kojii
2017/05/30 17:56:18
Sounds good, will work on other files this week.
|
| + // 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()) |