Index: third_party/WebKit/Source/core/layout/ng/ng_floats_utils.cc |
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_floats_utils.cc b/third_party/WebKit/Source/core/layout/ng/ng_floats_utils.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..61b987bb7d44fb52fa76f33f1a59422dd9ad1ce9 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/layout/ng/ng_floats_utils.cc |
@@ -0,0 +1,166 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "core/layout/ng/ng_floats_utils.h" |
+ |
+#include "core/layout/ng/ng_box_fragment.h" |
+ |
+namespace blink { |
+namespace { |
+ |
+// Adjusts the provided offset to the top edge alignment rule. |
+// Top edge alignment rule: the outer top of a floating box may not be higher |
+// than the outer top of any block or floated box generated by an element |
+// earlier in the source document. |
+NGLogicalOffset AdjustToTopEdgeAlignmentRule(const NGConstraintSpace& space, |
+ const NGLogicalOffset& offset) { |
+ NGLogicalOffset adjusted_offset = offset; |
+ LayoutUnit& adjusted_block_offset = adjusted_offset.block_offset; |
+ if (space.Exclusions()->last_left_float) |
+ adjusted_block_offset = |
+ std::max(adjusted_block_offset, |
+ space.Exclusions()->last_left_float->rect.BlockStartOffset()); |
+ if (space.Exclusions()->last_right_float) |
+ adjusted_block_offset = |
+ std::max(adjusted_block_offset, |
+ space.Exclusions()->last_right_float->rect.BlockStartOffset()); |
+ return adjusted_offset; |
+} |
+ |
+// Finds a layout opportunity for the fragment. |
+// It iterates over all layout opportunities in the constraint space and returns |
+// the first layout opportunity that is wider than the fragment or returns the |
+// last one which is always the widest. |
+// |
+// @param space Constraint space that is used to find layout opportunity for |
+// the fragment. |
+// @param fragment Fragment that needs to be placed. |
+// @param origin_point {@code space}'s offset relative to the space that |
+// establishes a new formatting context that we're currently |
+// in and where all our exclusions reside. |
+// @param margins Margins of the fragment. |
+// @return Layout opportunity for the fragment. |
+const NGLayoutOpportunity FindLayoutOpportunityForFragment( |
+ const NGConstraintSpace* space, |
+ const NGFragment& fragment, |
+ const NGLogicalOffset& origin_point, |
+ const NGBoxStrut& margins) { |
+ NGLogicalOffset adjusted_origin_point = |
+ AdjustToTopEdgeAlignmentRule(*space, origin_point); |
+ |
+ NGLayoutOpportunityIterator opportunity_iter(space, adjusted_origin_point); |
+ NGLayoutOpportunity opportunity; |
+ NGLayoutOpportunity opportunity_candidate = opportunity_iter.Next(); |
+ |
+ while (!opportunity_candidate.IsEmpty()) { |
+ opportunity = opportunity_candidate; |
+ // Checking opportunity's block size is not necessary as a float cannot be |
+ // positioned on top of another float inside of the same constraint space. |
+ auto fragment_inline_size = fragment.InlineSize() + margins.InlineSum(); |
+ if (opportunity.size.inline_size >= fragment_inline_size) |
+ break; |
+ |
+ opportunity_candidate = opportunity_iter.Next(); |
+ } |
+ return opportunity; |
+} |
+ |
+// Calculates the logical offset for opportunity. |
+NGLogicalOffset CalculateLogicalOffsetForOpportunity( |
+ const NGLayoutOpportunity& opportunity, |
+ const LayoutUnit float_offset, |
+ const NGLogicalOffset& from_offset, |
+ NGFloatingObject* floating_object) { |
+ DCHECK(floating_object); |
+ auto margins = floating_object->margins; |
+ // Adjust to child's margin. |
+ LayoutUnit inline_offset = margins.inline_start; |
+ LayoutUnit block_offset = margins.block_start; |
+ |
+ // Offset from the opportunity's block/inline start. |
+ inline_offset += opportunity.offset.inline_offset; |
+ block_offset += opportunity.offset.block_offset; |
+ |
+ // Adjust to float: right offset if needed. |
+ inline_offset += float_offset; |
+ |
+ block_offset -= from_offset.block_offset; |
+ inline_offset -= from_offset.inline_offset; |
+ |
+ return NGLogicalOffset(inline_offset, block_offset); |
+} |
+ |
+// Creates an exclusion from the fragment that will be placed in the provided |
+// layout opportunity. |
+NGExclusion CreateExclusion(const NGFragment& fragment, |
+ const NGLayoutOpportunity& opportunity, |
+ const LayoutUnit float_offset, |
+ const NGBoxStrut& margins, |
+ NGExclusion::Type exclusion_type) { |
+ NGExclusion exclusion; |
+ exclusion.type = exclusion_type; |
+ NGLogicalRect& rect = exclusion.rect; |
+ rect.offset = opportunity.offset; |
+ rect.offset.inline_offset += float_offset; |
+ |
+ rect.size.inline_size = fragment.InlineSize() + margins.InlineSum(); |
+ rect.size.block_size = fragment.BlockSize() + margins.BlockSum(); |
+ return exclusion; |
+} |
+ |
+// Updates the Floating Object's left offset from the provided parent_space |
+// and {@code floating_object}'s space and margins. |
+void UpdateFloatingObjectLeftOffset(const NGConstraintSpace& new_parent_space, |
+ const NGLogicalOffset& float_logical_offset, |
+ NGFloatingObject* floating_object) { |
+ DCHECK(floating_object); |
+ // TODO(glebl): We should use physical offset here. |
+ floating_object->left_offset = |
+ floating_object->original_parent_space->BfcOffset().inline_offset - |
+ new_parent_space.BfcOffset().inline_offset + |
+ float_logical_offset.inline_offset; |
+} |
+} // namespace |
+ |
+// Calculates the relative position from {@code from_offset} of the |
+// floating object that is requested to be positioned from {@code origin_point}. |
+NGLogicalOffset PositionFloat(const NGLogicalOffset& origin_point, |
+ const NGLogicalOffset& from_offset, |
+ NGFloatingObject* floating_object, |
+ NGConstraintSpace* new_parent_space) { |
+ DCHECK(floating_object); |
+ const auto* float_space = floating_object->space.get(); |
+ DCHECK(floating_object->fragment) << "Fragment cannot be null here"; |
+ |
+ // TODO(ikilpatrick): The writing mode switching here looks wrong. |
+ NGBoxFragment float_fragment( |
+ float_space->WritingMode(), |
+ toNGPhysicalBoxFragment(floating_object->fragment.get())); |
+ |
+ // Find a layout opportunity that will fit our float. |
+ const NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment( |
+ float_space, float_fragment, origin_point, floating_object->margins); |
+ DCHECK(!opportunity.IsEmpty()) << "Opportunity is empty but it shouldn't be"; |
+ |
+ // Calculate the float offset if needed. |
+ LayoutUnit float_offset; |
+ if (floating_object->exclusion_type == NGExclusion::kFloatRight) { |
+ LayoutUnit float_margin_box_inline_size = |
+ float_fragment.InlineSize() + floating_object->margins.InlineSum(); |
+ float_offset = opportunity.size.inline_size - float_margin_box_inline_size; |
+ } |
+ |
+ // Add the float as an exclusion. |
+ const NGExclusion exclusion = CreateExclusion( |
+ float_fragment, opportunity, float_offset, floating_object->margins, |
+ floating_object->exclusion_type); |
+ new_parent_space->AddExclusion(exclusion); |
+ |
+ NGLogicalOffset logical_offset = CalculateLogicalOffsetForOpportunity( |
+ opportunity, float_offset, from_offset, floating_object); |
+ UpdateFloatingObjectLeftOffset(*new_parent_space, logical_offset, |
+ floating_object); |
+ return logical_offset; |
+} |
+} // namespace blink |