blob: 53a8b890ea2268a4d951c33c6c01b5b210b488c5 [file] [log] [blame]
// Copyright 2019 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_INLINE_NG_FRAGMENT_ITEMS_BUILDER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_FRAGMENT_ITEMS_BUILDER_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_logical_line_item.h"
#include "third_party/blink/renderer/platform/text/writing_direction_mode.h"
namespace blink {
class NGFragmentItem;
class NGFragmentItems;
class NGInlineNode;
// This class builds |NGFragmentItems|.
//
// Once |NGFragmentItems| is built, it is immutable.
class CORE_EXPORT NGFragmentItemsBuilder {
STACK_ALLOCATED();
public:
explicit NGFragmentItemsBuilder(WritingDirectionMode writing_direction);
NGFragmentItemsBuilder(const NGInlineNode& node,
WritingDirectionMode writing_direction);
~NGFragmentItemsBuilder();
WritingDirectionMode GetWritingDirection() const {
return writing_direction_;
}
WritingMode GetWritingMode() const {
return writing_direction_.GetWritingMode();
}
TextDirection Direction() const { return writing_direction_.Direction(); }
wtf_size_t Size() const { return items_.size(); }
// Returns true if we have any floating descendants which need to be
// traversed during the float paint phase.
bool HasFloatingDescendantsForPaint() const {
return has_floating_descendants_for_paint_;
}
const String& TextContent(bool first_line) const {
return UNLIKELY(first_line && first_line_text_content_)
? first_line_text_content_
: text_content_;
}
// Adding a line is a three-pass operation, because |NGInlineLayoutAlgorithm|
// creates and positions children within a line box, but its parent algorithm
// positions the line box.
//
// 1. |AcquireLogicalLineItems| to get an instance of |NGLogicalLineItems|.
// 2. Add items to |NGLogicalLineItems| and create |NGPhysicalFragment|,
// then associate them by |AssociateLogicalLineItems|.
// 3. |AddLine| adds the |NGPhysicalLineBoxFragment|.
//
// |NGBlockLayoutAlgorithm| runs these phases in the order for each line. In
// this case, one instance of |NGLogicalLineItems| is reused for all lines to
// reduce memory allocations.
//
// Custom layout produces all line boxes first by running only 1 and 2 (in
// |NGInlineLayoutAlgorithm|). Then after worklet determined the position and
// the order of line boxes, it runs 3 for each line. In this case,
// |NGFragmentItemsBuilder| allocates new instance for each line, and keeps
// them alive until |AddLine|.
NGLogicalLineItems* AcquireLogicalLineItems();
void AssociateLogicalLineItems(NGLogicalLineItems* line_items,
const NGPhysicalFragment& line_fragment);
void AddLine(const NGPhysicalLineBoxFragment& line,
const LogicalOffset& offset);
// Add to |NGLogicalLineItems| instance pool. |AcquireLogicalLineItems|
// uses pooled instances first if available to avoid memory allocations.
void AddLogicalLineItemsPool(NGLogicalLineItems* line_items);
// Add a list marker to the current line.
void AddListMarker(const NGPhysicalBoxFragment& marker_fragment,
const LogicalOffset& offset);
// See |AddPreviousItems| below.
struct AddPreviousItemsResult {
STACK_ALLOCATED();
public:
const NGInlineBreakToken* inline_break_token = nullptr;
LayoutUnit used_block_size;
wtf_size_t line_count = 0;
bool succeeded = false;
};
// Add previously laid out |NGFragmentItems|.
//
// When |stop_at_dirty| is true, this function checks reusability of previous
// items and stops copying before the first dirty line.
AddPreviousItemsResult AddPreviousItems(
const NGPhysicalBoxFragment& container,
const NGFragmentItems& items,
NGBoxFragmentBuilder* container_builder = nullptr,
const NGFragmentItem* end_item = nullptr,
wtf_size_t max_lines = 0);
struct ItemWithOffset {
DISALLOW_NEW();
public:
template <class... Args>
explicit ItemWithOffset(const LogicalOffset& offset, Args&&... args)
: item(std::forward<Args>(args)...), offset(offset) {}
const NGFragmentItem& operator*() const { return item; }
const NGFragmentItem* operator->() const { return &item; }
NGFragmentItem item;
LogicalOffset offset;
};
// Give an inline size, the allocation of this vector is hot. "128" is
// heuristic. Usually 10-40, some wikipedia pages have >64 items.
using ItemWithOffsetList = Vector<ItemWithOffset, 128>;
// Find |LogicalOffset| of the first |NGFragmentItem| for |LayoutObject|.
base::Optional<LogicalOffset> LogicalOffsetFor(const LayoutObject&) const;
// Moves all the |NGFragmentItem|s by |offset| in the block-direction.
void MoveChildrenInBlockDirection(LayoutUnit offset);
// Converts the |NGFragmentItem| vector to the physical coordinate space and
// returns the result. This should only be used for determining the inline
// containing block geometry for OOF-positioned nodes.
//
// Once this method has been called, new items cannot be added.
const ItemWithOffsetList& Items(const PhysicalSize& outer_size);
// Build a |NGFragmentItems|. The builder cannot build twice because data set
// to this builder may be cleared.
void ToFragmentItems(const PhysicalSize& outer_size, void* data);
private:
void ReleaseCurrentLogicalLineItems();
void MoveCurrentLogicalLineItemsToMap();
void AddItems(NGLogicalLineItem* child_begin, NGLogicalLineItem* child_end);
void ConvertToPhysical(const PhysicalSize& outer_size);
ItemWithOffsetList items_;
String text_content_;
String first_line_text_content_;
// Keeps children of a line until the offset is determined. See |AddLine|.
NGLogicalLineItems* current_line_items_ = nullptr;
const NGPhysicalFragment* current_line_fragment_ = nullptr;
HashMap<const NGPhysicalFragment*, NGLogicalLineItems*> line_items_map_;
NGLogicalLineItems* line_items_pool_ = nullptr;
NGInlineNode node_;
WritingDirectionMode writing_direction_;
bool has_floating_descendants_for_paint_ = false;
bool is_converted_to_physical_ = false;
bool is_line_items_pool_acquired_ = false;
friend class NGFragmentItems;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_FRAGMENT_ITEMS_BUILDER_H_