blob: 19aee7982dd4813d64950dc549e502ecb2b57409 [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 NGBlockLayoutAlgorithm_h
#define NGBlockLayoutAlgorithm_h
#include "core/CoreExport.h"
#include "core/layout/ng/geometry/ng_margin_strut.h"
#include "core/layout/ng/ng_block_break_token.h"
#include "core/layout/ng/ng_block_node.h"
#include "core/layout/ng/ng_fragment_builder.h"
#include "core/layout/ng/ng_layout_algorithm.h"
#include "platform/wtf/RefPtr.h"
namespace blink {
class NGConstraintSpace;
class NGFragment;
class NGLayoutResult;
// This struct is used for communicating to a child the position of the
// previous inflow child.
struct NGPreviousInflowPosition {
LayoutUnit bfc_block_offset;
LayoutUnit logical_block_offset;
NGMarginStrut margin_strut;
bool empty_block_affected_by_clearance;
};
// This strut holds information for the current inflow child. The data is not
// useful outside of handling this single inflow child.
struct NGInflowChildData {
NGBfcOffset bfc_offset_estimate;
NGMarginStrut margin_strut;
NGBoxStrut margins;
};
// A class for general block layout (e.g. a <div> with no special style).
// Lays out the children in sequence.
class CORE_EXPORT NGBlockLayoutAlgorithm
: public NGLayoutAlgorithm<NGBlockNode,
NGFragmentBuilder,
NGBlockBreakToken> {
public:
// Default constructor.
// @param node The input node to perform layout upon.
// @param space The constraint space which the algorithm should generate a
// fragment within.
// @param break_token The break token from which the layout should start.
NGBlockLayoutAlgorithm(NGBlockNode node,
const NGConstraintSpace& space,
NGBlockBreakToken* break_token = nullptr);
Optional<MinMaxSize> ComputeMinMaxSize() const override;
virtual scoped_refptr<NGLayoutResult> Layout() override;
private:
NGBoxStrut CalculateMargins(NGLayoutInputNode child,
const NGBreakToken* child_break_token);
// Creates a new constraint space for the current child.
scoped_refptr<NGConstraintSpace> CreateConstraintSpaceForChild(
const NGLayoutInputNode child,
const NGInflowChildData& child_data,
const WTF::Optional<NGBfcOffset> floats_bfc_offset = WTF::nullopt,
const WTF::Optional<LayoutUnit> fixed_inline_size = WTF::nullopt);
// @return Estimated BFC offset for the "to be layout" child.
NGInflowChildData ComputeChildData(const NGPreviousInflowPosition&,
NGLayoutInputNode,
const NGBreakToken* child_break_token);
NGPreviousInflowPosition ComputeInflowPosition(
const NGPreviousInflowPosition& previous_inflow_position,
const NGLayoutInputNode child,
const NGInflowChildData& child_data,
const WTF::Optional<NGBfcOffset>& child_bfc_offset,
const NGLogicalOffset& logical_offset,
const NGLayoutResult& layout_result,
const NGFragment& fragment,
bool empty_block_affected_by_clearance);
// Positions the fragment that knows its BFC offset.
WTF::Optional<NGBfcOffset> PositionWithBfcOffset(
const NGBfcOffset& bfc_offset);
bool PositionWithBfcOffset(const NGBfcOffset& bfc_offset,
WTF::Optional<NGBfcOffset>* child_bfc_offset);
// Positions using the parent BFC offset.
// Fragment doesn't know its offset but we can still calculate its BFC
// position because the parent fragment's BFC is known.
// Example:
// BFC Offset is known here because of the padding.
// <div style="padding: 1px">
// <div id="empty-div" style="margins: 1px"></div>
NGBfcOffset PositionWithParentBfc(const NGLayoutInputNode& child,
const NGConstraintSpace&,
const NGInflowChildData& child_data,
const NGLayoutResult&,
bool* empty_block_affected_by_clearance);
void HandleOutOfFlowPositioned(const NGPreviousInflowPosition&, NGBlockNode);
void HandleFloat(const NGPreviousInflowPosition&,
NGBlockNode,
NGBlockBreakToken*);
// This uses the NGLayoutOpporunityIterator to position the fragment.
//
// An element that establishes a new formatting context must not overlap the
// margin box of any floats within the current BFC.
//
// Example:
// <div id="container">
// <div id="float"></div>
// <div id="new-fc" style="margin-top: 20px;"></div>
// </div>
// 1) If #new-fc is small enough to fit the available space right from #float
// then it will be placed there and we collapse its margin.
// 2) If #new-fc is too big then we need to clear its position and place it
// below #float ignoring its vertical margin.
//
// Returns false if we need to abort layout, because a previously unknown BFC
// offset has now been resolved.
bool HandleNewFormattingContext(
NGLayoutInputNode child,
NGBreakToken* child_break_token,
NGPreviousInflowPosition*,
RefPtr<NGBreakToken>* previous_inline_break_token);
// Performs the actual layout of a new formatting context. This may be called
// multiple times from HandleNewFormattingContext.
std::pair<scoped_refptr<NGLayoutResult>, NGLayoutOpportunity>
LayoutNewFormattingContext(NGLayoutInputNode child,
NGBreakToken* child_break_token,
bool is_auto_inline_size,
const NGInflowChildData&,
LayoutUnit child_origin_block_offset);
// Handle an in-flow child.
// Returns false if we need to abort layout, because a previously unknown BFC
// offset has now been resolved. (Same as HandleNewFormattingContext).
bool HandleInflow(NGLayoutInputNode child,
NGBreakToken* child_break_token,
NGPreviousInflowPosition*,
RefPtr<NGBreakToken>* previous_inline_break_token);
// Return the amount of block space available in the current fragmentainer
// for the node being laid out by this algorithm.
LayoutUnit FragmentainerSpaceAvailable() const;
// Return true if the node being laid out by this fragmentainer has used all
// the available space in the current fragmentainer.
bool IsFragmentainerOutOfSpace() const;
// Given a child fragment and the corresponding node's style, return true if
// we need to insert a fragmentainer break in front of it.
bool ShouldBreakBeforeChild(NGLayoutInputNode child,
const NGPhysicalFragment& physical_fragment,
LayoutUnit block_offset) const;
// Final adjustments before fragment creation. We need to prevent the
// fragment from crossing fragmentainer boundaries, and rather create a break
// token if we're out of space.
void FinalizeForFragmentation();
void PropagateBaselinesFromChildren();
bool AddBaseline(const NGBaselineRequest&,
const NGPhysicalFragment*,
LayoutUnit child_offset);
// Updates the fragment's BFC offset if it's not already set.
bool MaybeUpdateFragmentBfcOffset(LayoutUnit bfc_block_offset);
// Positions pending floats starting from {@origin_block_offset}.
void PositionPendingFloats(LayoutUnit origin_block_offset);
// Adds a set of positioned floats as children to the current fragment.
void AddPositionedFloats(const Vector<NGPositionedFloat>& positioned_floats);
// Calculates logical offset for the current fragment using either {@code
// intrinsic_block_size_} when the fragment doesn't know it's offset or
// {@code known_fragment_offset} if the fragment knows it's offset
// @return Fragment's offset relative to the fragment's parent.
NGLogicalOffset CalculateLogicalOffset(
const NGFragment&,
const NGBoxStrut& child_margins,
const WTF::Optional<NGBfcOffset>& known_fragment_offset);
NGLogicalSize child_available_size_;
NGLogicalSize child_percentage_size_;
NGBoxStrut border_scrollbar_padding_;
LayoutUnit intrinsic_block_size_;
bool abort_when_bfc_resolved_;
std::unique_ptr<NGExclusionSpace> exclusion_space_;
Vector<scoped_refptr<NGUnpositionedFloat>> unpositioned_floats_;
};
} // namespace blink
#endif // NGBlockLayoutAlgorithm_h