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_block_layout_algorithm.h" | 5 #include "core/layout/ng/ng_block_layout_algorithm.h" |
| 6 | 6 |
| 7 #include "core/layout/ng/ng_absolute_utils.h" | 7 #include "core/layout/ng/ng_absolute_utils.h" |
| 8 #include "core/layout/ng/ng_block_break_token.h" | 8 #include "core/layout/ng/ng_block_break_token.h" |
| 9 #include "core/layout/ng/ng_box_fragment.h" | 9 #include "core/layout/ng/ng_box_fragment.h" |
| 10 #include "core/layout/ng/ng_column_mapper.h" | 10 #include "core/layout/ng/ng_column_mapper.h" |
| 11 #include "core/layout/ng/ng_constraint_space.h" | 11 #include "core/layout/ng/ng_constraint_space.h" |
| 12 #include "core/layout/ng/ng_constraint_space_builder.h" | 12 #include "core/layout/ng/ng_constraint_space_builder.h" |
| 13 #include "core/layout/ng/ng_fragment.h" | 13 #include "core/layout/ng/ng_fragment.h" |
| 14 #include "core/layout/ng/ng_fragment_builder.h" | 14 #include "core/layout/ng/ng_fragment_builder.h" |
| 15 #include "core/layout/ng/ng_layout_opportunity_iterator.h" | 15 #include "core/layout/ng/ng_layout_opportunity_iterator.h" |
| 16 #include "core/layout/ng/ng_length_utils.h" | 16 #include "core/layout/ng/ng_length_utils.h" |
| 17 #include "core/layout/ng/ng_out_of_flow_layout_part.h" | 17 #include "core/layout/ng/ng_out_of_flow_layout_part.h" |
| 18 #include "core/layout/ng/ng_units.h" | 18 #include "core/layout/ng/ng_units.h" |
| 19 #include "core/style/ComputedStyle.h" | 19 #include "core/style/ComputedStyle.h" |
| 20 #include "platform/LengthFunctions.h" | 20 #include "platform/LengthFunctions.h" |
| 21 #include "wtf/Optional.h" | 21 #include "wtf/Optional.h" |
| 22 | 22 |
| 23 namespace blink { | 23 namespace blink { |
| 24 namespace { | 24 namespace { |
| 25 | 25 |
| 26 // Adjusts content's offset to CSS "clear" property. | 26 // Adjusts content_size to CSS "clear" property. |
|
ikilpatrick
2017/01/30 22:26:48
Adjusts content_size to respect the CSS "clear" pr
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
| 27 // TODO(glebl): Support margin collapsing edge cases, e.g. margin collapsing | 27 // Picks up the maximum between left/right exclusions and content_size depending |
| 28 // should not occur if "clear" is applied to non-floating blocks. | 28 // on the value of style.clear() property. |
| 29 // TODO(layout-ng): the call to AdjustToClearance should be moved to | 29 void AdjustToClearance(const std::shared_ptr<NGExclusions>& exclusions, |
| 30 // CreateConstraintSpaceForChild once ConstraintSpaceBuilder is sharing the | |
| 31 // exclusion information between constraint spaces. | |
| 32 void AdjustToClearance(const NGConstraintSpace& space, | |
| 33 const ComputedStyle& style, | 30 const ComputedStyle& style, |
| 31 const NGLogicalOffset& from_offset, | |
| 34 LayoutUnit* content_size) { | 32 LayoutUnit* content_size) { |
| 35 const NGExclusion* right_exclusion = space.Exclusions()->last_right_float; | 33 DCHECK(content_size) << "content_size cannot be null here"; |
| 36 const NGExclusion* left_exclusion = space.Exclusions()->last_left_float; | 34 const NGExclusion* right_exclusion = exclusions->last_right_float; |
| 35 const NGExclusion* left_exclusion = exclusions->last_left_float; | |
| 37 | 36 |
| 38 // Calculates Left/Right block end offset from left/right float exclusions or | 37 // Exclusions(stored in BFC coordinates), content_size can be negative or 0 |
|
ikilpatrick
2017/01/30 22:26:48
space between "s("
ikilpatrick
2017/01/30 22:26:49
consider re-wording this line, not sure what it is
Gleb Lanbin
2017/01/31 00:25:02
I also found it's confusing. I tried to rephrase i
| |
| 39 // use the default content offset position. | 38 // If left or right exclusion are available then convert them to the relative |
| 40 LayoutUnit left_block_end_offset = | 39 // offset(exclusion.BlockEnd - from_offset) and compare them with content_size |
|
ikilpatrick
2017/01/30 22:26:48
.nit period.
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
| 41 left_exclusion ? left_exclusion->rect.BlockEndOffset() : *content_size; | 40 LayoutUnit left_block_end_offset = *content_size; |
| 42 LayoutUnit right_block_end_offset = | 41 if (left_exclusion) { |
| 43 right_exclusion ? right_exclusion->rect.BlockEndOffset() : *content_size; | 42 left_block_end_offset = std::max( |
| 43 left_exclusion->rect.BlockEndOffset() - from_offset.block_offset, | |
| 44 *content_size); | |
| 45 } | |
| 46 LayoutUnit right_block_end_offset = *content_size; | |
| 47 if (right_exclusion) { | |
| 48 right_block_end_offset = std::max( | |
| 49 right_exclusion->rect.BlockEndOffset() - from_offset.block_offset, | |
| 50 *content_size); | |
| 51 } | |
| 44 | 52 |
| 45 switch (style.clear()) { | 53 switch (style.clear()) { |
| 46 case EClear::ClearNone: | 54 case EClear::ClearNone: |
| 47 return; // nothing to do here. | 55 return; // nothing to do here. |
| 48 case EClear::ClearLeft: | 56 case EClear::ClearLeft: |
| 49 *content_size = left_block_end_offset; | 57 *content_size = left_block_end_offset; |
| 50 break; | 58 break; |
| 51 case EClear::ClearRight: | 59 case EClear::ClearRight: |
| 52 *content_size = right_block_end_offset; | 60 *content_size = right_block_end_offset; |
| 53 break; | 61 break; |
| 54 case EClear::ClearBoth: | 62 case EClear::ClearBoth: |
| 55 *content_size = std::max(left_block_end_offset, right_block_end_offset); | 63 *content_size = std::max(left_block_end_offset, right_block_end_offset); |
| 56 break; | 64 break; |
| 57 default: | 65 default: |
| 58 ASSERT_NOT_REACHED(); | 66 ASSERT_NOT_REACHED(); |
| 59 } | 67 } |
| 60 } | 68 } |
| 61 | 69 |
| 62 LayoutUnit ComputeCollapsedMarginBlockStart( | |
| 63 const NGDeprecatedMarginStrut& prev_margin_strut, | |
| 64 const NGDeprecatedMarginStrut& curr_margin_strut) { | |
| 65 return std::max(prev_margin_strut.margin_block_end, | |
| 66 curr_margin_strut.margin_block_start) - | |
| 67 std::max(prev_margin_strut.negative_margin_block_end.abs(), | |
| 68 curr_margin_strut.negative_margin_block_start.abs()); | |
| 69 } | |
| 70 | |
| 71 // Creates an exclusion from the fragment that will be placed in the provided | 70 // Creates an exclusion from the fragment that will be placed in the provided |
| 72 // layout opportunity. | 71 // layout opportunity. |
| 73 NGExclusion CreateExclusion(const NGFragment& fragment, | 72 NGExclusion CreateExclusion(const NGFragment& fragment, |
| 74 const NGLayoutOpportunity& opportunity, | 73 const NGLayoutOpportunity& opportunity, |
| 75 LayoutUnit float_offset, | 74 const LayoutUnit float_offset, |
| 76 NGBoxStrut margins, | 75 const NGBoxStrut& margins, |
| 77 NGExclusion::Type exclusion_type) { | 76 NGExclusion::Type exclusion_type) { |
| 78 NGExclusion exclusion; | 77 NGExclusion exclusion; |
| 79 exclusion.type = exclusion_type; | 78 exclusion.type = exclusion_type; |
| 80 NGLogicalRect& rect = exclusion.rect; | 79 NGLogicalRect& rect = exclusion.rect; |
| 81 rect.offset = opportunity.offset; | 80 rect.offset = opportunity.offset; |
| 82 rect.offset.inline_offset += float_offset; | 81 rect.offset.inline_offset += float_offset; |
| 83 | 82 |
| 84 rect.size.inline_size = fragment.InlineSize(); | 83 rect.size.inline_size = fragment.InlineSize() + margins.InlineSum(); |
| 85 rect.size.block_size = fragment.BlockSize(); | 84 rect.size.block_size = fragment.BlockSize() + margins.BlockSum(); |
| 85 return exclusion; | |
| 86 } | |
| 86 | 87 |
| 87 // Adjust to child's margin. | 88 // Adjusts the provided offset to the top edge alignment rule. |
| 88 rect.size.block_size += margins.BlockSum(); | 89 // Top edge alignment rule: the outer top of a floating box may not be higher |
| 89 rect.size.inline_size += margins.InlineSum(); | 90 // than the outer top of any block or floated box generated by an element |
| 90 | 91 // earlier in the source document |
|
ikilpatrick
2017/01/30 22:26:48
.nit period
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
| 91 return exclusion; | 92 NGLogicalOffset AdjustToTopEdgeAlignmentRule(const NGConstraintSpace& space, |
| 93 const NGLogicalOffset& offset) { | |
| 94 NGLogicalOffset adjusted_offset = offset; | |
| 95 LayoutUnit& adjusted_block_offset = adjusted_offset.block_offset; | |
| 96 if (space.Exclusions()->last_left_float) | |
| 97 adjusted_block_offset = | |
| 98 std::max(adjusted_block_offset, | |
| 99 space.Exclusions()->last_left_float->rect.BlockStartOffset()); | |
| 100 if (space.Exclusions()->last_right_float) | |
| 101 adjusted_block_offset = | |
| 102 std::max(adjusted_block_offset, | |
| 103 space.Exclusions()->last_right_float->rect.BlockStartOffset()); | |
| 104 return adjusted_offset; | |
| 92 } | 105 } |
| 93 | 106 |
| 94 // Finds a layout opportunity for the fragment. | 107 // Finds a layout opportunity for the fragment. |
| 95 // It iterates over all layout opportunities in the constraint space and returns | 108 // It iterates over all layout opportunities in the constraint space and returns |
| 96 // the first layout opportunity that is wider than the fragment or returns the | 109 // the first layout opportunity that is wider than the fragment or returns the |
| 97 // last one which is always the widest. | 110 // last one which is always the widest. |
| 98 // | 111 // |
| 99 // @param space Constraint space that is used to find layout opportunity for | 112 // @param space Constraint space that is used to find layout opportunity for |
| 100 // the fragment. | 113 // the fragment. |
| 101 // @param fragment Fragment that needs to be placed. | 114 // @param fragment Fragment that needs to be placed. |
| 115 // @param origin_point {@code space}'s offset relative to the space that | |
| 116 // establishes a new formatting context that we're currently | |
| 117 // in and where all our exclusions reside. | |
| 102 // @param margins Margins of the fragment. | 118 // @param margins Margins of the fragment. |
| 103 // @return Layout opportunity for the fragment. | 119 // @return Layout opportunity for the fragment. |
| 104 const NGLayoutOpportunity FindLayoutOpportunityForFragment( | 120 const NGLayoutOpportunity FindLayoutOpportunityForFragment( |
| 105 NGConstraintSpace* space, | 121 NGConstraintSpace* space, |
| 106 const NGFragment& fragment, | 122 const NGFragment& fragment, |
| 123 const NGLogicalOffset& origin_point, | |
| 107 const NGBoxStrut& margins) { | 124 const NGBoxStrut& margins) { |
| 108 NGLayoutOpportunityIterator* opportunity_iter = space->LayoutOpportunities(); | 125 NGLogicalOffset adjusted_origin_point = |
| 126 AdjustToTopEdgeAlignmentRule(*space, origin_point); | |
| 127 | |
| 128 NGLayoutOpportunityIterator* opportunity_iter = | |
| 129 space->LayoutOpportunities(adjusted_origin_point); | |
| 109 NGLayoutOpportunity opportunity; | 130 NGLayoutOpportunity opportunity; |
| 110 NGLayoutOpportunity opportunity_candidate = opportunity_iter->Next(); | 131 NGLayoutOpportunity opportunity_candidate = opportunity_iter->Next(); |
| 111 | 132 |
| 112 while (!opportunity_candidate.IsEmpty()) { | 133 while (!opportunity_candidate.IsEmpty()) { |
| 113 opportunity = opportunity_candidate; | 134 opportunity = opportunity_candidate; |
| 114 // Checking opportunity's block size is not necessary as a float cannot be | 135 // Checking opportunity's block size is not necessary as a float cannot be |
| 115 // positioned on top of another float inside of the same constraint space. | 136 // positioned on top of another float inside of the same constraint space. |
| 116 auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); | 137 auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); |
| 117 if (opportunity.size.inline_size > fragment_inline_size) | 138 if (opportunity.size.inline_size >= fragment_inline_size) |
| 118 break; | 139 break; |
| 119 | |
| 120 opportunity_candidate = opportunity_iter->Next(); | 140 opportunity_candidate = opportunity_iter->Next(); |
| 121 } | 141 } |
| 122 | |
| 123 return opportunity; | 142 return opportunity; |
| 124 } | 143 } |
| 125 | 144 |
| 126 // Calculates the logical offset for opportunity. | 145 // Calculates the logical offset for opportunity. |
| 127 NGLogicalOffset CalculateLogicalOffsetForOpportunity( | 146 NGLogicalOffset CalculateLogicalOffsetForOpportunity( |
| 128 const NGLayoutOpportunity& opportunity, | 147 const NGLayoutOpportunity& opportunity, |
| 129 LayoutUnit float_offset, | 148 const LayoutUnit float_offset, |
| 130 NGBoxStrut margins) { | 149 const NGBoxStrut& margins, |
| 150 const NGLogicalOffset& space_offset) { | |
| 131 // Adjust to child's margin. | 151 // Adjust to child's margin. |
| 132 LayoutUnit inline_offset = margins.inline_start; | 152 LayoutUnit inline_offset = margins.inline_start; |
| 133 LayoutUnit block_offset = margins.block_start; | 153 LayoutUnit block_offset = margins.block_start; |
| 134 | 154 |
| 135 // Offset from the opportunity's block/inline start. | 155 // Offset from the opportunity's block/inline start. |
| 136 inline_offset += opportunity.offset.inline_offset; | 156 inline_offset += opportunity.offset.inline_offset; |
| 137 block_offset += opportunity.offset.block_offset; | 157 block_offset += opportunity.offset.block_offset; |
| 138 | 158 |
| 139 inline_offset += float_offset; | 159 inline_offset += float_offset; |
| 140 | 160 |
| 161 block_offset -= space_offset.block_offset; | |
| 162 inline_offset -= space_offset.inline_offset; | |
| 163 | |
| 141 return NGLogicalOffset(inline_offset, block_offset); | 164 return NGLogicalOffset(inline_offset, block_offset); |
| 142 } | 165 } |
| 143 | 166 |
| 167 // Calculates the relative position from {@code from_offset} of the | |
| 168 // floating object that is requested to be positioned from {@code origin_point}. | |
| 169 NGLogicalOffset PositionFloat(const NGLogicalOffset& origin_point, | |
| 170 const NGLogicalOffset& from_offset, | |
| 171 NGFloatingObject* floating_object) { | |
| 172 NGConstraintSpace* float_space = floating_object->space; | |
| 173 DCHECK(floating_object->fragment) << "Fragment cannot be null here"; | |
| 174 NGBoxFragment* float_fragment = | |
| 175 new NGBoxFragment(float_space->WritingMode(), float_space->Direction(), | |
| 176 toNGPhysicalBoxFragment(floating_object->fragment)); | |
| 177 // Find a layout opportunity that will fit our float. | |
| 178 const NGLayoutOpportunity opportunity = | |
| 179 FindLayoutOpportunityForFragment(floating_object->space, *float_fragment, | |
| 180 origin_point, floating_object->margins); | |
| 181 DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; | |
| 182 | |
| 183 // Calculate the float offset if needed. | |
| 184 LayoutUnit float_offset; | |
| 185 if (floating_object->exclusion_type == NGExclusion::kFloatRight) { | |
| 186 float_offset = opportunity.size.inline_size - float_fragment->InlineSize(); | |
| 187 } | |
| 188 | |
| 189 // Add the float as an exclusion. | |
| 190 const NGExclusion exclusion = CreateExclusion( | |
| 191 *float_fragment, opportunity, float_offset, floating_object->margins, | |
| 192 floating_object->exclusion_type); | |
| 193 float_space->AddExclusion(exclusion); | |
| 194 | |
| 195 return CalculateLogicalOffsetForOpportunity( | |
| 196 opportunity, float_offset, floating_object->margins, from_offset); | |
| 197 } | |
| 198 | |
| 199 // Positions pending floats stored on the fragment builder starting from | |
| 200 // {@code origin_point}. | |
| 201 void PositionPendingFloats(const NGLogicalOffset& origin_point, | |
| 202 NGFragmentBuilder* builder) { | |
| 203 DCHECK(builder->BfcOffset()) << "Parent BFC offset should be known here"; | |
| 204 NGLogicalOffset from_offset = builder->BfcOffset().value(); | |
| 205 | |
| 206 for (auto& floating_object : builder->UnpositionedFloats()) { | |
| 207 NGLogicalOffset float_fragment_offset = | |
| 208 PositionFloat(origin_point, from_offset, floating_object); | |
| 209 builder->AddFloatingObject(floating_object, float_fragment_offset); | |
| 210 } | |
| 211 builder->MutableUnpositionedFloats().clear(); | |
| 212 } | |
| 213 | |
| 144 // Whether an in-flow block-level child creates a new formatting context. | 214 // Whether an in-flow block-level child creates a new formatting context. |
| 145 // | 215 // |
| 146 // This will *NOT* check the following cases: | 216 // This will *NOT* check the following cases: |
| 147 // - The child is out-of-flow, e.g. floating or abs-pos. | 217 // - The child is out-of-flow, e.g. floating or abs-pos. |
| 148 // - The child is a inline-level, e.g. "display: inline-block". | 218 // - The child is a inline-level, e.g. "display: inline-block". |
| 149 // - The child establishes a new formatting context, but should be a child of | 219 // - The child establishes a new formatting context, but should be a child of |
| 150 // another layout algorithm, e.g. "display: table-caption" or flex-item. | 220 // another layout algorithm, e.g. "display: table-caption" or flex-item. |
| 151 bool IsNewFormattingContextForInFlowBlockLevelChild( | 221 bool IsNewFormattingContextForInFlowBlockLevelChild( |
| 152 const NGConstraintSpace& space, | 222 const NGConstraintSpace& space, |
| 153 const ComputedStyle& style) { | 223 const ComputedStyle& style) { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 183 PassRefPtr<const ComputedStyle> style, | 253 PassRefPtr<const ComputedStyle> style, |
| 184 NGBlockNode* first_child, | 254 NGBlockNode* first_child, |
| 185 NGConstraintSpace* constraint_space, | 255 NGConstraintSpace* constraint_space, |
| 186 NGBreakToken* break_token) | 256 NGBreakToken* break_token) |
| 187 : NGLayoutAlgorithm(kBlockLayoutAlgorithm), | 257 : NGLayoutAlgorithm(kBlockLayoutAlgorithm), |
| 188 style_(style), | 258 style_(style), |
| 189 first_child_(first_child), | 259 first_child_(first_child), |
| 190 constraint_space_(constraint_space), | 260 constraint_space_(constraint_space), |
| 191 break_token_(break_token), | 261 break_token_(break_token), |
| 192 builder_(new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, | 262 builder_(new NGFragmentBuilder(NGPhysicalFragment::kFragmentBox, |
| 193 layout_object)), | 263 layout_object)) { |
| 194 is_fragment_margin_strut_block_start_updated_(false) { | |
| 195 DCHECK(style_); | 264 DCHECK(style_); |
| 196 } | 265 } |
| 197 | 266 |
| 198 bool NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes( | 267 bool NGBlockLayoutAlgorithm::ComputeMinAndMaxContentSizes( |
| 199 MinAndMaxContentSizes* sizes) const { | 268 MinAndMaxContentSizes* sizes) const { |
| 200 sizes->min_content = LayoutUnit(); | 269 sizes->min_content = LayoutUnit(); |
| 201 sizes->max_content = LayoutUnit(); | 270 sizes->max_content = LayoutUnit(); |
| 202 | 271 |
| 203 // Size-contained elements don't consider their contents for intrinsic sizing. | 272 // Size-contained elements don't consider their contents for intrinsic sizing. |
| 204 if (Style().containsSize()) | 273 if (Style().containsSize()) |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 215 ComputeMinAndMaxContentContribution(*node->Style(), child_minmax); | 284 ComputeMinAndMaxContentContribution(*node->Style(), child_minmax); |
| 216 | 285 |
| 217 sizes->min_content = std::max(sizes->min_content, child_sizes.min_content); | 286 sizes->min_content = std::max(sizes->min_content, child_sizes.min_content); |
| 218 sizes->max_content = std::max(sizes->max_content, child_sizes.max_content); | 287 sizes->max_content = std::max(sizes->max_content, child_sizes.max_content); |
| 219 } | 288 } |
| 220 | 289 |
| 221 sizes->max_content = std::max(sizes->min_content, sizes->max_content); | 290 sizes->max_content = std::max(sizes->min_content, sizes->max_content); |
| 222 return true; | 291 return true; |
| 223 } | 292 } |
| 224 | 293 |
| 294 NGLogicalOffset NGBlockLayoutAlgorithm::PositionFragmentWithKnownBfcOffset( | |
|
ikilpatrick
2017/01/30 22:26:48
It might be worth just placing this function inlin
Gleb Lanbin
2017/01/31 00:25:02
PTAL
| |
| 295 const NGLogicalOffset& offset) { | |
| 296 curr_bfc_offset_.block_offset = offset.block_offset; | |
| 297 // First block that knows its position. Update the parent's BFC offset. | |
| 298 if (!builder_->BfcOffset()) { | |
| 299 NGLogicalOffset parent_bfc_offset = | |
| 300 ConstraintSpace().IsNewFormattingContext() ? NGLogicalOffset() | |
| 301 : curr_bfc_offset_; | |
| 302 builder_->SetBfcOffset(parent_bfc_offset); | |
| 303 } | |
| 304 | |
| 305 // OK to position pending floats. curr_bfc_offset_ and parent's BFC offset | |
| 306 // are accurate here. | |
| 307 PositionPendingFloats(curr_bfc_offset_, builder_); | |
| 308 | |
| 309 LayoutUnit block_offset = | |
| 310 offset.block_offset - builder_->BfcOffset().value().block_offset; | |
| 311 LayoutUnit inline_offset = | |
| 312 border_and_padding_.inline_start + curr_child_margins_.inline_start; | |
| 313 return {inline_offset, block_offset}; | |
| 314 } | |
| 315 | |
| 225 NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { | 316 NGPhysicalFragment* NGBlockLayoutAlgorithm::Layout() { |
| 226 WTF::Optional<MinAndMaxContentSizes> sizes; | 317 WTF::Optional<MinAndMaxContentSizes> sizes; |
| 227 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) { | 318 if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style())) { |
| 228 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return | 319 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return |
| 229 // MinAndMaxContentSizes. | 320 // MinAndMaxContentSizes. |
| 230 sizes = MinAndMaxContentSizes(); | 321 sizes = MinAndMaxContentSizes(); |
| 231 ComputeMinAndMaxContentSizes(&*sizes); | 322 ComputeMinAndMaxContentSizes(&*sizes); |
| 232 } | 323 } |
| 233 | 324 |
| 234 border_and_padding_ = | 325 border_and_padding_ = |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 261 } | 352 } |
| 262 space_builder_->SetAvailableSize( | 353 space_builder_->SetAvailableSize( |
| 263 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); | 354 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
| 264 space_builder_->SetPercentageResolutionSize( | 355 space_builder_->SetPercentageResolutionSize( |
| 265 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); | 356 NGLogicalSize(adjusted_inline_size, adjusted_block_size)); |
| 266 | 357 |
| 267 builder_->SetDirection(constraint_space_->Direction()); | 358 builder_->SetDirection(constraint_space_->Direction()); |
| 268 builder_->SetWritingMode(constraint_space_->WritingMode()); | 359 builder_->SetWritingMode(constraint_space_->WritingMode()); |
| 269 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); | 360 builder_->SetInlineSize(inline_size).SetBlockSize(block_size); |
| 270 | 361 |
| 362 // TODO(glebl): fix multicol after the new margin collapsing/floats algorithm | |
| 363 // based on BFCOffset is checked in. | |
| 271 if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { | 364 if (NGBlockBreakToken* token = CurrentBlockBreakToken()) { |
| 272 // Resume after a previous break. | 365 // Resume after a previous break. |
| 273 content_size_ = token->BreakOffset(); | 366 content_size_ = token->BreakOffset(); |
| 274 current_child_ = token->InputNode(); | 367 current_child_ = token->InputNode(); |
| 275 } else { | 368 } else { |
| 276 content_size_ = border_and_padding_.block_start; | 369 content_size_ = border_and_padding_.block_start; |
| 277 current_child_ = first_child_; | 370 current_child_ = first_child_; |
| 278 } | 371 } |
| 279 | 372 |
| 373 curr_margin_strut_ = ConstraintSpace().MarginStrut(); | |
| 374 curr_bfc_offset_ = ConstraintSpace().BfcOffset(); | |
| 375 | |
| 376 // Margins collapsing: | |
| 377 // Do not collapse margins between parent and its child if there is | |
| 378 // border/padding between them. | |
| 379 if (border_and_padding_.block_start) { | |
| 380 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | |
| 381 builder_->SetBfcOffset(curr_bfc_offset_); | |
| 382 curr_margin_strut_ = NGMarginStrut(); | |
| 383 } | |
| 384 curr_bfc_offset_.block_offset += content_size_; | |
| 385 | |
| 280 while (current_child_) { | 386 while (current_child_) { |
| 281 EPosition position = current_child_->Style()->position(); | 387 EPosition position = current_child_->Style()->position(); |
| 282 if (position == AbsolutePosition || position == FixedPosition) { | 388 if (position == AbsolutePosition || position == FixedPosition) { |
| 283 builder_->AddOutOfFlowChildCandidate(current_child_, | 389 builder_->AddOutOfFlowChildCandidate(current_child_, |
| 284 GetChildSpaceOffset()); | 390 GetChildSpaceOffset()); |
| 285 current_child_ = current_child_->NextSibling(); | 391 current_child_ = current_child_->NextSibling(); |
| 286 continue; | 392 continue; |
| 287 } | 393 } |
| 288 | 394 |
| 289 DCHECK(!ConstraintSpace().HasBlockFragmentation() || | 395 DCHECK(!ConstraintSpace().HasBlockFragmentation() || |
| 290 SpaceAvailableForCurrentChild() > LayoutUnit()); | 396 SpaceAvailableForCurrentChild() > LayoutUnit()); |
| 291 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); | 397 space_for_current_child_ = CreateConstraintSpaceForCurrentChild(); |
| 292 | 398 |
| 293 NGPhysicalFragment* child_fragment = | 399 NGPhysicalFragment* child_fragment = |
| 294 current_child_->Layout(space_for_current_child_); | 400 current_child_->Layout(space_for_current_child_); |
| 295 | 401 |
| 296 FinishCurrentChildLayout(new NGBoxFragment( | 402 FinishCurrentChildLayout(new NGBoxFragment( |
| 297 ConstraintSpace().WritingMode(), ConstraintSpace().Direction(), | 403 ConstraintSpace().WritingMode(), ConstraintSpace().Direction(), |
| 298 toNGPhysicalBoxFragment(child_fragment))); | 404 toNGPhysicalBoxFragment(child_fragment))); |
| 299 | 405 |
| 300 if (!ProceedToNextUnfinishedSibling(child_fragment)) | 406 if (!ProceedToNextUnfinishedSibling(child_fragment)) |
| 301 break; | 407 break; |
| 302 } | 408 } |
| 303 | 409 |
| 410 // Margins collapsing: | |
| 411 // Bottom margins of an in-flow block box doesn't collapse with its last | |
| 412 // in-flow block-level child's bottom margin if the box has bottom | |
| 413 // border/padding. | |
| 304 content_size_ += border_and_padding_.block_end; | 414 content_size_ += border_and_padding_.block_end; |
| 415 if (border_and_padding_.block_end || | |
| 416 ConstraintSpace().IsNewFormattingContext()) { | |
| 417 content_size_ += curr_margin_strut_.Sum(); | |
|
ikilpatrick
2017/01/30 22:26:48
is there a test case for this?
Gleb Lanbin
2017/01/31 00:25:02
I believe it's covered in CollapsingMarginsCase4
/
| |
| 418 curr_margin_strut_ = NGMarginStrut(); | |
| 419 } | |
| 305 | 420 |
| 306 // Recompute the block-axis size now that we know our content size. | 421 // Recompute the block-axis size now that we know our content size. |
| 307 block_size = | 422 block_size = |
| 308 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); | 423 ComputeBlockSizeForFragment(ConstraintSpace(), Style(), content_size_); |
| 309 builder_->SetBlockSize(block_size); | 424 builder_->SetBlockSize(block_size); |
| 310 | 425 |
| 311 LayoutOutOfFlowChildren(); | 426 LayoutOutOfFlowChildren(); |
|
ikilpatrick
2017/01/30 22:26:48
you may need to rebase :)
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
| 312 | 427 |
| 428 // Set out BFC offset if the size is not empty. | |
| 429 if (block_size && !builder_->BfcOffset()) { | |
| 430 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | |
| 431 builder_->SetBfcOffset(curr_bfc_offset_); | |
| 432 } | |
| 433 | |
| 434 // Margins collapsing: | |
| 435 // Do not collapse margins between the last in-flow child and bottom margin | |
| 436 // of its parent if the parent has height != auto() | |
| 437 if (!Style().logicalHeight().isAuto()) { | |
| 438 // TODO(glebl): handle minLogicalHeight, maxLogicalHeight. | |
| 439 curr_margin_strut_ = NGMarginStrut(); | |
| 440 } | |
| 441 builder_->SetEndMarginStrut(curr_margin_strut_); | |
| 442 | |
| 313 builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); | 443 builder_->SetInlineOverflow(max_inline_size_).SetBlockOverflow(content_size_); |
| 314 | 444 |
| 315 if (ConstraintSpace().HasBlockFragmentation()) | 445 if (ConstraintSpace().HasBlockFragmentation()) |
| 316 FinalizeForFragmentation(); | 446 FinalizeForFragmentation(); |
| 317 | 447 |
| 318 NGPhysicalFragment* fragment = builder_->ToBoxFragment(); | 448 NGPhysicalFragment* fragment = builder_->ToBoxFragment(); |
| 319 | 449 |
| 320 return fragment; | 450 return fragment; |
| 321 } | 451 } |
| 322 | 452 |
| 323 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout(NGFragment* fragment) { | 453 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout( |
| 324 NGBoxStrut child_margins = ComputeMargins( | 454 NGFragment* base_fragment) { |
| 325 *space_for_current_child_, CurrentChildStyle(), | 455 const NGBoxFragment& fragment = *toNGBoxFragment(base_fragment); |
| 326 constraint_space_->WritingMode(), constraint_space_->Direction()); | 456 // Pull out unpositioned floats to the current fragment. This may needed if |
| 327 NGLogicalOffset fragment_offset; | 457 // for example the child fragment could not position its floats because it's |
| 458 // empty and therefore couldn't determine its position in space. | |
| 459 builder_->MutableUnpositionedFloats().appendVector( | |
| 460 fragment.PhysicalFragment()->UnpositionedFloats()); | |
|
ikilpatrick
2017/01/30 22:26:49
is it worth adding a DCHECK if there are unpositio
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
| 461 | |
| 328 if (CurrentChildStyle().isFloating()) { | 462 if (CurrentChildStyle().isFloating()) { |
| 329 fragment_offset = PositionFloatFragment(*fragment, child_margins); | 463 NGFloatingObject* floating_object = new NGFloatingObject( |
| 330 } else { | 464 fragment.PhysicalFragment(), space_for_current_child_, current_child_, |
| 331 ApplyAutoMargins(*space_for_current_child_, CurrentChildStyle(), | 465 CurrentChildStyle(), curr_child_margins_); |
| 332 fragment->InlineSize(), &child_margins); | 466 builder_->AddUnpositionedFloat(floating_object); |
| 333 fragment_offset = PositionFragment(*fragment, child_margins); | 467 // No need to postpone the positioning as we know the correct offset. |
|
ikilpatrick
2017/01/30 22:26:48
// No need to postpone the positioning if we know
Gleb Lanbin
2017/01/31 00:25:02
Done.
| |
| 468 if (builder_->BfcOffset()) { | |
| 469 NGLogicalOffset origin_point = curr_bfc_offset_; | |
| 470 // Adjust origin point to the margins of the last child. | |
| 471 // Example: <div style="margin-bottom: 20px"><float></div> | |
| 472 // <div style="margin-bottom: 30px"></div> | |
| 473 origin_point.block_offset += curr_margin_strut_.Sum(); | |
| 474 PositionPendingFloats(origin_point, builder_); | |
| 475 } | |
| 476 return; | |
| 334 } | 477 } |
| 478 | |
| 479 // Collapse empty block's margins. | |
| 480 if (!fragment.BlockSize()) { | |
|
ikilpatrick
2017/01/30 22:26:48
You can remove this? This happens below:
498 /
Gleb Lanbin
2017/01/31 00:25:02
thanks.
| |
| 481 curr_margin_strut_.Append(curr_child_margins_.block_end); | |
| 482 } | |
| 483 | |
| 484 NGLogicalOffset fragment_offset = { | |
| 485 border_and_padding_.inline_start + curr_child_margins_.inline_start, | |
| 486 content_size_}; | |
| 487 if (fragment.BfcOffset()) | |
| 488 fragment_offset = | |
| 489 PositionFragmentWithKnownBfcOffset(fragment.BfcOffset().value()); | |
| 490 | |
| 335 if (fragmentainer_mapper_) | 491 if (fragmentainer_mapper_) |
| 336 fragmentainer_mapper_->ToVisualOffset(fragment_offset); | 492 fragmentainer_mapper_->ToVisualOffset(fragment_offset); |
| 337 else | 493 else |
| 338 fragment_offset.block_offset -= PreviousBreakOffset(); | 494 fragment_offset.block_offset -= PreviousBreakOffset(); |
| 339 builder_->AddChild(fragment, fragment_offset); | 495 |
| 496 builder_->AddChild(base_fragment, fragment_offset); | |
| 497 | |
| 498 // Update margin strut. | |
| 499 curr_margin_strut_ = fragment.EndMarginStrut(); | |
| 500 curr_margin_strut_.Append(curr_child_margins_.block_end); | |
| 501 | |
| 502 content_size_ = fragment.BlockSize() + fragment_offset.block_offset; | |
| 503 max_inline_size_ = | |
| 504 std::max(max_inline_size_, fragment.InlineSize() + | |
| 505 curr_child_margins_.InlineSum() + | |
| 506 border_and_padding_.InlineSum()); | |
| 340 } | 507 } |
| 341 | 508 |
| 342 void NGBlockLayoutAlgorithm::LayoutOutOfFlowChildren() { | 509 void NGBlockLayoutAlgorithm::LayoutOutOfFlowChildren() { |
| 343 HeapLinkedHashSet<WeakMember<NGBlockNode>> out_of_flow_candidates; | 510 HeapLinkedHashSet<WeakMember<NGBlockNode>> out_of_flow_candidates; |
| 344 Vector<NGStaticPosition> out_of_flow_candidate_positions; | 511 Vector<NGStaticPosition> out_of_flow_candidate_positions; |
| 345 builder_->GetAndClearOutOfFlowDescendantCandidates( | 512 builder_->GetAndClearOutOfFlowDescendantCandidates( |
| 346 &out_of_flow_candidates, &out_of_flow_candidate_positions); | 513 &out_of_flow_candidates, &out_of_flow_candidate_positions); |
| 347 | 514 |
| 348 Member<NGOutOfFlowLayoutPart> out_of_flow_layout = | 515 Member<NGOutOfFlowLayoutPart> out_of_flow_layout = |
| 349 new NGOutOfFlowLayoutPart(&Style(), builder_->Size()); | 516 new NGOutOfFlowLayoutPart(&Style(), builder_->Size()); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 498 if (fragmentainer_mapper_) | 665 if (fragmentainer_mapper_) |
| 499 space_left = fragmentainer_mapper_->BlockSize(); | 666 space_left = fragmentainer_mapper_->BlockSize(); |
| 500 else if (ConstraintSpace().HasBlockFragmentation()) | 667 else if (ConstraintSpace().HasBlockFragmentation()) |
| 501 space_left = ConstraintSpace().FragmentainerSpaceAvailable(); | 668 space_left = ConstraintSpace().FragmentainerSpaceAvailable(); |
| 502 else | 669 else |
| 503 return NGSizeIndefinite; | 670 return NGSizeIndefinite; |
| 504 space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset(); | 671 space_left -= BorderEdgeForCurrentChild() - PreviousBreakOffset(); |
| 505 return space_left; | 672 return space_left; |
| 506 } | 673 } |
| 507 | 674 |
| 508 NGBoxStrut NGBlockLayoutAlgorithm::CollapseMargins( | |
| 509 const NGBoxStrut& margins, | |
| 510 const NGBoxFragment& fragment) { | |
| 511 bool is_zero_height_box = !fragment.BlockSize() && margins.IsEmpty() && | |
| 512 fragment.MarginStrut().IsEmpty(); | |
| 513 // Create the current child's margin strut from its children's margin strut or | |
| 514 // use margin strut from the the last non-empty child. | |
| 515 NGDeprecatedMarginStrut curr_margin_strut = | |
| 516 is_zero_height_box ? prev_child_margin_strut_ : fragment.MarginStrut(); | |
| 517 | |
| 518 // Calculate borders and padding for the current child. | |
| 519 NGBoxStrut border_and_padding = | |
| 520 ComputeBorders(CurrentChildStyle()) + | |
| 521 ComputePadding(ConstraintSpace(), CurrentChildStyle()); | |
| 522 | |
| 523 // Collapse BLOCK-START margins if there is no padding or border between | |
| 524 // parent (current child) and its first in-flow child. | |
| 525 if (border_and_padding.block_start) { | |
| 526 curr_margin_strut.SetMarginBlockStart(margins.block_start); | |
| 527 } else { | |
| 528 curr_margin_strut.AppendMarginBlockStart(margins.block_start); | |
| 529 } | |
| 530 | |
| 531 // Collapse BLOCK-END margins if | |
| 532 // 1) there is no padding or border between parent (current child) and its | |
| 533 // first/last in-flow child | |
| 534 // 2) parent's logical height is auto. | |
| 535 if (CurrentChildStyle().logicalHeight().isAuto() && | |
| 536 !border_and_padding.block_end) { | |
| 537 curr_margin_strut.AppendMarginBlockEnd(margins.block_end); | |
| 538 } else { | |
| 539 curr_margin_strut.SetMarginBlockEnd(margins.block_end); | |
| 540 } | |
| 541 | |
| 542 NGBoxStrut result_margins; | |
| 543 // Margins of the newly established formatting context do not participate | |
| 544 // in Collapsing Margins: | |
| 545 // - Compute margins block start for adjoining blocks *including* 1st block. | |
| 546 // - Compute margins block end for the last block. | |
| 547 // - Do not set the computed margins to the parent fragment. | |
| 548 if (constraint_space_->IsNewFormattingContext()) { | |
| 549 result_margins.block_start = ComputeCollapsedMarginBlockStart( | |
| 550 prev_child_margin_strut_, curr_margin_strut); | |
| 551 bool is_last_child = !current_child_->NextSibling(); | |
| 552 if (is_last_child) | |
| 553 result_margins.block_end = curr_margin_strut.BlockEndSum(); | |
| 554 return result_margins; | |
| 555 } | |
| 556 | |
| 557 // Zero-height boxes are ignored and do not participate in margin collapsing. | |
| 558 if (is_zero_height_box) | |
| 559 return result_margins; | |
| 560 | |
| 561 // Compute the margin block start for adjoining blocks *excluding* 1st block | |
| 562 if (is_fragment_margin_strut_block_start_updated_) { | |
| 563 result_margins.block_start = ComputeCollapsedMarginBlockStart( | |
| 564 prev_child_margin_strut_, curr_margin_strut); | |
| 565 } | |
| 566 | |
| 567 // Update the parent fragment's margin strut | |
| 568 UpdateMarginStrut(curr_margin_strut); | |
| 569 | |
| 570 prev_child_margin_strut_ = curr_margin_strut; | |
| 571 return result_margins; | |
| 572 } | |
| 573 | |
| 574 NGLogicalOffset NGBlockLayoutAlgorithm::PositionFragment( | |
| 575 const NGFragment& fragment, | |
| 576 const NGBoxStrut& margins) { | |
| 577 const NGBoxStrut collapsed_margins = | |
| 578 CollapseMargins(margins, toNGBoxFragment(fragment)); | |
| 579 | |
| 580 AdjustToClearance(ConstraintSpace(), CurrentChildStyle(), &content_size_); | |
| 581 | |
| 582 LayoutUnit inline_offset = | |
| 583 border_and_padding_.inline_start + margins.inline_start; | |
| 584 LayoutUnit block_offset = content_size_ + collapsed_margins.block_start; | |
| 585 | |
| 586 content_size_ += fragment.BlockSize() + collapsed_margins.BlockSum(); | |
| 587 max_inline_size_ = | |
| 588 std::max(max_inline_size_, fragment.InlineSize() + margins.InlineSum() + | |
| 589 border_and_padding_.InlineSum()); | |
| 590 return NGLogicalOffset(inline_offset, block_offset); | |
| 591 } | |
| 592 | |
| 593 NGLogicalOffset NGBlockLayoutAlgorithm::PositionFloatFragment( | |
| 594 const NGFragment& fragment, | |
| 595 const NGBoxStrut& margins) { | |
| 596 // TODO(glebl@chromium.org): Support the top edge alignment rule. | |
| 597 // Find a layout opportunity that will fit our float. | |
| 598 | |
| 599 // Update offset if there is a clearance. | |
| 600 NGLogicalOffset offset = CurrentChildConstraintSpace().Offset(); | |
| 601 AdjustToClearance(ConstraintSpace(), CurrentChildStyle(), | |
| 602 &offset.block_offset); | |
| 603 space_for_current_child_->SetOffset(offset); | |
| 604 | |
| 605 const NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( | |
| 606 space_for_current_child_, fragment, margins); | |
| 607 DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; | |
| 608 | |
| 609 NGExclusion::Type exclusion_type = NGExclusion::kFloatLeft; | |
| 610 // Calculate the float offset if needed. | |
| 611 LayoutUnit float_offset; | |
| 612 if (CurrentChildStyle().floating() == EFloat::kRight) { | |
| 613 float_offset = opportunity.size.inline_size - fragment.InlineSize(); | |
| 614 exclusion_type = NGExclusion::kFloatRight; | |
| 615 } | |
| 616 | |
| 617 // Add the float as an exclusion. | |
| 618 const NGExclusion exclusion = CreateExclusion( | |
| 619 fragment, opportunity, float_offset, margins, exclusion_type); | |
| 620 constraint_space_->AddExclusion(exclusion); | |
| 621 | |
| 622 return CalculateLogicalOffsetForOpportunity(opportunity, float_offset, | |
| 623 margins); | |
| 624 } | |
| 625 | |
| 626 void NGBlockLayoutAlgorithm::UpdateMarginStrut( | |
| 627 const NGDeprecatedMarginStrut& from) { | |
| 628 if (!is_fragment_margin_strut_block_start_updated_) { | |
| 629 builder_->SetMarginStrutBlockStart(from); | |
| 630 is_fragment_margin_strut_block_start_updated_ = true; | |
| 631 } | |
| 632 builder_->SetMarginStrutBlockEnd(from); | |
| 633 } | |
| 634 | |
| 635 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( | 675 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins( |
| 636 const NGConstraintSpace& space, | 676 const NGConstraintSpace& space, |
| 637 const ComputedStyle& style) { | 677 const ComputedStyle& style) { |
| 638 WTF::Optional<MinAndMaxContentSizes> sizes; | 678 WTF::Optional<MinAndMaxContentSizes> sizes; |
| 639 if (NeedMinAndMaxContentSizes(space, style)) { | 679 if (NeedMinAndMaxContentSizes(space, style)) { |
| 640 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return | 680 // TODO(ikilpatrick): Change ComputeMinAndMaxContentSizes to return |
| 641 // MinAndMaxContentSizes. | 681 // MinAndMaxContentSizes. |
| 642 sizes = current_child_->ComputeMinAndMaxContentSizesSync(); | 682 sizes = current_child_->ComputeMinAndMaxContentSizesSync(); |
| 643 } | 683 } |
| 644 LayoutUnit child_inline_size = | 684 LayoutUnit child_inline_size = |
| 645 ComputeInlineSizeForFragment(space, style, sizes); | 685 ComputeInlineSizeForFragment(space, style, sizes); |
| 646 NGBoxStrut margins = | 686 NGBoxStrut margins = |
| 647 ComputeMargins(space, style, space.WritingMode(), space.Direction()); | 687 ComputeMargins(space, style, space.WritingMode(), space.Direction()); |
| 648 if (!style.isFloating()) { | 688 if (!style.isFloating()) { |
| 649 ApplyAutoMargins(space, style, child_inline_size, &margins); | 689 ApplyAutoMargins(space, style, child_inline_size, &margins); |
| 650 } | 690 } |
| 651 return margins; | 691 return margins; |
| 652 } | 692 } |
| 653 | 693 |
| 654 NGConstraintSpace* | 694 NGConstraintSpace* |
| 655 NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { | 695 NGBlockLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() { |
| 656 // TODO(layout-ng): Orthogonal children should also shrink to fit (in *their* | 696 // TODO(layout-ng): Orthogonal children should also shrink to fit (in *their* |
| 657 // inline axis) | 697 // inline axis) |
| 658 // We have to keep this commented out for now until we correctly compute | 698 // We have to keep this commented out for now until we correctly compute |
| 659 // min/max content sizes in Layout(). | 699 // min/max content sizes in Layout(). |
| 660 bool shrink_to_fit = CurrentChildStyle().display() == EDisplay::InlineBlock || | 700 bool shrink_to_fit = CurrentChildStyle().display() == EDisplay::InlineBlock || |
| 661 CurrentChildStyle().isFloating(); | 701 CurrentChildStyle().isFloating(); |
| 662 DCHECK(current_child_); | 702 DCHECK(current_child_); |
| 663 space_builder_ | 703 bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild( |
| 664 ->SetIsNewFormattingContext( | 704 ConstraintSpace(), CurrentChildStyle()); |
| 665 IsNewFormattingContextForInFlowBlockLevelChild(ConstraintSpace(), | 705 space_builder_->SetIsNewFormattingContext(is_new_bfc) |
| 666 CurrentChildStyle())) | |
| 667 .SetIsShrinkToFit(shrink_to_fit) | 706 .SetIsShrinkToFit(shrink_to_fit) |
| 668 .SetWritingMode( | 707 .SetWritingMode( |
| 669 FromPlatformWritingMode(CurrentChildStyle().getWritingMode())) | 708 FromPlatformWritingMode(CurrentChildStyle().getWritingMode())) |
| 670 .SetTextDirection(CurrentChildStyle().direction()); | 709 .SetTextDirection(CurrentChildStyle().direction()); |
| 671 LayoutUnit space_available = SpaceAvailableForCurrentChild(); | 710 LayoutUnit space_available = SpaceAvailableForCurrentChild(); |
| 672 space_builder_->SetFragmentainerSpaceAvailable(space_available); | 711 space_builder_->SetFragmentainerSpaceAvailable(space_available); |
| 673 | 712 |
| 674 curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), | 713 curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(), |
| 675 CurrentChildStyle()); | 714 CurrentChildStyle()); |
| 676 | 715 |
| 677 NGConstraintSpace* child_space = space_builder_->ToConstraintSpace(); | 716 // Clearance : |
| 717 // - Collapse margins | |
| 718 // - Update curr_bfc_offset and parent BFC offset if needed. | |
| 719 // - Position all pending floats as position is known now. | |
| 720 // TODO(glebl): Fix the use case with clear: left and an intruding right. | |
| 721 // https://software.hixie.ch/utilities/js/live-dom-viewer/saved/4847 | |
| 722 if (CurrentChildStyle().clear()) { | |
| 723 curr_bfc_offset_.block_offset += curr_margin_strut_.Sum(); | |
| 724 if (!builder_->BfcOffset()) { | |
| 725 builder_->SetBfcOffset(curr_bfc_offset_); | |
| 726 } | |
| 727 // Only collapse margins if it's an adjoining block with clearance. | |
| 728 if (!content_size_) { | |
| 729 curr_margin_strut_ = NGMarginStrut(); | |
| 730 curr_child_margins_.block_start = LayoutUnit(); | |
| 731 } | |
| 732 PositionPendingFloats(curr_bfc_offset_, builder_); | |
| 733 AdjustToClearance(constraint_space_->Exclusions(), CurrentChildStyle(), | |
| 734 builder_->BfcOffset().value(), &content_size_); | |
| 735 } | |
| 678 | 736 |
| 679 // TODO(layout-ng): Set offset through the space builder. | 737 // Append the current margin strut with child's block start margin. |
| 680 child_space->SetOffset(GetChildSpaceOffset()); | 738 // Non empty border/padding use cases are handled inside of the child's |
| 681 return child_space; | 739 // layout. |
| 740 curr_margin_strut_.Append(curr_child_margins_.block_start); | |
| 741 space_builder_->SetMarginStrut(curr_margin_strut_); | |
| 742 | |
| 743 // Set estimated BFC offset to the next child's constraint space. | |
| 744 curr_bfc_offset_ = builder_->BfcOffset() ? builder_->BfcOffset().value() | |
| 745 : ConstraintSpace().BfcOffset(); | |
| 746 curr_bfc_offset_.block_offset += content_size_; | |
| 747 curr_bfc_offset_.inline_offset += border_and_padding_.inline_start; | |
| 748 if (ConstraintSpace().IsNewFormattingContext()) { | |
| 749 curr_bfc_offset_.inline_offset += curr_child_margins_.inline_start; | |
| 750 } | |
| 751 space_builder_->SetBfcOffset(curr_bfc_offset_); | |
| 752 | |
| 753 return space_builder_->ToConstraintSpace(); | |
| 682 } | 754 } |
| 683 | 755 |
| 684 DEFINE_TRACE(NGBlockLayoutAlgorithm) { | 756 DEFINE_TRACE(NGBlockLayoutAlgorithm) { |
| 685 NGLayoutAlgorithm::trace(visitor); | 757 NGLayoutAlgorithm::trace(visitor); |
| 686 visitor->trace(first_child_); | 758 visitor->trace(first_child_); |
| 687 visitor->trace(constraint_space_); | 759 visitor->trace(constraint_space_); |
| 688 visitor->trace(break_token_); | 760 visitor->trace(break_token_); |
| 689 visitor->trace(builder_); | 761 visitor->trace(builder_); |
| 690 visitor->trace(space_builder_); | 762 visitor->trace(space_builder_); |
| 691 visitor->trace(space_for_current_child_); | 763 visitor->trace(space_for_current_child_); |
| 692 visitor->trace(current_child_); | 764 visitor->trace(current_child_); |
| 693 visitor->trace(fragmentainer_mapper_); | 765 visitor->trace(fragmentainer_mapper_); |
| 694 } | 766 } |
| 695 | 767 |
| 696 } // namespace blink | 768 } // namespace blink |
| OLD | NEW |