OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "core/layout/ng/ng_floats_utils.h" |
| 6 |
| 7 #include "core/layout/ng/ng_box_fragment.h" |
| 8 |
| 9 namespace blink { |
| 10 namespace { |
| 11 |
| 12 // Adjusts the provided offset to the top edge alignment rule. |
| 13 // Top edge alignment rule: the outer top of a floating box may not be higher |
| 14 // than the outer top of any block or floated box generated by an element |
| 15 // earlier in the source document. |
| 16 NGLogicalOffset AdjustToTopEdgeAlignmentRule(const NGConstraintSpace& space, |
| 17 const NGLogicalOffset& offset) { |
| 18 NGLogicalOffset adjusted_offset = offset; |
| 19 LayoutUnit& adjusted_block_offset = adjusted_offset.block_offset; |
| 20 if (space.Exclusions()->last_left_float) |
| 21 adjusted_block_offset = |
| 22 std::max(adjusted_block_offset, |
| 23 space.Exclusions()->last_left_float->rect.BlockStartOffset()); |
| 24 if (space.Exclusions()->last_right_float) |
| 25 adjusted_block_offset = |
| 26 std::max(adjusted_block_offset, |
| 27 space.Exclusions()->last_right_float->rect.BlockStartOffset()); |
| 28 return adjusted_offset; |
| 29 } |
| 30 |
| 31 // Finds a layout opportunity for the fragment. |
| 32 // It iterates over all layout opportunities in the constraint space and returns |
| 33 // the first layout opportunity that is wider than the fragment or returns the |
| 34 // last one which is always the widest. |
| 35 // |
| 36 // @param space Constraint space that is used to find layout opportunity for |
| 37 // the fragment. |
| 38 // @param fragment Fragment that needs to be placed. |
| 39 // @param origin_point {@code space}'s offset relative to the space that |
| 40 // establishes a new formatting context that we're currently |
| 41 // in and where all our exclusions reside. |
| 42 // @param margins Margins of the fragment. |
| 43 // @return Layout opportunity for the fragment. |
| 44 const NGLayoutOpportunity FindLayoutOpportunityForFragment( |
| 45 const NGConstraintSpace* space, |
| 46 const NGFragment& fragment, |
| 47 const NGLogicalOffset& origin_point, |
| 48 const NGBoxStrut& margins) { |
| 49 NGLogicalOffset adjusted_origin_point = |
| 50 AdjustToTopEdgeAlignmentRule(*space, origin_point); |
| 51 |
| 52 NGLayoutOpportunityIterator opportunity_iter(space, adjusted_origin_point); |
| 53 NGLayoutOpportunity opportunity; |
| 54 NGLayoutOpportunity opportunity_candidate = opportunity_iter.Next(); |
| 55 |
| 56 while (!opportunity_candidate.IsEmpty()) { |
| 57 opportunity = opportunity_candidate; |
| 58 // Checking opportunity's block size is not necessary as a float cannot be |
| 59 // positioned on top of another float inside of the same constraint space. |
| 60 auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); |
| 61 if (opportunity.size.inline_size >= fragment_inline_size) |
| 62 break; |
| 63 |
| 64 opportunity_candidate = opportunity_iter.Next(); |
| 65 } |
| 66 return opportunity; |
| 67 } |
| 68 |
| 69 // Calculates the logical offset for opportunity. |
| 70 NGLogicalOffset CalculateLogicalOffsetForOpportunity( |
| 71 const NGLayoutOpportunity& opportunity, |
| 72 const LayoutUnit float_offset, |
| 73 const NGLogicalOffset& from_offset, |
| 74 NGFloatingObject* floating_object) { |
| 75 DCHECK(floating_object); |
| 76 auto margins = floating_object->margins; |
| 77 // Adjust to child's margin. |
| 78 LayoutUnit inline_offset = margins.inline_start; |
| 79 LayoutUnit block_offset = margins.block_start; |
| 80 |
| 81 // Offset from the opportunity's block/inline start. |
| 82 inline_offset += opportunity.offset.inline_offset; |
| 83 block_offset += opportunity.offset.block_offset; |
| 84 |
| 85 // Adjust to float: right offset if needed. |
| 86 inline_offset += float_offset; |
| 87 |
| 88 block_offset -= from_offset.block_offset; |
| 89 inline_offset -= from_offset.inline_offset; |
| 90 |
| 91 return NGLogicalOffset(inline_offset, block_offset); |
| 92 } |
| 93 |
| 94 // Creates an exclusion from the fragment that will be placed in the provided |
| 95 // layout opportunity. |
| 96 NGExclusion CreateExclusion(const NGFragment& fragment, |
| 97 const NGLayoutOpportunity& opportunity, |
| 98 const LayoutUnit float_offset, |
| 99 const NGBoxStrut& margins, |
| 100 NGExclusion::Type exclusion_type) { |
| 101 NGExclusion exclusion; |
| 102 exclusion.type = exclusion_type; |
| 103 NGLogicalRect& rect = exclusion.rect; |
| 104 rect.offset = opportunity.offset; |
| 105 rect.offset.inline_offset += float_offset; |
| 106 |
| 107 rect.size.inline_size = fragment.InlineSize() + margins.InlineSum(); |
| 108 rect.size.block_size = fragment.BlockSize() + margins.BlockSum(); |
| 109 return exclusion; |
| 110 } |
| 111 |
| 112 // Updates the Floating Object's left offset from the provided parent_space |
| 113 // and {@code floating_object}'s space and margins. |
| 114 void UpdateFloatingObjectLeftOffset(const NGConstraintSpace& new_parent_space, |
| 115 const NGLogicalOffset& float_logical_offset, |
| 116 NGFloatingObject* floating_object) { |
| 117 DCHECK(floating_object); |
| 118 // TODO(glebl): We should use physical offset here. |
| 119 floating_object->left_offset = |
| 120 floating_object->original_parent_space->BfcOffset().inline_offset - |
| 121 new_parent_space.BfcOffset().inline_offset + |
| 122 float_logical_offset.inline_offset; |
| 123 } |
| 124 } // namespace |
| 125 |
| 126 // Calculates the relative position from {@code from_offset} of the |
| 127 // floating object that is requested to be positioned from {@code origin_point}. |
| 128 NGLogicalOffset PositionFloat(const NGLogicalOffset& origin_point, |
| 129 const NGLogicalOffset& from_offset, |
| 130 NGFloatingObject* floating_object, |
| 131 NGConstraintSpace* new_parent_space) { |
| 132 DCHECK(floating_object); |
| 133 const auto* float_space = floating_object->space.get(); |
| 134 DCHECK(floating_object->fragment) << "Fragment cannot be null here"; |
| 135 |
| 136 // TODO(ikilpatrick): The writing mode switching here looks wrong. |
| 137 NGBoxFragment float_fragment( |
| 138 float_space->WritingMode(), |
| 139 toNGPhysicalBoxFragment(floating_object->fragment.get())); |
| 140 |
| 141 // Find a layout opportunity that will fit our float. |
| 142 const NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( |
| 143 float_space, float_fragment, origin_point, floating_object->margins); |
| 144 DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; |
| 145 |
| 146 // Calculate the float offset if needed. |
| 147 LayoutUnit float_offset; |
| 148 if (floating_object->exclusion_type == NGExclusion::kFloatRight) { |
| 149 LayoutUnit float_margin_box_inline_size = |
| 150 float_fragment.InlineSize() + floating_object->margins.InlineSum(); |
| 151 float_offset = opportunity.size.inline_size - float_margin_box_inline_size; |
| 152 } |
| 153 |
| 154 // Add the float as an exclusion. |
| 155 const NGExclusion exclusion = CreateExclusion( |
| 156 float_fragment, opportunity, float_offset, floating_object->margins, |
| 157 floating_object->exclusion_type); |
| 158 new_parent_space->AddExclusion(exclusion); |
| 159 |
| 160 NGLogicalOffset logical_offset = CalculateLogicalOffsetForOpportunity( |
| 161 opportunity, float_offset, from_offset, floating_object); |
| 162 UpdateFloatingObjectLeftOffset(*new_parent_space, logical_offset, |
| 163 floating_object); |
| 164 return logical_offset; |
| 165 } |
| 166 } // namespace blink |
OLD | NEW |