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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 NGConstraintSpace* space, | 60 NGConstraintSpace* space, |
61 NGFragmentBuilder* container_builder, | 61 NGFragmentBuilder* container_builder, |
62 const NGInlineBreakToken* break_token) | 62 const NGInlineBreakToken* break_token) |
63 : node_(node), | 63 : node_(node), |
64 constraint_space_(space), | 64 constraint_space_(space), |
65 container_builder_(container_builder), | 65 container_builder_(container_builder), |
66 item_index_(0), | 66 item_index_(0), |
67 offset_(0), | 67 offset_(0), |
68 break_iterator_(node.Text()), | 68 break_iterator_(node.Text()), |
69 shaper_(node.Text().Characters16(), node.Text().length()), | 69 shaper_(node.Text().Characters16(), node.Text().length()), |
70 spacing_(node.Text()) { | 70 spacing_(node.Text()), |
| 71 auto_wrap_(false), |
| 72 should_create_line_box_(false), |
| 73 is_after_forced_break_(false) { |
71 if (break_token) { | 74 if (break_token) { |
72 item_index_ = break_token->ItemIndex(); | 75 item_index_ = break_token->ItemIndex(); |
73 offset_ = break_token->TextOffset(); | 76 offset_ = break_token->TextOffset(); |
74 node.AssertOffset(item_index_, offset_); | 77 node.AssertOffset(item_index_, offset_); |
75 } | 78 } |
76 } | 79 } |
77 | 80 |
| 81 // @return if this is the "first formatted line". |
| 82 // https://www.w3.org/TR/CSS22/selector.html#first-formatted-line |
| 83 bool NGLineBreaker::IsFirstFormattedLine() const { |
| 84 if (item_index_ || offset_) |
| 85 return false; |
| 86 // The first line of an anonymous block box is only affected if it is the |
| 87 // first child of its parent element. |
| 88 // https://drafts.csswg.org/css-text-3/#text-indent-property |
| 89 LayoutBlockFlow* block = node_.GetLayoutBlockFlow(); |
| 90 if (block->IsAnonymousBlock() && block->PreviousSibling()) { |
| 91 // TODO(kojii): In NG, leading OOF creates a block box. |
| 92 // text-indent-first-line-002.html fails for this reason. |
| 93 // crbug.com/734554 |
| 94 return false; |
| 95 } |
| 96 return true; |
| 97 } |
| 98 |
78 bool NGLineBreaker::NextLine(NGLineInfo* line_info, | 99 bool NGLineBreaker::NextLine(NGLineInfo* line_info, |
79 const NGLogicalOffset& content_offset) { | 100 const NGLogicalOffset& content_offset) { |
80 content_offset_ = content_offset; | 101 content_offset_ = content_offset; |
81 BreakLine(line_info); | 102 BreakLine(line_info); |
82 | 103 |
83 // TODO(kojii): When editing, or caret is enabled, trailing spaces at wrap | 104 // TODO(kojii): When editing, or caret is enabled, trailing spaces at wrap |
84 // point should not be removed. For other cases, we can a) remove, b) leave | 105 // point should not be removed. For other cases, we can a) remove, b) leave |
85 // characters without glyphs, or c) leave both characters and glyphs without | 106 // characters without glyphs, or c) leave both characters and glyphs without |
86 // measuring. Need to decide which one works the best. | 107 // measuring. Need to decide which one works the best. |
87 SkipCollapsibleWhitespaces(); | 108 SkipCollapsibleWhitespaces(); |
88 | 109 |
89 if (line_info->Results().IsEmpty()) | 110 if (line_info->Results().IsEmpty()) |
90 return false; | 111 return false; |
91 | 112 |
92 // TODO(kojii): There are cases where we need to PlaceItems() without creating | 113 // TODO(kojii): There are cases where we need to PlaceItems() without creating |
93 // line boxes. These cases need to be reviewed. | 114 // line boxes. These cases need to be reviewed. |
94 if (should_create_line_box_) | 115 if (should_create_line_box_) |
95 ComputeLineLocation(line_info); | 116 ComputeLineLocation(line_info); |
96 | 117 |
97 return true; | 118 return true; |
98 } | 119 } |
99 | 120 |
100 void NGLineBreaker::BreakLine(NGLineInfo* line_info) { | 121 void NGLineBreaker::BreakLine(NGLineInfo* line_info) { |
101 NGInlineItemResults* item_results = &line_info->Results(); | 122 NGInlineItemResults* item_results = &line_info->Results(); |
102 item_results->clear(); | 123 item_results->clear(); |
103 const Vector<NGInlineItem>& items = node_.Items(); | 124 const Vector<NGInlineItem>& items = node_.Items(); |
104 line_info->SetLineStyle(node_, !item_index_ && !offset_); | 125 line_info->SetLineStyle(node_, *constraint_space_, IsFirstFormattedLine(), |
| 126 is_after_forced_break_); |
105 SetCurrentStyle(line_info->LineStyle()); | 127 SetCurrentStyle(line_info->LineStyle()); |
106 position_ = LayoutUnit(0); | 128 is_after_forced_break_ = false; |
107 should_create_line_box_ = false; | 129 should_create_line_box_ = false; |
108 LineBreakState state = LineBreakState::kNotBreakable; | 130 LineBreakState state = LineBreakState::kNotBreakable; |
109 | 131 |
| 132 // Use 'text-indent' as the initial position. This lets tab positions to align |
| 133 // regardless of 'text-indent'. |
| 134 position_ = line_info->TextIndent(); |
| 135 |
110 // We are only able to calculate our available_width if our container has | 136 // We are only able to calculate our available_width if our container has |
111 // been positioned in the BFC coordinate space yet. | 137 // been positioned in the BFC coordinate space yet. |
112 if (container_builder_->BfcOffset()) | 138 if (container_builder_->BfcOffset()) |
113 UpdateAvailableWidth(); | 139 UpdateAvailableWidth(); |
114 else | 140 else |
115 opportunity_.reset(); | 141 opportunity_.reset(); |
116 | 142 |
117 while (item_index_ < items.size()) { | 143 while (item_index_ < items.size()) { |
118 // CloseTag prohibits to break before. | 144 // CloseTag prohibits to break before. |
119 const NGInlineItem& item = items[item_index_]; | 145 const NGInlineItem& item = items[item_index_]; |
(...skipping 15 matching lines...) Expand all Loading... |
135 item_results->push_back( | 161 item_results->push_back( |
136 NGInlineItemResult(item_index_, offset_, item.EndOffset())); | 162 NGInlineItemResult(item_index_, offset_, item.EndOffset())); |
137 NGInlineItemResult* item_result = &item_results->back(); | 163 NGInlineItemResult* item_result = &item_results->back(); |
138 if (item.Type() == NGInlineItem::kText) { | 164 if (item.Type() == NGInlineItem::kText) { |
139 state = HandleText(item, item_result); | 165 state = HandleText(item, item_result); |
140 } else if (item.Type() == NGInlineItem::kAtomicInline) { | 166 } else if (item.Type() == NGInlineItem::kAtomicInline) { |
141 state = HandleAtomicInline(item, item_result); | 167 state = HandleAtomicInline(item, item_result); |
142 } else if (item.Type() == NGInlineItem::kControl) { | 168 } else if (item.Type() == NGInlineItem::kControl) { |
143 state = HandleControlItem(item, item_result); | 169 state = HandleControlItem(item, item_result); |
144 if (state == LineBreakState::kForcedBreak) { | 170 if (state == LineBreakState::kForcedBreak) { |
| 171 is_after_forced_break_ = true; |
145 line_info->SetIsLastLine(true); | 172 line_info->SetIsLastLine(true); |
146 return; | 173 return; |
147 } | 174 } |
148 } else if (item.Type() == NGInlineItem::kOpenTag) { | 175 } else if (item.Type() == NGInlineItem::kOpenTag) { |
149 HandleOpenTag(item, item_result); | 176 HandleOpenTag(item, item_result); |
150 state = LineBreakState::kNotBreakable; | 177 state = LineBreakState::kNotBreakable; |
151 } else if (item.Type() == NGInlineItem::kFloating) { | 178 } else if (item.Type() == NGInlineItem::kFloating) { |
152 HandleFloat(item, item_results); | 179 HandleFloat(item, item_results); |
153 } else { | 180 } else { |
154 MoveToNextOf(item); | 181 MoveToNextOf(item); |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 } | 652 } |
626 | 653 |
627 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const { | 654 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const { |
628 const Vector<NGInlineItem>& items = node_.Items(); | 655 const Vector<NGInlineItem>& items = node_.Items(); |
629 if (item_index_ >= items.size()) | 656 if (item_index_ >= items.size()) |
630 return nullptr; | 657 return nullptr; |
631 return NGInlineBreakToken::Create(node_, item_index_, offset_); | 658 return NGInlineBreakToken::Create(node_, item_index_, offset_); |
632 } | 659 } |
633 | 660 |
634 } // namespace blink | 661 } // namespace blink |
OLD | NEW |