diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc | 200 |
1 files changed, 116 insertions, 84 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc index 452e1c2f102..74f8d5d2feb 100644 --- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc +++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc @@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h" +#include "third_party/blink/renderer/core/layout/geometry/writing_mode_converter.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h" #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h" @@ -11,7 +12,14 @@ namespace blink { -NGFragmentItemsBuilder::NGFragmentItemsBuilder(const NGInlineNode& node) { +NGFragmentItemsBuilder::NGFragmentItemsBuilder( + WritingDirectionMode writing_direction) + : node_(nullptr), writing_direction_(writing_direction) {} + +NGFragmentItemsBuilder::NGFragmentItemsBuilder( + const NGInlineNode& node, + WritingDirectionMode writing_direction) + : node_(node), writing_direction_(writing_direction) { const NGInlineItemsData& items_data = node.ItemsData(false); text_content_ = items_data.text_content; const NGInlineItemsData& first_line = node.ItemsData(true); @@ -30,11 +38,17 @@ NGFragmentItemsBuilder::NGFragmentItemsBuilder(const NGInlineNode& node) { void NGFragmentItemsBuilder::SetCurrentLine( const NGPhysicalLineBoxFragment& line, - ChildList&& children) { + NGLogicalLineItems* current_line) { #if DCHECK_IS_ON() current_line_fragment_ = &line; #endif - current_line_ = std::move(children); + DCHECK(current_line); + DCHECK(!current_line_); // Check |AddLine| runs after |SetCurrentLine|. + current_line_ = current_line; +} + +void NGFragmentItemsBuilder::ClearCurrentLineForTesting() { + current_line_ = nullptr; } void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line, @@ -43,79 +57,81 @@ void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line, #if DCHECK_IS_ON() DCHECK_EQ(current_line_fragment_, &line); #endif + DCHECK(current_line_); // Reserve the capacity for (children + line box item). const wtf_size_t size_before = items_.size(); - const wtf_size_t estimated_size = size_before + current_line_.size() + 1; + const wtf_size_t estimated_size = size_before + current_line_->size() + 1; const wtf_size_t old_capacity = items_.capacity(); if (estimated_size > old_capacity) items_.ReserveCapacity(std::max(estimated_size, old_capacity * 2)); // Add an empty item so that the start of the line can be set later. const wtf_size_t line_start_index = items_.size(); - items_.emplace_back(offset); + items_.emplace_back(offset, line); - AddItems(current_line_.begin(), current_line_.end()); + AddItems(current_line_->begin(), current_line_->end()); // All children are added. Create an item for the start of the line. + NGFragmentItem& line_item = items_[line_start_index].item; const wtf_size_t item_count = items_.size() - line_start_index; - DCHECK(!items_[line_start_index].item); - items_[line_start_index].item = - base::MakeRefCounted<NGFragmentItem>(line, item_count); + DCHECK_EQ(line_item.DescendantsCount(), 1u); + line_item.SetDescendantsCount(item_count); // Keep children's offsets relative to |line|. They will be adjusted later in // |ConvertToPhysical()|. - current_line_.clear(); + // Clear the current line without releasing the buffer. It is likely to be + // reused again. + current_line_->Shrink(0); #if DCHECK_IS_ON() + current_line_ = nullptr; current_line_fragment_ = nullptr; #endif DCHECK_LE(items_.size(), estimated_size); } -void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) { +void NGFragmentItemsBuilder::AddItems(NGLogicalLineItem* child_begin, + NGLogicalLineItem* child_end) { DCHECK(!is_converted_to_physical_); - for (Child* child_iter = child_begin; child_iter != child_end;) { - Child& child = *child_iter; + const WritingMode writing_mode = GetWritingMode(); + for (NGLogicalLineItem* child_iter = child_begin; child_iter != child_end;) { + NGLogicalLineItem& child = *child_iter; // OOF children should have been added to their parent box fragments. DCHECK(!child.out_of_flow_positioned_box); - if (!child.fragment_item) { + if (!child.CanCreateFragmentItem()) { ++child_iter; continue; } if (child.children_count <= 1) { - items_.emplace_back(std::move(child.fragment_item), child.rect.offset); + items_.emplace_back(child.rect.offset, std::move(child), writing_mode); ++child_iter; continue; } - DCHECK(child.fragment_item->IsContainer()); - DCHECK(!child.fragment_item->IsFloating()); // Children of inline boxes are flattened and added to |items_|, with the // count of descendant items to preserve the tree structure. // // Add an empty item so that the start of the box can be set later. - wtf_size_t box_start_index = items_.size(); - items_.emplace_back(child.rect.offset); + const wtf_size_t box_start_index = items_.size(); + items_.emplace_back(child.rect.offset, std::move(child), writing_mode); // Add all children, including their desendants, skipping this item. CHECK_GE(child.children_count, 1u); // 0 will loop infinitely. - Child* end_child_iter = child_iter + child.children_count; + NGLogicalLineItem* end_child_iter = child_iter + child.children_count; CHECK_LE(end_child_iter - child_begin, child_end - child_begin); AddItems(child_iter + 1, end_child_iter); child_iter = end_child_iter; // All children are added. Compute how many items are actually added. The // number of items added maybe different from |child.children_count|. - wtf_size_t item_count = items_.size() - box_start_index; - - // Create an item for the start of the box. - child.fragment_item->SetDescendantsCount(item_count); - DCHECK(!items_[box_start_index].item); - items_[box_start_index].item = std::move(child.fragment_item); + const wtf_size_t item_count = items_.size() - box_start_index; + NGFragmentItem& box_item = items_[box_start_index].item; + DCHECK_EQ(box_item.DescendantsCount(), 1u); + box_item.SetDescendantsCount(item_count); } } @@ -127,24 +143,28 @@ void NGFragmentItemsBuilder::AddListMarker( // Resolved direction matters only for inline items, and outside list markers // are not inline. const TextDirection resolved_direction = TextDirection::kLtr; - items_.emplace_back( - base::MakeRefCounted<NGFragmentItem>(marker_fragment, resolved_direction), - offset); + items_.emplace_back(offset, marker_fragment, resolved_direction); } NGFragmentItemsBuilder::AddPreviousItemsResult NGFragmentItemsBuilder::AddPreviousItems( const NGFragmentItems& items, - WritingMode writing_mode, - TextDirection direction, const PhysicalSize& container_size, NGBoxFragmentBuilder* container_builder, - bool stop_at_dirty) { - AddPreviousItemsResult result; - if (stop_at_dirty) { + const NGFragmentItem* end_item) { + if (end_item) { + DCHECK(node_); DCHECK(container_builder); DCHECK(text_content_); + + if (UNLIKELY(items.FirstLineText() && !first_line_text_content_)) { + // Don't reuse previous items if they have different `::first-line` style + // but |this| doesn't. Reaching here means that computed style doesn't + // change, but |NGFragmentItem| has wrong |NGStyleVariant|. + return AddPreviousItemsResult(); + } } else { + DCHECK(!container_builder); DCHECK(!text_content_); text_content_ = items.Text(false); first_line_text_content_ = items.Text(true); @@ -159,11 +179,13 @@ NGFragmentItemsBuilder::AddPreviousItems( // This is needed because the container size may be different, in that case, // the physical offsets are different when `writing-mode: vertial-rl`. DCHECK(!is_converted_to_physical_); - const WritingMode line_writing_mode = ToLineWritingMode(writing_mode); + const WritingModeConverter converter(GetWritingDirection(), container_size); + const WritingMode writing_mode = GetWritingMode(); + WritingModeConverter line_converter( + {ToLineWritingMode(writing_mode), TextDirection::kLtr}); - const NGFragmentItem* const end_item = - stop_at_dirty ? items.EndOfReusableItems() : nullptr; - const NGFragmentItem* last_line_start_item = nullptr; + const NGInlineBreakToken* last_break_token = nullptr; + const NGInlineItemsData* items_data = nullptr; LayoutUnit used_block_size; for (NGInlineCursor cursor(items); cursor;) { @@ -174,74 +196,88 @@ NGFragmentItemsBuilder::AddPreviousItems( DCHECK(!item.IsDirty()); const LogicalOffset item_offset = - item.OffsetInContainerBlock().ConvertToLogical( - writing_mode, direction, container_size, item.Size()); - items_.emplace_back(&item, item_offset); + converter.ToLogical(item.OffsetInContainerBlock(), item.Size()); if (item.Type() == NGFragmentItem::kLine) { + DCHECK(item.LineBoxFragment()); + if (end_item) { + // Check if this line has valid item_index and offset. + const NGPhysicalLineBoxFragment* line_fragment = item.LineBoxFragment(); + const NGInlineBreakToken* break_token = + To<NGInlineBreakToken>(line_fragment->BreakToken()); + DCHECK(!break_token->IsFinished()); + const NGInlineItemsData* current_items_data; + if (UNLIKELY(break_token->UseFirstLineStyle())) + current_items_data = &node_.ItemsData(true); + else if (items_data) + current_items_data = items_data; + else + current_items_data = items_data = &node_.ItemsData(false); + if (UNLIKELY(!current_items_data->IsValidOffset( + break_token->ItemIndex(), break_token->TextOffset()))) { + NOTREACHED(); + break; + } + + last_break_token = break_token; + container_builder->AddChild(*line_fragment, item_offset); + used_block_size += + item.Size().ConvertToLogical(writing_mode).block_size; + } + + items_.emplace_back(item_offset, item); const PhysicalRect line_box_bounds = item.RectInContainerBlock(); + line_converter.SetOuterSize(line_box_bounds.size); for (NGInlineCursor line = cursor.CursorForDescendants(); line; line.MoveToNext()) { const NGFragmentItem& line_child = *line.Current().Item(); DCHECK(line_child.CanReuse()); items_.emplace_back( - &line_child, - (line_child.OffsetInContainerBlock() - line_box_bounds.offset) - .ConvertToLogical(line_writing_mode, TextDirection::kLtr, - line_box_bounds.size, line_child.Size())); + line_converter.ToLogical( + line_child.OffsetInContainerBlock() - line_box_bounds.offset, + line_child.Size()), + line_child); } cursor.MoveToNextSkippingChildren(); - DCHECK(item.LineBoxFragment()); - if (stop_at_dirty) { - container_builder->AddChild(*item.LineBoxFragment(), item_offset); - last_line_start_item = &item; - used_block_size += - item.Size().ConvertToLogical(writing_mode).block_size; - } continue; } DCHECK_NE(item.Type(), NGFragmentItem::kLine); - DCHECK(!stop_at_dirty); + DCHECK(!end_item); + items_.emplace_back(item_offset, item); cursor.MoveToNext(); } + DCHECK_LE(items_.size(), estimated_size); - if (stop_at_dirty && last_line_start_item) { - result.inline_break_token = last_line_start_item->InlineBreakToken(); - DCHECK(result.inline_break_token); - DCHECK(!result.inline_break_token->IsFinished()); - result.used_block_size = used_block_size; - result.succeeded = true; + if (end_item && last_break_token) { + DCHECK(!last_break_token->IsFinished()); + return AddPreviousItemsResult{last_break_token, used_block_size, true}; } - - DCHECK_LE(items_.size(), estimated_size); - return result; + return AddPreviousItemsResult(); } const NGFragmentItemsBuilder::ItemWithOffsetList& NGFragmentItemsBuilder::Items( - WritingMode writing_mode, - TextDirection direction, const PhysicalSize& outer_size) { - ConvertToPhysical(writing_mode, direction, outer_size); + ConvertToPhysical(outer_size); return items_; } // Convert internal logical offsets to physical. Items are kept with logical // offset until outer box size is determined. -void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode, - TextDirection direction, - const PhysicalSize& outer_size) { +void NGFragmentItemsBuilder::ConvertToPhysical(const PhysicalSize& outer_size) { if (is_converted_to_physical_) return; + const WritingModeConverter converter(GetWritingDirection(), outer_size); // Children of lines have line-relative offsets. Use line-writing mode to - // convert their logical offsets. - const WritingMode line_writing_mode = ToLineWritingMode(writing_mode); + // convert their logical offsets. Use `kLtr` because inline items are after + // bidi-reoder, and that their offset is visual, not logical. + WritingModeConverter line_converter( + {ToLineWritingMode(GetWritingMode()), TextDirection::kLtr}); for (ItemWithOffset* iter = items_.begin(); iter != items_.end(); ++iter) { - NGFragmentItem* item = const_cast<NGFragmentItem*>(iter->item.get()); - item->SetOffset(iter->offset.ConvertToPhysical(writing_mode, direction, - outer_size, item->Size())); + NGFragmentItem* item = &iter->item; + item->SetOffset(converter.ToPhysical(iter->offset, item->Size())); // Transform children of lines separately from children of the block, // because they may have different directions from the block. To do @@ -251,16 +287,14 @@ void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode, DCHECK(descendants_count); if (descendants_count) { const PhysicalRect line_box_bounds = item->RectInContainerBlock(); + line_converter.SetOuterSize(line_box_bounds.size); while (--descendants_count) { ++iter; DCHECK_NE(iter, items_.end()); - item = const_cast<NGFragmentItem*>(iter->item.get()); - // Use `kLtr` because inline items are after bidi-reoder, and that - // their offset is visual, not logical. - item->SetOffset(iter->offset.ConvertToPhysical( - line_writing_mode, TextDirection::kLtr, - line_box_bounds.size, item->Size()) + - line_box_bounds.offset); + item = &iter->item; + item->SetOffset( + line_converter.ToPhysical(iter->offset, item->Size()) + + line_box_bounds.offset); } } } @@ -278,12 +312,10 @@ base::Optional<LogicalOffset> NGFragmentItemsBuilder::LogicalOffsetFor( return base::nullopt; } -void NGFragmentItemsBuilder::ToFragmentItems(WritingMode writing_mode, - TextDirection direction, - const PhysicalSize& outer_size, +void NGFragmentItemsBuilder::ToFragmentItems(const PhysicalSize& outer_size, void* data) { DCHECK(text_content_); - ConvertToPhysical(writing_mode, direction, outer_size); + ConvertToPhysical(outer_size); new (data) NGFragmentItems(this); } |