Chromium Code Reviews| 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, |
| 312 LayoutNGBlockFlow* block_flow = toLayoutNGBlockFlow(layout_object); | 324 LayoutObject* layout_object) { |
| 313 NGBlockNode* node = new NGBlockNode(block_flow); | 325 NGBlockNode* node = new NGBlockNode(layout_object); |
| 314 | 326 |
| 315 RefPtr<NGConstraintSpace> float_space = CreateConstraintSpaceForFloat( | 327 RefPtr<NGConstraintSpace> float_space = CreateConstraintSpaceForFloat( |
| 316 node->Style(), ConstraintSpace(), &space_builder_); | 328 node->Style(), ConstraintSpace(), &space_builder_); |
| 317 // TODO(glebl): add the fragmentation support: | 329 // TODO(glebl): add the fragmentation support: |
| 318 // same writing mode - get the inline size ComputeInlineSizeForFragment to | 330 // same writing mode - get the inline size ComputeInlineSizeForFragment to |
| 319 // determine if it fits on this line, then perform layout with the correct | 331 // determine if it fits on this line, then perform layout with the correct |
| 320 // fragmentation line. | 332 // fragmentation line. |
| 321 // diff writing mode - get the inline size from performing layout. | 333 // diff writing mode - get the inline size from performing layout. |
| 322 RefPtr<NGLayoutResult> layout_result = node->Layout(float_space.get()); | 334 RefPtr<NGLayoutResult> layout_result = node->Layout(float_space.get()); |
| 323 | 335 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 340 NGLogicalOffset origin_point = | 352 NGLogicalOffset origin_point = |
| 341 GetOriginPointForFloats(ConstraintSpace(), content_size_); | 353 GetOriginPointForFloats(ConstraintSpace(), content_size_); |
| 342 NGLogicalOffset offset = | 354 NGLogicalOffset offset = |
| 343 PositionFloat(origin_point, constraint_space_->BfcOffset(), | 355 PositionFloat(origin_point, constraint_space_->BfcOffset(), |
| 344 floating_object.get(), constraint_space_); | 356 floating_object.get(), constraint_space_); |
| 345 container_builder_.AddFloatingObject(floating_object, offset); | 357 container_builder_.AddFloatingObject(floating_object, offset); |
| 346 FindNextLayoutOpportunity(); | 358 FindNextLayoutOpportunity(); |
| 347 } | 359 } |
| 348 } | 360 } |
| 349 | 361 |
| 350 void NGLineBuilder::PlaceItems( | 362 bool NGInlineLayoutAlgorithm::PlaceItems( |
| 351 const Vector<LineItemChunk, 32>& line_item_chunks) { | 363 const Vector<LineItemChunk, 32>& line_item_chunks) { |
| 352 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); | 364 const Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
| 353 | 365 |
| 354 NGLineBoxFragmentBuilder line_box(inline_box_); | 366 NGLineBoxFragmentBuilder line_box(inline_box_); |
| 355 NGTextFragmentBuilder text_builder(inline_box_); | 367 NGTextFragmentBuilder text_builder(inline_box_); |
| 356 | 368 |
| 357 // Accumulate a "strut"; a zero-width inline box with the element's font and | 369 // Accumulate a "strut"; a zero-width inline box with the element's font and |
| 358 // line height properties. https://drafts.csswg.org/css2/visudet.html#strut | 370 // line height properties. https://drafts.csswg.org/css2/visudet.html#strut |
| 359 const ComputedStyle* block_style = inline_box_->BlockStyle(); | 371 const ComputedStyle* block_style = inline_box_->BlockStyle(); |
| 360 NGLineHeightMetrics block_metrics(*block_style, baseline_type_); | 372 NGLineHeightMetrics block_metrics(*block_style, baseline_type_); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 418 | 430 |
| 419 NGLogicalOffset logical_offset( | 431 NGLogicalOffset logical_offset( |
| 420 inline_size + current_opportunity_.InlineStartOffset() - | 432 inline_size + current_opportunity_.InlineStartOffset() - |
| 421 ConstraintSpace().BfcOffset().inline_offset, | 433 ConstraintSpace().BfcOffset().inline_offset, |
| 422 block_start); | 434 block_start); |
| 423 line_box.AddChild(std::move(text_fragment), logical_offset); | 435 line_box.AddChild(std::move(text_fragment), logical_offset); |
| 424 inline_size += line_item_chunk.inline_size; | 436 inline_size += line_item_chunk.inline_size; |
| 425 } | 437 } |
| 426 | 438 |
| 427 if (line_box.Children().isEmpty()) { | 439 if (line_box.Children().isEmpty()) { |
| 428 // The line was empty. | 440 return true; // The line was empty. |
| 429 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; | |
| 430 } | 449 } |
| 431 | 450 |
| 432 // 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 |
| 433 // fragments in the block direction. | 452 // fragments in the block direction. |
| 434 LayoutUnit adjust_baseline(line_box.Metrics().ascent_and_leading - | 453 LayoutUnit adjust_baseline(line_box.Metrics().ascent_and_leading - |
| 435 block_metrics.ascent_and_leading); | 454 block_metrics.ascent_and_leading); |
| 436 if (adjust_baseline) | 455 if (adjust_baseline) |
| 437 line_box.MoveChildrenInBlockDirection(adjust_baseline); | 456 line_box.MoveChildrenInBlockDirection(adjust_baseline); |
| 438 | 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 | |
| 439 line_box.SetInlineSize(inline_size); | 466 line_box.SetInlineSize(inline_size); |
| 440 NGLogicalOffset offset(LayoutUnit(), content_size_); | 467 container_builder_.AddChild(line_box.ToLineBoxFragment(), |
| 441 container_builder_.AddChild(line_box.ToLineBoxFragment(), offset); | 468 {LayoutUnit(), content_size_}); |
| 469 | |
| 442 max_inline_size_ = std::max(max_inline_size_, inline_size); | 470 max_inline_size_ = std::max(max_inline_size_, inline_size); |
| 443 content_size_ += line_box.Metrics().LineHeight(); | 471 content_size_ = block_end; |
| 472 return true; | |
| 444 } | 473 } |
| 445 | 474 |
| 446 void NGLineBuilder::AccumulateUsedFonts(const NGLayoutInlineItem& item, | 475 void NGInlineLayoutAlgorithm::AccumulateUsedFonts( |
| 447 const LineItemChunk& line_item_chunk, | 476 const NGLayoutInlineItem& item, |
| 448 NGLineBoxFragmentBuilder* line_box) { | 477 const LineItemChunk& line_item_chunk, |
| 478 NGLineBoxFragmentBuilder* line_box) { | |
| 449 HashSet<const SimpleFontData*> fallback_fonts; | 479 HashSet<const SimpleFontData*> fallback_fonts; |
| 450 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, | 480 item.GetFallbackFonts(&fallback_fonts, line_item_chunk.start_offset, |
| 451 line_item_chunk.end_offset); | 481 line_item_chunk.end_offset); |
| 452 for (const auto& fallback_font : fallback_fonts) { | 482 for (const auto& fallback_font : fallback_fonts) { |
| 453 NGLineHeightMetrics metrics(fallback_font->getFontMetrics(), | 483 NGLineHeightMetrics metrics(fallback_font->getFontMetrics(), |
| 454 baseline_type_); | 484 baseline_type_); |
| 455 line_box->UniteMetrics(metrics); | 485 line_box->UniteMetrics(metrics); |
| 456 } | 486 } |
| 457 } | 487 } |
| 458 | 488 |
| 459 LayoutUnit NGLineBuilder::PlaceAtomicInline( | 489 LayoutUnit NGInlineLayoutAlgorithm::PlaceAtomicInline( |
| 460 const NGLayoutInlineItem& item, | 490 const NGLayoutInlineItem& item, |
| 461 LayoutUnit estimated_baseline, | 491 LayoutUnit estimated_baseline, |
| 462 NGLineBoxFragmentBuilder* line_box, | 492 NGLineBoxFragmentBuilder* line_box, |
| 463 NGTextFragmentBuilder* text_builder) { | 493 NGTextFragmentBuilder* text_builder) { |
| 464 NGBoxFragment fragment( | 494 NGBoxFragment fragment( |
| 465 ConstraintSpace().WritingMode(), | 495 ConstraintSpace().WritingMode(), |
| 466 toNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().get())); | 496 toNGPhysicalBoxFragment(LayoutItem(item)->PhysicalFragment().get())); |
| 467 // TODO(kojii): Margin and border in block progression not implemented yet. | 497 // TODO(kojii): Margin and border in block progression not implemented yet. |
| 468 LayoutUnit block_size = fragment.BlockSize(); | 498 LayoutUnit block_size = fragment.BlockSize(); |
| 469 | 499 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 486 metrics.ascent_and_leading = baseline_offset; | 516 metrics.ascent_and_leading = baseline_offset; |
| 487 metrics.descent_and_leading = block_size - baseline_offset; | 517 metrics.descent_and_leading = block_size - baseline_offset; |
| 488 line_box->UniteMetrics(metrics); | 518 line_box->UniteMetrics(metrics); |
| 489 | 519 |
| 490 // TODO(kojii): Figure out what to do with OOF in NGLayoutResult. | 520 // TODO(kojii): Figure out what to do with OOF in NGLayoutResult. |
| 491 // Floats are ok because atomic inlines are BFC? | 521 // Floats are ok because atomic inlines are BFC? |
| 492 | 522 |
| 493 return block_start; | 523 return block_start; |
| 494 } | 524 } |
| 495 | 525 |
| 496 void NGLineBuilder::FindNextLayoutOpportunity() { | 526 void NGInlineLayoutAlgorithm::FindNextLayoutOpportunity() { |
| 497 NGLogicalOffset iter_offset = constraint_space_->BfcOffset(); | 527 NGLogicalOffset iter_offset = constraint_space_->BfcOffset(); |
| 498 iter_offset.block_offset += content_size_; | 528 iter_offset.block_offset += content_size_; |
| 499 auto* iter = constraint_space_->LayoutOpportunityIterator(iter_offset); | 529 auto* iter = constraint_space_->LayoutOpportunityIterator(iter_offset); |
| 500 NGLayoutOpportunity opportunity = iter->Next(); | 530 NGLayoutOpportunity opportunity = iter->Next(); |
| 501 if (!opportunity.IsEmpty()) | 531 if (!opportunity.IsEmpty()) |
| 502 current_opportunity_ = opportunity; | 532 current_opportunity_ = opportunity; |
| 503 } | 533 } |
| 504 | 534 |
| 505 RefPtr<NGLayoutResult> NGLineBuilder::CreateFragments() { | 535 RefPtr<NGLayoutResult> NGInlineLayoutAlgorithm::CreateFragments() { |
| 506 DCHECK(!HasItems()) << "Must call CreateLine()"; | |
| 507 | |
| 508 // TODO(kojii): Check if the line box width should be content or available. | 536 // TODO(kojii): Check if the line box width should be content or available. |
| 509 // TODO(kojii): Need to take constraint_space into account. | 537 // TODO(kojii): Need to take constraint_space into account. |
| 510 container_builder_.SetInlineSize(max_inline_size_) | 538 container_builder_.SetInlineSize(max_inline_size_) |
| 511 .SetInlineOverflow(max_inline_size_) | 539 .SetInlineOverflow(max_inline_size_) |
| 512 .SetBlockSize(content_size_) | 540 .SetBlockSize(content_size_) |
| 513 .SetBlockOverflow(content_size_); | 541 .SetBlockOverflow(content_size_); |
| 514 | 542 |
| 515 container_layout_result_ = container_builder_.ToBoxFragment(); | 543 return container_builder_.ToBoxFragment(); |
| 516 return container_layout_result_; | |
| 517 } | 544 } |
| 518 | 545 |
| 519 void NGLineBuilder::CopyFragmentDataToLayoutBlockFlow() { | 546 RefPtr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() { |
| 547 if (!inline_box_->Text().isEmpty()) | |
| 548 NGLineBreaker().BreakLines(this, inline_box_->Text(), start_offset_); | |
| 549 return CreateFragments(); | |
|
ikilpatrick
2017/03/24 20:58:05
can just inline this function now?
| |
| 550 } | |
| 551 | |
| 552 MinMaxContentSize NGInlineLayoutAlgorithm::ComputeMinMaxContentSizeByLayout() { | |
| 553 DCHECK(ConstraintSpace().AvailableSize().inline_size == LayoutUnit() && | |
| 554 ConstraintSpace().AvailableSize().block_size == NGSizeIndefinite); | |
| 555 if (!inline_box_->Text().isEmpty()) | |
| 556 NGLineBreaker().BreakLines(this, inline_box_->Text(), start_offset_); | |
| 557 MinMaxContentSize sizes; | |
| 558 sizes.min_content = MaxInlineSize(); | |
| 559 | |
| 560 // max-content is the width without any line wrapping. | |
| 561 // TODO(kojii): Implement hard breaks (<br> etc.) to break. | |
| 562 for (const auto& item : inline_box_->Items()) | |
| 563 sizes.max_content += InlineSize(item); | |
| 564 | |
| 565 return sizes; | |
| 566 } | |
| 567 | |
| 568 void NGInlineLayoutAlgorithm::CopyFragmentDataToLayoutBlockFlow( | |
| 569 NGLayoutResult* layout_result) { | |
| 520 LayoutBlockFlow* block = inline_box_->GetLayoutBlockFlow(); | 570 LayoutBlockFlow* block = inline_box_->GetLayoutBlockFlow(); |
| 521 block->deleteLineBoxTree(); | 571 block->deleteLineBoxTree(); |
| 522 | 572 |
| 523 Vector<NGLayoutInlineItem>& items = inline_box_->Items(); | 573 Vector<NGLayoutInlineItem>& items = inline_box_->Items(); |
| 524 Vector<unsigned, 32> text_offsets(items.size()); | 574 Vector<unsigned, 32> text_offsets(items.size()); |
| 525 inline_box_->GetLayoutTextOffsets(&text_offsets); | 575 inline_box_->GetLayoutTextOffsets(&text_offsets); |
| 526 | 576 |
| 527 Vector<const NGPhysicalFragment*, 32> fragments_for_bidi_runs; | 577 Vector<const NGPhysicalFragment*, 32> fragments_for_bidi_runs; |
| 528 fragments_for_bidi_runs.reserveInitialCapacity(items.size()); | 578 fragments_for_bidi_runs.reserveInitialCapacity(items.size()); |
| 529 BidiRunList<BidiRun> bidi_runs; | 579 BidiRunList<BidiRun> bidi_runs; |
| 530 LineInfo line_info; | 580 LineInfo line_info; |
| 531 NGPhysicalBoxFragment* box_fragment = toNGPhysicalBoxFragment( | 581 NGPhysicalBoxFragment* box_fragment = |
| 532 container_layout_result_->PhysicalFragment().get()); | 582 toNGPhysicalBoxFragment(layout_result->PhysicalFragment().get()); |
| 533 for (const auto& container_child : box_fragment->Children()) { | 583 for (const auto& container_child : box_fragment->Children()) { |
| 534 NGPhysicalLineBoxFragment* physical_line_box = | 584 NGPhysicalLineBoxFragment* physical_line_box = |
| 535 toNGPhysicalLineBoxFragment(container_child.get()); | 585 toNGPhysicalLineBoxFragment(container_child.get()); |
| 536 // Create a BidiRunList for this line. | 586 // Create a BidiRunList for this line. |
| 537 for (const auto& line_child : physical_line_box->Children()) { | 587 for (const auto& line_child : physical_line_box->Children()) { |
| 538 const auto* text_fragment = toNGPhysicalTextFragment(line_child.get()); | 588 const auto* text_fragment = toNGPhysicalTextFragment(line_child.get()); |
| 539 const NGLayoutInlineItem& item = items[text_fragment->ItemIndex()]; | 589 const NGLayoutInlineItem& item = items[text_fragment->ItemIndex()]; |
| 540 BidiRun* run; | 590 BidiRun* run; |
| 541 if (item.Type() == NGLayoutInlineItem::kText) { | 591 if (item.Type() == NGLayoutInlineItem::kText) { |
| 542 LayoutObject* layout_object = item.GetLayoutObject(); | 592 LayoutObject* layout_object = item.GetLayoutObject(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 597 root_line_box->setLineTopBottomPositions( | 647 root_line_box->setLineTopBottomPositions( |
| 598 baseline - LayoutUnit(metrics.ascent), | 648 baseline - LayoutUnit(metrics.ascent), |
| 599 baseline + LayoutUnit(metrics.descent), line_top_with_leading, | 649 baseline + LayoutUnit(metrics.descent), line_top_with_leading, |
| 600 baseline + LayoutUnit(metrics.descent_and_leading)); | 650 baseline + LayoutUnit(metrics.descent_and_leading)); |
| 601 | 651 |
| 602 bidi_runs.deleteRuns(); | 652 bidi_runs.deleteRuns(); |
| 603 fragments_for_bidi_runs.clear(); | 653 fragments_for_bidi_runs.clear(); |
| 604 } | 654 } |
| 605 } | 655 } |
| 606 } // namespace blink | 656 } // namespace blink |
| OLD | NEW |