| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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_inline_box_state.h" | 5 #include "core/layout/ng/inline/ng_inline_box_state.h" |
| 6 | 6 |
| 7 #include "core/layout/ng/inline/ng_inline_item_result.h" |
| 7 #include "core/layout/ng/inline/ng_inline_node.h" | 8 #include "core/layout/ng/inline/ng_inline_node.h" |
| 8 #include "core/layout/ng/inline/ng_line_box_fragment_builder.h" | 9 #include "core/layout/ng/inline/ng_line_box_fragment_builder.h" |
| 9 #include "core/layout/ng/inline/ng_text_fragment_builder.h" | 10 #include "core/layout/ng/inline/ng_text_fragment_builder.h" |
| 10 #include "core/layout/ng/ng_fragment_builder.h" | 11 #include "core/layout/ng/ng_fragment_builder.h" |
| 11 #include "core/layout/ng/ng_layout_result.h" | 12 #include "core/layout/ng/ng_layout_result.h" |
| 12 #include "core/style/ComputedStyle.h" | 13 #include "core/style/ComputedStyle.h" |
| 13 | 14 |
| 14 namespace blink { | 15 namespace blink { |
| 15 | 16 |
| 16 void NGInlineBoxState::ComputeTextMetrics(const ComputedStyle& style, | 17 void NGInlineBoxState::ComputeTextMetrics(const ComputedStyle& style, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 31 item.GetFallbackFonts(&fallback_fonts, start, end); | 32 item.GetFallbackFonts(&fallback_fonts, start, end); |
| 32 for (const auto& fallback_font : fallback_fonts) { | 33 for (const auto& fallback_font : fallback_fonts) { |
| 33 NGLineHeightMetrics fallback_metrics(fallback_font->GetFontMetrics(), | 34 NGLineHeightMetrics fallback_metrics(fallback_font->GetFontMetrics(), |
| 34 baseline_type); | 35 baseline_type); |
| 35 fallback_metrics.AddLeading( | 36 fallback_metrics.AddLeading( |
| 36 fallback_font->GetFontMetrics().FixedLineSpacing()); | 37 fallback_font->GetFontMetrics().FixedLineSpacing()); |
| 37 metrics.Unite(fallback_metrics); | 38 metrics.Unite(fallback_metrics); |
| 38 } | 39 } |
| 39 } | 40 } |
| 40 | 41 |
| 41 void NGInlineBoxState::SetNeedsBoxFragment( | |
| 42 LayoutUnit position, | |
| 43 LayoutUnit borders_paddings_block_start, | |
| 44 LayoutUnit borders_paddings_block_height) { | |
| 45 needs_box_fragment = true; | |
| 46 line_left_position = position; | |
| 47 this->borders_paddings_block_start = borders_paddings_block_start; | |
| 48 this->borders_paddings_block_height = borders_paddings_block_height; | |
| 49 } | |
| 50 | |
| 51 NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems( | 42 NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems( |
| 52 const ComputedStyle* line_style, | 43 const ComputedStyle* line_style, |
| 53 FontBaseline baseline_type) { | 44 FontBaseline baseline_type) { |
| 54 if (stack_.IsEmpty()) { | 45 if (stack_.IsEmpty()) { |
| 55 // For the first line, push a box state for the line itself. | 46 // For the first line, push a box state for the line itself. |
| 56 stack_.resize(1); | 47 stack_.resize(1); |
| 57 NGInlineBoxState* box = &stack_.back(); | 48 NGInlineBoxState* box = &stack_.back(); |
| 58 box->fragment_start = 0; | 49 box->fragment_start = 0; |
| 59 } else { | 50 } else { |
| 60 // For the following lines, clear states that are not shared across lines. | 51 // For the following lines, clear states that are not shared across lines. |
| 61 for (auto& box : stack_) { | 52 for (auto& box : stack_) { |
| 62 box.fragment_start = 0; | 53 box.fragment_start = 0; |
| 63 box.metrics = NGLineHeightMetrics(); | 54 box.metrics = NGLineHeightMetrics(); |
| 55 // Existing box states are wrapped boxes, and hence no left edges. |
| 56 box.border_edges.line_left = false; |
| 64 DCHECK(box.pending_descendants.IsEmpty()); | 57 DCHECK(box.pending_descendants.IsEmpty()); |
| 65 } | 58 } |
| 66 } | 59 } |
| 67 | 60 |
| 68 // Initialize the box state for the line box. | 61 // Initialize the box state for the line box. |
| 69 NGInlineBoxState& line_box = LineBoxState(); | 62 NGInlineBoxState& line_box = LineBoxState(); |
| 70 line_box.style = line_style; | 63 line_box.style = line_style; |
| 71 | 64 |
| 72 // Use a "strut" (a zero-width inline box with the element's font and | 65 // Use a "strut" (a zero-width inline box with the element's font and |
| 73 // line height properties) as the initial metrics for the line box. | 66 // line height properties) as the initial metrics for the line box. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 85 box->fragment_start = line_box->Children().size(); | 78 box->fragment_start = line_box->Children().size(); |
| 86 box->item = &item; | 79 box->item = &item; |
| 87 box->style = item.Style(); | 80 box->style = item.Style(); |
| 88 return box; | 81 return box; |
| 89 } | 82 } |
| 90 | 83 |
| 91 NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag( | 84 NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag( |
| 92 const NGInlineItem& item, | 85 const NGInlineItem& item, |
| 93 NGLineBoxFragmentBuilder* line_box, | 86 NGLineBoxFragmentBuilder* line_box, |
| 94 NGInlineBoxState* box, | 87 NGInlineBoxState* box, |
| 95 FontBaseline baseline_type, | 88 FontBaseline baseline_type) { |
| 96 LayoutUnit position) { | 89 EndBoxState(box, line_box, baseline_type); |
| 97 EndBoxState(box, line_box, baseline_type, position); | |
| 98 // TODO(kojii): When the algorithm restarts from a break token, the stack may | 90 // TODO(kojii): When the algorithm restarts from a break token, the stack may |
| 99 // underflow. We need either synthesize a missing box state, or push all | 91 // underflow. We need either synthesize a missing box state, or push all |
| 100 // parents on initialize. | 92 // parents on initialize. |
| 101 stack_.pop_back(); | 93 stack_.pop_back(); |
| 102 return &stack_.back(); | 94 return &stack_.back(); |
| 103 } | 95 } |
| 104 | 96 |
| 105 void NGInlineLayoutStateStack::OnEndPlaceItems( | 97 void NGInlineLayoutStateStack::OnEndPlaceItems( |
| 106 NGLineBoxFragmentBuilder* line_box, | 98 NGLineBoxFragmentBuilder* line_box, |
| 107 FontBaseline baseline_type, | 99 FontBaseline baseline_type, |
| 108 LayoutUnit position) { | 100 LayoutUnit position) { |
| 109 for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) { | 101 for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) { |
| 110 NGInlineBoxState* box = &(*it); | 102 NGInlineBoxState* box = &(*it); |
| 111 EndBoxState(box, line_box, baseline_type, position); | 103 box->line_right_position = position; |
| 104 EndBoxState(box, line_box, baseline_type); |
| 112 } | 105 } |
| 113 | 106 |
| 114 if (!box_placeholders_.IsEmpty()) | 107 if (!box_placeholders_.IsEmpty()) |
| 115 CreateBoxFragments(line_box); | 108 CreateBoxFragments(line_box); |
| 116 | 109 |
| 117 DCHECK(!LineBoxState().metrics.IsEmpty()); | 110 DCHECK(!LineBoxState().metrics.IsEmpty()); |
| 118 line_box->SetMetrics(LineBoxState().metrics); | 111 line_box->SetMetrics(LineBoxState().metrics); |
| 119 } | 112 } |
| 120 | 113 |
| 121 void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box, | 114 void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box, |
| 122 NGLineBoxFragmentBuilder* line_box, | 115 NGLineBoxFragmentBuilder* line_box, |
| 123 FontBaseline baseline_type, | 116 FontBaseline baseline_type) { |
| 124 LayoutUnit position) { | |
| 125 if (box->needs_box_fragment) | 117 if (box->needs_box_fragment) |
| 126 AddBoxFragmentPlaceholder(box, line_box, baseline_type, position); | 118 AddBoxFragmentPlaceholder(box, line_box, baseline_type); |
| 127 | 119 |
| 128 PositionPending position_pending = | 120 PositionPending position_pending = |
| 129 ApplyBaselineShift(box, line_box, baseline_type); | 121 ApplyBaselineShift(box, line_box, baseline_type); |
| 130 | 122 |
| 131 // Unite the metrics to the parent box. | 123 // Unite the metrics to the parent box. |
| 132 if (position_pending == kPositionNotPending && box != stack_.begin()) { | 124 if (position_pending == kPositionNotPending && box != stack_.begin()) { |
| 133 box[-1].metrics.Unite(box->metrics); | 125 box[-1].metrics.Unite(box->metrics); |
| 134 } | 126 } |
| 135 } | 127 } |
| 136 | 128 |
| 129 void NGInlineBoxState::SetNeedsBoxFragment( |
| 130 const NGInlineItem& item, |
| 131 const NGInlineItemResult& item_result, |
| 132 LayoutUnit position) { |
| 133 needs_box_fragment = true; |
| 134 line_left_position = position + item_result.margins.inline_start; |
| 135 borders_paddings_block_start = item_result.borders_paddings_block_start; |
| 136 borders_paddings_block_end = item_result.borders_paddings_block_end; |
| 137 // We have left edge on open tag, and if the box is not a continuation. |
| 138 // TODO(kojii): Needs review when we change SplitInlines(). |
| 139 bool has_line_left_edge = item.Style()->IsLeftToRightDirection() |
| 140 ? item.HasStartEdge() |
| 141 : item.HasEndEdge(); |
| 142 border_edges = {true, false, true, has_line_left_edge}; |
| 143 } |
| 144 |
| 145 void NGInlineBoxState::SetLineRightForBoxFragment( |
| 146 const NGInlineItem& item, |
| 147 const NGInlineItemResult& item_result, |
| 148 LayoutUnit position) { |
| 149 DCHECK(needs_box_fragment); |
| 150 line_right_position = position - item_result.margins.inline_end; |
| 151 // We have right edge on close tag, and if the box does not have a |
| 152 // continuation. |
| 153 // TODO(kojii): Needs review when we change SplitInlines(). |
| 154 border_edges.line_right = item.Style()->IsLeftToRightDirection() |
| 155 ? item.HasEndEdge() |
| 156 : item.HasStartEdge(); |
| 157 } |
| 158 |
| 137 // Crete a placeholder for a box fragment. | 159 // Crete a placeholder for a box fragment. |
| 138 // We keep a flat list of fragments because it is more suitable for operations | 160 // We keep a flat list of fragments because it is more suitable for operations |
| 139 // such as ApplyBaselineShift. Later, CreateBoxFragments() creates box fragments | 161 // such as ApplyBaselineShift. Later, CreateBoxFragments() creates box fragments |
| 140 // from placeholders. | 162 // from placeholders. |
| 141 void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder( | 163 void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder( |
| 142 NGInlineBoxState* box, | 164 NGInlineBoxState* box, |
| 143 NGLineBoxFragmentBuilder* line_box, | 165 NGLineBoxFragmentBuilder* line_box, |
| 144 FontBaseline baseline_type, | 166 FontBaseline baseline_type) { |
| 145 LayoutUnit position) { | 167 LayoutUnit inline_size = box->line_right_position - box->line_left_position; |
| 146 if (box->fragment_start == line_box->Children().size()) { | 168 if (box->fragment_start == line_box->Children().size() && inline_size <= 0) { |
| 147 // Don't create a placeholder if the inline box is empty. | 169 // Don't create a box if the inline box is "empty". |
| 170 // Inline boxes with inline margins/borders/paddings are not "empty", |
| 171 // but background doesn't make difference in this context. |
| 148 // Whether to create this box or not affects layout when the line contains | 172 // Whether to create this box or not affects layout when the line contains |
| 149 // only this box, since this box participates the line height. | 173 // only this box, since this box participates the line height. |
| 150 // TODO(kojii): Testing indicates that we should create a box if it has | |
| 151 // borders, but not for backgrounds. But creating such a RootInlineBox needs | |
| 152 // additional code. The plan is to enable such line box when NG paint is | |
| 153 // enabled. | |
| 154 return; | 174 return; |
| 155 } | 175 } |
| 156 | 176 |
| 157 // The inline box should have the height of the font metrics without the | 177 // The inline box should have the height of the font metrics without the |
| 158 // line-height property. Compute from style because |box->metrics| includes | 178 // line-height property. Compute from style because |box->metrics| includes |
| 159 // the line-height property. | 179 // the line-height property. |
| 160 DCHECK(box->style); | 180 DCHECK(box->style); |
| 161 const ComputedStyle& style = *box->style; | 181 const ComputedStyle& style = *box->style; |
| 162 NGLineHeightMetrics metrics(style, baseline_type); | 182 NGLineHeightMetrics metrics(style, baseline_type); |
| 163 | 183 |
| 164 // Extend the block direction of the box by borders and paddings. Inline | 184 // Extend the block direction of the box by borders and paddings. Inline |
| 165 // direction is already included into positions in NGLineBreaker. | 185 // direction is already included into positions in NGLineBreaker. |
| 166 NGLogicalRect bounds( | 186 NGLogicalRect bounds( |
| 167 box->line_left_position, | 187 box->line_left_position, |
| 168 -metrics.ascent - box->borders_paddings_block_start, | 188 -metrics.ascent - box->borders_paddings_block_start, inline_size, |
| 169 position - box->line_left_position, | 189 metrics.LineHeight() + box->borders_paddings_block_start + |
| 170 metrics.LineHeight() + box->borders_paddings_block_height); | 190 box->borders_paddings_block_end); |
| 171 | 191 |
| 172 // The start is marked only in BoxFragmentPlaceholder, while end is marked | 192 // The start is marked only in BoxFragmentPlaceholder, while end is marked |
| 173 // in both BoxFragmentPlaceholder and the list itself. | 193 // in both BoxFragmentPlaceholder and the list itself. |
| 174 // With a list of 4 text fragments: | 194 // With a list of 4 text fragments: |
| 175 // | 0 | 1 | 2 | 3 | | 195 // | 0 | 1 | 2 | 3 | |
| 176 // |text0|text1|text2|text3| | 196 // |text0|text1|text2|text3| |
| 177 // By adding a BoxFragmentPlaceholder(2,4) (end is exclusive), it becomes: | 197 // By adding a BoxFragmentPlaceholder(2,4) (end is exclusive), it becomes: |
| 178 // | 0 | 1 | 2 | 3 | 4 | | 198 // | 0 | 1 | 2 | 3 | 4 | |
| 179 // |text0|text1|text2|text3|null | | 199 // |text0|text1|text2|text3|null | |
| 180 // The "null" is added to the list to compute baseline shift of the box | 200 // The "null" is added to the list to compute baseline shift of the box |
| 181 // separately from text fragments. | 201 // separately from text fragments. |
| 182 unsigned fragment_end = line_box->Children().size(); | 202 unsigned fragment_end = line_box->Children().size(); |
| 183 box_placeholders_.push_back(BoxFragmentPlaceholder{ | 203 box_placeholders_.push_back( |
| 184 box->fragment_start, fragment_end, box->item, bounds.size}); | 204 BoxFragmentPlaceholder{box->fragment_start, fragment_end, box->item, |
| 205 bounds.size, box->border_edges}); |
| 185 line_box->AddChild(nullptr, bounds.offset); | 206 line_box->AddChild(nullptr, bounds.offset); |
| 186 } | 207 } |
| 187 | 208 |
| 188 // Create box fragments and construct a tree from the placeholders. | 209 // Create box fragments and construct a tree from the placeholders. |
| 189 void NGInlineLayoutStateStack::CreateBoxFragments( | 210 void NGInlineLayoutStateStack::CreateBoxFragments( |
| 190 NGLineBoxFragmentBuilder* line_box) { | 211 NGLineBoxFragmentBuilder* line_box) { |
| 191 DCHECK(!box_placeholders_.IsEmpty()); | 212 DCHECK(!box_placeholders_.IsEmpty()); |
| 192 | 213 |
| 193 Vector<RefPtr<NGPhysicalFragment>> children = | 214 Vector<RefPtr<NGPhysicalFragment>> children = |
| 194 std::move(line_box->MutableChildren()); | 215 std::move(line_box->MutableChildren()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 209 for (unsigned i = placeholder.fragment_start; i < placeholder.fragment_end; | 230 for (unsigned i = placeholder.fragment_start; i < placeholder.fragment_end; |
| 210 i++) { | 231 i++) { |
| 211 if (RefPtr<NGPhysicalFragment>& child = children[i]) { | 232 if (RefPtr<NGPhysicalFragment>& child = children[i]) { |
| 212 box.AddChild(std::move(child), offsets[i] - box_offset); | 233 box.AddChild(std::move(child), offsets[i] - box_offset); |
| 213 DCHECK(!children[i]); | 234 DCHECK(!children[i]); |
| 214 } | 235 } |
| 215 } | 236 } |
| 216 | 237 |
| 217 box.SetWritingMode(line_box->WritingMode()); | 238 box.SetWritingMode(line_box->WritingMode()); |
| 218 box.SetDirection(placeholder.item->Direction()); | 239 box.SetDirection(placeholder.item->Direction()); |
| 240 // Inline boxes have block start/end borders, even when its containing block |
| 241 // was fragmented. Fragmenting a line box in block direction is not |
| 242 // supported today. |
| 243 box.SetBorderEdges(placeholder.border_edges); |
| 219 box.SetSize(placeholder.size); | 244 box.SetSize(placeholder.size); |
| 220 // TODO(kojii): Overflow size should be computed from children. | 245 // TODO(kojii): Overflow size should be computed from children. |
| 221 box.SetOverflowSize(placeholder.size); | 246 box.SetOverflowSize(placeholder.size); |
| 222 RefPtr<NGLayoutResult> layout_result = box.ToBoxFragment(); | 247 RefPtr<NGLayoutResult> layout_result = box.ToBoxFragment(); |
| 223 DCHECK(!children[placeholder.fragment_end]); | 248 DCHECK(!children[placeholder.fragment_end]); |
| 224 children[placeholder.fragment_end] = | 249 children[placeholder.fragment_end] = |
| 225 std::move(layout_result->MutablePhysicalFragment()); | 250 std::move(layout_result->MutablePhysicalFragment()); |
| 226 } | 251 } |
| 227 box_placeholders_.clear(); | 252 box_placeholders_.clear(); |
| 228 | 253 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 box->fragment_start, fragment_end, box->metrics, vertical_align}); | 354 box->fragment_start, fragment_end, box->metrics, vertical_align}); |
| 330 return kPositionPending; | 355 return kPositionPending; |
| 331 } | 356 } |
| 332 box->metrics.Move(baseline_shift); | 357 box->metrics.Move(baseline_shift); |
| 333 line_box->MoveChildrenInBlockDirection(baseline_shift, box->fragment_start, | 358 line_box->MoveChildrenInBlockDirection(baseline_shift, box->fragment_start, |
| 334 fragment_end); | 359 fragment_end); |
| 335 return kPositionNotPending; | 360 return kPositionNotPending; |
| 336 } | 361 } |
| 337 | 362 |
| 338 } // namespace blink | 363 } // namespace blink |
| OLD | NEW |