Commit 343dcb4f authored by Ian Kilpatrick's avatar Ian Kilpatrick Committed by Commit Bot

[LayoutNG] Optimize resolving lengths.

This patch splits up resolving different types of lengths (min, max,
and content) into their own functions.

This has two effects:
1) The functions are now (arguably) easier to follow. All of the
   preamble logic within ResolveInlineLength/ResolveBlockLength are
   moved to their respective functions.

2) Slightly faster in the common cases due to less branches.

Bug: 635619
Change-Id: I35d305b458f4dfbb25cb6f55c21db2d3361e046e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1533385
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarAleks Totic <atotic@chromium.org>
Reviewed-by: default avatarChristian Biesinger <cbiesinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#645313}
parent 05564265
......@@ -50,12 +50,12 @@ LayoutUnit ConstrainColumnBlockSize(LayoutUnit size,
ComputeBorders(space, node) + ComputePadding(space, node.Style());
const ComputedStyle& style = node.Style();
LayoutUnit max = ResolveBlockLength(
space, style, border_padding, style.LogicalMaxHeight(), size,
LengthResolveType::kMaxSize, LengthResolvePhase::kLayout);
LayoutUnit extent = ResolveBlockLength(
space, style, border_padding, style.LogicalHeight(), size,
LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
LayoutUnit max = ResolveMaxBlockLength(space, style, border_padding,
style.LogicalMaxHeight(), size,
LengthResolvePhase::kLayout);
LayoutUnit extent = ResolveMainBlockLength(space, style, border_padding,
style.LogicalHeight(), size,
LengthResolvePhase::kLayout);
if (extent != NGSizeIndefinite) {
// A specified height/width will just constrain the maximum length.
max = std::min(max, extent);
......
......@@ -121,17 +121,16 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
DCHECK(!length_to_resolve.IsAuto());
if (MainAxisIsInlineAxis(child)) {
flex_base_border_box = ResolveInlineLength(
flex_base_border_box = ResolveMainInlineLength(
child_space, child_style, border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, length_to_resolve,
LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
intrinsic_sizes_border_box, length_to_resolve);
} else {
// Flex container's main axis is in child's block direction. Child's
// flex basis is in child's block direction.
flex_base_border_box = ResolveBlockLength(
flex_base_border_box = ResolveMainBlockLength(
child_space, child_style, border_padding_in_child_writing_mode,
length_to_resolve, fragment_in_child_writing_mode.BlockSize(),
LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
LengthResolvePhase::kLayout);
}
}
......@@ -153,15 +152,14 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
const Length& max = is_horizontal_flow ? child.Style().MaxWidth()
: child.Style().MaxHeight();
if (MainAxisIsInlineAxis(child)) {
min_max_sizes_in_main_axis_direction.max_size = ResolveInlineLength(
min_max_sizes_in_main_axis_direction.max_size = ResolveMaxInlineLength(
child_space, child_style, border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, max, LengthResolveType::kMaxSize,
LengthResolvePhase::kLayout);
intrinsic_sizes_border_box, max, LengthResolvePhase::kLayout);
} else {
min_max_sizes_in_main_axis_direction.max_size = ResolveBlockLength(
min_max_sizes_in_main_axis_direction.max_size = ResolveMaxBlockLength(
child_space, child_style, border_padding_in_child_writing_mode, max,
fragment_in_child_writing_mode.BlockSize(),
LengthResolveType::kMaxSize, LengthResolvePhase::kLayout);
LengthResolvePhase::kLayout);
}
const Length& min = is_horizontal_flow ? child.Style().MinWidth()
......@@ -173,15 +171,14 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
// LayoutFlexibleBox::ComputeMinAndMaxSizesForChild
}
} else if (MainAxisIsInlineAxis(child)) {
min_max_sizes_in_main_axis_direction.min_size = ResolveInlineLength(
min_max_sizes_in_main_axis_direction.min_size = ResolveMinInlineLength(
child_space, child_style, border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, min, LengthResolveType::kMinSize,
LengthResolvePhase::kLayout);
intrinsic_sizes_border_box, min, LengthResolvePhase::kLayout);
} else {
min_max_sizes_in_main_axis_direction.min_size = ResolveBlockLength(
min_max_sizes_in_main_axis_direction.min_size = ResolveMinBlockLength(
child_space, child_style, border_padding_in_child_writing_mode, min,
fragment_in_child_writing_mode.BlockSize(),
LengthResolveType::kMinSize, LengthResolvePhase::kLayout);
LengthResolvePhase::kLayout);
}
algorithm_
......
......@@ -76,7 +76,7 @@ inline bool InlineLengthMayChange(const ComputedStyle& style,
const NGLayoutResult& layout_result) {
DCHECK_EQ(new_space.IsShrinkToFit(), old_space.IsShrinkToFit());
#if DCHECK_IS_ON()
if (type == LengthResolveType::kContentSize && new_space.IsShrinkToFit())
if (type == LengthResolveType::kMainSize && new_space.IsShrinkToFit())
DCHECK(length.IsAuto());
#endif
......@@ -97,7 +97,7 @@ inline bool InlineLengthMayChange(const ComputedStyle& style,
// where we can skip relayout if the element was sized to its min-content or
// max-content size.
bool is_content_shrink_to_fit =
type == LengthResolveType::kContentSize &&
type == LengthResolveType::kMainSize &&
(new_space.IsShrinkToFit() || length.IsFitContent());
if (is_content_shrink_to_fit) {
......@@ -156,7 +156,7 @@ bool SizeMayChange(const ComputedStyle& style,
return true;
} else {
if (InlineLengthMayChange(style, style.LogicalWidth(),
LengthResolveType::kContentSize, new_space,
LengthResolveType::kMainSize, new_space,
old_space, layout_result) ||
InlineLengthMayChange(style, style.LogicalMinWidth(),
LengthResolveType::kMinSize, new_space, old_space,
......
......@@ -34,8 +34,8 @@ enum class LengthResolvePhase { kIntrinsic, kLayout };
// based on its CSS property. E.g.
// kMinSize - min-width / min-height
// kMaxSize - max-width / max-height
// kContentSize - width / height
enum class LengthResolveType { kMinSize, kMaxSize, kContentSize };
// kMainSize - width / height
enum class LengthResolveType { kMinSize, kMaxSize, kMainSize };
inline bool NeedMinMaxSize(const ComputedStyle& style) {
// This check is technically too broad (fill-available does not need intrinsic
......@@ -47,7 +47,7 @@ inline bool NeedMinMaxSize(const ComputedStyle& style) {
}
// Whether the caller needs to compute min-content and max-content sizes to
// pass them to ResolveInlineLength / ComputeInlineSizeForFragment.
// pass them to ResolveMainInlineLength / ComputeInlineSizeForFragment.
// If this function returns false, it is safe to pass an empty
// MinMaxSize struct to those functions.
inline bool NeedMinMaxSize(const NGConstraintSpace& constraint_space,
......@@ -63,35 +63,146 @@ inline bool NeedMinMaxSize(const NGConstraintSpace& constraint_space,
CORE_EXPORT bool NeedMinMaxSizeForContentContribution(WritingMode mode,
const ComputedStyle&);
// Resolve means translate a Length to a LayoutUnit, using parent info
// (represented by ConstraintSpace) as necessary for things like percents.
// - |MinMaxSize| is only used when the length is intrinsic (fit-content, etc).
// Returns if the given |Length| is unresolvable, e.g. the length is %-based
// during the intrinsic phase.
CORE_EXPORT bool InlineLengthUnresolvable(const Length&, LengthResolvePhase);
CORE_EXPORT bool BlockLengthUnresolvable(
const NGConstraintSpace&,
const Length&,
LengthResolvePhase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr);
// Resolve means translate a Length to a LayoutUnit.
// - |NGConstraintSpace| the information given by the parent, e.g. the
// available-size.
// - |ComputedStyle| the style of the node.
// - |border_padding| the resolved border, and padding of the node.
// - |MinMaxSize| is only used when the length is intrinsic (fit-content).
// - |Length| is the length to resolve.
// - |LengthResolveType| is the type of length function, based on its CSS
// property (see definition above).
// - |LengthResolveType| indicates what type of layout pass we are within (see
// definition above).
CORE_EXPORT LayoutUnit ResolveInlineLength(const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>&,
const Length&,
LengthResolveType,
LengthResolvePhase);
// Same as ResolveInlineLength, except here |content_size| roughly plays the
// part of |MinMaxSize|.
CORE_EXPORT LayoutUnit ResolveBlockLength(
CORE_EXPORT LayoutUnit
ResolveInlineLengthInternal(const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>&,
const Length&);
// Same as ResolveInlineLengthInternal, except here |content_size| roughly plays
// the part of |MinMaxSize|.
CORE_EXPORT LayoutUnit ResolveBlockLengthInternal(
const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
const Length&,
LayoutUnit content_size,
LengthResolveType,
LengthResolvePhase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr);
// Used for resolving min inline lengths, (|ComputedStyle::MinLogicalWidth|).
inline LayoutUnit ResolveMinInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_and_max,
const Length& length,
LengthResolvePhase phase) {
if (LIKELY(length.IsAuto() || InlineLengthUnresolvable(length, phase)))
return border_padding.InlineSum();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_and_max, length);
}
// Used for resolving max inline lengths, (|ComputedStyle::MaxLogicalWidth|).
inline LayoutUnit ResolveMaxInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_and_max,
const Length& length,
LengthResolvePhase phase) {
if (LIKELY(length.IsMaxSizeNone() || InlineLengthUnresolvable(length, phase)))
return LayoutUnit::Max();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_and_max, length);
}
// Used for resolving main inline lengths, (|ComputedStyle::LogicalWidth|).
inline LayoutUnit ResolveMainInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_and_max,
const Length& length) {
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_and_max, length);
}
// Used for resolving min block lengths, (|ComputedStyle::MinLogicalHeight|).
inline LayoutUnit ResolveMinBlockLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
LayoutUnit content_size,
LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
if (LIKELY(length.IsAuto() ||
BlockLengthUnresolvable(
constraint_space, length, phase,
opt_percentage_resolution_block_size_for_min_max)))
return border_padding.BlockSum();
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, content_size, phase,
opt_percentage_resolution_block_size_for_min_max);
}
// Used for resolving max block lengths, (|ComputedStyle::MaxLogicalHeight|).
inline LayoutUnit ResolveMaxBlockLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
LayoutUnit content_size,
LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
if (LIKELY(length.IsMaxSizeNone() ||
BlockLengthUnresolvable(
constraint_space, length, phase,
opt_percentage_resolution_block_size_for_min_max)))
return LayoutUnit::Max();
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, content_size, phase,
opt_percentage_resolution_block_size_for_min_max);
}
// Used for resolving main block lengths, (|ComputedStyle::LogicalHeight|).
inline LayoutUnit ResolveMainBlockLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
LayoutUnit content_size,
LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
if (UNLIKELY((length.IsPercentOrCalc() || length.IsFillAvailable()) &&
BlockLengthUnresolvable(
constraint_space, length, phase,
opt_percentage_resolution_block_size_for_min_max)))
return content_size;
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, content_size, phase,
opt_percentage_resolution_block_size_for_min_max);
}
// For the given style and min/max content sizes, computes the min and max
// content contribution (https://drafts.csswg.org/css-sizing/#contributions).
// This is similar to ComputeInlineSizeForFragment except that it does not
......
......@@ -40,31 +40,50 @@ class NGLengthUtilsTest : public testing::Test {
protected:
void SetUp() override { style_ = ComputedStyle::Create(); }
LayoutUnit ResolveInlineLength(
LayoutUnit ResolveMainInlineLength(
const Length& length,
const base::Optional<MinMaxSize>& sizes = base::nullopt) {
NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
return ::blink::ResolveMainInlineLength(constraint_space, *style_,
border_padding, sizes, length);
}
LayoutUnit ResolveMinInlineLength(
const Length& length,
LengthResolveType type = LengthResolveType::kContentSize,
LengthResolvePhase phase = LengthResolvePhase::kLayout,
const base::Optional<MinMaxSize>& sizes = base::nullopt) {
NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
return ::blink::ResolveInlineLength(
constraint_space, *style_, border_padding, sizes, length, type, phase);
return ::blink::ResolveMinInlineLength(
constraint_space, *style_, border_padding, sizes, length, phase);
}
LayoutUnit ResolveBlockLength(
LayoutUnit ResolveMaxInlineLength(
const Length& length,
LengthResolveType type = LengthResolveType::kContentSize,
LengthResolvePhase phase = LengthResolvePhase::kLayout,
LayoutUnit content_size = LayoutUnit()) {
const base::Optional<MinMaxSize>& sizes = base::nullopt) {
NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
return ::blink::ResolveBlockLength(constraint_space, *style_,
border_padding, length, content_size,
type, phase);
return ::blink::ResolveMaxInlineLength(
constraint_space, *style_, border_padding, sizes, length, phase);
}
LayoutUnit ResolveMainBlockLength(const Length& length,
LayoutUnit content_size = LayoutUnit()) {
NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
return ::blink::ResolveMainBlockLength(constraint_space, *style_,
border_padding, length, content_size,
LengthResolvePhase::kLayout);
}
LayoutUnit ComputeBlockSizeForFragment(
......@@ -105,57 +124,45 @@ class NGLengthUtilsTestWithNode : public NGLayoutTest {
};
TEST_F(NGLengthUtilsTest, testResolveInlineLength) {
EXPECT_EQ(LayoutUnit(60), ResolveInlineLength(Length::Percent(30)));
EXPECT_EQ(LayoutUnit(150), ResolveInlineLength(Length::Fixed(150)));
EXPECT_EQ(LayoutUnit(0),
ResolveInlineLength(Length::Auto(), LengthResolveType::kMinSize,
LengthResolvePhase::kIntrinsic));
EXPECT_EQ(LayoutUnit(200), ResolveInlineLength(Length::Auto()));
EXPECT_EQ(LayoutUnit(200), ResolveInlineLength(Length::FillAvailable()));
EXPECT_EQ(
LayoutUnit::Max(),
ResolveInlineLength(Length::Percent(30), LengthResolveType::kMaxSize,
LengthResolvePhase::kIntrinsic));
EXPECT_EQ(
LayoutUnit::Max(),
ResolveInlineLength(Length::FillAvailable(), LengthResolveType::kMaxSize,
LengthResolvePhase::kIntrinsic));
EXPECT_EQ(LayoutUnit(60), ResolveMainInlineLength(Length::Percent(30)));
EXPECT_EQ(LayoutUnit(150), ResolveMainInlineLength(Length::Fixed(150)));
EXPECT_EQ(LayoutUnit(0), ResolveMinInlineLength(
Length::Auto(), LengthResolvePhase::kIntrinsic));
EXPECT_EQ(LayoutUnit(200), ResolveMainInlineLength(Length::Auto()));
EXPECT_EQ(LayoutUnit(200), ResolveMainInlineLength(Length::FillAvailable()));
EXPECT_EQ(LayoutUnit::Max(),
ResolveMaxInlineLength(Length::Percent(30),
LengthResolvePhase::kIntrinsic));
EXPECT_EQ(LayoutUnit::Max(),
ResolveMaxInlineLength(Length::FillAvailable(),
LengthResolvePhase::kIntrinsic));
MinMaxSize sizes;
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
EXPECT_EQ(
LayoutUnit(30),
ResolveInlineLength(Length::MinContent(), LengthResolveType::kContentSize,
LengthResolvePhase::kLayout, sizes));
EXPECT_EQ(
LayoutUnit(40),
ResolveInlineLength(Length::MaxContent(), LengthResolveType::kContentSize,
LengthResolvePhase::kLayout, sizes));
EXPECT_EQ(
LayoutUnit(40),
ResolveInlineLength(Length::FitContent(), LengthResolveType::kContentSize,
LengthResolvePhase::kLayout, sizes));
EXPECT_EQ(LayoutUnit(30),
ResolveMainInlineLength(Length::MinContent(), sizes));
EXPECT_EQ(LayoutUnit(40),
ResolveMainInlineLength(Length::MaxContent(), sizes));
EXPECT_EQ(LayoutUnit(40),
ResolveMainInlineLength(Length::FitContent(), sizes));
sizes.max_size = LayoutUnit(800);
EXPECT_EQ(
LayoutUnit(200),
ResolveInlineLength(Length::FitContent(), LengthResolveType::kContentSize,
LengthResolvePhase::kLayout, sizes));
EXPECT_EQ(LayoutUnit(200),
ResolveMainInlineLength(Length::FitContent(), sizes));
#if DCHECK_IS_ON()
// This should fail a DCHECK.
EXPECT_DEATH_IF_SUPPORTED(ResolveInlineLength(Length::FitContent()), "");
EXPECT_DEATH_IF_SUPPORTED(ResolveMainInlineLength(Length::FitContent()), "");
#endif
}
TEST_F(NGLengthUtilsTest, testResolveBlockLength) {
EXPECT_EQ(LayoutUnit(90), ResolveBlockLength(Length::Percent(30)));
EXPECT_EQ(LayoutUnit(150), ResolveBlockLength(Length::Fixed(150)));
EXPECT_EQ(LayoutUnit(0), ResolveBlockLength(Length::Auto()));
EXPECT_EQ(LayoutUnit(300), ResolveBlockLength(Length::FillAvailable()));
EXPECT_EQ(LayoutUnit(90), ResolveMainBlockLength(Length::Percent(30)));
EXPECT_EQ(LayoutUnit(150), ResolveMainBlockLength(Length::Fixed(150)));
EXPECT_EQ(LayoutUnit(0), ResolveMainBlockLength(Length::Auto()));
EXPECT_EQ(LayoutUnit(300), ResolveMainBlockLength(Length::FillAvailable()));
EXPECT_EQ(LayoutUnit(0), ResolveBlockLength(Length::Auto()));
EXPECT_EQ(LayoutUnit(300), ResolveBlockLength(Length::FillAvailable()));
EXPECT_EQ(LayoutUnit(300), ResolveMainBlockLength(Length::FillAvailable()));
}
TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
......
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