blob: 9f40cb2ae36be3d210015b8e501f9c127f614f3b [file] [log] [blame]
// 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.
#ifndef NGLengthUtils_h
#define NGLengthUtils_h
#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
#include "third_party/blink/renderer/core/layout/min_max_size.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_fragment_geometry.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
namespace blink {
class ComputedStyle;
class Length;
struct MinMaxSizeInput;
class NGConstraintSpace;
class NGBlockNode;
class NGLayoutInputNode;
// LengthResolvePhase indicates what type of layout pass we are currently in.
// This changes how lengths are resolved. kIntrinsic must be used during the
// intrinsic sizes pass, and kLayout must be used during the layout pass.
enum class LengthResolvePhase { kIntrinsic, kLayout };
inline bool NeedMinMaxSize(const ComputedStyle& style) {
// This check is technically too broad (fill-available does not need intrinsic
// size computation) but that's a rare case and only affects performance, not
// correctness.
return style.LogicalWidth().IsIntrinsic() ||
style.LogicalMinWidth().IsIntrinsic() ||
style.LogicalMaxWidth().IsIntrinsic();
}
// Whether the caller needs to compute min-content and max-content sizes to
// 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,
const ComputedStyle& style) {
return constraint_space.IsShrinkToFit() || NeedMinMaxSize(style);
}
// Like NeedMinMaxSize, but for use when calling
// ComputeMinAndMaxContentContribution.
// Because content contributions are commonly needed by a block's parent,
// we also take a writing mode here so we can check this in the parent's
// coordinate system.
CORE_EXPORT bool NeedMinMaxSizeForContentContribution(WritingMode mode,
const ComputedStyle&);
// Returns if the given |Length| is unresolvable, e.g. the length is %-based
// during the intrinsic phase. For block lengths we also consider 'auto',
// 'min-content', 'max-content', 'fit-content' and 'none' (for max-block-size)
// as unresolvable.
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.
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,
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(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(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
// require a constraint space (percentage sizes as well as auto margins compute
// to zero) and that an auto inline size resolves to the respective min/max
// content size.
// Also, the min/max contribution does include the inline margins as well.
// Because content contributions are commonly needed by a block's parent,
// we also take a writing mode here so we can compute this in the parent's
// coordinate system.
CORE_EXPORT MinMaxSize
ComputeMinAndMaxContentContribution(WritingMode writing_mode,
const ComputedStyle&,
const NGBoxStrut& border_padding,
const base::Optional<MinMaxSize>&);
// A version of ComputeMinAndMaxContentContribution that does not require you
// to compute the min/max content size of the child. Instead, this function
// will compute it if necessary.
// |child| is the node of which to compute the min/max content contribution.
// Note that if the writing mode of the child is orthogonal to that of the
// parent, we'll still return the inline min/max contribution in the writing
// mode of the parent (i.e. typically something based on the preferred *block*
// size of the child).
MinMaxSize ComputeMinAndMaxContentContribution(
const ComputedStyle& parent_style,
NGLayoutInputNode child,
const MinMaxSizeInput&);
// Computes the min/max-content size for an out-of-flow positioned node and
// returns it, using the cache where possible. ALways computes it in the writing
// mode of the node itself.
MinMaxSize ComputeMinAndMaxContentSizeForOutOfFlow(
const NGConstraintSpace&,
NGLayoutInputNode,
const NGBoxStrut& border_padding,
const MinMaxSizeInput&);
// Returns inline size of the node's border box by resolving the computed value
// in style.logicalWidth (Length) to a layout unit, adding border and padding,
// 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.
CORE_EXPORT LayoutUnit ComputeInlineSizeForFragment(
const NGConstraintSpace&,
NGLayoutInputNode,
const NGBoxStrut& border_padding,
const MinMaxSize* override_minmax_for_test = nullptr);
// Same as ComputeInlineSizeForFragment, but uses height instead of width.
CORE_EXPORT LayoutUnit
ComputeBlockSizeForFragment(const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
LayoutUnit content_size);
// Intrinsic size for replaced elements is computed as:
// - |out_replaced_size| intrinsic size of the element. It might have no value.
// - |out_aspect_ratio| only set if out_replaced_size is empty.
// If out_replaced_size is not empty, that is the aspect ratio.
// This routine will return one of the following:
// - out_replaced_size, and no out_aspect_ratio
// - out_aspect_ratio, and no out_replaced_size
// - neither out_aspect_ratio, nor out_replaced_size
// SVG elements can return any of the three options above.
CORE_EXPORT void ComputeReplacedSize(
const NGLayoutInputNode&,
const NGConstraintSpace&,
const base::Optional<MinMaxSize>&,
base::Optional<LogicalSize>* out_replaced_size,
base::Optional<LogicalSize>* out_aspect_ratio);
// Based on available inline size, CSS computed column-width, CSS computed
// column-count and CSS used column-gap, return CSS used column-count.
CORE_EXPORT int ResolveUsedColumnCount(int computed_count,
LayoutUnit computed_size,
LayoutUnit used_gap,
LayoutUnit available_size);
CORE_EXPORT int ResolveUsedColumnCount(LayoutUnit available_size,
const ComputedStyle&);
// Based on available inline size, CSS computed column-width, CSS computed
// column-count and CSS used column-gap, return CSS used column-width.
CORE_EXPORT LayoutUnit ResolveUsedColumnInlineSize(int computed_count,
LayoutUnit computed_size,
LayoutUnit used_gap,
LayoutUnit available_size);
CORE_EXPORT LayoutUnit ResolveUsedColumnInlineSize(LayoutUnit available_size,
const ComputedStyle&);
CORE_EXPORT LayoutUnit ResolveUsedColumnGap(LayoutUnit available_size,
const ComputedStyle&);
// Compute physical margins.
CORE_EXPORT NGPhysicalBoxStrut
ComputePhysicalMargins(const ComputedStyle&,
LayoutUnit percentage_resolution_size);
inline NGPhysicalBoxStrut ComputePhysicalMargins(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style) {
LayoutUnit percentage_resolution_size =
constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
return ComputePhysicalMargins(style, percentage_resolution_size);
}
// Compute margins for the specified NGConstraintSpace.
CORE_EXPORT NGBoxStrut ComputeMarginsFor(const NGConstraintSpace&,
const ComputedStyle&,
const NGConstraintSpace& compute_for);
inline NGBoxStrut ComputeMarginsFor(const ComputedStyle& child_style,
LayoutUnit percentage_resolution_size,
WritingMode container_writing_mode,
TextDirection container_direction) {
return ComputePhysicalMargins(child_style, percentage_resolution_size)
.ConvertToLogical(container_writing_mode, container_direction);
}
// Compute margins for the style owner.
inline NGBoxStrut ComputeMarginsForSelf(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style) {
if (!style.MayHaveMargin() || constraint_space.IsAnonymous())
return NGBoxStrut();
LayoutUnit percentage_resolution_size =
constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
return ComputePhysicalMargins(style, percentage_resolution_size)
.ConvertToLogical(style.GetWritingMode(), style.Direction());
}
// Compute line logical margins for the style owner.
//
// The "line" versions compute line-relative logical values. See NGLineBoxStrut
// for more details.
inline NGLineBoxStrut ComputeLineMarginsForSelf(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style) {
if (!style.MayHaveMargin() || constraint_space.IsAnonymous())
return NGLineBoxStrut();
LayoutUnit percentage_resolution_size =
constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
return ComputePhysicalMargins(style, percentage_resolution_size)
.ConvertToLineLogical(style.GetWritingMode(), style.Direction());
}
// Compute line logical margins for the constraint space, in the visual order
// (always assumes LTR, ignoring the direction) for inline layout algorithm.
inline NGLineBoxStrut ComputeLineMarginsForVisualContainer(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style) {
if (!style.MayHaveMargin() || constraint_space.IsAnonymous())
return NGLineBoxStrut();
LayoutUnit percentage_resolution_size =
constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
return ComputePhysicalMargins(style, percentage_resolution_size)
.ConvertToLineLogical(constraint_space.GetWritingMode(),
TextDirection::kLtr);
}
// Compute margins for a child during the min-max size calculation.
CORE_EXPORT NGBoxStrut ComputeMinMaxMargins(const ComputedStyle& parent_style,
NGLayoutInputNode child);
CORE_EXPORT NGBoxStrut ComputeBorders(const NGConstraintSpace&,
const NGLayoutInputNode);
CORE_EXPORT NGBoxStrut ComputeBordersForInline(const ComputedStyle& style);
inline NGLineBoxStrut ComputeLineBorders(
const ComputedStyle& style) {
return NGLineBoxStrut(ComputeBordersForInline(style),
style.IsFlippedLinesWritingMode());
}
CORE_EXPORT NGBoxStrut ComputeBordersForTest(const ComputedStyle& style);
CORE_EXPORT NGBoxStrut ComputeIntrinsicPadding(const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& scrollbar);
CORE_EXPORT NGBoxStrut ComputePadding(const NGConstraintSpace&,
const ComputedStyle&);
inline NGLineBoxStrut ComputeLinePadding(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style) {
return NGLineBoxStrut(ComputePadding(constraint_space, style),
style.IsFlippedLinesWritingMode());
}
CORE_EXPORT NGBoxStrut ComputeScrollbars(const NGConstraintSpace&,
const NGLayoutInputNode);
// Return true if we need to know the inline size of the fragment in order to
// calculate its line-left offset. This is the case when we have auto margins,
// or when block alignment isn't line-left (e.g. with align!=left, and always in
// RTL mode).
bool NeedsInlineSizeToResolveLineLeft(
const ComputedStyle& style,
const ComputedStyle& containing_block_style);
// Convert inline margins from computed to used values. This will resolve 'auto'
// values and over-constrainedness. This uses the available size from the
// constraint space and inline size to compute the margins that are auto, if
// any, and adjusts the given NGBoxStrut accordingly.
// available_inline_size, inline_size, and margins are all in the
// containing_block's writing mode.
CORE_EXPORT void ResolveInlineMargins(
const ComputedStyle& child_style,
const ComputedStyle& containing_block_style,
LayoutUnit available_inline_size,
LayoutUnit inline_size,
NGBoxStrut* margins);
// Calculate the adjustment needed for the line's left position, based on
// text-align, direction and amount of unused space.
CORE_EXPORT LayoutUnit LineOffsetForTextAlign(ETextAlign,
TextDirection,
LayoutUnit space_left);
inline LayoutUnit ConstrainByMinMax(LayoutUnit length,
LayoutUnit min,
LayoutUnit max) {
return std::max(min, std::min(length, max));
}
// Calculates the initial (pre-layout) fragment geometry given a node, and a
// constraint space.
// The "pre-layout" block-size may be indefinite, as we'll only have enough
// information to determine this post-layout.
CORE_EXPORT NGFragmentGeometry
CalculateInitialFragmentGeometry(const NGConstraintSpace&, const NGBlockNode&);
// Similar to |CalculateInitialFragmentGeometry| however will only calculate
// the border, scrollbar, and padding (resolving percentages to zero).
CORE_EXPORT NGFragmentGeometry
CalculateInitialMinMaxFragmentGeometry(const NGConstraintSpace&,
const NGBlockNode&);
// Shrink and return the available size by an inset. This may e.g. be used to
// convert from border-box to content-box size. Indefinite block size is
// allowed, in which case the inset will be ignored for block size.
LogicalSize ShrinkAvailableSize(LogicalSize size, const NGBoxStrut& inset);
// Calculates the percentage resolution size that children of the node should
// use.
LogicalSize CalculateChildPercentageSize(
const NGConstraintSpace&,
const NGBlockNode node,
const LogicalSize child_available_size);
// Calculates the percentage resolution size that replaced children of the node
// should use.
LogicalSize CalculateReplacedChildPercentageSize(
const NGConstraintSpace&,
const NGBlockNode node,
const LogicalSize child_available_size,
const NGBoxStrut& border_scrollbar_padding,
const NGBoxStrut& border_padding);
LayoutUnit CalculateChildPercentageBlockSizeForMinMax(
const NGConstraintSpace& constraint_space,
const NGBlockNode node,
const NGBoxStrut& border_padding,
LayoutUnit parent_percentage_block_size);
// The following function clamps the calculated size based on the node
// requirements. Specifically, this adjusts the size based on size containment
// and display locking status.
LayoutUnit ClampIntrinsicBlockSize(const NGBlockNode&,
const NGBoxStrut& border_scrollbar_padding,
LayoutUnit current_intrinsic_block_size);
// This function checks if the inline size of this node has to be calculated
// without considering children. If so, it returns the calculated size.
// Otherwise, it returns base::nullopt and the caller has to compute the size
// itself.
base::Optional<MinMaxSize> CalculateMinMaxSizesIgnoringChildren(
const NGBlockNode&,
const NGBoxStrut& border_scrollbar_padding,
NGMinMaxSizeType);
} // namespace blink
#endif // NGLengthUtils_h