| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/layout/ng/inline/ng_line_breaker.h" | 5 #include "core/layout/ng/inline/ng_line_breaker.h" |
| 6 | 6 |
| 7 #include "core/layout/ng/inline/ng_inline_break_token.h" | 7 #include "core/layout/ng/inline/ng_inline_break_token.h" |
| 8 #include "core/layout/ng/inline/ng_inline_layout_algorithm.h" | 8 #include "core/layout/ng/inline/ng_inline_layout_algorithm.h" |
| 9 #include "core/layout/ng/inline/ng_inline_node.h" | 9 #include "core/layout/ng/inline/ng_inline_node.h" |
| 10 #include "core/layout/ng/inline/ng_text_fragment.h" | 10 #include "core/layout/ng/inline/ng_text_fragment.h" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 return std::make_pair(next_break, next_inline_size); | 49 return std::make_pair(next_break, next_inline_size); |
| 50 offset = next_break; | 50 offset = next_break; |
| 51 inline_size = next_inline_size; | 51 inline_size = next_inline_size; |
| 52 has_break_opportunities = true; | 52 has_break_opportunities = true; |
| 53 } | 53 } |
| 54 } | 54 } |
| 55 #endif | 55 #endif |
| 56 | 56 |
| 57 } // namespace | 57 } // namespace |
| 58 | 58 |
| 59 NGLineBreaker::NGLineBreaker(NGInlineNode* node, | 59 NGLineBreaker::NGLineBreaker(NGInlineNode node, |
| 60 const NGConstraintSpace* space, | 60 const NGConstraintSpace* space, |
| 61 NGInlineBreakToken* break_token) | 61 NGInlineBreakToken* break_token) |
| 62 : node_(node), | 62 : node_(node), |
| 63 constraint_space_(space), | 63 constraint_space_(space), |
| 64 item_index_(0), | 64 item_index_(0), |
| 65 offset_(0), | 65 offset_(0), |
| 66 break_iterator_(node->Text()) { | 66 break_iterator_(node.Text()) { |
| 67 if (break_token) { | 67 if (break_token) { |
| 68 item_index_ = break_token->ItemIndex(); | 68 item_index_ = break_token->ItemIndex(); |
| 69 offset_ = break_token->TextOffset(); | 69 offset_ = break_token->TextOffset(); |
| 70 node->AssertOffset(item_index_, offset_); | 70 node.AssertOffset(item_index_, offset_); |
| 71 } | 71 } |
| 72 } | 72 } |
| 73 | 73 |
| 74 void NGLineBreaker::NextLine(NGInlineItemResults* item_results, | 74 void NGLineBreaker::NextLine(NGInlineItemResults* item_results, |
| 75 NGInlineLayoutAlgorithm* algorithm) { | 75 NGInlineLayoutAlgorithm* algorithm) { |
| 76 BreakLine(item_results, algorithm); | 76 BreakLine(item_results, algorithm); |
| 77 | 77 |
| 78 // TODO(kojii): When editing, or caret is enabled, trailing spaces at wrap | 78 // TODO(kojii): When editing, or caret is enabled, trailing spaces at wrap |
| 79 // point should not be removed. For other cases, we can a) remove, b) leave | 79 // point should not be removed. For other cases, we can a) remove, b) leave |
| 80 // characters without glyphs, or c) leave both characters and glyphs without | 80 // characters without glyphs, or c) leave both characters and glyphs without |
| 81 // measuring. Need to decide which one works the best. | 81 // measuring. Need to decide which one works the best. |
| 82 SkipCollapsibleWhitespaces(); | 82 SkipCollapsibleWhitespaces(); |
| 83 } | 83 } |
| 84 | 84 |
| 85 void NGLineBreaker::BreakLine(NGInlineItemResults* item_results, | 85 void NGLineBreaker::BreakLine(NGInlineItemResults* item_results, |
| 86 NGInlineLayoutAlgorithm* algorithm) { | 86 NGInlineLayoutAlgorithm* algorithm) { |
| 87 DCHECK(item_results->IsEmpty()); | 87 DCHECK(item_results->IsEmpty()); |
| 88 const Vector<NGInlineItem>& items = node_->Items(); | 88 const Vector<NGInlineItem>& items = node_.Items(); |
| 89 const ComputedStyle& style = node_->Style(); | 89 const ComputedStyle& style = node_.Style(); |
| 90 UpdateBreakIterator(style); | 90 UpdateBreakIterator(style); |
| 91 #if !defined(MOCK_SHAPE_LINE) | 91 #if !defined(MOCK_SHAPE_LINE) |
| 92 // TODO(kojii): Instantiate in the constructor. | 92 // TODO(kojii): Instantiate in the constructor. |
| 93 HarfBuzzShaper shaper(text.Characters16(), text.length()); | 93 HarfBuzzShaper shaper(text.Characters16(), text.length()); |
| 94 #endif | 94 #endif |
| 95 available_width_ = algorithm->AvailableWidth(); | 95 available_width_ = algorithm->AvailableWidth(); |
| 96 position_ = LayoutUnit(0); | 96 position_ = LayoutUnit(0); |
| 97 LineBreakState state = LineBreakState::kNotBreakable; | 97 LineBreakState state = LineBreakState::kNotBreakable; |
| 98 | 98 |
| 99 while (item_index_ < items.size()) { | 99 while (item_index_ < items.size()) { |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 item_result->end_offset = item.EndOffset(); | 223 item_result->end_offset = item.EndOffset(); |
| 224 } | 224 } |
| 225 } | 225 } |
| 226 | 226 |
| 227 // Measure control items; new lines and tab, that are similar to text, affect | 227 // Measure control items; new lines and tab, that are similar to text, affect |
| 228 // layout, but do not need shaping/painting. | 228 // layout, but do not need shaping/painting. |
| 229 NGLineBreaker::LineBreakState NGLineBreaker::HandleControlItem( | 229 NGLineBreaker::LineBreakState NGLineBreaker::HandleControlItem( |
| 230 const NGInlineItem& item, | 230 const NGInlineItem& item, |
| 231 NGInlineItemResult* item_result) { | 231 NGInlineItemResult* item_result) { |
| 232 DCHECK_EQ(item.Length(), 1u); | 232 DCHECK_EQ(item.Length(), 1u); |
| 233 UChar character = node_->Text()[item.StartOffset()]; | 233 UChar character = node_.Text()[item.StartOffset()]; |
| 234 if (character == kNewlineCharacter) { | 234 if (character == kNewlineCharacter) { |
| 235 MoveToNextOf(item); | 235 MoveToNextOf(item); |
| 236 return LineBreakState::kForcedBreak; | 236 return LineBreakState::kForcedBreak; |
| 237 } | 237 } |
| 238 DCHECK_EQ(character, kTabulationCharacter); | 238 DCHECK_EQ(character, kTabulationCharacter); |
| 239 DCHECK(item.Style()); | 239 DCHECK(item.Style()); |
| 240 const ComputedStyle& style = *item.Style(); | 240 const ComputedStyle& style = *item.Style(); |
| 241 const Font& font = style.GetFont(); | 241 const Font& font = style.GetFont(); |
| 242 item_result->inline_size = font.TabWidth(style.GetTabSize(), position_); | 242 item_result->inline_size = font.TabWidth(style.GetTabSize(), position_); |
| 243 position_ += item_result->inline_size; | 243 position_ += item_result->inline_size; |
| 244 MoveToNextOf(item); | 244 MoveToNextOf(item); |
| 245 // TODO(kojii): Implement break around the tab character. | 245 // TODO(kojii): Implement break around the tab character. |
| 246 return LineBreakState::kIsBreakable; | 246 return LineBreakState::kIsBreakable; |
| 247 } | 247 } |
| 248 | 248 |
| 249 NGLineBreaker::LineBreakState NGLineBreaker::HandleAtomicInline( | 249 NGLineBreaker::LineBreakState NGLineBreaker::HandleAtomicInline( |
| 250 const NGInlineItem& item, | 250 const NGInlineItem& item, |
| 251 NGInlineItemResult* item_result) { | 251 NGInlineItemResult* item_result) { |
| 252 DCHECK_EQ(item.Type(), NGInlineItem::kAtomicInline); | 252 DCHECK_EQ(item.Type(), NGInlineItem::kAtomicInline); |
| 253 NGBlockNode* node = new NGBlockNode(item.GetLayoutObject()); | 253 NGBlockNode node = NGBlockNode(ToLayoutBox(item.GetLayoutObject())); |
| 254 const ComputedStyle& style = node->Style(); | 254 const ComputedStyle& style = node.Style(); |
| 255 NGConstraintSpaceBuilder constraint_space_builder(constraint_space_); | 255 NGConstraintSpaceBuilder constraint_space_builder(constraint_space_); |
| 256 RefPtr<NGConstraintSpace> constraint_space = | 256 RefPtr<NGConstraintSpace> constraint_space = |
| 257 constraint_space_builder.SetIsNewFormattingContext(true) | 257 constraint_space_builder.SetIsNewFormattingContext(true) |
| 258 .SetIsShrinkToFit(true) | 258 .SetIsShrinkToFit(true) |
| 259 .SetTextDirection(style.Direction()) | 259 .SetTextDirection(style.Direction()) |
| 260 .ToConstraintSpace(FromPlatformWritingMode(style.GetWritingMode())); | 260 .ToConstraintSpace(FromPlatformWritingMode(style.GetWritingMode())); |
| 261 item_result->layout_result = node->Layout(constraint_space.Get()); | 261 item_result->layout_result = node.Layout(constraint_space.Get()); |
| 262 | 262 |
| 263 item_result->inline_size = | 263 item_result->inline_size = |
| 264 NGBoxFragment(constraint_space_->WritingMode(), | 264 NGBoxFragment(constraint_space_->WritingMode(), |
| 265 ToNGPhysicalBoxFragment( | 265 ToNGPhysicalBoxFragment( |
| 266 item_result->layout_result->PhysicalFragment().Get())) | 266 item_result->layout_result->PhysicalFragment().Get())) |
| 267 .InlineSize(); | 267 .InlineSize(); |
| 268 | 268 |
| 269 item_result->margins = | 269 item_result->margins = |
| 270 ComputeMargins(*constraint_space_, style, | 270 ComputeMargins(*constraint_space_, style, |
| 271 constraint_space_->WritingMode(), style.Direction()); | 271 constraint_space_->WritingMode(), style.Direction()); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 } | 324 } |
| 325 DCHECK(item.GetLayoutObject() && item.GetLayoutObject()->Parent()); | 325 DCHECK(item.GetLayoutObject() && item.GetLayoutObject()->Parent()); |
| 326 UpdateBreakIterator(item.GetLayoutObject()->Parent()->StyleRef()); | 326 UpdateBreakIterator(item.GetLayoutObject()->Parent()->StyleRef()); |
| 327 MoveToNextOf(item); | 327 MoveToNextOf(item); |
| 328 } | 328 } |
| 329 | 329 |
| 330 // Handles when the last item overflows. | 330 // Handles when the last item overflows. |
| 331 // At this point, item_results does not fit into the current line, and there | 331 // At this point, item_results does not fit into the current line, and there |
| 332 // are no break opportunities in item_results.back(). | 332 // are no break opportunities in item_results.back(). |
| 333 void NGLineBreaker::HandleOverflow(NGInlineItemResults* item_results) { | 333 void NGLineBreaker::HandleOverflow(NGInlineItemResults* item_results) { |
| 334 const Vector<NGInlineItem>& items = node_->Items(); | 334 const Vector<NGInlineItem>& items = node_.Items(); |
| 335 LayoutUnit rewind_width = available_width_ - position_; | 335 LayoutUnit rewind_width = available_width_ - position_; |
| 336 DCHECK_LT(rewind_width, 0); | 336 DCHECK_LT(rewind_width, 0); |
| 337 | 337 |
| 338 // Search for a break opportunity that can fit. | 338 // Search for a break opportunity that can fit. |
| 339 // Also keep track of the first break opportunity in case of overflow. | 339 // Also keep track of the first break opportunity in case of overflow. |
| 340 unsigned break_before = 0; | 340 unsigned break_before = 0; |
| 341 unsigned break_before_if_before_allow = 0; | 341 unsigned break_before_if_before_allow = 0; |
| 342 LayoutUnit rewind_width_if_before_allow; | 342 LayoutUnit rewind_width_if_before_allow; |
| 343 bool last_item_prohibits_break_before = true; | 343 bool last_item_prohibits_break_before = true; |
| 344 for (unsigned i = item_results->size(); i;) { | 344 for (unsigned i = item_results->size(); i;) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 break_iterator_.SetBreakType(LineBreakType::kKeepAll); | 418 break_iterator_.SetBreakType(LineBreakType::kKeepAll); |
| 419 } else { | 419 } else { |
| 420 break_iterator_.SetBreakType(LineBreakType::kNormal); | 420 break_iterator_.SetBreakType(LineBreakType::kNormal); |
| 421 } | 421 } |
| 422 | 422 |
| 423 // TODO(kojii): Implement word-wrap/overflow-wrap property | 423 // TODO(kojii): Implement word-wrap/overflow-wrap property |
| 424 } | 424 } |
| 425 } | 425 } |
| 426 | 426 |
| 427 void NGLineBreaker::MoveToNextOf(const NGInlineItem& item) { | 427 void NGLineBreaker::MoveToNextOf(const NGInlineItem& item) { |
| 428 DCHECK_EQ(&item, &node_->Items()[item_index_]); | 428 DCHECK_EQ(&item, &node_.Items()[item_index_]); |
| 429 offset_ = item.EndOffset(); | 429 offset_ = item.EndOffset(); |
| 430 item_index_++; | 430 item_index_++; |
| 431 } | 431 } |
| 432 | 432 |
| 433 void NGLineBreaker::MoveToNextOf(const NGInlineItemResult& item_result) { | 433 void NGLineBreaker::MoveToNextOf(const NGInlineItemResult& item_result) { |
| 434 offset_ = item_result.end_offset; | 434 offset_ = item_result.end_offset; |
| 435 item_index_ = item_result.item_index; | 435 item_index_ = item_result.item_index; |
| 436 const NGInlineItem& item = node_->Items()[item_result.item_index]; | 436 const NGInlineItem& item = node_.Items()[item_result.item_index]; |
| 437 if (offset_ == item.EndOffset()) | 437 if (offset_ == item.EndOffset()) |
| 438 item_index_++; | 438 item_index_++; |
| 439 } | 439 } |
| 440 | 440 |
| 441 void NGLineBreaker::SkipCollapsibleWhitespaces() { | 441 void NGLineBreaker::SkipCollapsibleWhitespaces() { |
| 442 const Vector<NGInlineItem>& items = node_->Items(); | 442 const Vector<NGInlineItem>& items = node_.Items(); |
| 443 if (item_index_ >= items.size()) | 443 if (item_index_ >= items.size()) |
| 444 return; | 444 return; |
| 445 const NGInlineItem& item = items[item_index_]; | 445 const NGInlineItem& item = items[item_index_]; |
| 446 if (item.Type() != NGInlineItem::kText || !item.Style()->CollapseWhiteSpace()) | 446 if (item.Type() != NGInlineItem::kText || !item.Style()->CollapseWhiteSpace()) |
| 447 return; | 447 return; |
| 448 | 448 |
| 449 DCHECK_LT(offset_, item.EndOffset()); | 449 DCHECK_LT(offset_, item.EndOffset()); |
| 450 if (node_->Text()[offset_] == kSpaceCharacter) { | 450 if (node_.Text()[offset_] == kSpaceCharacter) { |
| 451 // Skip one whitespace. Collapsible spaces are collapsed to single space in | 451 // Skip one whitespace. Collapsible spaces are collapsed to single space in |
| 452 // NGInlineItemBuilder, so this removes all collapsible spaces. | 452 // NGInlineItemBuilder, so this removes all collapsible spaces. |
| 453 offset_++; | 453 offset_++; |
| 454 if (offset_ == item.EndOffset()) | 454 if (offset_ == item.EndOffset()) |
| 455 item_index_++; | 455 item_index_++; |
| 456 } | 456 } |
| 457 } | 457 } |
| 458 | 458 |
| 459 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const { | 459 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const { |
| 460 const Vector<NGInlineItem>& items = node_->Items(); | 460 const Vector<NGInlineItem>& items = node_.Items(); |
| 461 if (item_index_ >= items.size()) | 461 if (item_index_ >= items.size()) |
| 462 return nullptr; | 462 return nullptr; |
| 463 return NGInlineBreakToken::Create(node_, item_index_, offset_); | 463 return NGInlineBreakToken::Create(node_, item_index_, offset_); |
| 464 } | 464 } |
| 465 | 465 |
| 466 } // namespace blink | 466 } // namespace blink |
| OLD | NEW |