| 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_block_child_iterator.h" | 9 #include "core/layout/ng/ng_block_child_iterator.h" |
| 10 #include "core/layout/ng/ng_box_fragment.h" | 10 #include "core/layout/ng/ng_box_fragment.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_floats_utils.h" |
| 13 #include "core/layout/ng/ng_fragment.h" | 14 #include "core/layout/ng/ng_fragment.h" |
| 14 #include "core/layout/ng/ng_fragment_builder.h" | 15 #include "core/layout/ng/ng_fragment_builder.h" |
| 15 #include "core/layout/ng/ng_inline_node.h" | 16 #include "core/layout/ng/ng_inline_node.h" |
| 16 #include "core/layout/ng/ng_layout_opportunity_iterator.h" | 17 #include "core/layout/ng/ng_layout_opportunity_iterator.h" |
| 17 #include "core/layout/ng/ng_length_utils.h" | 18 #include "core/layout/ng/ng_length_utils.h" |
| 18 #include "core/layout/ng/ng_line_builder.h" | 19 #include "core/layout/ng/ng_line_builder.h" |
| 19 #include "core/layout/ng/ng_out_of_flow_layout_part.h" | 20 #include "core/layout/ng/ng_out_of_flow_layout_part.h" |
| 20 #include "core/style/ComputedStyle.h" | 21 #include "core/style/ComputedStyle.h" |
| 21 #include "platform/LengthFunctions.h" | 22 #include "platform/LengthFunctions.h" |
| 22 #include "wtf/Optional.h" | 23 #include "wtf/Optional.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 case EClear::kRight: | 76 case EClear::kRight: |
| 76 return right_offset; | 77 return right_offset; |
| 77 case EClear::kBoth: | 78 case EClear::kBoth: |
| 78 return OptionalMax<LayoutUnit>(left_offset, right_offset); | 79 return OptionalMax<LayoutUnit>(left_offset, right_offset); |
| 79 default: | 80 default: |
| 80 ASSERT_NOT_REACHED(); | 81 ASSERT_NOT_REACHED(); |
| 81 } | 82 } |
| 82 return WTF::nullopt; | 83 return WTF::nullopt; |
| 83 } | 84 } |
| 84 | 85 |
| 85 // Creates an exclusion from the fragment that will be placed in the provided | |
| 86 // layout opportunity. | |
| 87 NGExclusion CreateExclusion(const NGFragment& fragment, | |
| 88 const NGLayoutOpportunity& opportunity, | |
| 89 const LayoutUnit float_offset, | |
| 90 const NGBoxStrut& margins, | |
| 91 NGExclusion::Type exclusion_type) { | |
| 92 NGExclusion exclusion; | |
| 93 exclusion.type = exclusion_type; | |
| 94 NGLogicalRect& rect = exclusion.rect; | |
| 95 rect.offset = opportunity.offset; | |
| 96 rect.offset.inline_offset += float_offset; | |
| 97 | |
| 98 rect.size.inline_size = fragment.InlineSize() + margins.InlineSum(); | |
| 99 rect.size.block_size = fragment.BlockSize() + margins.BlockSum(); | |
| 100 return exclusion; | |
| 101 } | |
| 102 | |
| 103 // Adjusts the provided offset to the top edge alignment rule. | |
| 104 // Top edge alignment rule: the outer top of a floating box may not be higher | |
| 105 // than the outer top of any block or floated box generated by an element | |
| 106 // earlier in the source document. | |
| 107 NGLogicalOffset AdjustToTopEdgeAlignmentRule(const NGConstraintSpace& space, | |
| 108 const NGLogicalOffset& offset) { | |
| 109 NGLogicalOffset adjusted_offset = offset; | |
| 110 LayoutUnit& adjusted_block_offset = adjusted_offset.block_offset; | |
| 111 if (space.Exclusions()->last_left_float) | |
| 112 adjusted_block_offset = | |
| 113 std::max(adjusted_block_offset, | |
| 114 space.Exclusions()->last_left_float->rect.BlockStartOffset()); | |
| 115 if (space.Exclusions()->last_right_float) | |
| 116 adjusted_block_offset = | |
| 117 std::max(adjusted_block_offset, | |
| 118 space.Exclusions()->last_right_float->rect.BlockStartOffset()); | |
| 119 return adjusted_offset; | |
| 120 } | |
| 121 | |
| 122 // Finds a layout opportunity for the fragment. | |
| 123 // It iterates over all layout opportunities in the constraint space and returns | |
| 124 // the first layout opportunity that is wider than the fragment or returns the | |
| 125 // last one which is always the widest. | |
| 126 // | |
| 127 // @param space Constraint space that is used to find layout opportunity for | |
| 128 // the fragment. | |
| 129 // @param fragment Fragment that needs to be placed. | |
| 130 // @param origin_point {@code space}'s offset relative to the space that | |
| 131 // establishes a new formatting context that we're currently | |
| 132 // in and where all our exclusions reside. | |
| 133 // @param margins Margins of the fragment. | |
| 134 // @return Layout opportunity for the fragment. | |
| 135 const NGLayoutOpportunity FindLayoutOpportunityForFragment( | |
| 136 const NGConstraintSpace* space, | |
| 137 const NGFragment& fragment, | |
| 138 const NGLogicalOffset& origin_point, | |
| 139 const NGBoxStrut& margins) { | |
| 140 NGLogicalOffset adjusted_origin_point = | |
| 141 AdjustToTopEdgeAlignmentRule(*space, origin_point); | |
| 142 | |
| 143 NGLayoutOpportunityIterator opportunity_iter(space, adjusted_origin_point); | |
| 144 NGLayoutOpportunity opportunity; | |
| 145 NGLayoutOpportunity opportunity_candidate = opportunity_iter.Next(); | |
| 146 | |
| 147 while (!opportunity_candidate.IsEmpty()) { | |
| 148 opportunity = opportunity_candidate; | |
| 149 // Checking opportunity's block size is not necessary as a float cannot be | |
| 150 // positioned on top of another float inside of the same constraint space. | |
| 151 auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); | |
| 152 if (opportunity.size.inline_size >= fragment_inline_size) | |
| 153 break; | |
| 154 | |
| 155 opportunity_candidate = opportunity_iter.Next(); | |
| 156 } | |
| 157 return opportunity; | |
| 158 } | |
| 159 | |
| 160 // Calculates the logical offset for opportunity. | |
| 161 NGLogicalOffset CalculateLogicalOffsetForOpportunity( | |
| 162 const NGLayoutOpportunity& opportunity, | |
| 163 const LayoutUnit float_offset, | |
| 164 const NGLogicalOffset& from_offset, | |
| 165 NGFloatingObject* floating_object) { | |
| 166 DCHECK(floating_object); | |
| 167 auto margins = floating_object->margins; | |
| 168 // Adjust to child's margin. | |
| 169 LayoutUnit inline_offset = margins.inline_start; | |
| 170 LayoutUnit block_offset = margins.block_start; | |
| 171 | |
| 172 // Offset from the opportunity's block/inline start. | |
| 173 inline_offset += opportunity.offset.inline_offset; | |
| 174 block_offset += opportunity.offset.block_offset; | |
| 175 | |
| 176 // Adjust to float: right offset if needed. | |
| 177 inline_offset += float_offset; | |
| 178 | |
| 179 block_offset -= from_offset.block_offset; | |
| 180 inline_offset -= from_offset.inline_offset; | |
| 181 | |
| 182 return NGLogicalOffset(inline_offset, block_offset); | |
| 183 } | |
| 184 | |
| 185 // Calculates the relative position from {@code from_offset} of the | |
| 186 // floating object that is requested to be positioned from {@code origin_point}. | |
| 187 NGLogicalOffset PositionFloat(const NGLogicalOffset& origin_point, | |
| 188 const NGLogicalOffset& from_offset, | |
| 189 NGFloatingObject* floating_object, | |
| 190 NGConstraintSpace* new_parent_space) { | |
| 191 DCHECK(floating_object); | |
| 192 const auto* float_space = floating_object->space.get(); | |
| 193 DCHECK(floating_object->fragment) << "Fragment cannot be null here"; | |
| 194 | |
| 195 // TODO(ikilpatrick): The writing mode switching here looks wrong. | |
| 196 NGBoxFragment float_fragment( | |
| 197 float_space->WritingMode(), | |
| 198 toNGPhysicalBoxFragment(floating_object->fragment.get())); | |
| 199 | |
| 200 // Find a layout opportunity that will fit our float. | |
| 201 const NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( | |
| 202 float_space, float_fragment, origin_point, floating_object->margins); | |
| 203 DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; | |
| 204 | |
| 205 // Calculate the float offset if needed. | |
| 206 LayoutUnit float_offset; | |
| 207 if (floating_object->exclusion_type == NGExclusion::kFloatRight) { | |
| 208 LayoutUnit float_margin_box_inline_size = | |
| 209 float_fragment.InlineSize() + floating_object->margins.InlineSum(); | |
| 210 float_offset = opportunity.size.inline_size - float_margin_box_inline_size; | |
| 211 } | |
| 212 | |
| 213 // Add the float as an exclusion. | |
| 214 const NGExclusion exclusion = CreateExclusion( | |
| 215 float_fragment, opportunity, float_offset, floating_object->margins, | |
| 216 floating_object->exclusion_type); | |
| 217 new_parent_space->AddExclusion(exclusion); | |
| 218 | |
| 219 return CalculateLogicalOffsetForOpportunity(opportunity, float_offset, | |
| 220 from_offset, floating_object); | |
| 221 } | |
| 222 | |
| 223 // Updates the Floating Object's left offset from the provided parent_space | |
| 224 // and {@code floating_object}'s space and margins. | |
| 225 void UpdateFloatingObjectLeftOffset(const NGConstraintSpace& new_parent_space, | |
| 226 const NGLogicalOffset& float_logical_offset, | |
| 227 NGFloatingObject* floating_object) { | |
| 228 DCHECK(floating_object); | |
| 229 // TODO(glebl): We should use physical offset here. | |
| 230 floating_object->left_offset = | |
| 231 floating_object->original_parent_space->BfcOffset().inline_offset - | |
| 232 new_parent_space.BfcOffset().inline_offset + | |
| 233 float_logical_offset.inline_offset; | |
| 234 } | |
| 235 | |
| 236 // Positions pending floats stored on the fragment builder starting from | 86 // Positions pending floats stored on the fragment builder starting from |
| 237 // {@code origin_point_block_offset}. | 87 // {@code origin_point_block_offset}. |
| 238 void PositionPendingFloats(const LayoutUnit origin_point_block_offset, | 88 void PositionPendingFloats(const LayoutUnit origin_point_block_offset, |
| 239 NGConstraintSpace* new_parent_space, | 89 NGConstraintSpace* new_parent_space, |
| 240 NGFragmentBuilder* builder) { | 90 NGFragmentBuilder* builder) { |
| 241 DCHECK(builder->BfcOffset()) << "Parent BFC offset should be known here"; | 91 DCHECK(builder->BfcOffset()) << "Parent BFC offset should be known here"; |
| 242 LayoutUnit bfc_block_offset = builder->BfcOffset().value().block_offset; | 92 LayoutUnit bfc_block_offset = builder->BfcOffset().value().block_offset; |
| 243 | 93 |
| 244 for (auto& floating_object : builder->UnpositionedFloats()) { | 94 for (auto& floating_object : builder->UnpositionedFloats()) { |
| 245 const auto* float_space = floating_object->space.get(); | 95 const auto* float_space = floating_object->space.get(); |
| 246 const NGConstraintSpace* original_parent_space = | 96 const NGConstraintSpace* original_parent_space = |
| 247 floating_object->original_parent_space.get(); | 97 floating_object->original_parent_space.get(); |
| 248 | 98 |
| 249 NGLogicalOffset origin_point = {float_space->BfcOffset().inline_offset, | 99 NGLogicalOffset origin_point = {float_space->BfcOffset().inline_offset, |
| 250 origin_point_block_offset}; | 100 origin_point_block_offset}; |
| 251 NGLogicalOffset from_offset = { | 101 NGLogicalOffset from_offset = { |
| 252 original_parent_space->BfcOffset().inline_offset, bfc_block_offset}; | 102 original_parent_space->BfcOffset().inline_offset, bfc_block_offset}; |
| 253 | 103 |
| 254 NGLogicalOffset float_fragment_offset = PositionFloat( | 104 NGLogicalOffset float_fragment_offset = PositionFloat( |
| 255 origin_point, from_offset, floating_object.get(), new_parent_space); | 105 origin_point, from_offset, floating_object.get(), new_parent_space); |
| 256 builder->AddFloatingObject(floating_object, float_fragment_offset); | 106 builder->AddFloatingObject(floating_object, float_fragment_offset); |
| 257 UpdateFloatingObjectLeftOffset(*new_parent_space, float_fragment_offset, | |
| 258 floating_object.get()); | |
| 259 } | 107 } |
| 260 builder->MutableUnpositionedFloats().clear(); | 108 builder->MutableUnpositionedFloats().clear(); |
| 261 } | 109 } |
| 262 | 110 |
| 263 // Whether an in-flow block-level child creates a new formatting context. | 111 // Whether an in-flow block-level child creates a new formatting context. |
| 264 // | 112 // |
| 265 // This will *NOT* check the following cases: | 113 // This will *NOT* check the following cases: |
| 266 // - The child is out-of-flow, e.g. floating or abs-pos. | 114 // - The child is out-of-flow, e.g. floating or abs-pos. |
| 267 // - The child is a inline-level, e.g. "display: inline-block". | 115 // - The child is a inline-level, e.g. "display: inline-block". |
| 268 // - The child establishes a new formatting context, but should be a child of | 116 // - The child establishes a new formatting context, but should be a child of |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 746 DCHECK(builder_.BfcOffset()); | 594 DCHECK(builder_.BfcOffset()); |
| 747 space_available -= curr_bfc_offset_.block_offset; | 595 space_available -= curr_bfc_offset_.block_offset; |
| 748 } | 596 } |
| 749 } | 597 } |
| 750 space_builder_.SetFragmentainerSpaceAvailable(space_available); | 598 space_builder_.SetFragmentainerSpaceAvailable(space_available); |
| 751 | 599 |
| 752 return space_builder_.ToConstraintSpace( | 600 return space_builder_.ToConstraintSpace( |
| 753 FromPlatformWritingMode(child_style.getWritingMode())); | 601 FromPlatformWritingMode(child_style.getWritingMode())); |
| 754 } | 602 } |
| 755 } // namespace blink | 603 } // namespace blink |
| OLD | NEW |