// 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 explicit ItemWithOffset(const LogicalOffset& offset, Args&&... args) : item(std::forward(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; // Find |LogicalOffset| of the first |NGFragmentItem| for |LayoutObject|. base::Optional 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 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_