Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(683)

Unified Diff: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc

Issue 2435803005: Initial implementation of LayoutNG's block layout algorithm for floats. (Closed)
Patch Set: fix PositionFragment's doc, added TODO to fix floats with margins and add more test expectations. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 83dc704dc140f08afb9ca7375eecc29a49f333ac..24ec11459275cba7c3080c5c31a4fd5e59c7a85d 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -7,6 +7,7 @@
#include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_fragment_builder.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_units.h"
#include "core/style/ComputedStyle.h"
@@ -24,6 +25,78 @@ LayoutUnit ComputeCollapsedMarginBlockStart(
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.
//
// This will *NOT* check the following cases:
@@ -76,16 +149,16 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space,
switch (state_) {
case kStateInit: {
border_and_padding_ =
- ComputeBorders(*style_) + ComputePadding(*constraint_space, *style_);
+ ComputeBorders(Style()) + ComputePadding(*constraint_space, Style());
LayoutUnit inline_size =
- ComputeInlineSizeForFragment(*constraint_space, *style_);
+ ComputeInlineSizeForFragment(*constraint_space, Style());
LayoutUnit adjusted_inline_size =
inline_size - border_and_padding_.InlineSum();
// TODO(layout-ng): For quirks mode, should we pass blockSize instead of
// -1?
LayoutUnit block_size = ComputeBlockSizeForFragment(
- *constraint_space, *style_, NGSizeIndefinite);
+ *constraint_space, Style(), NGSizeIndefinite);
LayoutUnit adjusted_block_size(block_size);
// Our calculated block-axis size may be indefinite at this point.
// If so, just leave the size as NGSizeIndefinite instead of subtracting
@@ -93,8 +166,8 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space,
if (adjusted_block_size != NGSizeIndefinite)
adjusted_block_size -= border_and_padding_.BlockSum();
constraint_space_for_children_ = new NGConstraintSpace(
- FromPlatformWritingMode(style_->getWritingMode()),
- FromPlatformDirection(style_->direction()), *constraint_space,
+ FromPlatformWritingMode(Style().getWritingMode()),
+ FromPlatformDirection(Style().direction()), *constraint_space,
NGLogicalSize(adjusted_inline_size, adjusted_block_size));
content_size_ = border_and_padding_.block_start;
@@ -115,27 +188,24 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space,
NGFragment* fragment;
if (!current_child_->Layout(constraint_space_for_children_, &fragment))
return false;
+
NGBoxStrut child_margins = ComputeMargins(
*constraint_space_for_children_, *current_child_->Style(),
constraint_space_for_children_->WritingMode(),
constraint_space_for_children_->Direction());
- ApplyAutoMargins(*constraint_space_for_children_,
- *current_child_->Style(), *fragment, child_margins);
-
- const NGBoxStrut margins =
- CollapseMargins(*constraint_space, child_margins, *fragment);
-
- // TODO(layout-ng): Support auto margins
- builder_->AddChild(
- fragment, NGLogicalOffset(border_and_padding_.inline_start +
- child_margins.inline_start,
- content_size_ + margins.block_start));
-
- content_size_ += fragment->BlockSize() + margins.BlockSum();
- max_inline_size_ =
- std::max(max_inline_size_, fragment->InlineSize() +
- child_margins.InlineSum() +
- border_and_padding_.InlineSum());
+
+ NGLogicalOffset fragment_offset;
+ if (current_child_->Style()->isFloating()) {
+ fragment_offset = PositionFloatFragment(*fragment, child_margins);
+ } else {
+ // TODO(layout-ng): move ApplyAutoMargins to PositionFragment
+ ApplyAutoMargins(*constraint_space_for_children_,
+ *current_child_->Style(), *fragment, child_margins);
+ fragment_offset =
+ PositionFragment(*fragment, child_margins, *constraint_space);
+ }
+ builder_->AddChild(fragment, fragment_offset);
+
current_child_ = current_child_->NextSibling();
if (current_child_)
return false;
@@ -148,7 +218,7 @@ bool NGBlockLayoutAlgorithm::Layout(const NGConstraintSpace* constraint_space,
// Recompute the block-axis size now that we know our content size.
LayoutUnit block_size = ComputeBlockSizeForFragment(
- *constraint_space, *style_, content_size_);
+ *constraint_space, Style(), content_size_);
builder_->SetBlockSize(block_size)
.SetInlineOverflow(max_inline_size_)
@@ -230,6 +300,48 @@ NGBoxStrut NGBlockLayoutAlgorithm::CollapseMargins(
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) {
if (!is_fragment_margin_strut_block_start_updated_) {
builder_->SetMarginStrutBlockStart(from);

Powered by Google App Engine
This is Rietveld 408576698