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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 item_results->push_back( | 120 item_results->push_back( |
121 NGInlineItemResult(item_index_, offset_, item.EndOffset())); | 121 NGInlineItemResult(item_index_, offset_, item.EndOffset())); |
122 NGInlineItemResult* item_result = &item_results->back(); | 122 NGInlineItemResult* item_result = &item_results->back(); |
123 | 123 |
124 // If the start offset is at the item boundary, try to add the entire item. | 124 // If the start offset is at the item boundary, try to add the entire item. |
125 if (offset_ == item.StartOffset()) { | 125 if (offset_ == item.StartOffset()) { |
126 if (item.Type() == NGInlineItem::kText) { | 126 if (item.Type() == NGInlineItem::kText) { |
127 item_result->inline_size = item.InlineSize(); | 127 item_result->inline_size = item.InlineSize(); |
128 } else if (item.Type() == NGInlineItem::kAtomicInline) { | 128 } else if (item.Type() == NGInlineItem::kAtomicInline) { |
129 LayoutAtomicInline(item, item_result); | 129 LayoutAtomicInline(item, item_result); |
| 130 } else if (item.Type() == NGInlineItem::kControl) { |
| 131 if (HandleControlItem(item, text, item_result, position)) { |
| 132 MoveToNextOf(item); |
| 133 break; |
| 134 } |
130 } else if (item.Type() == NGInlineItem::kFloating) { | 135 } else if (item.Type() == NGInlineItem::kFloating) { |
131 algorithm->LayoutAndPositionFloat(position, item.GetLayoutObject()); | 136 algorithm->LayoutAndPositionFloat(position, item.GetLayoutObject()); |
132 // Floats may change the available width if they fit. | 137 // Floats may change the available width if they fit. |
133 available_width = algorithm->AvailableWidth(); | 138 available_width = algorithm->AvailableWidth(); |
134 // Floats are already positioned in the container_builder. | 139 // Floats are already positioned in the container_builder. |
135 item_results->pop_back(); | 140 item_results->pop_back(); |
136 offset_ = item.EndOffset(); | 141 MoveToNextOf(item); |
137 item_index_++; | |
138 continue; | 142 continue; |
139 } else { | 143 } else { |
140 offset_ = item.EndOffset(); | 144 MoveToNextOf(item); |
141 item_index_++; | |
142 continue; | 145 continue; |
143 } | 146 } |
144 LayoutUnit next_position = position + item_result->inline_size; | 147 LayoutUnit next_position = position + item_result->inline_size; |
145 if (next_position <= available_width) { | 148 if (next_position <= available_width) { |
146 offset_ = item.EndOffset(); | 149 MoveToNextOf(item); |
147 item_index_++; | |
148 position = next_position; | 150 position = next_position; |
149 continue; | 151 continue; |
150 } | 152 } |
151 | 153 |
152 // The entire item does not fit. Handle non-text items as overflow, | 154 // The entire item does not fit. Handle non-text items as overflow, |
153 // since only text item is breakable. | 155 // since only text item is breakable. |
154 if (item.Type() != NGInlineItem::kText) { | 156 if (item.Type() != NGInlineItem::kText) { |
155 offset_ = item.EndOffset(); | 157 MoveToNextOf(item); |
156 item_index_++; | |
157 return HandleOverflow(item_results, break_iterator); | 158 return HandleOverflow(item_results, break_iterator); |
158 } | 159 } |
159 } | 160 } |
160 | 161 |
161 // Either the start or the break is in the mid of a text item. | 162 // Either the start or the break is in the mid of a text item. |
162 DCHECK_EQ(item.Type(), NGInlineItem::kText); | 163 DCHECK_EQ(item.Type(), NGInlineItem::kText); |
163 DCHECK_LT(offset_, item.EndOffset()); | 164 DCHECK_LT(offset_, item.EndOffset()); |
164 break_iterator.SetLocale(item.Style()->LocaleForLineBreakIterator()); | 165 break_iterator.SetLocale(item.Style()->LocaleForLineBreakIterator()); |
165 break_iterator.SetBreakType(GetLineBreakType(*item.Style())); | 166 break_iterator.SetBreakType(GetLineBreakType(*item.Style())); |
166 #if defined(MOCK_SHAPE_LINE) | 167 #if defined(MOCK_SHAPE_LINE) |
(...skipping 20 matching lines...) Expand all Loading... |
187 | 188 |
188 // If the break found within the item, break here. | 189 // If the break found within the item, break here. |
189 if (break_offset < item.EndOffset()) { | 190 if (break_offset < item.EndOffset()) { |
190 offset_ = item_result->end_offset = break_offset; | 191 offset_ = item_result->end_offset = break_offset; |
191 if (position <= available_width) | 192 if (position <= available_width) |
192 break; | 193 break; |
193 // The first break opportunity of the item does not fit. | 194 // The first break opportunity of the item does not fit. |
194 } else { | 195 } else { |
195 // No break opporunity in the item, or the first break opportunity is at | 196 // No break opporunity in the item, or the first break opportunity is at |
196 // the end of the item. If it fits, continue to the next item. | 197 // the end of the item. If it fits, continue to the next item. |
197 offset_ = item_result->end_offset = item.EndOffset(); | 198 item_result->end_offset = item.EndOffset(); |
198 item_index_++; | 199 MoveToNextOf(item); |
199 if (position <= available_width) | 200 if (position <= available_width) |
200 continue; | 201 continue; |
201 } | 202 } |
202 | 203 |
203 // We need to look at next item if we're overflowing, and the break | 204 // We need to look at next item if we're overflowing, and the break |
204 // opportunity is beyond this item. | 205 // opportunity is beyond this item. |
205 if (break_offset > item.EndOffset()) | 206 if (break_offset > item.EndOffset()) |
206 continue; | 207 continue; |
207 return HandleOverflow(item_results, break_iterator); | 208 return HandleOverflow(item_results, break_iterator); |
208 } | 209 } |
209 } | 210 } |
210 | 211 |
| 212 // Measure control items; new lines and tab, that are similar to text, affect |
| 213 // layout, but do not need shaping/painting. |
| 214 bool NGLineBreaker::HandleControlItem(const NGInlineItem& item, |
| 215 const String& text, |
| 216 NGInlineItemResult* item_result, |
| 217 LayoutUnit position) { |
| 218 DCHECK_EQ(item.Length(), 1u); |
| 219 UChar character = text[item.StartOffset()]; |
| 220 if (character == kNewlineCharacter) |
| 221 return true; |
| 222 |
| 223 DCHECK_EQ(character, kTabulationCharacter); |
| 224 DCHECK(item.Style()); |
| 225 const ComputedStyle& style = *item.Style(); |
| 226 const Font& font = style.GetFont(); |
| 227 item_result->inline_size = font.TabWidth(style.GetTabSize(), position); |
| 228 return false; |
| 229 } |
| 230 |
211 void NGLineBreaker::LayoutAtomicInline(const NGInlineItem& item, | 231 void NGLineBreaker::LayoutAtomicInline(const NGInlineItem& item, |
212 NGInlineItemResult* item_result) { | 232 NGInlineItemResult* item_result) { |
213 DCHECK_EQ(item.Type(), NGInlineItem::kAtomicInline); | 233 DCHECK_EQ(item.Type(), NGInlineItem::kAtomicInline); |
214 NGBlockNode* node = new NGBlockNode(item.GetLayoutObject()); | 234 NGBlockNode* node = new NGBlockNode(item.GetLayoutObject()); |
215 const ComputedStyle& style = node->Style(); | 235 const ComputedStyle& style = node->Style(); |
216 NGConstraintSpaceBuilder constraint_space_builder(constraint_space_); | 236 NGConstraintSpaceBuilder constraint_space_builder(constraint_space_); |
217 RefPtr<NGConstraintSpace> constraint_space = | 237 RefPtr<NGConstraintSpace> constraint_space = |
218 constraint_space_builder.SetIsNewFormattingContext(true) | 238 constraint_space_builder.SetIsNewFormattingContext(true) |
219 .SetIsShrinkToFit(true) | 239 .SetIsShrinkToFit(true) |
220 .SetTextDirection(style.Direction()) | 240 .SetTextDirection(style.Direction()) |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 item_results->Shrink(new_end); | 305 item_results->Shrink(new_end); |
286 | 306 |
287 // Update the current item index and offset to the new break point. | 307 // Update the current item index and offset to the new break point. |
288 const NGInlineItemResult& last_item_result = item_results->back(); | 308 const NGInlineItemResult& last_item_result = item_results->back(); |
289 offset_ = last_item_result.end_offset; | 309 offset_ = last_item_result.end_offset; |
290 item_index_ = last_item_result.item_index; | 310 item_index_ = last_item_result.item_index; |
291 if (items[item_index_].EndOffset() == offset_) | 311 if (items[item_index_].EndOffset() == offset_) |
292 item_index_++; | 312 item_index_++; |
293 } | 313 } |
294 | 314 |
| 315 void NGLineBreaker::MoveToNextOf(const NGInlineItem& item) { |
| 316 DCHECK_EQ(&item, &node_->Items()[item_index_]); |
| 317 offset_ = item.EndOffset(); |
| 318 item_index_++; |
| 319 } |
| 320 |
295 void NGLineBreaker::SkipCollapsibleWhitespaces() { | 321 void NGLineBreaker::SkipCollapsibleWhitespaces() { |
296 const Vector<NGInlineItem>& items = node_->Items(); | 322 const Vector<NGInlineItem>& items = node_->Items(); |
297 if (item_index_ >= items.size()) | 323 if (item_index_ >= items.size()) |
298 return; | 324 return; |
299 const NGInlineItem& item = items[item_index_]; | 325 const NGInlineItem& item = items[item_index_]; |
300 if (item.Type() != NGInlineItem::kText || !item.Style()->CollapseWhiteSpace()) | 326 if (item.Type() != NGInlineItem::kText || !item.Style()->CollapseWhiteSpace()) |
301 return; | 327 return; |
302 | 328 |
303 DCHECK_LT(offset_, item.EndOffset()); | 329 DCHECK_LT(offset_, item.EndOffset()); |
304 if (node_->Text()[offset_] == kSpaceCharacter) { | 330 if (node_->Text()[offset_] == kSpaceCharacter) { |
(...skipping 17 matching lines...) Expand all Loading... |
322 } | 348 } |
323 | 349 |
324 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const { | 350 RefPtr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken() const { |
325 const Vector<NGInlineItem>& items = node_->Items(); | 351 const Vector<NGInlineItem>& items = node_->Items(); |
326 if (item_index_ >= items.size()) | 352 if (item_index_ >= items.size()) |
327 return nullptr; | 353 return nullptr; |
328 return NGInlineBreakToken::Create(node_, item_index_, offset_); | 354 return NGInlineBreakToken::Create(node_, item_index_, offset_); |
329 } | 355 } |
330 | 356 |
331 } // namespace blink | 357 } // namespace blink |
OLD | NEW |