Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1058)

Side by Side Diff: third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc

Issue 2910133002: [LayoutNG] Handle empty inlines and border edges (Closed)
Patch Set: Rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698