summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
diff options
context:
space:
mode:
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.cc200
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);
}