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 |