blob: fc5ab4ba4855a181f550202457fae1c87caa7803 [file] [log] [blame]
// Copyright 2017 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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_BLOCK_BREAK_TOKEN_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_BLOCK_BREAK_TOKEN_H_
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
class NGInlineBreakToken;
// Represents a break token for a block node.
class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
public:
// Creates a break token for a node which did fragment, and can potentially
// produce more fragments.
//
// The node is NGBlockNode, or any other NGLayoutInputNode that produces
// anonymous box.
static scoped_refptr<NGBlockBreakToken> Create(
NGLayoutInputNode node,
LayoutUnit consumed_block_size,
const NGBreakTokenVector& child_break_tokens,
NGBreakAppeal break_appeal,
bool has_seen_all_children) {
// We store the children list inline in the break token as a flexible
// array. Therefore, we need to make sure to allocate enough space for
// that array here, which requires a manual allocation + placement new.
void* data = ::WTF::Partitions::FastMalloc(
sizeof(NGBlockBreakToken) +
child_break_tokens.size() * sizeof(NGBreakToken*),
::WTF::GetStringWithTypeName<NGBlockBreakToken>());
new (data) NGBlockBreakToken(node, consumed_block_size, child_break_tokens,
break_appeal, has_seen_all_children);
return base::AdoptRef(static_cast<NGBlockBreakToken*>(data));
}
// Creates a break token for a node that needs to produce its first fragment
// in the next fragmentainer. In this case we create a break token for a node
// that hasn't yet produced any fragments.
static scoped_refptr<NGBlockBreakToken> CreateBreakBefore(
NGLayoutInputNode node,
bool is_forced_break) {
auto* token = new NGBlockBreakToken(node);
token->is_break_before_ = true;
token->is_forced_break_ = is_forced_break;
return base::AdoptRef(token);
}
~NGBlockBreakToken() override {
for (const NGBreakToken* token : ChildBreakTokens())
token->Release();
}
// Represents the amount of block-size consumed by previous fragments.
//
// E.g. if the node specifies a block-size of 200px, and the previous
// fragments generated for this box consumed 150px in total (which is what
// this method would return then), there's 50px left to consume. The next
// fragment will become 50px tall, assuming no additional fragmentation (if
// the fragmentainer is shorter than 50px, for instance).
LayoutUnit ConsumedBlockSize() const { return consumed_block_size_; }
// Return true if this is a break token that was produced without any
// "preceding" fragment. This happens when we determine that the first
// fragment for a node needs to be created in a later fragmentainer than the
// one it was it was first encountered, due to block space shortage.
bool IsBreakBefore() const { return is_break_before_; }
bool IsForcedBreak() const { return is_forced_break_; }
// Return true if all children have been "seen". When we have reached this
// point, and resume layout in a fragmentainer, we should only process child
// break tokens, if any, and not attempt to start laying out nodes that don't
// have one (since all children are either finished, or have a break token).
bool HasSeenAllChildren() const { return has_seen_all_children_; }
// The break tokens for children of the layout node.
//
// Each child we have visited previously in the block-flow layout algorithm
// has an associated break token. This may be either finished (we should skip
// this child) or unfinished (we should try and produce the next fragment for
// this child).
//
// A child which we haven't visited yet doesn't have a break token here.
const base::span<const NGBreakToken* const> ChildBreakTokens() const {
return base::make_span(child_break_tokens_, num_children_);
}
// Find the child NGInlineBreakToken for the specified node.
const NGInlineBreakToken* InlineBreakTokenFor(const NGLayoutInputNode&) const;
const NGInlineBreakToken* InlineBreakTokenFor(const LayoutBox&) const;
#if DCHECK_IS_ON()
String ToString() const override;
#endif
private:
// Must only be called from Create(), because it assumes that enough space
// has been allocated in the flexible array to store the children.
NGBlockBreakToken(NGLayoutInputNode node,
LayoutUnit consumed_block_size,
const NGBreakTokenVector& child_break_tokens,
NGBreakAppeal break_appeal,
bool has_seen_all_children);
explicit NGBlockBreakToken(NGLayoutInputNode node);
LayoutUnit consumed_block_size_;
wtf_size_t num_children_;
// This must be the last member, because it is a flexible array.
const NGBreakToken* child_break_tokens_[];
};
template <>
struct DowncastTraits<NGBlockBreakToken> {
static bool AllowFrom(const NGBreakToken& token) {
return token.IsBlockType();
}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_BLOCK_BREAK_TOKEN_H_