Commit 4b4053d0 authored by Ian Kilpatrick's avatar Ian Kilpatrick Committed by Commit Bot

[FlexNG] Lazily calculate the MinMaxSize and IntrinsicBlockSize for flex-items.

This patch introduces variants of:
Resolve{Main,Min,Max}{Inline,Block}Length

With a callback function to provide the MinMaxSize, or IntrinsicBlockSize
as needed.

This in instead of logic used by other algorithms via. NeedMinMaxSize
et. al.

There are pros/cons to this approach:
Pro - Much more precise (and easier to maintain) calls to
      NGBlockNode::ComputeMinMaxSize and NGBlockNode::Layout.
Con - Duplicate logic for Resolve*Length.

I tried moving Resolve*InlineLength to all being callback based but some
other refactoring needs to occur first (mainly an additional ng cache).

An alternate version of this patch would be either:
1) A NeedsMinMaxSize / NeedsIntrinsicBlockSize similar to other callers
   of these functions.
2) Adding the branch before the Resolve*Length calls to check if we
   need to provide the appropriate argument.

Bug: 845235
Change-Id: I8e26e0171adc60a7e3d244af3cb21e119b2653f1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2027075Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarDavid Grogan <dgrogan@chromium.org>
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#738379}
parent ecde9593
......@@ -353,7 +353,6 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
const ComputedStyle& child_style = child.Style();
NGConstraintSpace flex_basis_space = BuildSpaceForFlexBasis(child);
NGConstraintSpace child_space = BuildSpaceForIntrinsicBlockSize(child);
NGBoxStrut border_padding_in_child_writing_mode =
ComputeBorders(flex_basis_space, child) +
......@@ -370,20 +369,29 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
is_horizontal_flow_ ? physical_border_padding.VerticalSum()
: physical_border_padding.HorizontalSum();
// TODO(dgrogan): Don't layout every time, just when you need to.
// Use ChildHasIntrinsicMainAxisSize as a guide.
scoped_refptr<const NGLayoutResult> layout_result =
child.Layout(child_space, /* break_token */ nullptr);
// We want the child's min/max size in its writing mode, not ours. We'll
// only ever use it if the child's inline axis is our main axis.
//
// Always calculate the min/max sizes after a layout in order to corrrectly
// account for any scrollbars.
MinMaxSizeInput input(
/* percentage_resolution_block_size */ content_box_size_.block_size);
MinMaxSize intrinsic_sizes_border_box = child.ComputeMinMaxSize(
child_style.GetWritingMode(), input, &child_space);
base::Optional<LayoutUnit> intrinsic_block_size;
auto IntrinsicBlockSizeFunc = [&]() -> LayoutUnit {
if (!intrinsic_block_size) {
NGConstraintSpace child_space = BuildSpaceForIntrinsicBlockSize(child);
intrinsic_block_size =
child.Layout(child_space, /* break_token */ nullptr)
->IntrinsicBlockSize();
}
return *intrinsic_block_size;
};
base::Optional<MinMaxSize> min_max_size;
auto MinMaxSizeFunc = [&]() -> MinMaxSize {
if (!min_max_size) {
// We want the child's min/max size in its writing mode, not ours.
// We'll only ever use it if the child's inline axis is our main axis.
NGConstraintSpace child_space = BuildSpaceForIntrinsicBlockSize(child);
min_max_size = child.ComputeMinMaxSize(
child_style.GetWritingMode(),
MinMaxSizeInput(content_box_size_.block_size), &child_space);
}
return *min_max_size;
};
LayoutUnit flex_base_border_box;
const Length& specified_length_in_main_axis =
......@@ -396,9 +404,9 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
// we should interpret it as flex-basis:content.
if (flex_basis.IsAuto() && specified_length_in_main_axis.IsAuto()) {
if (MainAxisIsInlineAxis(child))
flex_base_border_box = intrinsic_sizes_border_box.max_size;
flex_base_border_box = MinMaxSizeFunc().max_size;
else
flex_base_border_box = layout_result->IntrinsicBlockSize();
flex_base_border_box = IntrinsicBlockSizeFunc();
} else {
// TODO(dgrogan): Check for definiteness.
// This block covers case A in
......@@ -410,13 +418,13 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
if (MainAxisIsInlineAxis(child)) {
flex_base_border_box = ResolveMainInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, length_to_resolve);
MinMaxSizeFunc, 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 = ResolveMainBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
length_to_resolve, layout_result->IntrinsicBlockSize(),
length_to_resolve, IntrinsicBlockSizeFunc,
LengthResolvePhase::kLayout);
}
}
......@@ -444,28 +452,28 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
if (MainAxisIsInlineAxis(child)) {
min_max_sizes_in_main_axis_direction.max_size = ResolveMaxInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, max_property_in_main_axis,
MinMaxSizeFunc, max_property_in_main_axis,
LengthResolvePhase::kLayout);
min_max_sizes_in_cross_axis_direction.max_size = ResolveMaxBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
max_property_in_cross_axis, layout_result->IntrinsicBlockSize(),
max_property_in_cross_axis, IntrinsicBlockSizeFunc,
LengthResolvePhase::kLayout);
min_max_sizes_in_cross_axis_direction.min_size = ResolveMinBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
min_property_in_cross_axis, layout_result->IntrinsicBlockSize(),
min_property_in_cross_axis, IntrinsicBlockSizeFunc,
LengthResolvePhase::kLayout);
} else {
min_max_sizes_in_main_axis_direction.max_size = ResolveMaxBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
max_property_in_main_axis, layout_result->IntrinsicBlockSize(),
max_property_in_main_axis, IntrinsicBlockSizeFunc,
LengthResolvePhase::kLayout);
min_max_sizes_in_cross_axis_direction.max_size = ResolveMaxInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, max_property_in_cross_axis,
MinMaxSizeFunc, max_property_in_cross_axis,
LengthResolvePhase::kLayout);
min_max_sizes_in_cross_axis_direction.min_size = ResolveMinInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, min_property_in_cross_axis,
MinMaxSizeFunc, min_property_in_cross_axis,
LengthResolvePhase::kLayout);
}
......@@ -486,9 +494,9 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
// TODO(dgrogan): Do the aspect ratio parts of
// https://www.w3.org/TR/css-flexbox-1/#min-size-auto
LayoutUnit content_size_suggestion =
MainAxisIsInlineAxis(child) ? intrinsic_sizes_border_box.min_size
: layout_result->IntrinsicBlockSize();
LayoutUnit content_size_suggestion = MainAxisIsInlineAxis(child)
? MinMaxSizeFunc().min_size
: IntrinsicBlockSizeFunc();
content_size_suggestion =
std::min(content_size_suggestion,
min_max_sizes_in_main_axis_direction.max_size);
......@@ -518,18 +526,17 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
// calculation. Reuse that if possible.
specified_size_suggestion = ResolveMainInlineLength(
flex_basis_space, child_style,
border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, specified_length_in_main_axis);
border_padding_in_child_writing_mode, MinMaxSizeFunc,
specified_length_in_main_axis);
}
} else if (!BlockLengthUnresolvable(flex_basis_space,
specified_length_in_main_axis,
LengthResolvePhase::kLayout)) {
specified_size_suggestion =
ResolveMainBlockLength(flex_basis_space, child_style,
border_padding_in_child_writing_mode,
specified_length_in_main_axis,
layout_result->IntrinsicBlockSize(),
LengthResolvePhase::kLayout);
specified_size_suggestion = ResolveMainBlockLength(
flex_basis_space, child_style,
border_padding_in_child_writing_mode,
specified_length_in_main_axis, IntrinsicBlockSizeFunc,
LengthResolvePhase::kLayout);
DCHECK_NE(specified_size_suggestion, kIndefiniteSize);
}
// Spec says to clamp specified_size_suggestion by max size but
......@@ -544,12 +551,11 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
} else if (MainAxisIsInlineAxis(child)) {
min_max_sizes_in_main_axis_direction.min_size = ResolveMinInlineLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
intrinsic_sizes_border_box, min, LengthResolvePhase::kLayout);
MinMaxSizeFunc, min, LengthResolvePhase::kLayout);
} else {
min_max_sizes_in_main_axis_direction.min_size = ResolveMinBlockLength(
flex_basis_space, child_style, border_padding_in_child_writing_mode,
min, layout_result->IntrinsicBlockSize(),
LengthResolvePhase::kLayout);
min, IntrinsicBlockSizeFunc, LengthResolvePhase::kLayout);
}
min_max_sizes_in_main_axis_direction -= main_axis_border_padding;
......
......@@ -97,44 +97,100 @@ CORE_EXPORT LayoutUnit ResolveBlockLengthInternal(
nullptr);
// Used for resolving min inline lengths, (|ComputedStyle::MinLogicalWidth|).
template <typename MinMaxSizeFunc>
inline LayoutUnit ResolveMinInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_and_max,
const MinMaxSizeFunc& min_max_size_func,
const Length& length,
LengthResolvePhase phase) {
if (LIKELY(length.IsAuto() || InlineLengthUnresolvable(length, phase)))
return border_padding.InlineSum();
base::Optional<MinMaxSize> min_max_size;
if (length.IsIntrinsic())
min_max_size = min_max_size_func();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_and_max, length);
min_max_size, length);
}
template <>
inline LayoutUnit ResolveMinInlineLength<base::Optional<MinMaxSize>>(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_max_size,
const Length& length,
LengthResolvePhase phase) {
if (LIKELY(length.IsAuto() || InlineLengthUnresolvable(length, phase)))
return border_padding.InlineSum();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_max_size, length);
}
// Used for resolving max inline lengths, (|ComputedStyle::MaxLogicalWidth|).
template <typename MinMaxSizeFunc>
inline LayoutUnit ResolveMaxInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_and_max,
const MinMaxSizeFunc& min_max_size_func,
const Length& length,
LengthResolvePhase phase) {
if (LIKELY(length.IsNone() || InlineLengthUnresolvable(length, phase)))
return LayoutUnit::Max();
base::Optional<MinMaxSize> min_max_size;
if (length.IsIntrinsic())
min_max_size = min_max_size_func();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_max_size, length);
}
template <>
inline LayoutUnit ResolveMaxInlineLength<base::Optional<MinMaxSize>>(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_max_size,
const Length& length,
LengthResolvePhase phase) {
if (LIKELY(length.IsNone() || InlineLengthUnresolvable(length, phase)))
return LayoutUnit::Max();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_and_max, length);
min_max_size, length);
}
// Used for resolving main inline lengths, (|ComputedStyle::LogicalWidth|).
template <typename MinMaxSizeFunc>
inline LayoutUnit ResolveMainInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_and_max,
const MinMaxSizeFunc& min_max_size_func,
const Length& length) {
base::Optional<MinMaxSize> min_max_size;
if (length.IsIntrinsic())
min_max_size = min_max_size_func();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_max_size, length);
}
template <>
inline LayoutUnit ResolveMainInlineLength<base::Optional<MinMaxSize>>(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>& min_max_size,
const Length& length) {
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
min_and_max, length);
min_max_size, length);
}
// Used for resolving min block lengths, (|ComputedStyle::MinLogicalHeight|).
......@@ -157,6 +213,30 @@ inline LayoutUnit ResolveMinBlockLength(
opt_percentage_resolution_block_size_for_min_max);
}
template <typename IntrinsicBlockSizeFunc>
inline LayoutUnit ResolveMinBlockLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
const IntrinsicBlockSizeFunc& intrinsic_block_size_func,
LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
if (LIKELY(BlockLengthUnresolvable(
constraint_space, length, phase,
opt_percentage_resolution_block_size_for_min_max)))
return border_padding.BlockSum();
LayoutUnit intrinsic_block_size = kIndefiniteSize;
if (length.IsIntrinsicOrAuto())
intrinsic_block_size = intrinsic_block_size_func();
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, intrinsic_block_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,
......@@ -177,6 +257,30 @@ inline LayoutUnit ResolveMaxBlockLength(
opt_percentage_resolution_block_size_for_min_max);
}
template <typename IntrinsicBlockSizeFunc>
inline LayoutUnit ResolveMaxBlockLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
const IntrinsicBlockSizeFunc& intrinsic_block_size_func,
LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
if (LIKELY(BlockLengthUnresolvable(
constraint_space, length, phase,
opt_percentage_resolution_block_size_for_min_max)))
return LayoutUnit::Max();
LayoutUnit intrinsic_block_size = kIndefiniteSize;
if (length.IsIntrinsicOrAuto())
intrinsic_block_size = intrinsic_block_size_func();
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, intrinsic_block_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,
......@@ -198,6 +302,31 @@ inline LayoutUnit ResolveMainBlockLength(
opt_percentage_resolution_block_size_for_min_max);
}
template <typename IntrinsicBlockSizeFunc>
inline LayoutUnit ResolveMainBlockLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
const IntrinsicBlockSizeFunc& intrinsic_block_size_func,
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 intrinsic_block_size_func();
LayoutUnit intrinsic_block_size = kIndefiniteSize;
if (length.IsIntrinsicOrAuto())
intrinsic_block_size = intrinsic_block_size_func();
return ResolveBlockLengthInternal(
constraint_space, style, border_padding, length, intrinsic_block_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
......@@ -241,12 +370,12 @@ MinMaxSize ComputeMinAndMaxContentSizeForOutOfFlow(
// then constraining the result by the resolved min logical width and max
// logical width from the ComputedStyle object. Calls Node::ComputeMinMaxSize
// if needed.
// |override_minmax_for_test| is provided *solely* for use by unit tests.
// |override_min_max_size_for_test| is provided *solely* for use by unit tests.
CORE_EXPORT LayoutUnit ComputeInlineSizeForFragment(
const NGConstraintSpace&,
NGLayoutInputNode,
const NGBoxStrut& border_padding,
const MinMaxSize* override_minmax_for_test = nullptr);
const MinMaxSize* override_min_max_size_for_test = nullptr);
// Same as ComputeInlineSizeForFragment, but uses height instead of width.
CORE_EXPORT LayoutUnit
......
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