Commit b0eec41c authored by Ian Kilpatrick's avatar Ian Kilpatrick Committed by Commit Bot

[LayoutNG] Fix %-resolution for ancestors of table cells.

This patch does a few things:
1) Introduces the concept of a "ReplacedPercentageResolutionSize".
   This is needed as replaced descandants of table cells have a
   different percentage resolution size than normal descendants.

2) This adds a bunch of special cases for how percentage resolution
   sizes are handled for table cells.

3) Adds the "scrollable" children of table cell quirk. This is during
   the "measure" phase, scrollable children contribute nothing to the
   size of the cell.

4) Adds the "box-sizing: border-box" table cell quirk. That is
   percentage children, during the layout phase, are sized as if they
   have box-sizing: border-box on them.

It was easier to perform all these changes as a single monolithic patch
to ensure correct behaviour.

Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng
Change-Id: I881a21662bfdf6b4ab7a0f62df6970143008ebca
Reviewed-on: https://chromium-review.googlesource.com/1207890
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarDavid Grogan <dgrogan@chromium.org>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#591507}
parent dcd91e38
......@@ -85,7 +85,6 @@ crbug.com/591099 external/wpt/css/css-rhythm/ [ Skip ]
crbug.com/714962 external/wpt/css/css-scroll-anchoring/wrapped-text.html [ Failure ]
crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ Pass ]
crbug.com/845902 external/wpt/css/css-sizing/whitespace-and-break.html [ Pass ]
crbug.com/591099 external/wpt/css/css-tables/height-distribution/percentage-sizing-of-table-cell-children.html [ Failure ]
crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-009.html [ Pass ]
crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-011.html [ Pass ]
crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-ic-002.html [ Pass ]
......@@ -345,7 +344,6 @@ crbug.com/591099 external/wpt/xhr/send-authentication-prompt-2-manual.htm [ Fail
crbug.com/591099 external/wpt/xhr/send-content-type-string.htm [ Pass ]
crbug.com/591099 external/wpt/xhr/send-entity-body-document.htm [ Pass ]
crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
crbug.com/591099 fast/block/basic/quirk-percent-height-table-cell.html [ Failure ]
crbug.com/591099 fast/block/float-avoids-padding-inline-ancestors.html [ Crash ]
crbug.com/591099 fast/block/float/nopaint-after-layer-destruction.html [ Failure ]
crbug.com/591099 fast/block/float/nopaint-after-layer-destruction2.html [ Failure ]
......@@ -386,15 +384,10 @@ crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure ]
crbug.com/591099 fast/sub-pixel/sub-pixel-border-2.html [ Failure ]
crbug.com/591099 fast/table/border-collapsing/004-vertical.html [ Failure ]
crbug.com/591099 fast/table/border-collapsing/composited-cell-collapsed-border.html [ Failure ]
crbug.com/591099 fast/table/dynamic-descendant-percentage-height.html [ Failure ]
crbug.com/591099 fast/table/empty-table-percent-height.html [ Failure ]
crbug.com/591099 fast/table/height-percent-test-vertical.html [ Failure ]
crbug.com/591099 fast/table/percent-height-overflow-auto-content-in-cell.html [ Failure ]
crbug.com/591099 fast/table/percent-height-overflow-scroll-content-in-cell.html [ Failure Pass ]
crbug.com/858998 fast/table/table-continuation-outline-paint-crash.html [ Failure ]
crbug.com/591099 fast/table/table-display-types-vertical.html [ Failure ]
crbug.com/591099 fast/table/unbreakable-images-quirk.html [ Failure ]
crbug.com/591099 fast/table/vertical-align-baseline-readjust.html [ Failure ]
crbug.com/591099 fast/text/descent-clip-in-scaled-page.html [ Failure ]
crbug.com/591099 fast/text/ellipsis-in-relative-inline-right.html [ Failure ]
crbug.com/591099 fast/text/ellipsis-in-relative-inline.html [ Failure ]
......@@ -499,16 +492,9 @@ crbug.com/591099 svg/zoom/page/zoom-svg-through-object-with-absolute-size-2.xhtm
crbug.com/591099 svg/zoom/page/zoom-svg-through-object-with-absolute-size.xhtml [ Failure ]
crbug.com/591099 svg/zoom/page/zoom-svg-through-object-with-percentage-size.xhtml [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug101674.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug131020-2.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug137388-2.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug137388-3.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Pass ]
crbug.com/591099 tables/mozilla/bugs/bug149275-1.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug149275-2.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug18440.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug23235.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug2973.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug30692.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug50695-2.html [ Failure ]
crbug.com/591099 tables/mozilla/bugs/bug55527.html [ Failure ]
crbug.com/591099 tables/mozilla_expected_failures/bugs/bug3166-16.html [ Failure ]
......
<link rel="help" href="https://drafts.csswg.org/css-tables-3/">
<meta name="assert" content="This test checks that table cell children, in quirks mode, don't apply the percentage height quirk to their children." />
<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
<p style="margin-top: 1em;">Test passes if there is a filled green square.</p>
<div style="display:table-cell; height:100px; background:green;">
<div style="width:100px;">
<div style="height:100%; background:red;"></div>
</div>
</div>
<link rel="help" href="https://drafts.csswg.org/css-tables-3/">
<meta name="assert" content="This test checks that table cell children, in quirks mode, pass the correct percentage resolution size to their children." />
<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
<p style="margin-top: 1em;">Test passes if there is a filled green square.</p>
<div style="display:table-cell; height:100px; background:red;">
<div style="width:100px; height: 100%;">
<div style="height:100%; background:green;"></div>
</div>
</div>
......@@ -1012,6 +1012,10 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
virtual LayoutUnit ComputeReplacedLogicalHeight(
LayoutUnit estimated_used_width = LayoutUnit()) const;
virtual bool ShouldComputeSizeAsReplaced() const {
return IsAtomicInlineLevel() && !IsInlineBlockOrInlineTable();
}
// Returns the size that percentage logical heights of this box should be
// resolved against. This function will walk the ancestor chain of this
// object to determine this size.
......@@ -1570,10 +1574,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutUnit intrinsic_content_height,
LayoutUnit border_and_padding) const;
virtual bool ShouldComputeSizeAsReplaced() const {
return IsAtomicInlineLevel() && !IsInlineBlockOrInlineTable();
}
LayoutObject* SplitAnonymousBoxesAroundChild(LayoutObject* before_child);
virtual bool HitTestOverflowControl(HitTestResult&,
......
......@@ -856,6 +856,7 @@ void NGInlineLayoutAlgorithm::PositionPendingFloats(
const Vector<NGPositionedFloat> positioned_floats =
PositionFloats(ConstraintSpace().AvailableSize(),
ConstraintSpace().PercentageResolutionSize(),
ConstraintSpace().ReplacedPercentageResolutionSize(),
origin_bfc_offset, bfc_block_offset, unpositioned_floats_,
ConstraintSpace(), exclusion_space);
......
......@@ -880,6 +880,7 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item) {
NGPositionedFloat positioned_float = PositionFloat(
constraint_space_.AvailableSize(),
constraint_space_.PercentageResolutionSize(),
constraint_space_.ReplacedPercentageResolutionSize(),
{constraint_space_.BfcOffset().line_offset, bfc_block_offset},
constraint_space_.BfcOffset().block_offset, &unpositioned_float,
constraint_space_, exclusion_space_);
......
......@@ -353,8 +353,8 @@ NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset(
scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
NGBoxStrut borders = ComputeBorders(ConstraintSpace(), Node());
NGBoxStrut padding = ComputePadding(ConstraintSpace(), Style()) +
ComputeIntrinsicPadding(ConstraintSpace(), Node());
NGBoxStrut padding = ComputePadding(ConstraintSpace(), Style());
border_padding_ = borders + padding;
NGLogicalSize border_box_size = CalculateBorderBoxSize(
ConstraintSpace(), Node(), CalculateDefaultBlockSize(), border_padding_);
......@@ -380,6 +380,15 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
child_percentage_size_ = CalculateChildPercentageSize(
ConstraintSpace(), Node(), child_available_size_);
replaced_child_percentage_size_ = CalculateReplacedChildPercentageSize(
ConstraintSpace(), Node(), border_box_size, border_scrollbar_padding_,
border_padding_);
// All of the above calculations with border_scrollbar_padding_ shouldn't
// include the table cell's intrinsic padding. We can now add this.
NGBoxStrut intrinsic_padding =
ComputeIntrinsicPadding(ConstraintSpace(), Node());
border_scrollbar_padding_ += intrinsic_padding;
container_builder_.SetInlineSize(border_box_size.inline_size);
container_builder_.SetBfcLineOffset(
......@@ -605,8 +614,12 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
intrinsic_block_size_ = border_scrollbar_padding_.BlockSum();
// Recompute the block-axis size now that we know our content size.
border_box_size.block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), intrinsic_block_size_, border_padding_);
// NOTE: For table cells, the block-size is just the intrinsic block-size.
border_box_size.block_size =
Node().IsTableCell()
? intrinsic_block_size_
: ComputeBlockSizeForFragment(ConstraintSpace(), Style(),
intrinsic_block_size_, border_padding_);
container_builder_.SetBlockSize(border_box_size.block_size);
// If our BFC block offset is still unknown, there's one last thing to take
......@@ -1811,7 +1824,16 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
NGConstraintSpaceBuilder space_builder(ConstraintSpace());
space_builder.SetAvailableSize(child_available_size)
.SetPercentageResolutionSize(child_percentage_size_);
.SetPercentageResolutionSize(child_percentage_size_)
.SetReplacedPercentageResolutionSize(replaced_child_percentage_size_);
if (Node().IsTableCell()) {
// If we have a fixed block-size we are in the "layout" phase.
space_builder.SetTableCellChildLayoutPhase(
ConstraintSpace().IsFixedSizeBlock()
? NGTableCellChildLayoutPhase::kLayout
: NGTableCellChildLayoutPhase::kMeasure);
}
if (NGBaseline::ShouldPropagateBaselines(child))
space_builder.AddBaselineRequests(ConstraintSpace().BaselineRequests());
......@@ -2045,10 +2067,10 @@ void NGBlockLayoutAlgorithm::PositionPendingFloats(
? container_builder_.BfcBlockOffset().value()
: ConstraintSpace().FloatsBfcBlockOffset().value();
const auto positioned_floats =
PositionFloats(child_available_size_, child_percentage_size_,
origin_bfc_offset, bfc_block_offset, unpositioned_floats_,
ConstraintSpace(), &exclusion_space_);
const auto positioned_floats = PositionFloats(
child_available_size_, child_percentage_size_,
replaced_child_percentage_size_, origin_bfc_offset, bfc_block_offset,
unpositioned_floats_, ConstraintSpace(), &exclusion_space_);
AddPositionedFloats(positioned_floats);
......
......@@ -271,6 +271,7 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
NGLogicalSize child_available_size_;
NGLogicalSize child_percentage_size_;
NGLogicalSize replaced_child_percentage_size_;
NGBoxStrut border_padding_;
NGBoxStrut border_scrollbar_padding_;
......
......@@ -139,6 +139,32 @@ NGConstraintSpaceBuilder CreateConstraintSpaceBuilderForMinMax(
.SetFloatsBfcBlockOffset(LayoutUnit());
}
LayoutUnit CalculateAvailableInlineSizeForLegacy(
const LayoutBox& box,
const NGConstraintSpace& space) {
if (box.StyleRef().LogicalWidth().IsPercent()) {
if (box.ShouldComputeSizeAsReplaced())
return space.ReplacedPercentageResolutionSize().inline_size;
return space.PercentageResolutionSize().inline_size;
}
return space.AvailableSize().inline_size;
}
LayoutUnit CalculateAvailableBlockSizeForLegacy(
const LayoutBox& box,
const NGConstraintSpace& space) {
if (box.StyleRef().LogicalHeight().IsPercent()) {
if (box.ShouldComputeSizeAsReplaced())
return space.ReplacedPercentageResolutionSize().block_size;
return space.PercentageResolutionSize().block_size;
}
return space.AvailableSize().block_size;
}
} // namespace
scoped_refptr<NGLayoutResult> NGBlockNode::Layout(
......@@ -718,6 +744,8 @@ scoped_refptr<NGLayoutResult> NGBlockNode::LayoutAtomicInline(
.SetAvailableSize(parent_constraint_space.AvailableSize())
.SetPercentageResolutionSize(
parent_constraint_space.PercentageResolutionSize())
.SetReplacedPercentageResolutionSize(
parent_constraint_space.ReplacedPercentageResolutionSize())
.SetTextDirection(style.Direction())
.ToConstraintSpace(style.GetWritingMode());
return Layout(*constraint_space);
......@@ -737,13 +765,10 @@ scoped_refptr<NGLayoutResult> NGBlockNode::RunOldLayout(
: nullptr;
if (!old_space || box_->NeedsLayout() || *old_space != constraint_space) {
LayoutUnit inline_size =
Style().LogicalWidth().IsPercent()
? constraint_space.PercentageResolutionSize().inline_size
: constraint_space.AvailableSize().inline_size;
CalculateAvailableInlineSizeForLegacy(*box_, constraint_space);
LayoutUnit block_size =
Style().LogicalHeight().IsPercent()
? constraint_space.PercentageResolutionSize().block_size
: constraint_space.AvailableSize().block_size;
CalculateAvailableBlockSizeForLegacy(*box_, constraint_space);
LayoutObject* containing_block = box_->ContainingBlock();
bool parallel_writing_mode;
if (!containing_block) {
......
......@@ -20,11 +20,13 @@ NGConstraintSpace::NGConstraintSpace(
TextDirection direction,
NGLogicalSize available_size,
NGLogicalSize percentage_resolution_size,
NGLogicalSize replaced_percentage_resolution_size,
LayoutUnit parent_percentage_resolution_inline_size,
NGPhysicalSize initial_containing_block_size,
LayoutUnit fragmentainer_block_size,
LayoutUnit fragmentainer_space_at_bfc_start,
NGFragmentationType block_direction_fragmentation_type,
NGTableCellChildLayoutPhase table_cell_child_layout_phase,
NGFloatTypes adjoining_floats,
const NGMarginStrut& margin_strut,
const NGBfcOffset& bfc_offset,
......@@ -35,12 +37,14 @@ NGConstraintSpace::NGConstraintSpace(
unsigned flags)
: available_size_(available_size),
percentage_resolution_size_(percentage_resolution_size),
replaced_percentage_resolution_size_(replaced_percentage_resolution_size),
parent_percentage_resolution_inline_size_(
parent_percentage_resolution_inline_size),
initial_containing_block_size_(initial_containing_block_size),
fragmentainer_block_size_(fragmentainer_block_size),
fragmentainer_space_at_bfc_start_(fragmentainer_space_at_bfc_start),
block_direction_fragmentation_type_(block_direction_fragmentation_type),
table_cell_child_layout_phase_(table_cell_child_layout_phase),
adjoining_floats_(adjoining_floats),
writing_mode_(static_cast<unsigned>(writing_mode)),
direction_(static_cast<unsigned>(direction)),
......@@ -186,6 +190,8 @@ NGFragmentationType NGConstraintSpace::BlockFragmentationType() const {
bool NGConstraintSpace::operator==(const NGConstraintSpace& other) const {
return available_size_ == other.available_size_ &&
percentage_resolution_size_ == other.percentage_resolution_size_ &&
replaced_percentage_resolution_size_ ==
other.replaced_percentage_resolution_size_ &&
parent_percentage_resolution_inline_size_ ==
other.parent_percentage_resolution_inline_size_ &&
initial_containing_block_size_ ==
......@@ -195,6 +201,8 @@ bool NGConstraintSpace::operator==(const NGConstraintSpace& other) const {
other.fragmentainer_space_at_bfc_start_ &&
block_direction_fragmentation_type_ ==
other.block_direction_fragmentation_type_ &&
table_cell_child_layout_phase_ ==
other.table_cell_child_layout_phase_ &&
flags_ == other.flags_ &&
adjoining_floats_ == other.adjoining_floats_ &&
writing_mode_ == other.writing_mode_ &&
......
......@@ -30,6 +30,18 @@ enum NGFragmentationType {
kFragmentRegion
};
// Tables have two passes, a "measure" phase (for determining the table row
// height), and a "layout" phase.
// See: https://drafts.csswg.org/css-tables-3/#row-layout
//
// This enum is used for communicating to *direct* children of table cells,
// which layout phase the table cell is in.
enum NGTableCellChildLayoutPhase {
kNone, // The node isn't a table cell child.
kMeasure, // The node is a table cell child, in the "measure" phase.
kLayout // The node is a table cell child, in the "layout" phase.
};
// The NGConstraintSpace represents a set of constraints and available space
// which a layout algorithm may produce a NGFragment within.
class CORE_EXPORT NGConstraintSpace final
......@@ -78,6 +90,11 @@ class CORE_EXPORT NGConstraintSpace final
return percentage_resolution_size_;
}
// The size to use for percentage resolution of replaced elements.
NGLogicalSize ReplacedPercentageResolutionSize() const {
return replaced_percentage_resolution_size_;
}
// The size to use for percentage resolution for margin/border/padding.
// They are always get computed relative to the inline size, in the parent
// writing mode.
......@@ -162,12 +179,19 @@ class CORE_EXPORT NGConstraintSpace final
// blockSize if possible.
NGFragmentationType BlockFragmentationType() const;
// Return true if this contraint space participates in a fragmentation
// Return true if this constraint space participates in a fragmentation
// context.
bool HasBlockFragmentation() const {
return BlockFragmentationType() != kFragmentNone;
}
// Returns if this node is a table cell child, and which table layout phase
// is occurring.
NGTableCellChildLayoutPhase TableCellChildLayoutPhase() const {
return static_cast<NGTableCellChildLayoutPhase>(
table_cell_child_layout_phase_);
}
NGMarginStrut MarginStrut() const { return margin_strut_; }
// The BfcOffset is where the MarginStrut is placed within the block
......@@ -258,11 +282,13 @@ class CORE_EXPORT NGConstraintSpace final
TextDirection,
NGLogicalSize available_size,
NGLogicalSize percentage_resolution_size,
NGLogicalSize replace_percentage_resolution_size,
LayoutUnit parent_percentage_resolution_inline_size,
NGPhysicalSize initial_containing_block_size,
LayoutUnit fragmentainer_block_size,
LayoutUnit fragmentainer_space_at_bfc_start,
NGFragmentationType block_direction_fragmentation_type,
NGTableCellChildLayoutPhase,
NGFloatTypes adjoining_floats,
const NGMarginStrut& margin_strut,
const NGBfcOffset& bfc_offset,
......@@ -278,6 +304,7 @@ class CORE_EXPORT NGConstraintSpace final
NGLogicalSize available_size_;
NGLogicalSize percentage_resolution_size_;
NGLogicalSize replaced_percentage_resolution_size_;
LayoutUnit parent_percentage_resolution_inline_size_;
NGPhysicalSize initial_containing_block_size_;
......@@ -285,7 +312,8 @@ class CORE_EXPORT NGConstraintSpace final
LayoutUnit fragmentainer_space_at_bfc_start_;
unsigned block_direction_fragmentation_type_ : 2;
unsigned adjoining_floats_ : 2; // NGFloatTypes
unsigned table_cell_child_layout_phase_ : 2; // NGTableCellChildLayoutPhase
unsigned adjoining_floats_ : 2; // NGFloatTypes
unsigned writing_mode_ : 3;
unsigned direction_ : 1;
unsigned flags_ : kNumberOfConstraintSpaceFlags; // ConstraintSpaceFlags
......
......@@ -38,6 +38,13 @@ NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetPercentageResolutionSize(
return *this;
}
NGConstraintSpaceBuilder&
NGConstraintSpaceBuilder::SetReplacedPercentageResolutionSize(
NGLogicalSize replaced_percentage_resolution_size) {
replaced_percentage_resolution_size_ = replaced_percentage_resolution_size;
return *this;
}
NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetTextDirection(
TextDirection text_direction) {
text_direction_ = text_direction;
......@@ -105,6 +112,8 @@ scoped_refptr<NGConstraintSpace> NGConstraintSpaceBuilder::ToConstraintSpace(
NGLogicalSize available_size = available_size_;
NGLogicalSize percentage_resolution_size = percentage_resolution_size_;
NGLogicalSize replaced_percentage_resolution_size =
replaced_percentage_resolution_size_;
NGLogicalSize parent_percentage_resolution_size =
parent_percentage_resolution_size_.value_or(percentage_resolution_size);
......@@ -116,6 +125,7 @@ scoped_refptr<NGConstraintSpace> NGConstraintSpaceBuilder::ToConstraintSpace(
if (!is_in_parallel_flow) {
available_size.Flip();
percentage_resolution_size.Flip();
replaced_percentage_resolution_size.Flip();
parent_percentage_resolution_size.Flip();
SetResolvedFlag(NGConstraintSpace::kFixedSizeInline,
flags_ & NGConstraintSpace::kFixedSizeBlock);
......@@ -147,6 +157,16 @@ scoped_refptr<NGConstraintSpace> NGConstraintSpaceBuilder::ToConstraintSpace(
initial_containing_block_size_.height;
}
}
if (replaced_percentage_resolution_size.inline_size == NGSizeIndefinite) {
DCHECK(!is_in_parallel_flow);
if (out_writing_mode == WritingMode::kHorizontalTb) {
replaced_percentage_resolution_size.inline_size =
initial_containing_block_size_.width;
} else {
replaced_percentage_resolution_size.inline_size =
initial_containing_block_size_.height;
}
}
bool is_new_fc_ = flags_ & NGConstraintSpace::kNewFormattingContext;
DCHECK(!is_new_fc_ || !adjoining_floats_);
......@@ -163,11 +183,13 @@ scoped_refptr<NGConstraintSpace> NGConstraintSpaceBuilder::ToConstraintSpace(
return base::AdoptRef(new NGConstraintSpace(
out_writing_mode, text_direction_, available_size,
percentage_resolution_size, parent_percentage_resolution_size.inline_size,
percentage_resolution_size, replaced_percentage_resolution_size,
parent_percentage_resolution_size.inline_size,
initial_containing_block_size_, fragmentainer_block_size_,
fragmentainer_space_at_bfc_start_, fragmentation_type_, adjoining_floats_,
margin_strut, bfc_offset, floats_bfc_block_offset, exclusion_space,
clearance_offset, baseline_requests_, resolved_flags));
fragmentainer_space_at_bfc_start_, fragmentation_type_,
table_cell_child_layout_phase_, adjoining_floats_, margin_strut,
bfc_offset, floats_bfc_block_offset, exclusion_space, clearance_offset,
baseline_requests_, resolved_flags));
}
} // namespace blink
......@@ -31,8 +31,9 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
NGConstraintSpaceBuilder& SetAvailableSize(NGLogicalSize available_size);
NGConstraintSpaceBuilder& SetPercentageResolutionSize(
NGLogicalSize percentage_resolution_size);
NGConstraintSpaceBuilder& SetPercentageResolutionSize(NGLogicalSize);
NGConstraintSpaceBuilder& SetReplacedPercentageResolutionSize(NGLogicalSize);
NGConstraintSpaceBuilder& SetFragmentainerBlockSize(LayoutUnit size) {
fragmentainer_block_size_ = size;
......@@ -110,6 +111,12 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
return *this;
}
NGConstraintSpaceBuilder& SetTableCellChildLayoutPhase(
NGTableCellChildLayoutPhase table_cell_child_layout_phase) {
table_cell_child_layout_phase_ = table_cell_child_layout_phase;
return *this;
}
NGConstraintSpaceBuilder& SetExclusionSpace(
const NGExclusionSpace& exclusion_space);
......@@ -132,10 +139,11 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
(-(int32_t)value & static_cast<unsigned>(mask));
}
// Relative to parent_writing_mode_.
// NOTE: The below NGLogicalSizes are relative to parent_writing_mode_.
NGLogicalSize available_size_;
// Relative to parent_writing_mode_.
NGLogicalSize percentage_resolution_size_;
NGLogicalSize replaced_percentage_resolution_size_;
base::Optional<NGLogicalSize> parent_percentage_resolution_size_;
NGPhysicalSize initial_containing_block_size_;
LayoutUnit fragmentainer_block_size_ = NGSizeIndefinite;
......@@ -143,6 +151,7 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
WritingMode parent_writing_mode_;
NGFragmentationType fragmentation_type_ = kFragmentNone;
NGTableCellChildLayoutPhase table_cell_child_layout_phase_ = kNone;
NGFloatTypes adjoining_floats_ = kFloatTypeNone;
TextDirection text_direction_ = TextDirection::kLtr;
......
......@@ -62,6 +62,7 @@ NGLayoutOpportunity FindLayoutOpportunityForFloat(
scoped_refptr<NGConstraintSpace> CreateConstraintSpaceForFloat(
const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGLogicalSize& float_replaced_percentage_size,
const NGUnpositionedFloat& unpositioned_float,
const NGConstraintSpace& parent_space,
base::Optional<LayoutUnit> origin_block_offset = base::nullopt) {
......@@ -84,6 +85,7 @@ scoped_refptr<NGConstraintSpace> CreateConstraintSpaceForFloat(
return builder.SetPercentageResolutionSize(float_percentage_size)
.SetAvailableSize(float_available_size)
.SetReplacedPercentageResolutionSize(float_replaced_percentage_size)
.SetIsNewFormattingContext(true)
.SetIsShrinkToFit(true)
.SetTextDirection(style.Direction())
......@@ -93,6 +95,7 @@ scoped_refptr<NGConstraintSpace> CreateConstraintSpaceForFloat(
std::unique_ptr<NGExclusionShapeData> CreateExclusionShapeData(
const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGLogicalSize& float_replaced_percentage_size,
const NGBoxStrut& margins,
const LayoutBox* layout_box,
const NGUnpositionedFloat& unpositioned_float,
......@@ -118,7 +121,8 @@ std::unique_ptr<NGExclusionShapeData> CreateExclusionShapeData(
shape_insets =
ComputeBorders(*CreateConstraintSpaceForFloat(
float_available_size, float_percentage_size,
unpositioned_float, parent_space),
float_replaced_percentage_size, unpositioned_float,
parent_space),
style)
.ConvertToPhysical(style.GetWritingMode(), style.Direction())
.ConvertToLogical(parent_space.GetWritingMode(),
......@@ -126,9 +130,9 @@ std::unique_ptr<NGExclusionShapeData> CreateExclusionShapeData(
break;
case CSSBoxType::kContent:
const scoped_refptr<NGConstraintSpace> space =
CreateConstraintSpaceForFloat(float_available_size,
float_percentage_size,
unpositioned_float, parent_space);
CreateConstraintSpaceForFloat(
float_available_size, float_percentage_size,
float_replaced_percentage_size, unpositioned_float, parent_space);
NGBoxStrut border_padding =
ComputeBorders(*space, style) + ComputePadding(*space, style);
shape_insets =
......@@ -148,6 +152,7 @@ std::unique_ptr<NGExclusionShapeData> CreateExclusionShapeData(
scoped_refptr<NGExclusion> CreateExclusion(
const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGLogicalSize& float_replaced_percentage_size,
const NGFragment& fragment,
const NGBfcOffset& float_margin_bfc_offset,
const NGBoxStrut& margins,
......@@ -166,8 +171,9 @@ scoped_refptr<NGExclusion> CreateExclusion(
std::unique_ptr<NGExclusionShapeData> shape_data =
layout_box->GetShapeOutsideInfo()
? CreateExclusionShapeData(
float_available_size, float_percentage_size, margins,
layout_box, unpositioned_float, parent_space, direction)
float_available_size, float_percentage_size,
float_replaced_percentage_size, margins, layout_box,
unpositioned_float, parent_space, direction)
: nullptr;
return NGExclusion::Create(NGBfcRect(start_offset, end_offset), type,
......@@ -176,16 +182,18 @@ scoped_refptr<NGExclusion> CreateExclusion(
// Performs layout on a float, without fragmentation, and stores the result on
// the NGUnpositionedFloat data-structure.
void LayoutFloatWithoutFragmentation(const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGConstraintSpace& parent_space,
NGUnpositionedFloat* unpositioned_float) {
void LayoutFloatWithoutFragmentation(
const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGLogicalSize& float_replaced_percentage_size,
const NGConstraintSpace& parent_space,
NGUnpositionedFloat* unpositioned_float) {
if (unpositioned_float->layout_result)
return;
const scoped_refptr<NGConstraintSpace> space =
CreateConstraintSpaceForFloat(float_available_size, float_percentage_size,
*unpositioned_float, parent_space);
const scoped_refptr<NGConstraintSpace> space = CreateConstraintSpaceForFloat(
float_available_size, float_percentage_size,
float_replaced_percentage_size, *unpositioned_float, parent_space);
unpositioned_float->layout_result = unpositioned_float->node.Layout(*space);
unpositioned_float->margins =
......@@ -201,9 +209,10 @@ LayoutUnit ComputeMarginBoxInlineSizeForUnpositionedFloat(
// NOTE: We can safely use the parent space's available and percentage size
// as this function should only be called within an inline context.
LayoutFloatWithoutFragmentation(parent_space.AvailableSize(),
parent_space.PercentageResolutionSize(),
parent_space, unpositioned_float);
LayoutFloatWithoutFragmentation(
parent_space.AvailableSize(), parent_space.PercentageResolutionSize(),
parent_space.ReplacedPercentageResolutionSize(), parent_space,
unpositioned_float);
DCHECK(unpositioned_float->layout_result);
const auto& fragment = unpositioned_float->layout_result->PhysicalFragment();
......@@ -215,13 +224,15 @@ LayoutUnit ComputeMarginBoxInlineSizeForUnpositionedFloat(
.ClampNegativeToZero();
}
NGPositionedFloat PositionFloat(const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGBfcOffset& origin_bfc_offset,
LayoutUnit parent_bfc_block_offset,
NGUnpositionedFloat* unpositioned_float,
const NGConstraintSpace& parent_space,
NGExclusionSpace* exclusion_space) {
NGPositionedFloat PositionFloat(
const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGLogicalSize& float_replaced_percentage_size,
const NGBfcOffset& origin_bfc_offset,
LayoutUnit parent_bfc_block_offset,
NGUnpositionedFloat* unpositioned_float,
const NGConstraintSpace& parent_space,
NGExclusionSpace* exclusion_space) {
DCHECK(unpositioned_float);
bool is_same_writing_mode =
......@@ -238,13 +249,15 @@ NGPositionedFloat PositionFloat(const NGLogicalSize& float_available_size,
// inline-size, if there is no block fragmentation.
if (!is_fragmentable) {
LayoutFloatWithoutFragmentation(float_available_size, float_percentage_size,
float_replaced_percentage_size,
parent_space, unpositioned_float);
layout_result = unpositioned_float->layout_result;
fragment_margins = unpositioned_float->margins;
} else {
scoped_refptr<NGConstraintSpace> space = CreateConstraintSpaceForFloat(
float_available_size, float_percentage_size, *unpositioned_float,
parent_space, origin_bfc_offset.block_offset);
float_available_size, float_percentage_size,
float_replaced_percentage_size, *unpositioned_float, parent_space,
origin_bfc_offset.block_offset);
layout_result = unpositioned_float->node.Layout(
*space, unpositioned_float->token.get());
fragment_margins = ComputeMarginsFor(
......@@ -278,10 +291,10 @@ NGPositionedFloat PositionFloat(const NGLogicalSize& float_available_size,
// Add the float as an exclusion.
scoped_refptr<NGExclusion> exclusion = CreateExclusion(
float_available_size, float_percentage_size, float_fragment,
float_margin_bfc_offset, fragment_margins,
unpositioned_float->node.GetLayoutBox(), *unpositioned_float,
parent_space, parent_space.Direction(),
float_available_size, float_percentage_size,
float_replaced_percentage_size, float_fragment, float_margin_bfc_offset,
fragment_margins, unpositioned_float->node.GetLayoutBox(),
*unpositioned_float, parent_space, parent_space.Direction(),
unpositioned_float->IsRight() ? EFloat::kRight : EFloat::kLeft);
exclusion_space->Add(std::move(exclusion));
......@@ -297,6 +310,7 @@ NGPositionedFloat PositionFloat(const NGLogicalSize& float_available_size,
const Vector<NGPositionedFloat> PositionFloats(
const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGLogicalSize& float_replaced_percentage_size,
const NGBfcOffset& origin_bfc_offset,
LayoutUnit parent_bfc_block_offset,
NGUnpositionedFloatVector& unpositioned_floats,
......@@ -307,7 +321,8 @@ const Vector<NGPositionedFloat> PositionFloats(
for (NGUnpositionedFloat& unpositioned_float : unpositioned_floats) {
positioned_floats.push_back(PositionFloat(
float_available_size, float_percentage_size, origin_bfc_offset,
float_available_size, float_percentage_size,
float_replaced_percentage_size, origin_bfc_offset,
parent_bfc_block_offset, &unpositioned_float, space, exclusion_space));
}
......
......@@ -42,6 +42,7 @@ CORE_EXPORT LayoutUnit ComputeMarginBoxInlineSizeForUnpositionedFloat(
CORE_EXPORT NGPositionedFloat
PositionFloat(const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGLogicalSize& float_replaced_percentage_size,
const NGBfcOffset& origin_bfc_offset,
LayoutUnit parent_bfc_block_offset,
NGUnpositionedFloat*,
......@@ -53,6 +54,7 @@ PositionFloat(const NGLogicalSize& float_available_size,
CORE_EXPORT const Vector<NGPositionedFloat> PositionFloats(
const NGLogicalSize& float_available_size,
const NGLogicalSize& float_percentage_size,
const NGLogicalSize& float_replaced_percentage_size,
const NGBfcOffset& origin_bfc_offset,
LayoutUnit container_block_offset,
NGUnpositionedFloatVector& unpositioned_floats,
......
......@@ -132,6 +132,10 @@ bool NGLayoutInputNode::IsDocumentElement() const {
return box_->IsDocumentElement();
}
bool NGLayoutInputNode::IsFlexItem() const {
return IsBlock() && box_->IsFlexItem();
}
bool NGLayoutInputNode::CreatesNewFormattingContext() const {
return IsBlock() && box_->AvoidsFloats();
}
......
......@@ -67,6 +67,7 @@ class CORE_EXPORT NGLayoutInputNode {
bool IsFixedContainer() const;
bool IsBody() const;
bool IsDocumentElement() const;
bool IsFlexItem() const;
bool ShouldBeConsideredAsReplaced() const;
bool IsListItem() const;
bool IsListMarker() const;
......
......@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
#include "third_party/blink/renderer/platform/length.h"
......@@ -169,6 +170,16 @@ LayoutUnit ResolveBlockLength(
if (type == LengthResolveType::kMinSize && length.IsAuto())
return border_and_padding.BlockSum();
// Scrollable percentage-sized children of table cells, in the table
// "measure" phase contribute nothing to the row height measurement.
// See: https://drafts.csswg.org/css-tables-3/#row-layout
if (length.IsPercentOrCalc() &&
constraint_space.TableCellChildLayoutPhase() ==
NGTableCellChildLayoutPhase::kMeasure &&
(style.OverflowY() == EOverflow::kAuto ||
style.OverflowY() == EOverflow::kScroll))
return border_and_padding.BlockSum();
bool is_percentage_indefinite =
constraint_space.PercentageResolutionSize().block_size ==
NGSizeIndefinite;
......@@ -204,10 +215,18 @@ LayoutUnit ResolveBlockLength(
LayoutUnit percentage_resolution_size =
constraint_space.PercentageResolutionSize().block_size;
LayoutUnit value = ValueForLength(length, percentage_resolution_size);
if (style.BoxSizing() == EBoxSizing::kContentBox) {
value += border_and_padding.BlockSum();
} else {
// Percentage-sized children of table cells, in the table "layout" phase,
// pretend they have box-sizing: border-box.
// TODO(crbug.com/285744): FF/Edge don't do this. Determine if there
// would be compat issues for matching their behavior.
if (style.BoxSizing() == EBoxSizing::kBorderBox ||
(length.IsPercentOrCalc() &&
constraint_space.TableCellChildLayoutPhase() ==
NGTableCellChildLayoutPhase::kLayout)) {
value = std::max(border_and_padding.BlockSum(), value);
} else {
value += border_and_padding.BlockSum();
}
return value;
}
......@@ -460,19 +479,14 @@ LayoutUnit ComputeInlineSizeForFragment(
return ConstrainByMinMax(extent, min, max);
}
LayoutUnit ComputeBlockSizeForFragment(
namespace {
// Computes the block-size for a fragment, ignoring the fixed block-size if set.
LayoutUnit ComputeBlockSizeForFragmentInternal(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
LayoutUnit content_size,
const base::Optional<NGBoxStrut>& border_padding) {
if (constraint_space.IsFixedSizeBlock())
return constraint_space.AvailableSize().block_size;
if (style.Display() == EDisplay::kTableCell) {
// All handled by the table layout code or not applicable.
return content_size;
}
LayoutUnit extent =
ResolveBlockLength(constraint_space, style, style.LogicalHeight(),
content_size, LengthResolveType::kContentSize,
......@@ -492,6 +506,20 @@ LayoutUnit ComputeBlockSizeForFragment(
return ConstrainByMinMax(extent, min, max);
}
} // namespace
LayoutUnit ComputeBlockSizeForFragment(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
LayoutUnit content_size,
const base::Optional<NGBoxStrut>& border_padding) {
if (constraint_space.IsFixedSizeBlock())
return constraint_space.AvailableSize().block_size;
return ComputeBlockSizeForFragmentInternal(constraint_space, style,
content_size, border_padding);
}
// Computes size for a replaced element.
NGLogicalSize ComputeReplacedSize(
const NGLayoutInputNode& node,
......@@ -954,6 +982,37 @@ NGLogicalSize CalculateContentBoxSize(
return size;
}
namespace {
// Implements the common part of the child percentage size calculation. Deals
// with how percentages are propagated from parent to child in quirks mode.
NGLogicalSize AdjustChildPercentageSizeForQuirksAndFlex(
const NGConstraintSpace& space,
const NGBlockNode node,
NGLogicalSize child_percentage_size,
LayoutUnit parent_percentage_block_size) {
// Flex items may have a fixed block-size, but children shouldn't resolve
// their percentages against this.
if (space.IsFixedSizeBlock() && !space.FixedSizeBlockIsDefinite()) {
DCHECK(node.IsFlexItem());
child_percentage_size.block_size = NGSizeIndefinite;
return child_percentage_size;
}
// In quirks mode the percentage resolution height is passed from parent to
// child.
// https://quirks.spec.whatwg.org/#the-percentage-height-calculation-quirk
if (child_percentage_size.block_size == NGSizeIndefinite &&
node.GetDocument().InQuirksMode() && !node.Style().IsDisplayTableType() &&
!node.Style().HasOutOfFlowPosition()) {
child_percentage_size.block_size = parent_percentage_block_size;
}
return child_percentage_size;
}
} // namespace
NGLogicalSize CalculateChildPercentageSize(
const NGConstraintSpace& space,
const NGBlockNode node,
......@@ -964,20 +1023,60 @@ NGLogicalSize CalculateChildPercentageSize(
NGLogicalSize child_percentage_size = child_available_size;
if (space.IsFixedSizeBlock() && !space.FixedSizeBlockIsDefinite())
bool is_table_cell_in_measure_phase =
node.IsTableCell() && !space.IsFixedSizeBlock();
// Table cells which are measuring their content, force their children to
// have an indefinite percentage resolution size.
if (is_table_cell_in_measure_phase) {
child_percentage_size.block_size = NGSizeIndefinite;
return child_percentage_size;
}
// In quirks mode the percentage resolution height is passed from parent to
// child.
// https://quirks.spec.whatwg.org/#the-percentage-height-calculation-quirk
if (child_percentage_size.block_size == NGSizeIndefinite &&
node.GetDocument().InQuirksMode() && !node.Style().IsDisplayTableType() &&
!node.Style().HasOutOfFlowPosition()) {
child_percentage_size.block_size =
space.PercentageResolutionSize().block_size;
// Table cell children don't apply the "percentage-quirk". I.e. if their
// percentage resolution block-size is indefinite, they don't pass through
// their parent's percentage resolution block-size.
if (space.TableCellChildLayoutPhase() != NGTableCellChildLayoutPhase::kNone)
return child_percentage_size;
return AdjustChildPercentageSizeForQuirksAndFlex(
space, node, child_percentage_size,
space.PercentageResolutionSize().block_size);
}
NGLogicalSize CalculateReplacedChildPercentageSize(
const NGConstraintSpace& space,
const NGBlockNode node,
NGLogicalSize border_box_size,
const NGBoxStrut& border_scrollbar_padding,
const NGBoxStrut& border_padding) {
// Anonymous block or spaces should pass the percent size straight through.
if (space.IsAnonymous() || node.IsAnonymousBlock())
return space.ReplacedPercentageResolutionSize();
bool has_resolvable_block_size = !node.Style().LogicalHeight().IsAuto() ||
!node.Style().LogicalMinHeight().IsAuto();
bool is_table_cell_in_layout_phase =
node.IsTableCell() && space.IsFixedSizeBlock();
// Table cells in the "layout" phase have a fixed block-size. However
// replaced children should resolve their percentages against the size given
// in the "measure" phase.
//
// To handle this we recalculate the border-box block-size, ignoring the
// fixed size constraint.
if (is_table_cell_in_layout_phase && has_resolvable_block_size) {
border_box_size.block_size = ComputeBlockSizeForFragmentInternal(
space, node.Style(), NGSizeIndefinite, border_padding);
}
return child_percentage_size;
NGLogicalSize child_percentage_size =
CalculateContentBoxSize(border_box_size, border_scrollbar_padding);
return AdjustChildPercentageSizeForQuirksAndFlex(
space, node, child_percentage_size,
space.ReplacedPercentageResolutionSize().block_size);
}
} // namespace blink
......@@ -257,12 +257,22 @@ NGLogicalSize CalculateContentBoxSize(
const NGLogicalSize border_box_size,
const NGBoxStrut& border_scrollbar_padding);
// Calculates the percentage resolution size children of node should use.
// Calculates the percentage resolution size that children of the node should
// use.
NGLogicalSize CalculateChildPercentageSize(
const NGConstraintSpace&,
const NGBlockNode node,
const NGLogicalSize& child_available_size);
// Calculates the percentage resolution size that replaced children of the node
// should use.
NGLogicalSize CalculateReplacedChildPercentageSize(
const NGConstraintSpace&,
const NGBlockNode node,
NGLogicalSize border_box_size,
const NGBoxStrut& border_scrollbar_padding,
const NGBoxStrut& border_padding);
} // namespace blink
#endif // NGLengthUtils_h
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