Commit 05059b38 authored by glebl's avatar glebl Committed by Commit bot

Initial implementation of LayoutNG's block layout algorithm for floats.

This patch adds support of left/right floats in LayoutNG code.

Things that are not supported yet:
 - top aligning floats
 - clearing
 - child blocks in the same formatting formatting context

BUG=635619
TEST=virtual/layout_ng/fast/block/float, NGBlockLayoutAlgorithmTest::PositionFloatFragments

Review-Url: https://chromiumcodereview.appspot.com/2435803005
Cr-Commit-Position: refs/heads/master@{#426982}
parent c067174d
...@@ -303,5 +303,10 @@ ...@@ -303,5 +303,10 @@
"prefix": "layout_ng", "prefix": "layout_ng",
"base": "fast/block/margin-collapse", "base": "fast/block/margin-collapse",
"args": ["--enable-blink-features=LayoutNG"] "args": ["--enable-blink-features=LayoutNG"]
},
{
"prefix": "layout_ng",
"base": "fast/block/float",
"args": ["--enable-blink-features=LayoutNG"]
} }
] ]
# This suite runs the tests in fast/block/float with
# --enable-blink-features=LayoutNG.
# The LayoutNG project is described here: http://goo.gl/1hwhfX
...@@ -296,6 +296,7 @@ blink_core_sources("layout") { ...@@ -296,6 +296,7 @@ blink_core_sources("layout") {
"ng/ng_layout_input_text.h", "ng/ng_layout_input_text.h",
"ng/ng_layout_opportunity_iterator.cc", "ng/ng_layout_opportunity_iterator.cc",
"ng/ng_layout_opportunity_iterator.h", "ng/ng_layout_opportunity_iterator.h",
"ng/ng_layout_opportunity_tree_node.cc",
"ng/ng_layout_opportunity_tree_node.h", "ng/ng_layout_opportunity_tree_node.h",
"ng/ng_length_utils.cc", "ng/ng_length_utils.cc",
"ng/ng_length_utils.h", "ng/ng_length_utils.h",
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "core/layout/ng/ng_constraint_space.h" #include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_fragment_builder.h" #include "core/layout/ng/ng_fragment_builder.h"
#include "core/layout/ng/ng_fragment.h" #include "core/layout/ng/ng_fragment.h"
#include "core/layout/ng/ng_layout_opportunity_iterator.h"
#include "core/layout/ng/ng_length_utils.h" #include "core/layout/ng/ng_length_utils.h"
#include "core/layout/ng/ng_units.h" #include "core/layout/ng/ng_units.h"
#include "core/style/ComputedStyle.h" #include "core/style/ComputedStyle.h"
...@@ -24,6 +25,78 @@ LayoutUnit ComputeCollapsedMarginBlockStart( ...@@ -24,6 +25,78 @@ LayoutUnit ComputeCollapsedMarginBlockStart(
curr_margin_strut.negative_margin_block_start.abs()); curr_margin_strut.negative_margin_block_start.abs());
} }
// Creates an exclusion from the fragment that will be placed in the provided
// layout opportunity.
NGExclusion* CreateExclusion(const NGFragment& fragment,
const NGConstraintSpace* opportunity,
LayoutUnit float_offset,
NGBoxStrut margins) {
LayoutUnit exclusion_top = opportunity->Offset().block_offset;
LayoutUnit exclusion_left = opportunity->Offset().inline_offset;
exclusion_left += float_offset;
LayoutUnit exclusion_bottom = exclusion_top + fragment.BlockSize();
LayoutUnit exclusion_right = exclusion_left + fragment.InlineSize();
// Adjust to child's margin.
exclusion_bottom += margins.BlockSum();
exclusion_right += margins.InlineSum();
return new NGExclusion(exclusion_top, exclusion_right, exclusion_bottom,
exclusion_left);
}
// 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.
// @return Layout opportunity for the fragment.
const NGConstraintSpace* FindLayoutOpportunityForFragment(
const Member<NGConstraintSpace>& space,
const NGFragment& fragment) {
NGLayoutOpportunityIterator* opportunity_iter = space->LayoutOpportunities();
const NGConstraintSpace* opportunity = nullptr;
while (const NGConstraintSpace* opportunity_candidate =
opportunity_iter->Next()) {
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.
if (opportunity->Size().inline_size > fragment.InlineSize())
break;
}
return opportunity;
}
// Calculates the logical offset for opportunity.
NGLogicalOffset CalculateLogicalOffsetForOpportunity(
const NGConstraintSpace* opportunity,
NGBoxStrut border_padding,
LayoutUnit float_offset,
NGBoxStrut margins) {
// TODO(layout-ng): create children_constraint_space with an offset for the
// border and padding.
// Offset from parent's border/padding.
LayoutUnit inline_offset = border_padding.inline_start;
LayoutUnit block_offset = border_padding.block_start;
// Adjust to child's margin.
inline_offset += margins.inline_start;
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;
inline_offset += float_offset;
return NGLogicalOffset(inline_offset, block_offset);
}
// Whether an in-flow block-level child creates a new formatting context. // Whether an in-flow block-level child creates a new formatting context.
// //
// This will *NOT* check the following cases: // This will *NOT* check the following cases:
...@@ -76,16 +149,16 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space, ...@@ -76,16 +149,16 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space,
switch (state_) { switch (state_) {
case kStateInit: { case kStateInit: {
border_and_padding_ = border_and_padding_ =
ComputeBorders(*style_) + ComputePadding(*constraint_space, *style_); ComputeBorders(Style()) + ComputePadding(*constraint_space, Style());
LayoutUnit inline_size = LayoutUnit inline_size =
ComputeInlineSizeForFragment(*constraint_space, *style_); ComputeInlineSizeForFragment(*constraint_space, Style());
LayoutUnit adjusted_inline_size = LayoutUnit adjusted_inline_size =
inline_size - border_and_padding_.InlineSum(); inline_size - border_and_padding_.InlineSum();
// TODO(layout-ng): For quirks mode, should we pass blockSize instead of // TODO(layout-ng): For quirks mode, should we pass blockSize instead of
// -1? // -1?
LayoutUnit block_size = ComputeBlockSizeForFragment( LayoutUnit block_size = ComputeBlockSizeForFragment(
*constraint_space, *style_, NGSizeIndefinite); *constraint_space, Style(), NGSizeIndefinite);
LayoutUnit adjusted_block_size(block_size); LayoutUnit adjusted_block_size(block_size);
// Our calculated block-axis size may be indefinite at this point. // Our calculated block-axis size may be indefinite at this point.
// If so, just leave the size as NGSizeIndefinite instead of subtracting // If so, just leave the size as NGSizeIndefinite instead of subtracting
...@@ -93,8 +166,8 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space, ...@@ -93,8 +166,8 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space,
if (adjusted_block_size != NGSizeIndefinite) if (adjusted_block_size != NGSizeIndefinite)
adjusted_block_size -= border_and_padding_.BlockSum(); adjusted_block_size -= border_and_padding_.BlockSum();
constraint_space_for_children_ = new NGConstraintSpace( constraint_space_for_children_ = new NGConstraintSpace(
FromPlatformWritingMode(style_->getWritingMode()), FromPlatformWritingMode(Style().getWritingMode()),
FromPlatformDirection(style_->direction()), *constraint_space, FromPlatformDirection(Style().direction()), *constraint_space,
NGLogicalSize(adjusted_inline_size, adjusted_block_size)); NGLogicalSize(adjusted_inline_size, adjusted_block_size));
content_size_ = border_and_padding_.block_start; content_size_ = border_and_padding_.block_start;
...@@ -115,27 +188,24 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space, ...@@ -115,27 +188,24 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space,
NGFragment* fragment; NGFragment* fragment;
if (!current_child_->Layout(constraint_space_for_children_, &fragment)) if (!current_child_->Layout(constraint_space_for_children_, &fragment))
return false; return false;
NGBoxStrut child_margins = ComputeMargins( NGBoxStrut child_margins = ComputeMargins(
*constraint_space_for_children_, *current_child_->Style(), *constraint_space_for_children_, *current_child_->Style(),
constraint_space_for_children_->WritingMode(), constraint_space_for_children_->WritingMode(),
constraint_space_for_children_->Direction()); constraint_space_for_children_->Direction());
ApplyAutoMargins(*constraint_space_for_children_,
*current_child_->Style(), *fragment, child_margins); NGLogicalOffset fragment_offset;
if (current_child_->Style()->isFloating()) {
const NGBoxStrut margins = fragment_offset = PositionFloatFragment(*fragment, child_margins);
CollapseMargins(*constraint_space, child_margins, *fragment); } else {
// TODO(layout-ng): move ApplyAutoMargins to PositionFragment
// TODO(layout-ng): Support auto margins ApplyAutoMargins(*constraint_space_for_children_,
builder_->AddChild( *current_child_->Style(), *fragment, child_margins);
fragment, NGLogicalOffset(border_and_padding_.inline_start + fragment_offset =
child_margins.inline_start, PositionFragment(*fragment, child_margins, *constraint_space);
content_size_ + margins.block_start)); }
builder_->AddChild(fragment, fragment_offset);
content_size_ += fragment->BlockSize() + margins.BlockSum();
max_inline_size_ =
std::max(max_inline_size_, fragment->InlineSize() +
child_margins.InlineSum() +
border_and_padding_.InlineSum());
current_child_ = current_child_->NextSibling(); current_child_ = current_child_->NextSibling();
if (current_child_) if (current_child_)
return false; return false;
...@@ -148,7 +218,7 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space, ...@@ -148,7 +218,7 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space,
// Recompute the block-axis size now that we know our content size. // Recompute the block-axis size now that we know our content size.
LayoutUnit block_size = ComputeBlockSizeForFragment( LayoutUnit block_size = ComputeBlockSizeForFragment(
*constraint_space, *style_, content_size_); *constraint_space, Style(), content_size_);
builder_->SetBlockSize(block_size) builder_->SetBlockSize(block_size)
.SetInlineOverflow(max_inline_size_) .SetInlineOverflow(max_inline_size_)
...@@ -230,6 +300,48 @@ NGBoxStrut NGBlockLayoutAlgorithm::CollapseMargins( ...@@ -230,6 +300,48 @@ NGBoxStrut NGBlockLayoutAlgorithm::CollapseMargins(
return result_margins; return result_margins;
} }
NGLogicalOffset NGBlockLayoutAlgorithm::PositionFragment(
const NGFragment& fragment,
NGBoxStrut child_margins,
const NGConstraintSpace& space) {
const NGBoxStrut collapsed_margins =
CollapseMargins(space, child_margins, fragment);
LayoutUnit inline_offset =
border_and_padding_.inline_start + child_margins.inline_start;
LayoutUnit block_offset = content_size_ + collapsed_margins.block_start;
content_size_ += fragment.BlockSize() + collapsed_margins.BlockSum();
max_inline_size_ = std::max(
max_inline_size_, fragment.InlineSize() + child_margins.InlineSum() +
border_and_padding_.InlineSum());
return NGLogicalOffset(inline_offset, block_offset);
}
NGLogicalOffset NGBlockLayoutAlgorithm::PositionFloatFragment(
const NGFragment& fragment,
NGBoxStrut margins) {
// TODO(glebl@chromium.org): Support the top edge alignment rule.
// Find a layout opportunity that will fit our float.
const NGConstraintSpace* opportunity = FindLayoutOpportunityForFragment(
constraint_space_for_children_, fragment);
DCHECK(opportunity) << "Opportunity is NULL but it shouldn't be";
// Calculate the float offset if needed.
LayoutUnit float_offset;
if (current_child_->Style()->floating() == EFloat::Right) {
float_offset = opportunity->Size().inline_size - fragment.InlineSize();
}
// Add the float as an exclusion.
NGExclusion* exclusion =
CreateExclusion(fragment, opportunity, float_offset, margins);
constraint_space_for_children_->AddExclusion(exclusion);
return CalculateLogicalOffsetForOpportunity(opportunity, border_and_padding_,
float_offset, margins);
}
void NGBlockLayoutAlgorithm::UpdateMarginStrut(const NGMarginStrut& from) { void NGBlockLayoutAlgorithm::UpdateMarginStrut(const NGMarginStrut& from) {
if (!is_fragment_margin_strut_block_start_updated_) { if (!is_fragment_margin_strut_block_start_updated_) {
builder_->SetMarginStrutBlockStart(from); builder_->SetMarginStrutBlockStart(from);
......
...@@ -58,6 +58,26 @@ class CORE_EXPORT NGBlockLayoutAlgorithm : public NGLayoutAlgorithm { ...@@ -58,6 +58,26 @@ class CORE_EXPORT NGBlockLayoutAlgorithm : public NGLayoutAlgorithm {
const NGBoxStrut& child_margins, const NGBoxStrut& child_margins,
const NGFragment& fragment); const NGFragment& fragment);
// Calculates position of the in-flow block-level fragment that needs to be
// positioned relative to the current fragment that is being built.
//
// @param fragment Fragment that needs to be placed.
// @param child_margins Margins information for the current child fragment.
// @param space Constraint space for the block.
// @return Position of the fragment in the parent's constraint space.
NGLogicalOffset PositionFragment(const NGFragment& fragment,
NGBoxStrut child_margins,
const NGConstraintSpace& space);
// Calculates position of the float fragment that needs to be
// positioned relative to the current fragment that is being built.
//
// @param fragment Fragment that needs to be placed.
// @param margins Margins information for the fragment.
// @return Position of the fragment in the parent's constraint space.
NGLogicalOffset PositionFloatFragment(const NGFragment& fragment,
NGBoxStrut margins);
// Updates block-{start|end} of the currently constructed fragment. // Updates block-{start|end} of the currently constructed fragment.
// //
// This method is supposed to be called on every child but it only updates // This method is supposed to be called on every child but it only updates
...@@ -65,6 +85,9 @@ class CORE_EXPORT NGBlockLayoutAlgorithm : public NGLayoutAlgorithm { ...@@ -65,6 +85,9 @@ class CORE_EXPORT NGBlockLayoutAlgorithm : public NGLayoutAlgorithm {
// keeps updating block-end (on every non-zero height child). // keeps updating block-end (on every non-zero height child).
void UpdateMarginStrut(const NGMarginStrut& from); void UpdateMarginStrut(const NGMarginStrut& from);
// Read-only Getters.
const ComputedStyle& Style() const { return *style_; }
RefPtr<const ComputedStyle> style_; RefPtr<const ComputedStyle> style_;
Member<NGBox> first_child_; Member<NGBox> first_child_;
......
...@@ -582,5 +582,60 @@ TEST_F(NGBlockLayoutAlgorithmTest, AutoMargin) { ...@@ -582,5 +582,60 @@ TEST_F(NGBlockLayoutAlgorithmTest, AutoMargin) {
EXPECT_EQ(LayoutUnit(kPaddingLeft + 10), child->LeftOffset()); EXPECT_EQ(LayoutUnit(kPaddingLeft + 10), child->LeftOffset());
EXPECT_EQ(LayoutUnit(0), child->TopOffset()); EXPECT_EQ(LayoutUnit(0), child->TopOffset());
} }
// Verifies that 2 Left/Right float fragments are correctly positioned by the
// algorithm.
//
// Test case's HTML representation:
// <div id="parent" style="width: 200px; height: 200px;">
// <div style="float:left; width: 30px; height: 30px;
// margin: 15px;"/> <!-- DIV1 -->
// <div style="float:right; width: 30px; height: 30px;"/> <!-- DIV2 -->
// </div>
//
// Expected:
// - Left float(DIV1) is positioned at the left.
// - Right float(DIV2) is positioned at the right.
TEST_F(NGBlockLayoutAlgorithmTest, PositionFloatFragments) {
const int kDiv1Margin = 10;
const int kParentSize = 200;
const int kSmallDivSize = 30;
// DIV1
RefPtr<ComputedStyle> div1_style = ComputedStyle::create();
div1_style->setWidth(Length(kSmallDivSize, Fixed));
div1_style->setHeight(Length(kSmallDivSize, Fixed));
div1_style->setFloating(EFloat::Left);
div1_style->setMarginBottom(Length(kDiv1Margin, Fixed));
div1_style->setMarginTop(Length(kDiv1Margin, Fixed));
div1_style->setMarginLeft(Length(kDiv1Margin, Fixed));
div1_style->setMarginRight(Length(kDiv1Margin, Fixed));
NGBox* div1 = new NGBox(div1_style.get());
// DIV2
RefPtr<ComputedStyle> div2_style = ComputedStyle::create();
div2_style->setWidth(Length(kSmallDivSize, Fixed));
div2_style->setHeight(Length(kSmallDivSize, Fixed));
div2_style->setFloating(EFloat::Right);
NGBox* div2 = new NGBox(div2_style.get());
div1->SetNextSibling(div2);
auto* space = new NGConstraintSpace(
HorizontalTopBottom, LeftToRight,
NGLogicalSize(LayoutUnit(kParentSize), LayoutUnit(kParentSize)));
NGPhysicalFragment* frag = RunBlockLayoutAlgorithm(space, div1);
ASSERT_EQ(frag->Children().size(), 2UL);
// div1
const NGPhysicalFragmentBase* child1 = frag->Children()[0];
EXPECT_EQ(kDiv1Margin, child1->TopOffset());
EXPECT_EQ(kDiv1Margin, child1->LeftOffset());
// div2
const NGPhysicalFragmentBase* child2 = frag->Children()[1];
EXPECT_EQ(0, child2->TopOffset());
EXPECT_EQ(kParentSize - kSmallDivSize, child2->LeftOffset());
}
} // namespace } // namespace
} // namespace blink } // namespace blink
...@@ -31,7 +31,7 @@ NGConstraintSpace::NGConstraintSpace(NGWritingMode writing_mode, ...@@ -31,7 +31,7 @@ NGConstraintSpace::NGConstraintSpace(NGWritingMode writing_mode,
NGConstraintSpace::NGConstraintSpace(NGWritingMode writing_mode, NGConstraintSpace::NGConstraintSpace(NGWritingMode writing_mode,
NGDirection direction, NGDirection direction,
const NGConstraintSpace* constraint_space) const NGConstraintSpace* constraint_space)
: physical_space_(constraint_space->PhysicalSpace()), : physical_space_(constraint_space->MutablePhysicalSpace()),
offset_(constraint_space->Offset()), offset_(constraint_space->Offset()),
size_(constraint_space->Size()), size_(constraint_space->Size()),
writing_mode_(writing_mode), writing_mode_(writing_mode),
...@@ -40,7 +40,7 @@ NGConstraintSpace::NGConstraintSpace(NGWritingMode writing_mode, ...@@ -40,7 +40,7 @@ NGConstraintSpace::NGConstraintSpace(NGWritingMode writing_mode,
NGConstraintSpace::NGConstraintSpace(const NGConstraintSpace& other, NGConstraintSpace::NGConstraintSpace(const NGConstraintSpace& other,
NGLogicalOffset offset, NGLogicalOffset offset,
NGLogicalSize size) NGLogicalSize size)
: physical_space_(other.PhysicalSpace()), : physical_space_(other.MutablePhysicalSpace()),
offset_(offset), offset_(offset),
size_(size), size_(size),
writing_mode_(other.WritingMode()), writing_mode_(other.WritingMode()),
...@@ -101,6 +101,10 @@ NGConstraintSpace* NGConstraintSpace::CreateFromLayoutObject( ...@@ -101,6 +101,10 @@ NGConstraintSpace* NGConstraintSpace::CreateFromLayoutObject(
return derived_constraint_space; return derived_constraint_space;
} }
void NGConstraintSpace::AddExclusion(const NGExclusion* exclusion) const {
MutablePhysicalSpace()->AddExclusion(exclusion);
}
NGLogicalSize NGConstraintSpace::ContainerSize() const { NGLogicalSize NGConstraintSpace::ContainerSize() const {
return physical_space_->container_size_.ConvertToLogical( return physical_space_->container_size_.ConvertToLogical(
static_cast<NGWritingMode>(writing_mode_)); static_cast<NGWritingMode>(writing_mode_));
......
...@@ -61,7 +61,16 @@ class CORE_EXPORT NGConstraintSpace final ...@@ -61,7 +61,16 @@ class CORE_EXPORT NGConstraintSpace final
// NGConstraintSpace or a NGPhysicalConstraintSpace. // NGConstraintSpace or a NGPhysicalConstraintSpace.
static NGConstraintSpace* CreateFromLayoutObject(const LayoutBox&); static NGConstraintSpace* CreateFromLayoutObject(const LayoutBox&);
NGPhysicalConstraintSpace* PhysicalSpace() const { return physical_space_; } // Mutable Getters.
// TODO(layout-dev): remove const constraint from MutablePhysicalSpace method
NGPhysicalConstraintSpace* MutablePhysicalSpace() const {
return physical_space_;
}
// Read-only Getters.
const NGPhysicalConstraintSpace* PhysicalSpace() const {
return physical_space_;
}
NGDirection Direction() const { return static_cast<NGDirection>(direction_); } NGDirection Direction() const { return static_cast<NGDirection>(direction_); }
...@@ -69,6 +78,11 @@ class CORE_EXPORT NGConstraintSpace final ...@@ -69,6 +78,11 @@ class CORE_EXPORT NGConstraintSpace final
return static_cast<NGWritingMode>(writing_mode_); return static_cast<NGWritingMode>(writing_mode_);
} }
// Adds the exclusion in the physical constraint space.
// Passing the exclusion ignoring the writing mode is fine here since the
// exclusion is set in physical coordinates.
void AddExclusion(const NGExclusion* exclusion) const;
// Size of the container. Used for the following three cases: // Size of the container. Used for the following three cases:
// 1) Percentage resolution. // 1) Percentage resolution.
// 2) Resolving absolute positions of children. // 2) Resolving absolute positions of children.
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "core/layout/ng/ng_constraint_space.h" #include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_layout_opportunity_iterator.h" #include "core/layout/ng/ng_layout_opportunity_iterator.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
......
...@@ -148,6 +148,10 @@ NGConstraintSpace* GetTopSpace(const NGConstraintSpace& space, ...@@ -148,6 +148,10 @@ NGConstraintSpace* GetTopSpace(const NGConstraintSpace& space,
void InsertExclusion(NGLayoutOpportunityTreeNode* node, void InsertExclusion(NGLayoutOpportunityTreeNode* node,
const NGExclusion* exclusion, const NGExclusion* exclusion,
NGLayoutOpportunities& opportunities) { NGLayoutOpportunities& opportunities) {
// Base case: there is no node.
if (!node)
return;
// Base case: exclusion is not in the node's constraint space. // Base case: exclusion is not in the node's constraint space.
if (!IsExclusionWithinSpace(*node->space, *exclusion)) if (!IsExclusionWithinSpace(*node->space, *exclusion))
return; return;
...@@ -216,9 +220,9 @@ NGLayoutOpportunityIterator::NGLayoutOpportunityIterator( ...@@ -216,9 +220,9 @@ NGLayoutOpportunityIterator::NGLayoutOpportunityIterator(
opportunity_tree_root_ = new NGLayoutOpportunityTreeNode(space); opportunity_tree_root_ = new NGLayoutOpportunityTreeNode(space);
for (const auto exclusion : exclusions) { for (const auto exclusion : exclusions) {
InsertExclusion(opportunity_tree_root_, exclusion, opportunities_); InsertExclusion(MutableOpportunityTreeRoot(), exclusion, opportunities_);
} }
CollectAllOpportunities(opportunity_tree_root_, opportunities_); CollectAllOpportunities(OpportunityTreeRoot(), opportunities_);
std::sort(opportunities_.begin(), opportunities_.end(), std::sort(opportunities_.begin(), opportunities_.end(),
&CompareNGLayoutOpportunitesByStartPoint); &CompareNGLayoutOpportunitesByStartPoint);
opportunity_iter_ = opportunities_.begin(); opportunity_iter_ = opportunities_.begin();
......
...@@ -36,6 +36,16 @@ class CORE_EXPORT NGLayoutOpportunityIterator final ...@@ -36,6 +36,16 @@ class CORE_EXPORT NGLayoutOpportunityIterator final
} }
private: private:
// Mutable Getters.
NGLayoutOpportunityTreeNode* MutableOpportunityTreeRoot() {
return opportunity_tree_root_.get();
}
// Read-only Getters.
const NGLayoutOpportunityTreeNode* OpportunityTreeRoot() const {
return opportunity_tree_root_.get();
}
Member<NGConstraintSpace> constraint_space_; Member<NGConstraintSpace> constraint_space_;
NGLayoutOpportunities opportunities_; NGLayoutOpportunities opportunities_;
......
// Copyright 2016 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_layout_opportunity_tree_node.h"
#include "platform/heap/Handle.h"
#include "core/layout/ng/ng_constraint_space.h"
namespace blink {
NGLayoutOpportunityTreeNode::NGLayoutOpportunityTreeNode(
const NGConstraintSpace* space)
: space(space) {
exclusion_edge.start = space->Offset().inline_offset;
exclusion_edge.end = exclusion_edge.start + space->Size().inline_size;
}
NGLayoutOpportunityTreeNode::NGLayoutOpportunityTreeNode(
NGConstraintSpace* space,
NGEdge exclusion_edge)
: space(space), exclusion_edge(exclusion_edge) {}
DEFINE_TRACE(NGLayoutOpportunityTreeNode) {
visitor->trace(space);
visitor->trace(left);
visitor->trace(bottom);
visitor->trace(right);
visitor->trace(exclusion);
}
} // namespace blink
...@@ -5,30 +5,29 @@ ...@@ -5,30 +5,29 @@
#ifndef NGLayoutOpportunityTreeNode_h #ifndef NGLayoutOpportunityTreeNode_h
#define NGLayoutOpportunityTreeNode_h #define NGLayoutOpportunityTreeNode_h
#include "platform/heap/Handle.h"
#include "core/layout/ng/ng_units.h" #include "core/layout/ng/ng_units.h"
#include "platform/heap/Handle.h"
namespace blink { namespace blink {
class NGConstraintSpace;
struct NGExclusion;
// 3 node R-Tree that represents available space(left, bottom, right) or // 3 node R-Tree that represents available space(left, bottom, right) or
// layout opportunity after the parent spatial rectangle is split by the // layout opportunity after the parent spatial rectangle is split by the
// exclusion rectangle. // exclusion rectangle.
struct NGLayoutOpportunityTreeNode struct CORE_EXPORT NGLayoutOpportunityTreeNode
: public GarbageCollected<NGLayoutOpportunityTreeNode> { : public GarbageCollected<NGLayoutOpportunityTreeNode> {
// Default constructor. // Default constructor.
// Creates a Layout Opportunity tree node that is limited by it's own edge // Creates a Layout Opportunity tree node that is limited by it's own edge
// from above. // from above.
// @param space Constraint space associated with this node. // @param space Constraint space associated with this node.
NGLayoutOpportunityTreeNode(const NGConstraintSpace* space) : space(space) { NGLayoutOpportunityTreeNode(const NGConstraintSpace* space);
exclusion_edge.start = space->Offset().inline_offset;
exclusion_edge.end = exclusion_edge.start + space->Size().inline_size;
}
// Constructor that creates a node with explicitly set exclusion edge. // Constructor that creates a node with explicitly set exclusion edge.
// @param space Constraint space associated with this node. // @param space Constraint space associated with this node.
// @param exclusion_edge Edge that limits this node's space from above. // @param exclusion_edge Edge that limits this node's space from above.
NGLayoutOpportunityTreeNode(NGConstraintSpace* space, NGEdge exclusion_edge) NGLayoutOpportunityTreeNode(NGConstraintSpace* space, NGEdge exclusion_edge);
: space(space), exclusion_edge(exclusion_edge) {}
// Constraint space that is associated with this node. // Constraint space that is associated with this node.
Member<const NGConstraintSpace> space; Member<const NGConstraintSpace> space;
...@@ -48,13 +47,7 @@ struct NGLayoutOpportunityTreeNode ...@@ -48,13 +47,7 @@ struct NGLayoutOpportunityTreeNode
// The node is a leaf if it doen't have an exclusion that splits it apart. // The node is a leaf if it doen't have an exclusion that splits it apart.
bool IsLeafNode() const { return !exclusion; } bool IsLeafNode() const { return !exclusion; }
DEFINE_INLINE_TRACE() { DECLARE_TRACE();
visitor->trace(space);
visitor->trace(left);
visitor->trace(bottom);
visitor->trace(right);
visitor->trace(exclusion);
}
}; };
} // namespace blink } // namespace blink
......
...@@ -68,6 +68,10 @@ struct NGPhysicalSize { ...@@ -68,6 +68,10 @@ struct NGPhysicalSize {
LayoutUnit height; LayoutUnit height;
NGLogicalSize ConvertToLogical(NGWritingMode mode) const; NGLogicalSize ConvertToLogical(NGWritingMode mode) const;
String ToString() const {
return String::format("%dx%d", width.toInt(), height.toInt());
}
}; };
// NGPhysicalLocation is the position of a rect (typically a fragment) relative // NGPhysicalLocation is the position of a rect (typically a fragment) relative
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment