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/ng_line_builder.h" | 5 #include "core/layout/ng/ng_inline_layout_algorithm.h" |
6 | 6 |
7 #include "core/layout/BidiRun.h" | 7 #include "core/layout/BidiRun.h" |
8 #include "core/layout/LayoutBlockFlow.h" | 8 #include "core/layout/LayoutBlockFlow.h" |
9 #include "core/layout/line/LineInfo.h" | 9 #include "core/layout/line/LineInfo.h" |
10 #include "core/layout/line/RootInlineBox.h" | 10 #include "core/layout/line/RootInlineBox.h" |
11 #include "core/layout/ng/layout_ng_block_flow.h" | 11 #include "core/layout/ng/layout_ng_block_flow.h" |
12 #include "core/layout/ng/ng_bidi_paragraph.h" | 12 #include "core/layout/ng/ng_bidi_paragraph.h" |
13 #include "core/layout/ng/ng_block_layout_algorithm.h" | 13 #include "core/layout/ng/ng_block_layout_algorithm.h" |
14 #include "core/layout/ng/ng_box_fragment.h" | 14 #include "core/layout/ng/ng_box_fragment.h" |
15 #include "core/layout/ng/ng_constraint_space.h" | 15 #include "core/layout/ng/ng_constraint_space.h" |
16 #include "core/layout/ng/ng_constraint_space_builder.h" | 16 #include "core/layout/ng/ng_constraint_space_builder.h" |
17 #include "core/layout/ng/ng_floating_object.h" | 17 #include "core/layout/ng/ng_floating_object.h" |
18 #include "core/layout/ng/ng_floats_utils.h" | 18 #include "core/layout/ng/ng_floats_utils.h" |
19 #include "core/layout/ng/ng_fragment_builder.h" | 19 #include "core/layout/ng/ng_fragment_builder.h" |
| 20 #include "core/layout/ng/ng_inline_break_token.h" |
20 #include "core/layout/ng/ng_inline_node.h" | 21 #include "core/layout/ng/ng_inline_node.h" |
21 #include "core/layout/ng/ng_length_utils.h" | 22 #include "core/layout/ng/ng_length_utils.h" |
22 #include "core/layout/ng/ng_line_box_fragment.h" | 23 #include "core/layout/ng/ng_line_box_fragment.h" |
23 #include "core/layout/ng/ng_line_box_fragment_builder.h" | 24 #include "core/layout/ng/ng_line_box_fragment_builder.h" |
| 25 #include "core/layout/ng/ng_line_breaker.h" |
24 #include "core/layout/ng/ng_space_utils.h" | 26 #include "core/layout/ng/ng_space_utils.h" |
25 #include "core/layout/ng/ng_text_fragment.h" | 27 #include "core/layout/ng/ng_text_fragment.h" |
26 #include "core/layout/ng/ng_text_fragment_builder.h" | 28 #include "core/layout/ng/ng_text_fragment_builder.h" |
27 #include "core/style/ComputedStyle.h" | 29 #include "core/style/ComputedStyle.h" |
28 #include "platform/text/BidiRunList.h" | 30 #include "platform/text/BidiRunList.h" |
29 | 31 |
30 namespace blink { | 32 namespace blink { |
31 namespace { | 33 namespace { |
32 | 34 |
33 RefPtr<NGConstraintSpace> CreateConstraintSpaceForFloat( | 35 RefPtr<NGConstraintSpace> CreateConstraintSpaceForFloat( |
(...skipping 24 matching lines...) Expand all Loading... |
58 for (auto& floating_object : builder->UnpositionedFloats()) { | 60 for (auto& floating_object : builder->UnpositionedFloats()) { |
59 NGLogicalOffset offset = PositionFloat(origin_point, space->BfcOffset(), | 61 NGLogicalOffset offset = PositionFloat(origin_point, space->BfcOffset(), |
60 floating_object.get(), space); | 62 floating_object.get(), space); |
61 builder->AddFloatingObject(floating_object, offset); | 63 builder->AddFloatingObject(floating_object, offset); |
62 } | 64 } |
63 builder->MutableUnpositionedFloats().clear(); | 65 builder->MutableUnpositionedFloats().clear(); |
64 } | 66 } |
65 | 67 |
66 } // namespace | 68 } // namespace |
67 | 69 |
68 NGLineBuilder::NGLineBuilder(NGInlineNode* inline_box, | 70 NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm( |
69 NGConstraintSpace* constraint_space) | 71 NGInlineNode* inline_box, |
| 72 NGConstraintSpace* constraint_space, |
| 73 NGInlineBreakToken* break_token) |
70 : inline_box_(inline_box), | 74 : inline_box_(inline_box), |
71 constraint_space_(constraint_space), | 75 constraint_space_(constraint_space), |
72 container_builder_(NGPhysicalFragment::kFragmentBox, inline_box_), | 76 container_builder_(NGPhysicalFragment::kFragmentBox, inline_box_), |
73 container_layout_result_(nullptr), | |
74 is_horizontal_writing_mode_( | 77 is_horizontal_writing_mode_( |
75 blink::IsHorizontalWritingMode(constraint_space->WritingMode())), | 78 blink::IsHorizontalWritingMode(constraint_space->WritingMode())), |
76 space_builder_(constraint_space) | 79 space_builder_(constraint_space) |
77 #if DCHECK_IS_ON() | 80 #if DCHECK_IS_ON() |
78 , | 81 , |
79 is_bidi_reordered_(false) | 82 is_bidi_reordered_(false) |
80 #endif | 83 #endif |
81 { | 84 { |
82 if (!is_horizontal_writing_mode_) | 85 if (!is_horizontal_writing_mode_) |
83 baseline_type_ = FontBaseline::IdeographicBaseline; | 86 baseline_type_ = FontBaseline::IdeographicBaseline; |
| 87 if (break_token) |
| 88 Initialize(break_token->ItemIndex(), break_token->TextOffset()); |
| 89 else |
| 90 Initialize(0, 0); |
84 } | 91 } |
85 | 92 |
86 bool NGLineBuilder::CanFitOnLine() const { | 93 bool NGInlineLayoutAlgorithm::CanFitOnLine() const { |
87 LayoutUnit available_size = current_opportunity_.InlineSize(); | 94 LayoutUnit available_size = current_opportunity_.InlineSize(); |
88 if (available_size == NGSizeIndefinite) | 95 if (available_size == NGSizeIndefinite) |
89 return true; | 96 return true; |
90 return end_position_ <= available_size; | 97 return end_position_ <= available_size; |
91 } | 98 } |
92 | 99 |
93 bool NGLineBuilder::HasItems() const { | 100 bool NGInlineLayoutAlgorithm::HasItems() const { |
94 return start_offset_ != end_offset_; | 101 return start_offset_ != end_offset_; |
95 } | 102 } |
96 | 103 |
97 bool NGLineBuilder::HasBreakOpportunity() const { | 104 bool NGInlineLayoutAlgorithm::HasBreakOpportunity() const { |
98 return start_offset_ != last_break_opportunity_offset_; | 105 return start_offset_ != last_break_opportunity_offset_; |
99 } | 106 } |
100 | 107 |
101 bool NGLineBuilder::HasItemsAfterLastBreakOpportunity() const { | 108 bool NGInlineLayoutAlgorithm::HasItemsAfterLastBreakOpportunity() const { |
102 return last_break_opportunity_offset_ != end_offset_; | 109 return last_break_opportunity_offset_ != end_offset_; |
103 } | 110 } |
104 | 111 |
105 void NGLineBuilder::SetStart(unsigned index, unsigned offset) { | 112 void NGInlineLayoutAlgorithm::Initialize(unsigned index, unsigned offset) { |
106 inline_box_->AssertOffset(index, offset); | 113 if (index || offset) |
| 114 inline_box_->AssertOffset(index, offset); |
107 | 115 |
108 start_index_ = last_index_ = last_break_opportunity_index_ = index; | 116 start_index_ = last_index_ = last_break_opportunity_index_ = index; |
109 start_offset_ = end_offset_ = last_break_opportunity_offset_ = offset; | 117 start_offset_ = end_offset_ = last_break_opportunity_offset_ = offset; |
110 end_position_ = last_break_opportunity_position_ = LayoutUnit(); | 118 end_position_ = last_break_opportunity_position_ = LayoutUnit(); |
111 | 119 |
112 FindNextLayoutOpportunity(); | 120 FindNextLayoutOpportunity(); |
113 } | 121 } |
114 | 122 |
115 void NGLineBuilder::SetEnd(unsigned new_end_offset) { | 123 void NGInlineLayoutAlgorithm::SetEnd(unsigned new_end_offset) { |
116 DCHECK_GT(new_end_offset, end_offset_); | 124 DCHECK_GT(new_end_offset, end_offset_); |
117 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); | 125 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
118 DCHECK_LE(new_end_offset, items.back().EndOffset()); | 126 DCHECK_LE(new_end_offset, items.back().EndOffset()); |
119 | 127 |
120 // SetEnd() while |new_end_offset| is beyond the current last item. | 128 // SetEnd() while |new_end_offset| is beyond the current last item. |
121 unsigned index = last_index_; | 129 unsigned index = last_index_; |
122 const NGLayoutInlineItem* item = &items[index]; | 130 const NGLayoutInlineItem* item = &items[index]; |
123 if (new_end_offset > item->EndOffset()) { | 131 if (new_end_offset > item->EndOffset()) { |
124 if (end_offset_ < item->EndOffset()) { | 132 if (end_offset_ < item->EndOffset()) { |
125 SetEnd(index, item->EndOffset(), | 133 SetEnd(index, item->EndOffset(), |
(...skipping 11 matching lines...) Expand all Loading... |
137 | 145 |
138 // Include closing elements. | 146 // Include closing elements. |
139 while (new_end_offset == item->EndOffset() && index < items.size() - 1) { | 147 while (new_end_offset == item->EndOffset() && index < items.size() - 1) { |
140 item = &items[++index]; | 148 item = &items[++index]; |
141 if (item->Type() != NGLayoutInlineItem::kCloseTag) | 149 if (item->Type() != NGLayoutInlineItem::kCloseTag) |
142 break; | 150 break; |
143 SetEnd(index, new_end_offset, InlineSize(*item)); | 151 SetEnd(index, new_end_offset, InlineSize(*item)); |
144 } | 152 } |
145 } | 153 } |
146 | 154 |
147 void NGLineBuilder::SetEnd(unsigned index, | 155 void NGInlineLayoutAlgorithm::SetEnd(unsigned index, |
148 unsigned new_end_offset, | 156 unsigned new_end_offset, |
149 LayoutUnit inline_size_since_current_end) { | 157 LayoutUnit inline_size_since_current_end) { |
150 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); | 158 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
151 DCHECK_LE(new_end_offset, items.back().EndOffset()); | 159 DCHECK_LE(new_end_offset, items.back().EndOffset()); |
152 | 160 |
153 // |new_end_offset| should be in the current item or next. | 161 // |new_end_offset| should be in the current item or next. |
154 // TODO(kojii): Reconsider this restriction if needed. | 162 // TODO(kojii): Reconsider this restriction if needed. |
155 DCHECK((index == last_index_ && new_end_offset > end_offset_) || | 163 DCHECK((index == last_index_ && new_end_offset > end_offset_) || |
156 (index == last_index_ + 1 && new_end_offset >= end_offset_ && | 164 (index == last_index_ + 1 && new_end_offset >= end_offset_ && |
157 end_offset_ == items[last_index_].EndOffset())); | 165 end_offset_ == items[last_index_].EndOffset())); |
158 const NGLayoutInlineItem& item = items[index]; | 166 const NGLayoutInlineItem& item = items[index]; |
159 item.AssertEndOffset(new_end_offset); | 167 item.AssertEndOffset(new_end_offset); |
160 | 168 |
161 if (item.Type() == NGLayoutInlineItem::kFloating) { | 169 if (item.Type() == NGLayoutInlineItem::kFloating) { |
162 LayoutAndPositionFloat( | 170 LayoutAndPositionFloat( |
163 LayoutUnit(end_position_) + inline_size_since_current_end, | 171 LayoutUnit(end_position_) + inline_size_since_current_end, |
164 item.GetLayoutObject()); | 172 item.GetLayoutObject()); |
165 } | 173 } |
166 | 174 |
167 last_index_ = index; | 175 last_index_ = index; |
168 end_offset_ = new_end_offset; | 176 end_offset_ = new_end_offset; |
169 end_position_ += inline_size_since_current_end; | 177 end_position_ += inline_size_since_current_end; |
170 } | 178 } |
171 | 179 |
172 void NGLineBuilder::SetBreakOpportunity() { | 180 void NGInlineLayoutAlgorithm::SetBreakOpportunity() { |
173 last_break_opportunity_index_ = last_index_; | 181 last_break_opportunity_index_ = last_index_; |
174 last_break_opportunity_offset_ = end_offset_; | 182 last_break_opportunity_offset_ = end_offset_; |
175 last_break_opportunity_position_ = end_position_; | 183 last_break_opportunity_position_ = end_position_; |
176 } | 184 } |
177 | 185 |
178 void NGLineBuilder::SetStartOfHangables(unsigned offset) { | 186 void NGInlineLayoutAlgorithm::SetStartOfHangables(unsigned offset) { |
179 // TODO(kojii): Implement. | 187 // TODO(kojii): Implement. |
180 } | 188 } |
181 | 189 |
182 LayoutUnit NGLineBuilder::InlineSize(const NGLayoutInlineItem& item) { | 190 LayoutUnit NGInlineLayoutAlgorithm::InlineSize(const NGLayoutInlineItem& item) { |
183 if (item.Type() == NGLayoutInlineItem::kAtomicInline) | 191 if (item.Type() == NGLayoutInlineItem::kAtomicInline) |
184 return InlineSizeFromLayout(item); | 192 return InlineSizeFromLayout(item); |
185 return item.InlineSize(); | 193 return item.InlineSize(); |
186 } | 194 } |
187 | 195 |
188 LayoutUnit NGLineBuilder::InlineSize(const NGLayoutInlineItem& item, | 196 LayoutUnit NGInlineLayoutAlgorithm::InlineSize(const NGLayoutInlineItem& item, |
189 unsigned start_offset, | 197 unsigned start_offset, |
190 unsigned end_offset) { | 198 unsigned end_offset) { |
191 if (item.StartOffset() == start_offset && item.EndOffset() == end_offset) | 199 if (item.StartOffset() == start_offset && item.EndOffset() == end_offset) |
192 return InlineSize(item); | 200 return InlineSize(item); |
193 return item.InlineSize(start_offset, end_offset); | 201 return item.InlineSize(start_offset, end_offset); |
194 } | 202 } |
195 | 203 |
196 LayoutUnit NGLineBuilder::InlineSizeFromLayout(const NGLayoutInlineItem& item) { | 204 LayoutUnit NGInlineLayoutAlgorithm::InlineSizeFromLayout( |
| 205 const NGLayoutInlineItem& item) { |
197 return NGBoxFragment(ConstraintSpace().WritingMode(), | 206 return NGBoxFragment(ConstraintSpace().WritingMode(), |
198 toNGPhysicalBoxFragment( | 207 toNGPhysicalBoxFragment( |
199 LayoutItem(item)->PhysicalFragment().get())) | 208 LayoutItem(item)->PhysicalFragment().get())) |
200 .InlineSize(); | 209 .InlineSize(); |
201 } | 210 } |
202 | 211 |
203 const NGLayoutResult* NGLineBuilder::LayoutItem( | 212 const NGLayoutResult* NGInlineLayoutAlgorithm::LayoutItem( |
204 const NGLayoutInlineItem& item) { | 213 const NGLayoutInlineItem& item) { |
205 // Returns the cached NGLayoutResult if available. | 214 // Returns the cached NGLayoutResult if available. |
206 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); | 215 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
207 if (layout_results_.isEmpty()) | 216 if (layout_results_.isEmpty()) |
208 layout_results_.resize(items.size()); | 217 layout_results_.resize(items.size()); |
209 unsigned index = std::distance(items.begin(), &item); | 218 unsigned index = std::distance(items.begin(), &item); |
210 RefPtr<NGLayoutResult>* layout_result = &layout_results_[index]; | 219 RefPtr<NGLayoutResult>* layout_result = &layout_results_[index]; |
211 if (*layout_result) | 220 if (*layout_result) |
212 return layout_result->get(); | 221 return layout_result->get(); |
213 | 222 |
214 DCHECK(item.Type() == NGLayoutInlineItem::kAtomicInline); | 223 DCHECK(item.Type() == NGLayoutInlineItem::kAtomicInline); |
215 NGBlockNode* node = new NGBlockNode(item.GetLayoutObject()); | 224 NGBlockNode* node = new NGBlockNode(item.GetLayoutObject()); |
216 // TODO(kojii): Keep node in NGLayoutInlineItem. | 225 // TODO(kojii): Keep node in NGLayoutInlineItem. |
217 const ComputedStyle& style = node->Style(); | 226 const ComputedStyle& style = node->Style(); |
218 NGConstraintSpaceBuilder constraint_space_builder(&ConstraintSpace()); | 227 NGConstraintSpaceBuilder constraint_space_builder(&ConstraintSpace()); |
219 RefPtr<NGConstraintSpace> constraint_space = | 228 RefPtr<NGConstraintSpace> constraint_space = |
220 constraint_space_builder.SetIsNewFormattingContext(true) | 229 constraint_space_builder.SetIsNewFormattingContext(true) |
221 .SetIsShrinkToFit(true) | 230 .SetIsShrinkToFit(true) |
222 .SetTextDirection(style.direction()) | 231 .SetTextDirection(style.direction()) |
223 .ToConstraintSpace(FromPlatformWritingMode(style.getWritingMode())); | 232 .ToConstraintSpace(FromPlatformWritingMode(style.getWritingMode())); |
224 *layout_result = node->Layout(constraint_space.get()); | 233 *layout_result = node->Layout(constraint_space.get()); |
225 return layout_result->get(); | 234 return layout_result->get(); |
226 } | 235 } |
227 | 236 |
228 void NGLineBuilder::CreateLine() { | 237 bool NGInlineLayoutAlgorithm::CreateLine() { |
229 if (HasItemsAfterLastBreakOpportunity()) | 238 if (HasItemsAfterLastBreakOpportunity()) |
230 SetBreakOpportunity(); | 239 SetBreakOpportunity(); |
231 CreateLineUpToLastBreakOpportunity(); | 240 return CreateLineUpToLastBreakOpportunity(); |
232 } | 241 } |
233 | 242 |
234 void NGLineBuilder::CreateLineUpToLastBreakOpportunity() { | 243 bool NGInlineLayoutAlgorithm::CreateLineUpToLastBreakOpportunity() { |
235 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); | 244 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
236 | 245 |
237 // Create a list of LineItemChunk from |start| and |last_break_opportunity|. | 246 // Create a list of LineItemChunk from |start| and |last_break_opportunity|. |
238 // TODO(kojii): Consider refactoring LineItemChunk once NGLineBuilder's public | 247 // TODO(kojii): Consider refactoring LineItemChunk once NGLineBuilder's public |
239 // API is more finalized. It does not fit well with the current API. | 248 // API is more finalized. It does not fit well with the current API. |
240 Vector<LineItemChunk, 32> line_item_chunks; | 249 Vector<LineItemChunk, 32> line_item_chunks; |
241 unsigned start_offset = start_offset_; | 250 unsigned start_offset = start_offset_; |
242 for (unsigned i = start_index_; i <= last_break_opportunity_index_; i++) { | 251 for (unsigned i = start_index_; i <= last_break_opportunity_index_; i++) { |
243 const NGLayoutInlineItem& item = items[i]; | 252 const NGLayoutInlineItem& item = items[i]; |
244 unsigned end_offset = | 253 unsigned end_offset = |
245 std::min(item.EndOffset(), last_break_opportunity_offset_); | 254 std::min(item.EndOffset(), last_break_opportunity_offset_); |
246 line_item_chunks.push_back( | 255 line_item_chunks.push_back( |
247 LineItemChunk{i, start_offset, end_offset, | 256 LineItemChunk{i, start_offset, end_offset, |
248 InlineSize(item, start_offset, end_offset)}); | 257 InlineSize(item, start_offset, end_offset)}); |
249 start_offset = end_offset; | 258 start_offset = end_offset; |
250 } | 259 } |
251 | 260 |
252 if (inline_box_->IsBidiEnabled()) | 261 if (inline_box_->IsBidiEnabled()) |
253 BidiReorder(&line_item_chunks); | 262 BidiReorder(&line_item_chunks); |
254 | 263 |
255 PlaceItems(line_item_chunks); | 264 if (!PlaceItems(line_item_chunks)) |
| 265 return false; |
256 | 266 |
257 // Prepare for the next line. | 267 // Prepare for the next line. |
258 // Move |start| to |last_break_opportunity|, keeping items after | 268 // Move |start| to |last_break_opportunity|, keeping items after |
259 // |last_break_opportunity|. | 269 // |last_break_opportunity|. |
260 start_index_ = last_break_opportunity_index_; | 270 start_index_ = last_break_opportunity_index_; |
261 start_offset_ = last_break_opportunity_offset_; | 271 start_offset_ = last_break_opportunity_offset_; |
262 DCHECK_GE(end_position_, last_break_opportunity_position_); | 272 DCHECK_GE(end_position_, last_break_opportunity_position_); |
263 end_position_ -= last_break_opportunity_position_; | 273 end_position_ -= last_break_opportunity_position_; |
264 last_break_opportunity_position_ = LayoutUnit(); | 274 last_break_opportunity_position_ = LayoutUnit(); |
265 #if DCHECK_IS_ON() | 275 #if DCHECK_IS_ON() |
266 is_bidi_reordered_ = false; | 276 is_bidi_reordered_ = false; |
267 #endif | 277 #endif |
268 | 278 |
269 NGLogicalOffset origin_point = | 279 NGLogicalOffset origin_point = |
270 GetOriginPointForFloats(ConstraintSpace(), content_size_); | 280 GetOriginPointForFloats(ConstraintSpace(), content_size_); |
271 PositionPendingFloats(origin_point, constraint_space_, &container_builder_); | 281 PositionPendingFloats(origin_point, constraint_space_, &container_builder_); |
272 FindNextLayoutOpportunity(); | 282 FindNextLayoutOpportunity(); |
| 283 return true; |
273 } | 284 } |
274 | 285 |
275 void NGLineBuilder::BidiReorder(Vector<LineItemChunk, 32>* line_item_chunks) { | 286 void NGInlineLayoutAlgorithm::BidiReorder( |
| 287 Vector<LineItemChunk, 32>* line_item_chunks) { |
276 #if DCHECK_IS_ON() | 288 #if DCHECK_IS_ON() |
277 DCHECK(!is_bidi_reordered_); | 289 DCHECK(!is_bidi_reordered_); |
278 is_bidi_reordered_ = true; | 290 is_bidi_reordered_ = true; |
279 #endif | 291 #endif |
280 | 292 |
281 // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change | 293 // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change |
282 // embedding levels of parts of runs, which requires to split items. | 294 // embedding levels of parts of runs, which requires to split items. |
283 // http://unicode.org/reports/tr9/#L1 | 295 // http://unicode.org/reports/tr9/#L1 |
284 // BidiResolver does not support L1 crbug.com/316409. | 296 // BidiResolver does not support L1 crbug.com/316409. |
285 | 297 |
(...skipping 14 matching lines...) Expand all Loading... |
300 for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size(); | 312 for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size(); |
301 visual_index++) { | 313 visual_index++) { |
302 unsigned logical_index = indices_in_visual_order[visual_index]; | 314 unsigned logical_index = indices_in_visual_order[visual_index]; |
303 line_item_chunks_in_visual_order[visual_index] = | 315 line_item_chunks_in_visual_order[visual_index] = |
304 (*line_item_chunks)[logical_index]; | 316 (*line_item_chunks)[logical_index]; |
305 } | 317 } |
306 line_item_chunks->swap(line_item_chunks_in_visual_order); | 318 line_item_chunks->swap(line_item_chunks_in_visual_order); |
307 } | 319 } |
308 | 320 |
309 // TODO(glebl): Add the support of clearance for inline floats. | 321 // TODO(glebl): Add the support of clearance for inline floats. |
310 void NGLineBuilder::LayoutAndPositionFloat(LayoutUnit end_position, | 322 void NGInlineLayoutAlgorithm::LayoutAndPositionFloat( |
311 LayoutObject* layout_object) { | 323 LayoutUnit end_position, |
| 324 LayoutObject* layout_object) { |
312 NGBlockNode* node = new NGBlockNode(layout_object); | 325 NGBlockNode* node = new NGBlockNode(layout_object); |
| 326 |
313 RefPtr<NGConstraintSpace> float_space = CreateConstraintSpaceForFloat( | 327 RefPtr<NGConstraintSpace> float_space = CreateConstraintSpaceForFloat( |
314 node->Style(), ConstraintSpace(), &space_builder_); | 328 node->Style(), ConstraintSpace(), &space_builder_); |
315 | 329 |
316 // TODO(glebl): add the fragmentation support: | 330 // TODO(glebl): add the fragmentation support: |
317 // same writing mode - get the inline size ComputeInlineSizeForFragment to | 331 // same writing mode - get the inline size ComputeInlineSizeForFragment to |
318 // determine if it fits on this line, then perform layout with the correct | 332 // determine if it fits on this line, then perform layout with the correct |
319 // fragmentation line. | 333 // fragmentation line. |
320 // diff writing mode - get the inline size from performing layout. | 334 // diff writing mode - get the inline size from performing layout. |
321 RefPtr<NGLayoutResult> layout_result = node->Layout(float_space.get()); | 335 RefPtr<NGLayoutResult> layout_result = node->Layout(float_space.get()); |
322 | 336 |
(...skipping 16 matching lines...) Expand all Loading... |
339 NGLogicalOffset origin_point = | 353 NGLogicalOffset origin_point = |
340 GetOriginPointForFloats(ConstraintSpace(), content_size_); | 354 GetOriginPointForFloats(ConstraintSpace(), content_size_); |
341 NGLogicalOffset offset = | 355 NGLogicalOffset offset = |
342 PositionFloat(origin_point, constraint_space_->BfcOffset(), | 356 PositionFloat(origin_point, constraint_space_->BfcOffset(), |
343 floating_object.get(), constraint_space_); | 357 floating_object.get(), constraint_space_); |
344 container_builder_.AddFloatingObject(floating_object, offset); | 358 container_builder_.AddFloatingObject(floating_object, offset); |
345 FindNextLayoutOpportunity(); | 359 FindNextLayoutOpportunity(); |
346 } | 360 } |
347 } | 361 } |
348 | 362 |
349 void NGLineBuilder::PlaceItems( | 363 bool NGInlineLayoutAlgorithm::PlaceItems( |
350 const Vector<LineItemChunk, 32>& line_item_chunks) { | 364 const Vector<LineItemChunk, 32>& line_item_chunks) { |
351 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); | 365 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
352 | 366 |
353 NGLineBoxFragmentBuilder line_box(inline_box_); | 367 NGLineBoxFragmentBuilder line_box(inline_box_); |
354 NGTextFragmentBuilder text_builder(inline_box_); | 368 NGTextFragmentBuilder text_builder(inline_box_); |
355 | 369 |
356 // Accumulate a "strut"; a zero-width inline box with the element's font and | 370 // Accumulate a "strut"; a zero-width inline box with the element's font and |
357 // line height properties. https://drafts.csswg.org/css2/visudet.html#strut | 371 // line height properties. https://drafts.csswg.org/css2/visudet.html#strut |
358 NGLineHeightMetrics block_metrics(inline_box_->Style(), baseline_type_); | 372 NGLineHeightMetrics block_metrics(inline_box_->Style(), baseline_type_); |
359 line_box.UniteMetrics(block_metrics); | 373 line_box.UniteMetrics(block_metrics); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 | 430 |
417 NGLogicalOffset logical_offset( | 431 NGLogicalOffset logical_offset( |
418 inline_size + current_opportunity_.InlineStartOffset() - | 432 inline_size + current_opportunity_.InlineStartOffset() - |
419 ConstraintSpace().BfcOffset().inline_offset, | 433 ConstraintSpace().BfcOffset().inline_offset, |
420 block_start); | 434 block_start); |
421 line_box.AddChild(std::move(text_fragment), logical_offset); | 435 line_box.AddChild(std::move(text_fragment), logical_offset); |
422 inline_size += line_item_chunk.inline_size; | 436 inline_size += line_item_chunk.inline_size; |
423 } | 437 } |
424 | 438 |
425 if (line_box.Children().isEmpty()) { | 439 if (line_box.Children().isEmpty()) { |
426 // The line was empty. | 440 return true; // The line was empty. |
427 return; | 441 } |
| 442 |
| 443 // Check if the line fits into the constraint space in block direction. |
| 444 LayoutUnit block_end = content_size_ + line_box.Metrics().LineHeight(); |
| 445 if (!container_builder_.Children().isEmpty() && |
| 446 ConstraintSpace().AvailableSize().block_size != NGSizeIndefinite && |
| 447 block_end > ConstraintSpace().AvailableSize().block_size) { |
| 448 return false; |
428 } | 449 } |
429 | 450 |
430 // If the estimated baseline position was not the actual position, move all | 451 // If the estimated baseline position was not the actual position, move all |
431 // fragments in the block direction. | 452 // fragments in the block direction. |
432 LayoutUnit adjust_baseline(line_box.Metrics().ascent_and_leading - | 453 LayoutUnit adjust_baseline(line_box.Metrics().ascent_and_leading - |
433 block_metrics.ascent_and_leading); | 454 block_metrics.ascent_and_leading); |
434 if (adjust_baseline) | 455 if (adjust_baseline) |
435 line_box.MoveChildrenInBlockDirection(adjust_baseline); | 456 line_box.MoveChildrenInBlockDirection(adjust_baseline); |
436 | 457 |
| 458 // If there are more content to consume, create an unfinished break token. |
| 459 if (last_break_opportunity_index_ != items.size() - 1 || |
| 460 last_break_opportunity_offset_ != inline_box_->Text().length()) { |
| 461 line_box.SetBreakToken( |
| 462 NGInlineBreakToken::create(inline_box_, last_break_opportunity_index_, |
| 463 last_break_opportunity_offset_)); |
| 464 } |
| 465 |
437 line_box.SetInlineSize(inline_size); | 466 line_box.SetInlineSize(inline_size); |
438 NGLogicalOffset offset(LayoutUnit(), content_size_); | 467 container_builder_.AddChild(line_box.ToLineBoxFragment(), |
439 container_builder_.AddChild(line_box.ToLineBoxFragment(), offset); | 468 {LayoutUnit(), content_size_}); |
| 469 |
440 max_inline_size_ = std::max(max_inline_size_, inline_size); | 470 max_inline_size_ = std::max(max_inline_size_, inline_size); |
441 content_size_ += line_box.Metrics().LineHeight(); | 471 content_size_ = block_end; |
| 472 return true; |
442 } | 473 } |
443 | 474 |
444 void NGLineBuilder::AccumulateUsedFonts(const NGLayoutInlineItem& item, | 475 void NGInlineLayoutAlgorithm::AccumulateUsedFonts( |
445 const LineItemChunk& line_item_chunk, | 476 const NGLayoutInlineItem& item, |
446 NGLineBoxFragmentBuilder* line_box) { | 477 const LineItemChunk& line_item_chunk, |
| 478 NGLineBoxFragmentBuilder* line_box) { |
447 HashSet<const SimpleFontData*> fallback_fonts; | 479 HashSet<const SimpleFontData*> fallback_fonts; |
448 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, | 480 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, |
449 line_item_chunk.end_offset); | 481 line_item_chunk.end_offset); |
450 for (const auto& fallback_font : fallback_fonts) { | 482 for (const auto& fallback_font : fallback_fonts) { |
451 NGLineHeightMetrics metrics(fallback_font->getFontMetrics(), | 483 NGLineHeightMetrics metrics(fallback_font->getFontMetrics(), |
452 baseline_type_); | 484 baseline_type_); |
453 line_box->UniteMetrics(metrics); | 485 line_box->UniteMetrics(metrics); |
454 } | 486 } |
455 } | 487 } |
456 | 488 |
457 LayoutUnit NGLineBuilder::PlaceAtomicInline( | 489 LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline( |
458 const NGLayoutInlineItem& item, | 490 const NGLayoutInlineItem& item, |
459 LayoutUnit estimated_baseline, | 491 LayoutUnit estimated_baseline, |
460 NGLineBoxFragmentBuilder* line_box, | 492 NGLineBoxFragmentBuilder* line_box, |
461 NGTextFragmentBuilder* text_builder) { | 493 NGTextFragmentBuilder* text_builder) { |
462 NGBoxFragment fragment( | 494 NGBoxFragment fragment( |
463 ConstraintSpace().WritingMode(), | 495 ConstraintSpace().WritingMode(), |
464 toNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().get())); | 496 toNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().get())); |
465 // TODO(kojii): Margin and border in block progression not implemented yet. | 497 // TODO(kojii): Margin and border in block progression not implemented yet. |
466 LayoutUnit block_size = fragment.BlockSize(); | 498 LayoutUnit block_size = fragment.BlockSize(); |
467 | 499 |
(...skipping 16 matching lines...) Expand all Loading... |
484 metrics.ascent_and_leading = baseline_offset; | 516 metrics.ascent_and_leading = baseline_offset; |
485 metrics.descent_and_leading = block_size - baseline_offset; | 517 metrics.descent_and_leading = block_size - baseline_offset; |
486 line_box->UniteMetrics(metrics); | 518 line_box->UniteMetrics(metrics); |
487 | 519 |
488 // TODO(kojii): Figure out what to do with OOF in NGLayoutResult. | 520 // TODO(kojii): Figure out what to do with OOF in NGLayoutResult. |
489 // Floats are ok because atomic inlines are BFC? | 521 // Floats are ok because atomic inlines are BFC? |
490 | 522 |
491 return block_start; | 523 return block_start; |
492 } | 524 } |
493 | 525 |
494 void NGLineBuilder::FindNextLayoutOpportunity() { | 526 void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() { |
495 NGLogicalOffset iter_offset = constraint_space_->BfcOffset(); | 527 NGLogicalOffset iter_offset = constraint_space_->BfcOffset(); |
496 iter_offset.block_offset += content_size_; | 528 iter_offset.block_offset += content_size_; |
497 auto* iter = constraint_space_->LayoutOpportunityIterator(iter_offset); | 529 auto* iter = constraint_space_->LayoutOpportunityIterator(iter_offset); |
498 NGLayoutOpportunity opportunity = iter->Next(); | 530 NGLayoutOpportunity opportunity = iter->Next(); |
499 if (!opportunity.IsEmpty()) | 531 if (!opportunity.IsEmpty()) |
500 current_opportunity_ = opportunity; | 532 current_opportunity_ = opportunity; |
501 } | 533 } |
502 | 534 |
503 RefPtr<NGLayoutResult> NGLineBuilder::CreateFragments() { | 535 RefPtr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() { |
504 DCHECK(!HasItems()) << "Must call CreateLine()"; | 536 if (!inline_box_->Text().isEmpty()) |
| 537 NGLineBreaker().BreakLines(this, inline_box_->Text(), start_offset_); |
505 | 538 |
506 // TODO(kojii): Check if the line box width should be content or available. | 539 // TODO(kojii): Check if the line box width should be content or available. |
507 // TODO(kojii): Need to take constraint_space into account. | |
508 container_builder_.SetInlineSize(max_inline_size_) | 540 container_builder_.SetInlineSize(max_inline_size_) |
509 .SetInlineOverflow(max_inline_size_) | 541 .SetInlineOverflow(max_inline_size_) |
510 .SetBlockSize(content_size_) | 542 .SetBlockSize(content_size_) |
511 .SetBlockOverflow(content_size_); | 543 .SetBlockOverflow(content_size_); |
512 | 544 |
513 container_layout_result_ = container_builder_.ToBoxFragment(); | 545 return container_builder_.ToBoxFragment(); |
514 return container_layout_result_; | |
515 } | 546 } |
516 | 547 |
517 void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() { | 548 MinMaxContentSize NGInlineLayoutAlgorithm::ComputeMinMaxContentSizeByLayout() { |
| 549 DCHECK(ConstraintSpace().AvailableSize().inline_size == LayoutUnit() && |
| 550 ConstraintSpace().AvailableSize().block_size == NGSizeIndefinite); |
| 551 if (!inline_box_->Text().isEmpty()) |
| 552 NGLineBreaker().BreakLines(this, inline_box_->Text(), start_offset_); |
| 553 MinMaxContentSize sizes; |
| 554 sizes.min_content = MaxInlineSize(); |
| 555 |
| 556 // max-content is the width without any line wrapping. |
| 557 // TODO(kojii): Implement hard breaks (<br> etc.) to break. |
| 558 for (const auto& item : inline_box_->Items()) |
| 559 sizes.max_content += InlineSize(item); |
| 560 |
| 561 return sizes; |
| 562 } |
| 563 |
| 564 void NGInlineLayoutAlgorithm::CopyFragmentDataToLayoutBlockFlow( |
| 565 NGLayoutResult* layout_result) { |
518 LayoutBlockFlow* block = inline_box_->GetLayoutBlockFlow(); | 566 LayoutBlockFlow* block = inline_box_->GetLayoutBlockFlow(); |
519 block->deleteLineBoxTree(); | 567 block->deleteLineBoxTree(); |
520 | 568 |
521 Vector<NGLayoutInlineItem>& items = inline_box_->Items(); | 569 Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
522 Vector<unsigned, 32> text_offsets(items.size()); | 570 Vector<unsigned, 32> text_offsets(items.size()); |
523 inline_box_->GetLayoutTextOffsets(&text_offsets); | 571 inline_box_->GetLayoutTextOffsets(&text_offsets); |
524 | 572 |
525 Vector<const NGPhysicalFragment*, 32> fragments_for_bidi_runs; | 573 Vector<const NGPhysicalFragment*, 32> fragments_for_bidi_runs; |
526 fragments_for_bidi_runs.reserveInitialCapacity(items.size()); | 574 fragments_for_bidi_runs.reserveInitialCapacity(items.size()); |
527 BidiRunList<BidiRun> bidi_runs; | 575 BidiRunList<BidiRun> bidi_runs; |
528 LineInfo line_info; | 576 LineInfo line_info; |
529 NGPhysicalBoxFragment* box_fragment = toNGPhysicalBoxFragment( | 577 NGPhysicalBoxFragment* box_fragment = |
530 container_layout_result_->PhysicalFragment().get()); | 578 toNGPhysicalBoxFragment(layout_result->PhysicalFragment().get()); |
531 for (const auto& container_child : box_fragment->Children()) { | 579 for (const auto& container_child : box_fragment->Children()) { |
532 NGPhysicalLineBoxFragment* physical_line_box = | 580 NGPhysicalLineBoxFragment* physical_line_box = |
533 toNGPhysicalLineBoxFragment(container_child.get()); | 581 toNGPhysicalLineBoxFragment(container_child.get()); |
534 // Create a BidiRunList for this line. | 582 // Create a BidiRunList for this line. |
535 for (const auto& line_child : physical_line_box->Children()) { | 583 for (const auto& line_child : physical_line_box->Children()) { |
536 const auto* text_fragment = toNGPhysicalTextFragment(line_child.get()); | 584 const auto* text_fragment = toNGPhysicalTextFragment(line_child.get()); |
537 const NGLayoutInlineItem& item = items[text_fragment->ItemIndex()]; | 585 const NGLayoutInlineItem& item = items[text_fragment->ItemIndex()]; |
538 BidiRun* run; | 586 BidiRun* run; |
539 if (item.Type() == NGLayoutInlineItem::kText) { | 587 if (item.Type() == NGLayoutInlineItem::kText) { |
540 LayoutObject* layout_object = item.GetLayoutObject(); | 588 LayoutObject* layout_object = item.GetLayoutObject(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 root_line_box->setLineTopBottomPositions( | 643 root_line_box->setLineTopBottomPositions( |
596 baseline - LayoutUnit(metrics.ascent), | 644 baseline - LayoutUnit(metrics.ascent), |
597 baseline + LayoutUnit(metrics.descent), line_top_with_leading, | 645 baseline + LayoutUnit(metrics.descent), line_top_with_leading, |
598 baseline + LayoutUnit(metrics.descent_and_leading)); | 646 baseline + LayoutUnit(metrics.descent_and_leading)); |
599 | 647 |
600 bidi_runs.deleteRuns(); | 648 bidi_runs.deleteRuns(); |
601 fragments_for_bidi_runs.clear(); | 649 fragments_for_bidi_runs.clear(); |
602 } | 650 } |
603 } | 651 } |
604 } // namespace blink | 652 } // namespace blink |
OLD | NEW |