| // 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/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_logical_size.h" |
| #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h" |
| #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.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; |
| class NGLayoutResult; |
| |
| // 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 }; |
| |
| // LengthResolveType indicates what type length the function is being passed |
| // 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 }; |
| |
| 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 ResolveInlineLength / 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&); |
| |
| // Resolve means translate a Length to a LayoutUnit, using parent info |
| // (represented by ConstraintSpace) as necessary for things like percents. |
| // |
| // MinMaxSize is used only when the length is intrinsic (fit-content, etc) |
| // |
| // border_padding can be passed in as an optimization; otherwise this function |
| // will compute it itself. |
| CORE_EXPORT LayoutUnit ResolveInlineLength( |
| const NGConstraintSpace&, |
| const ComputedStyle&, |
| const base::Optional<MinMaxSize>&, |
| const Length&, |
| LengthResolveType, |
| LengthResolvePhase, |
| const base::Optional<NGBoxStrut>& border_padding = base::nullopt); |
| |
| // Same as ResolveInlineLength, except here content_size roughly plays the part |
| // of MinMaxSize. |
| CORE_EXPORT LayoutUnit ResolveBlockLength( |
| const NGConstraintSpace&, |
| const ComputedStyle&, |
| const Length&, |
| LayoutUnit content_size, |
| LengthResolveType, |
| LengthResolvePhase, |
| const base::Optional<NGBoxStrut>& border_padding = base::nullopt); |
| |
| // Convert margin/border/padding length to a layout unit using the |
| // given constraint space. |
| LayoutUnit ResolveMarginPaddingLength(LayoutUnit percentage_resolution_size, |
| const Length&); |
| inline LayoutUnit ResolveMarginPaddingLength( |
| const NGConstraintSpace& constraint_space, |
| const Length& length) { |
| LayoutUnit percentage_resolution_size = |
| constraint_space.PercentageResolutionInlineSizeForParentWritingMode(); |
| return ResolveMarginPaddingLength(percentage_resolution_size, length); |
| } |
| |
| // 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 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& input); |
| |
| // 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 is provided *solely* for use by unit tests. |
| // border_padding can be passed in as an optimization; otherwise this function |
| // will compute it itself. |
| CORE_EXPORT LayoutUnit ComputeInlineSizeForFragment( |
| const NGConstraintSpace&, |
| NGLayoutInputNode, |
| const base::Optional<NGBoxStrut>& border_padding = base::nullopt, |
| const MinMaxSize* override_minmax = nullptr); |
| |
| // Same as ComputeInlineSizeForFragment, but uses height instead of width. |
| CORE_EXPORT LayoutUnit ComputeBlockSizeForFragment( |
| const NGConstraintSpace&, |
| const ComputedStyle&, |
| LayoutUnit content_size, |
| const base::Optional<NGBoxStrut>& border_padding = base::nullopt); |
| |
| // Computes intrinsic size for replaced elements. |
| CORE_EXPORT NGLogicalSize |
| ComputeReplacedSize(const NGLayoutInputNode&, |
| const NGConstraintSpace&, |
| const base::Optional<MinMaxSize>&); |
| |
| // Return true if it's possible (but not necessarily guaranteed) that the new |
| // constraint space will give a different size compared to the old one, when |
| // computed style and child content remain unchanged. |
| bool SizeMayChange(const ComputedStyle&, |
| const NGConstraintSpace& new_space, |
| const NGConstraintSpace& old_space, |
| const NGLayoutResult& layout_result); |
| |
| // 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 (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 (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 (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 ComputedStyle&); |
| |
| CORE_EXPORT NGBoxStrut ComputeBorders(const NGConstraintSpace&, |
| const NGLayoutInputNode); |
| |
| inline NGLineBoxStrut ComputeLineBorders( |
| const NGConstraintSpace& constraint_space, |
| const ComputedStyle& style) { |
| return NGLineBoxStrut(ComputeBorders(constraint_space, style), |
| style.IsFlippedLinesWritingMode()); |
| } |
| |
| CORE_EXPORT NGBoxStrut ComputeIntrinsicPadding(const NGConstraintSpace&, |
| const NGLayoutInputNode); |
| |
| 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()); |
| } |
| |
| // 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); |
| |
| // Same as |LineOffsetForTextAlign| but returns the logical inline offset |
| // instead of line-left offset. |
| CORE_EXPORT LayoutUnit InlineOffsetForTextAlign(const ComputedStyle&, |
| LayoutUnit space_left); |
| |
| inline LayoutUnit ConstrainByMinMax(LayoutUnit length, |
| LayoutUnit min, |
| LayoutUnit max) { |
| return std::max(min, std::min(length, max)); |
| } |
| |
| // Clamp the inline size of the scrollbar, unless it's larger than the inline |
| // size of the content box, in which case we'll return that instead. Scrollbar |
| // handling is quite bad in such situations, and this method here is just to |
| // make sure that left-hand scrollbars don't mess up scrollWidth. For the full |
| // story, visit http://crbug.com/724255. |
| bool ClampScrollbarToContentBox(NGBoxStrut* scrollbars, |
| LayoutUnit content_box_inline_size); |
| |
| NGBoxStrut CalculateBorderScrollbarPadding( |
| const NGConstraintSpace& constraint_space, |
| const NGBlockNode node); |
| |
| // border_padding can be passed in as an optimization; otherwise this function |
| // will compute it itself. |
| NGLogicalSize CalculateBorderBoxSize( |
| const NGConstraintSpace& constraint_space, |
| const NGBlockNode& node, |
| LayoutUnit block_content_size = NGSizeIndefinite, |
| const base::Optional<NGBoxStrut>& border_padding = base::nullopt); |
| |
| // 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. |
| NGLogicalSize ShrinkAvailableSize(NGLogicalSize size, const NGBoxStrut& inset); |
| |
| // 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 |