blob: cef4eab54adb82957da944a26870e5396a7784f3 [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 NGBlockBreakToken_h
#define NGBlockBreakToken_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/vector.h"
namespace blink {
// Represents a break token for a block node.
class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
public:
class ChildTokenList {
public:
ChildTokenList(wtf_size_t count, const NGBreakToken* const* buffer)
: count_(count), buffer_(buffer) {}
wtf_size_t size() const { return count_; }
const NGBreakToken* operator[](wtf_size_t idx) const {
return buffer_[idx];
}
const NGBreakToken* const* begin() const { return buffer_; }
const NGBreakToken* const* end() const { return begin() + count_; }
private:
wtf_size_t count_;
const NGBreakToken* const* buffer_;
};
// 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 used_block_size,
const NGBreakTokenVector& child_break_tokens,
bool has_last_resort_break = false) {
// 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, used_block_size, child_break_tokens,
has_last_resort_break);
return base::AdoptRef(static_cast<NGBlockBreakToken*>(data));
}
// Creates a break token for a node which cannot produce any more fragments.
static scoped_refptr<NGBlockBreakToken> Create(
NGLayoutInputNode node,
LayoutUnit used_block_size,
bool has_last_resort_break = false) {
return base::AdoptRef(
new NGBlockBreakToken(node, used_block_size, has_last_resort_break));
}
// 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) {
auto* token = new NGBlockBreakToken(node);
token->is_break_before_ = true;
return base::AdoptRef(token);
}
~NGBlockBreakToken() override {
for (const NGBreakToken* token : ChildBreakTokens())
token->Release();
}
// Represents the amount of block size used in previous fragments.
//
// E.g. if the layout block specifies a block size of 200px, and the previous
// fragments of this block used 150px (used block size), the next fragment
// should have a size of 50px (assuming no additional fragmentation).
LayoutUnit UsedBlockSize() const { return used_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 HasLastResortBreak() const { return has_last_resort_break_; }
// 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 ChildTokenList ChildBreakTokens() const {
return ChildTokenList(num_children_, &child_break_tokens_[0]);
}
#ifndef NDEBUG
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 used_block_size,
const NGBreakTokenVector& child_break_tokens,
bool has_last_resort_break);
NGBlockBreakToken(NGLayoutInputNode node,
LayoutUnit used_block_size,
bool has_last_resort_break);
explicit NGBlockBreakToken(NGLayoutInputNode node);
LayoutUnit used_block_size_;
bool is_break_before_ = false;
// We're attempting to break at an undesirable place. Sometimes that's
// unavoidable, but we should only break here if we cannot find a better break
// point further up in the ancestry.
bool has_last_resort_break_ = false;
wtf_size_t num_children_;
// This must be the last member, because it is a flexible array.
NGBreakToken* child_break_tokens_[];
};
DEFINE_TYPE_CASTS(NGBlockBreakToken,
NGBreakToken,
token,
token->IsBlockType(),
token.IsBlockType());
} // namespace blink
#endif // NGBlockBreakToken_h