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/inline/ng_inline_layout_algorithm.h" | 5 #include "core/layout/ng/inline/ng_inline_layout_algorithm.h" |
6 | 6 |
7 #include "core/layout/ng/inline/ng_bidi_paragraph.h" | 7 #include "core/layout/ng/inline/ng_bidi_paragraph.h" |
8 #include "core/layout/ng/inline/ng_inline_break_token.h" | 8 #include "core/layout/ng/inline/ng_inline_break_token.h" |
9 #include "core/layout/ng/inline/ng_inline_node.h" | 9 #include "core/layout/ng/inline/ng_inline_node.h" |
10 #include "core/layout/ng/inline/ng_line_box_fragment.h" | 10 #include "core/layout/ng/inline/ng_line_box_fragment.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 const NGLogicalOffset& container_bfc_offset, | 33 const NGLogicalOffset& container_bfc_offset, |
34 LayoutUnit content_size) { | 34 LayoutUnit content_size) { |
35 NGLogicalOffset origin_point = container_bfc_offset; | 35 NGLogicalOffset origin_point = container_bfc_offset; |
36 origin_point.block_offset += content_size; | 36 origin_point.block_offset += content_size; |
37 return origin_point; | 37 return origin_point; |
38 } | 38 } |
39 | 39 |
40 } // namespace | 40 } // namespace |
41 | 41 |
42 NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm( | 42 NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm( |
43 NGInlineNode* inline_node, | 43 NGInlineNode inline_node, |
44 NGConstraintSpace* space, | 44 NGConstraintSpace* space, |
45 NGInlineBreakToken* break_token) | 45 NGInlineBreakToken* break_token) |
46 : NGLayoutAlgorithm(inline_node, space, break_token), | 46 : NGLayoutAlgorithm(inline_node, space, break_token), |
47 is_horizontal_writing_mode_( | 47 is_horizontal_writing_mode_( |
48 blink::IsHorizontalWritingMode(space->WritingMode())), | 48 blink::IsHorizontalWritingMode(space->WritingMode())), |
49 disallow_first_line_rules_(false), | 49 disallow_first_line_rules_(false), |
50 space_builder_(space) | 50 space_builder_(space) { |
51 { | |
52 container_builder_.MutableUnpositionedFloats() = space->UnpositionedFloats(); | 51 container_builder_.MutableUnpositionedFloats() = space->UnpositionedFloats(); |
53 | 52 |
54 // TODO(crbug.com/716930): We may be an empty LayoutInline due to splitting. | 53 // TODO(crbug.com/716930): We may be an empty LayoutInline due to splitting. |
55 // Only resolve our BFC offset if we know that we are non-empty as we may | 54 // Only resolve our BFC offset if we know that we are non-empty as we may |
56 // need to pass through our margin strut. | 55 // need to pass through our margin strut. |
57 if (!inline_node->Items().IsEmpty()) { | 56 if (!inline_node.Items().IsEmpty()) { |
58 LayoutUnit bfc_block_offset = ConstraintSpace().BfcOffset().block_offset; | 57 LayoutUnit bfc_block_offset = ConstraintSpace().BfcOffset().block_offset; |
59 bfc_block_offset += ConstraintSpace().MarginStrut().Sum(); | 58 bfc_block_offset += ConstraintSpace().MarginStrut().Sum(); |
60 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset, | 59 MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset, |
61 &container_builder_); | 60 &container_builder_); |
62 PositionPendingFloats(bfc_block_offset, &container_builder_, | 61 PositionPendingFloats(bfc_block_offset, &container_builder_, |
63 MutableConstraintSpace()); | 62 MutableConstraintSpace()); |
64 } | 63 } |
65 | 64 |
66 if (!is_horizontal_writing_mode_) | 65 if (!is_horizontal_writing_mode_) |
67 baseline_type_ = FontBaseline::kIdeographicBaseline; | 66 baseline_type_ = FontBaseline::kIdeographicBaseline; |
68 | 67 |
69 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + | 68 border_and_padding_ = ComputeBorders(ConstraintSpace(), Style()) + |
70 ComputePadding(ConstraintSpace(), Style()); | 69 ComputePadding(ConstraintSpace(), Style()); |
71 | 70 |
72 if (break_token) { | 71 if (break_token) { |
73 // If a break_token is given, we're re-starting layout for 2nd or later | 72 // If a break_token is given, we're re-starting layout for 2nd or later |
74 // lines, and that the first line we create should not use the first line | 73 // lines, and that the first line we create should not use the first line |
75 // rules. | 74 // rules. |
76 DCHECK(!break_token->IsFinished()); | 75 DCHECK(!break_token->IsFinished()); |
77 DCHECK(break_token->TextOffset() || break_token->ItemIndex()); | 76 DCHECK(break_token->TextOffset() || break_token->ItemIndex()); |
78 disallow_first_line_rules_ = true; | 77 disallow_first_line_rules_ = true; |
79 } else { | 78 } else { |
80 auto& engine = Node()->GetLayoutObject()->GetDocument().GetStyleEngine(); | 79 auto& engine = Node().GetLayoutObject()->GetDocument().GetStyleEngine(); |
81 disallow_first_line_rules_ = !engine.UsesFirstLineRules(); | 80 disallow_first_line_rules_ = !engine.UsesFirstLineRules(); |
82 } | 81 } |
83 | 82 |
84 FindNextLayoutOpportunity(); | 83 FindNextLayoutOpportunity(); |
85 } | 84 } |
86 | 85 |
87 bool NGInlineLayoutAlgorithm::IsFirstLine() const { | 86 bool NGInlineLayoutAlgorithm::IsFirstLine() const { |
88 return !disallow_first_line_rules_ && container_builder_.Children().IsEmpty(); | 87 return !disallow_first_line_rules_ && container_builder_.Children().IsEmpty(); |
89 } | 88 } |
90 | 89 |
91 const ComputedStyle& NGInlineLayoutAlgorithm::FirstLineStyle() const { | 90 const ComputedStyle& NGInlineLayoutAlgorithm::FirstLineStyle() const { |
92 return Node()->GetLayoutObject()->FirstLineStyleRef(); | 91 return Node().GetLayoutObject()->FirstLineStyleRef(); |
93 } | 92 } |
94 | 93 |
95 const ComputedStyle& NGInlineLayoutAlgorithm::LineStyle() const { | 94 const ComputedStyle& NGInlineLayoutAlgorithm::LineStyle() const { |
96 return IsFirstLine() ? FirstLineStyle() : Style(); | 95 return IsFirstLine() ? FirstLineStyle() : Style(); |
97 } | 96 } |
98 | 97 |
99 LayoutUnit NGInlineLayoutAlgorithm::AvailableWidth() const { | 98 LayoutUnit NGInlineLayoutAlgorithm::AvailableWidth() const { |
100 return current_opportunity_.InlineSize(); | 99 return current_opportunity_.InlineSize(); |
101 } | 100 } |
102 | 101 |
103 // The offset of 'line-left' side. | 102 // The offset of 'line-left' side. |
104 // https://drafts.csswg.org/css-writing-modes/#line-left | 103 // https://drafts.csswg.org/css-writing-modes/#line-left |
105 LayoutUnit NGInlineLayoutAlgorithm::LogicalLeftOffset() const { | 104 LayoutUnit NGInlineLayoutAlgorithm::LogicalLeftOffset() const { |
106 // TODO(kojii): We need to convert 'line start' to 'line left'. They're | 105 // TODO(kojii): We need to convert 'line start' to 'line left'. They're |
107 // different in RTL. Maybe there are more where start and left are misused. | 106 // different in RTL. Maybe there are more where start and left are misused. |
108 return current_opportunity_.InlineStartOffset() - | 107 return current_opportunity_.InlineStartOffset() - |
109 ConstraintSpace().BfcOffset().inline_offset; | 108 ConstraintSpace().BfcOffset().inline_offset; |
110 } | 109 } |
111 | 110 |
112 bool NGInlineLayoutAlgorithm::CreateLine( | 111 bool NGInlineLayoutAlgorithm::CreateLine( |
113 NGInlineItemResults* item_results, | 112 NGInlineItemResults* item_results, |
114 RefPtr<NGInlineBreakToken> break_token) { | 113 RefPtr<NGInlineBreakToken> break_token) { |
115 if (Node()->IsBidiEnabled()) | 114 if (Node().IsBidiEnabled()) |
116 BidiReorder(item_results); | 115 BidiReorder(item_results); |
117 | 116 |
118 if (!PlaceItems(item_results, break_token)) | 117 if (!PlaceItems(item_results, break_token)) |
119 return false; | 118 return false; |
120 | 119 |
121 // Prepare for the next line. | 120 // Prepare for the next line. |
122 NGLogicalOffset origin_point = | 121 NGLogicalOffset origin_point = |
123 GetOriginPointForFloats(ContainerBfcOffset(), content_size_); | 122 GetOriginPointForFloats(ContainerBfcOffset(), content_size_); |
124 PositionPendingFloats(origin_point.block_offset, &container_builder_, | 123 PositionPendingFloats(origin_point.block_offset, &container_builder_, |
125 MutableConstraintSpace()); | 124 MutableConstraintSpace()); |
126 FindNextLayoutOpportunity(); | 125 FindNextLayoutOpportunity(); |
127 return true; | 126 return true; |
128 } | 127 } |
129 | 128 |
130 void NGInlineLayoutAlgorithm::BidiReorder(NGInlineItemResults* line_items) { | 129 void NGInlineLayoutAlgorithm::BidiReorder(NGInlineItemResults* line_items) { |
131 // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change | 130 // TODO(kojii): UAX#9 L1 is not supported yet. Supporting L1 may change |
132 // embedding levels of parts of runs, which requires to split items. | 131 // embedding levels of parts of runs, which requires to split items. |
133 // http://unicode.org/reports/tr9/#L1 | 132 // http://unicode.org/reports/tr9/#L1 |
134 // BidiResolver does not support L1 crbug.com/316409. | 133 // BidiResolver does not support L1 crbug.com/316409. |
135 | 134 |
136 // Create a list of chunk indices in the visual order. | 135 // Create a list of chunk indices in the visual order. |
137 // ICU |ubidi_getVisualMap()| works for a run of characters. Since we can | 136 // ICU |ubidi_getVisualMap()| works for a run of characters. Since we can |
138 // handle the direction of each run, we use |ubidi_reorderVisual()| to reorder | 137 // handle the direction of each run, we use |ubidi_reorderVisual()| to reorder |
139 // runs instead of characters. | 138 // runs instead of characters. |
140 Vector<UBiDiLevel, 32> levels; | 139 Vector<UBiDiLevel, 32> levels; |
141 levels.ReserveInitialCapacity(line_items->size()); | 140 levels.ReserveInitialCapacity(line_items->size()); |
142 const Vector<NGInlineItem>& items = Node()->Items(); | 141 const Vector<NGInlineItem>& items = Node().Items(); |
143 for (const auto& item_result : *line_items) | 142 for (const auto& item_result : *line_items) |
144 levels.push_back(items[item_result.item_index].BidiLevel()); | 143 levels.push_back(items[item_result.item_index].BidiLevel()); |
145 Vector<int32_t, 32> indices_in_visual_order(line_items->size()); | 144 Vector<int32_t, 32> indices_in_visual_order(line_items->size()); |
146 NGBidiParagraph::IndicesInVisualOrder(levels, &indices_in_visual_order); | 145 NGBidiParagraph::IndicesInVisualOrder(levels, &indices_in_visual_order); |
147 | 146 |
148 // Reorder to the visual order. | 147 // Reorder to the visual order. |
149 NGInlineItemResults line_items_in_visual_order(line_items->size()); | 148 NGInlineItemResults line_items_in_visual_order(line_items->size()); |
150 for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size(); | 149 for (unsigned visual_index = 0; visual_index < indices_in_visual_order.size(); |
151 visual_index++) { | 150 visual_index++) { |
152 unsigned logical_index = indices_in_visual_order[visual_index]; | 151 unsigned logical_index = indices_in_visual_order[visual_index]; |
(...skipping 17 matching lines...) Expand all Loading... |
170 } | 169 } |
171 } | 170 } |
172 | 171 |
173 line_items->swap(line_items_in_visual_order); | 172 line_items->swap(line_items_in_visual_order); |
174 } | 173 } |
175 | 174 |
176 // TODO(glebl): Add the support of clearance for inline floats. | 175 // TODO(glebl): Add the support of clearance for inline floats. |
177 void NGInlineLayoutAlgorithm::LayoutAndPositionFloat( | 176 void NGInlineLayoutAlgorithm::LayoutAndPositionFloat( |
178 LayoutUnit end_position, | 177 LayoutUnit end_position, |
179 LayoutObject* layout_object) { | 178 LayoutObject* layout_object) { |
180 NGBlockNode* node = new NGBlockNode(layout_object); | 179 NGBlockNode node(ToLayoutBox(layout_object)); |
181 | 180 |
182 NGLogicalOffset origin_offset = | 181 NGLogicalOffset origin_offset = |
183 GetOriginPointForFloats(ContainerBfcOffset(), content_size_); | 182 GetOriginPointForFloats(ContainerBfcOffset(), content_size_); |
184 const ComputedStyle& float_style = node->Style(); | 183 const ComputedStyle& float_style = node.Style(); |
185 NGBoxStrut margins = ComputeMargins(ConstraintSpace(), float_style, | 184 NGBoxStrut margins = ComputeMargins(ConstraintSpace(), float_style, |
186 ConstraintSpace().WritingMode(), | 185 ConstraintSpace().WritingMode(), |
187 ConstraintSpace().Direction()); | 186 ConstraintSpace().Direction()); |
188 | 187 |
189 // TODO(ikilpatrick): Add support for float break tokens inside an inline | 188 // TODO(ikilpatrick): Add support for float break tokens inside an inline |
190 // layout context. | 189 // layout context. |
191 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( | 190 RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create( |
192 current_opportunity_.size, ConstraintSpace().PercentageResolutionSize(), | 191 current_opportunity_.size, ConstraintSpace().PercentageResolutionSize(), |
193 origin_offset, ContainerBfcOffset(), margins, node, | 192 origin_offset, ContainerBfcOffset(), margins, node, |
194 /* break_token */ nullptr); | 193 /* break_token */ nullptr); |
(...skipping 13 matching lines...) Expand all Loading... |
208 } else { | 207 } else { |
209 container_builder_.AddPositionedFloat( | 208 container_builder_.AddPositionedFloat( |
210 PositionFloat(unpositioned_float.Get(), MutableConstraintSpace())); | 209 PositionFloat(unpositioned_float.Get(), MutableConstraintSpace())); |
211 FindNextLayoutOpportunity(); | 210 FindNextLayoutOpportunity(); |
212 } | 211 } |
213 } | 212 } |
214 | 213 |
215 bool NGInlineLayoutAlgorithm::PlaceItems( | 214 bool NGInlineLayoutAlgorithm::PlaceItems( |
216 NGInlineItemResults* line_items, | 215 NGInlineItemResults* line_items, |
217 RefPtr<NGInlineBreakToken> break_token) { | 216 RefPtr<NGInlineBreakToken> break_token) { |
218 const Vector<NGInlineItem>& items = Node()->Items(); | 217 const Vector<NGInlineItem>& items = Node().Items(); |
219 | 218 |
220 const ComputedStyle& line_style = LineStyle(); | 219 const ComputedStyle& line_style = LineStyle(); |
221 NGLineHeightMetrics line_metrics(line_style, baseline_type_); | 220 NGLineHeightMetrics line_metrics(line_style, baseline_type_); |
222 NGLineHeightMetrics line_metrics_with_leading = line_metrics; | 221 NGLineHeightMetrics line_metrics_with_leading = line_metrics; |
223 line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed()); | 222 line_metrics_with_leading.AddLeading(line_style.ComputedLineHeightAsFixed()); |
224 NGLineBoxFragmentBuilder line_box(Node()); | 223 NGLineBoxFragmentBuilder line_box(Node()); |
225 line_box.SetWritingMode(ConstraintSpace().WritingMode()); | 224 line_box.SetWritingMode(ConstraintSpace().WritingMode()); |
226 | 225 |
227 // Compute heights of all inline items by placing the dominant baseline at 0. | 226 // Compute heights of all inline items by placing the dominant baseline at 0. |
228 // The baseline is adjusted after the height of the line box is computed. | 227 // The baseline is adjusted after the height of the line box is computed. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 } else if (item.Type() == NGInlineItem::kAtomicInline) { | 277 } else if (item.Type() == NGInlineItem::kAtomicInline) { |
279 box = PlaceAtomicInline(item, &item_result, position, &line_box, | 278 box = PlaceAtomicInline(item, &item_result, position, &line_box, |
280 &text_builder); | 279 &text_builder); |
281 } else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) { | 280 } else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) { |
282 // TODO(layout-dev): Report the correct static position for the out of | 281 // TODO(layout-dev): Report the correct static position for the out of |
283 // flow descendant. We can't do this here yet as it doesn't know the | 282 // flow descendant. We can't do this here yet as it doesn't know the |
284 // size of the line box. | 283 // size of the line box. |
285 container_builder_.AddOutOfFlowDescendant( | 284 container_builder_.AddOutOfFlowDescendant( |
286 // Absolute positioning blockifies the box's display type. | 285 // Absolute positioning blockifies the box's display type. |
287 // https://drafts.csswg.org/css-display/#transformations | 286 // https://drafts.csswg.org/css-display/#transformations |
288 new NGBlockNode(item.GetLayoutObject()), | 287 NGBlockNode(ToLayoutBox(item.GetLayoutObject())), |
289 NGStaticPosition::Create(ConstraintSpace().WritingMode(), | 288 NGStaticPosition::Create(ConstraintSpace().WritingMode(), |
290 ConstraintSpace().Direction(), | 289 ConstraintSpace().Direction(), |
291 NGPhysicalOffset())); | 290 NGPhysicalOffset())); |
292 continue; | 291 continue; |
293 } else { | 292 } else { |
294 continue; | 293 continue; |
295 } | 294 } |
296 | 295 |
297 position += item_result.inline_size; | 296 position += item_result.inline_size; |
298 } | 297 } |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 // Margin struts shouldn't need to be passed through like this once we've | 455 // Margin struts shouldn't need to be passed through like this once we've |
457 // removed LayoutInline splitting. | 456 // removed LayoutInline splitting. |
458 if (!container_builder_.BfcOffset()) { | 457 if (!container_builder_.BfcOffset()) { |
459 container_builder_.SetEndMarginStrut(ConstraintSpace().MarginStrut()); | 458 container_builder_.SetEndMarginStrut(ConstraintSpace().MarginStrut()); |
460 } | 459 } |
461 | 460 |
462 return container_builder_.ToBoxFragment(); | 461 return container_builder_.ToBoxFragment(); |
463 } | 462 } |
464 | 463 |
465 } // namespace blink | 464 } // namespace blink |
OLD | NEW |