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 |