Commit 076416bb authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[FragmentItem] Change to the array of |NGFragmentItem|

This patch changes the array of |scoped_refptr<NGFragmentItem>|
to the array of |NGFragmentItem|.

This change:
* Improves memory usages.
* Improves memory locality when traversing items.
* Slows copying |NGFragmentItem|.

Pinpoint results show the memory improvement:
https://pinpoint-dot-chromeperf.appspot.com/job/15aa024e120000
but layout/paint look almost neutral, less than originally
expected unfortunately; some tests are faster but tests that
leverage simplified layout a lot are slower:
win10 blink_perf.layout
https://pinpoint-dot-chromeperf.appspot.com/job/165dcc45120000
linux blink_perf.layout
https://pinpoint-dot-chromeperf.appspot.com/job/14b5417a120000
linux blink_perf.paint
https://pinpoint-dot-chromeperf.appspot.com/job/143fc65a120000

Bug: 982194
Change-Id: I86b8a7e5eff4ad211da2cdaed065eacbec316469
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2208806
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#774510}
parent 820dae59
...@@ -17,7 +17,7 @@ namespace blink { ...@@ -17,7 +17,7 @@ namespace blink {
namespace { namespace {
struct SameSizeAsNGFragmentItem : RefCounted<NGFragmentItem> { struct SameSizeAsNGFragmentItem {
struct { struct {
void* pointer; void* pointer;
NGTextOffset text_offset; NGTextOffset text_offset;
...@@ -87,10 +87,9 @@ NGFragmentItem::NGFragmentItem( ...@@ -87,10 +87,9 @@ NGFragmentItem::NGFragmentItem(
DCHECK(!IsFormattingContextRoot()); DCHECK(!IsFormattingContextRoot());
} }
NGFragmentItem::NGFragmentItem(const NGPhysicalLineBoxFragment& line, NGFragmentItem::NGFragmentItem(const NGPhysicalLineBoxFragment& line)
wtf_size_t item_count)
: layout_object_(line.ContainerLayoutObject()), : layout_object_(line.ContainerLayoutObject()),
line_({&line, item_count}), line_({&line, /* descendants_count */ 1}),
rect_({PhysicalOffset(), line.Size()}), rect_({PhysicalOffset(), line.Size()}),
type_(kLine), type_(kLine),
sub_type_(static_cast<unsigned>(line.LineBoxType())), sub_type_(static_cast<unsigned>(line.LineBoxType())),
...@@ -106,7 +105,7 @@ NGFragmentItem::NGFragmentItem(const NGPhysicalLineBoxFragment& line, ...@@ -106,7 +105,7 @@ NGFragmentItem::NGFragmentItem(const NGPhysicalLineBoxFragment& line,
NGFragmentItem::NGFragmentItem(const NGPhysicalBoxFragment& box, NGFragmentItem::NGFragmentItem(const NGPhysicalBoxFragment& box,
TextDirection resolved_direction) TextDirection resolved_direction)
: layout_object_(box.GetLayoutObject()), : layout_object_(box.GetLayoutObject()),
box_({&box, 1}), box_({&box, /* descendants_count */ 1}),
rect_({PhysicalOffset(), box.Size()}), rect_({PhysicalOffset(), box.Size()}),
type_(kBox), type_(kBox),
style_variant_(static_cast<unsigned>(box.StyleVariant())), style_variant_(static_cast<unsigned>(box.StyleVariant())),
...@@ -118,28 +117,66 @@ NGFragmentItem::NGFragmentItem(const NGPhysicalBoxFragment& box, ...@@ -118,28 +117,66 @@ NGFragmentItem::NGFragmentItem(const NGPhysicalBoxFragment& box,
DCHECK_EQ(IsFormattingContextRoot(), box.IsFormattingContextRoot()); DCHECK_EQ(IsFormattingContextRoot(), box.IsFormattingContextRoot());
} }
// static NGFragmentItem::NGFragmentItem(NGLogicalLineItem&& line_item,
scoped_refptr<NGFragmentItem> NGFragmentItem::Create( WritingMode writing_mode) {
NGLogicalLineItem&& line_item, DCHECK(line_item.CanCreateFragmentItem());
WritingMode writing_mode) {
if (line_item.fragment) if (line_item.fragment) {
return base::AdoptRef(new NGFragmentItem(*line_item.fragment)); new (this) NGFragmentItem(*line_item.fragment);
return;
}
if (line_item.inline_item) { if (line_item.inline_item) {
return base::AdoptRef(new NGFragmentItem( new (this)
*line_item.inline_item, std::move(line_item.shape_result), NGFragmentItem(*line_item.inline_item,
line_item.text_offset, std::move(line_item.shape_result), line_item.text_offset,
ToPhysicalSize(line_item.MarginSize(), writing_mode))); ToPhysicalSize(line_item.MarginSize(), writing_mode));
return;
} }
if (line_item.layout_result) { if (line_item.layout_result) {
const NGPhysicalBoxFragment& box_fragment = const NGPhysicalBoxFragment& box_fragment =
To<NGPhysicalBoxFragment>(line_item.layout_result->PhysicalFragment()); To<NGPhysicalBoxFragment>(line_item.layout_result->PhysicalFragment());
return base::AdoptRef( new (this) NGFragmentItem(box_fragment, line_item.ResolvedDirection());
new NGFragmentItem(box_fragment, line_item.ResolvedDirection())); return;
} }
return nullptr; // CanCreateFragmentItem()
NOTREACHED();
CHECK(false);
}
NGFragmentItem::NGFragmentItem(NGFragmentItem&& source)
: layout_object_(source.layout_object_),
rect_(source.rect_),
ink_overflow_(std::move(source.ink_overflow_)),
fragment_id_(source.fragment_id_),
delta_to_next_for_same_layout_object_(
source.delta_to_next_for_same_layout_object_),
type_(source.type_),
sub_type_(source.sub_type_),
style_variant_(source.style_variant_),
is_hidden_for_paint_(source.is_hidden_for_paint_),
text_direction_(source.text_direction_),
ink_overflow_computed_(source.ink_overflow_computed_),
is_dirty_(source.is_dirty_),
is_last_for_node_(source.is_last_for_node_) {
DCHECK(!source.ink_overflow_); // Ensure it was moved.
switch (Type()) {
case kText:
new (&text_) TextItem(std::move(source.text_));
break;
case kGeneratedText:
new (&generated_text_)
GeneratedTextItem(std::move(source.generated_text_));
break;
case kLine:
new (&line_) LineItem(std::move(source.line_));
break;
case kBox:
new (&box_) BoxItem(std::move(source.box_));
break;
}
} }
NGFragmentItem::~NGFragmentItem() { NGFragmentItem::~NGFragmentItem() {
......
...@@ -29,7 +29,7 @@ struct NGLogicalLineItem; ...@@ -29,7 +29,7 @@ struct NGLogicalLineItem;
// //
// This class consumes less memory than a full fragment, and can be stored in a // This class consumes less memory than a full fragment, and can be stored in a
// flat list (NGFragmentItems) for easier and faster traversal. // flat list (NGFragmentItems) for easier and faster traversal.
class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> { class CORE_EXPORT NGFragmentItem {
public: public:
// Represents regular text that exists in the DOM. // Represents regular text that exists in the DOM.
struct TextItem { struct TextItem {
...@@ -65,6 +65,8 @@ class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> { ...@@ -65,6 +65,8 @@ class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> {
enum ItemType { kText, kGeneratedText, kLine, kBox }; enum ItemType { kText, kGeneratedText, kLine, kBox };
// Create appropriate type for |line_item|.
NGFragmentItem(NGLogicalLineItem&& line_item, WritingMode writing_mode);
// Create a text item. // Create a text item.
// TODO(kojii): Should be able to create without once creating fragments. // TODO(kojii): Should be able to create without once creating fragments.
explicit NGFragmentItem(const NGPhysicalTextFragment& text); explicit NGFragmentItem(const NGPhysicalTextFragment& text);
...@@ -72,11 +74,10 @@ class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> { ...@@ -72,11 +74,10 @@ class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> {
NGFragmentItem(const NGPhysicalBoxFragment& box, NGFragmentItem(const NGPhysicalBoxFragment& box,
TextDirection resolved_direction); TextDirection resolved_direction);
// Create a line item. // Create a line item.
NGFragmentItem(const NGPhysicalLineBoxFragment& line, wtf_size_t item_count); explicit NGFragmentItem(const NGPhysicalLineBoxFragment& line);
// Create |NGFragmentItem| for all items in |child_list|. // The move constructor.
static scoped_refptr<NGFragmentItem> Create(NGLogicalLineItem&& child, NGFragmentItem(NGFragmentItem&&);
WritingMode writing_mode);
~NGFragmentItem(); ~NGFragmentItem();
...@@ -176,8 +177,15 @@ class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> { ...@@ -176,8 +177,15 @@ class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> {
} }
bool HasChildren() const { return DescendantsCount() > 1; } bool HasChildren() const { return DescendantsCount() > 1; }
void SetDescendantsCount(wtf_size_t count) { void SetDescendantsCount(wtf_size_t count) {
CHECK_EQ(Type(), kBox); if (Type() == kBox) {
box_.descendants_count = count; box_.descendants_count = count;
return;
}
if (Type() == kLine) {
line_.descendants_count = count;
return;
}
NOTREACHED();
} }
// Returns |NGPhysicalBoxFragment| if one is associated with this item. // Returns |NGPhysicalBoxFragment| if one is associated with this item.
...@@ -357,6 +365,8 @@ class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> { ...@@ -357,6 +365,8 @@ class CORE_EXPORT NGFragmentItem : public RefCounted<NGFragmentItem> {
// Returns true if this item is reusable. // Returns true if this item is reusable.
bool CanReuse() const; bool CanReuse() const;
const NGFragmentItem* operator->() const { return this; }
// Get a description of |this| for the debug purposes. // Get a description of |this| for the debug purposes.
String ToString() const; String ToString() const;
......
...@@ -20,16 +20,13 @@ NGFragmentItems::NGFragmentItems(NGFragmentItemsBuilder* builder) ...@@ -20,16 +20,13 @@ NGFragmentItems::NGFragmentItems(NGFragmentItemsBuilder* builder)
for (unsigned i = 0; i < size_; ++i) { for (unsigned i = 0; i < size_; ++i) {
// Call the move constructor to move without |AddRef|. Items in // Call the move constructor to move without |AddRef|. Items in
// |NGFragmentItemsBuilder| are not used after |this| was constructed. // |NGFragmentItemsBuilder| are not used after |this| was constructed.
DCHECK(source_items[i].item); new (&items_[i]) NGFragmentItem(std::move(source_items[i].item));
new (&items_[i])
scoped_refptr<const NGFragmentItem>(std::move(source_items[i].item));
DCHECK(!source_items[i].item); // Ensure the source was moved.
} }
} }
NGFragmentItems::~NGFragmentItems() { NGFragmentItems::~NGFragmentItems() {
for (unsigned i = 0; i < size_; ++i) for (unsigned i = 0; i < size_; ++i)
items_[i]->Release(); items_[i].~NGFragmentItem();
} }
bool NGFragmentItems::IsSubSpan(const Span& span) const { bool NGFragmentItems::IsSubSpan(const Span& span) const {
...@@ -58,27 +55,27 @@ void NGFragmentItems::FinalizeAfterLayout( ...@@ -58,27 +55,27 @@ void NGFragmentItems::FinalizeAfterLayout(
const Span items = current->Items(); const Span items = current->Items();
wtf_size_t index = 0; wtf_size_t index = 0;
for (const scoped_refptr<const NGFragmentItem>& item : items) { for (const NGFragmentItem& item : items) {
++index; ++index;
if (item->Type() == NGFragmentItem::kLine) { if (item.Type() == NGFragmentItem::kLine) {
DCHECK_EQ(item->DeltaToNextForSameLayoutObject(), 0u); DCHECK_EQ(item.DeltaToNextForSameLayoutObject(), 0u);
continue; continue;
} }
LayoutObject* const layout_object = item->GetMutableLayoutObject(); LayoutObject* const layout_object = item.GetMutableLayoutObject();
if (UNLIKELY(layout_object->IsFloating())) { if (UNLIKELY(layout_object->IsFloating())) {
DCHECK_EQ(item->DeltaToNextForSameLayoutObject(), 0u); DCHECK_EQ(item.DeltaToNextForSameLayoutObject(), 0u);
continue; continue;
} }
DCHECK(!layout_object->IsOutOfFlowPositioned()); DCHECK(!layout_object->IsOutOfFlowPositioned());
DCHECK(layout_object->IsInLayoutNGInlineFormattingContext()) << *item; DCHECK(layout_object->IsInLayoutNGInlineFormattingContext());
item->SetDeltaToNextForSameLayoutObject(0); item.SetDeltaToNextForSameLayoutObject(0);
item->SetIsLastForNode(false); item.SetIsLastForNode(false);
const auto last_item_result = const auto last_item_result =
last_items.insert(layout_object, LastItem{item.get(), 0, index}); last_items.insert(layout_object, LastItem{&item, 0, index});
if (last_item_result.is_new_entry) { if (last_item_result.is_new_entry) {
item->SetFragmentId(0); item.SetFragmentId(0);
if (create_index_cache) { if (create_index_cache) {
DCHECK_EQ(layout_object->FirstInlineFragmentItemIndex(), 0u); DCHECK_EQ(layout_object->FirstInlineFragmentItemIndex(), 0u);
layout_object->SetFirstInlineFragmentItemIndex(index); layout_object->SetFirstInlineFragmentItemIndex(index);
...@@ -91,13 +88,13 @@ void NGFragmentItems::FinalizeAfterLayout( ...@@ -91,13 +88,13 @@ void NGFragmentItems::FinalizeAfterLayout(
DCHECK_EQ(last_item->DeltaToNextForSameLayoutObject(), 0u); DCHECK_EQ(last_item->DeltaToNextForSameLayoutObject(), 0u);
if (create_index_cache) { if (create_index_cache) {
const wtf_size_t last_index = last->item_index; const wtf_size_t last_index = last->item_index;
DCHECK_GT(last_index, 0u) << *item; DCHECK_GT(last_index, 0u);
DCHECK_LT(last_index, items.size()); DCHECK_LT(last_index, items.size());
DCHECK_LT(last_index, index); DCHECK_LT(last_index, index);
last_item->SetDeltaToNextForSameLayoutObject(index - last_index); last_item->SetDeltaToNextForSameLayoutObject(index - last_index);
} }
item->SetFragmentId(++last->fragment_id); item.SetFragmentId(++last->fragment_id);
last->item = item.get(); last->item = &item;
last->item_index = index; last->item_index = index;
} }
} }
...@@ -182,7 +179,7 @@ bool NGFragmentItems::TryDirtyFirstLineFor( ...@@ -182,7 +179,7 @@ bool NGFragmentItems::TryDirtyFirstLineFor(
DCHECK(layout_object.IsInLayoutNGInlineFormattingContext()); DCHECK(layout_object.IsInLayoutNGInlineFormattingContext());
DCHECK(!layout_object.IsFloatingOrOutOfFlowPositioned()); DCHECK(!layout_object.IsFloatingOrOutOfFlowPositioned());
if (wtf_size_t index = layout_object.FirstInlineFragmentItemIndex()) { if (wtf_size_t index = layout_object.FirstInlineFragmentItemIndex()) {
const NGFragmentItem& item = *Items()[index - 1]; const NGFragmentItem& item = Items()[index - 1];
DCHECK_EQ(&layout_object, item.GetLayoutObject()); DCHECK_EQ(&layout_object, item.GetLayoutObject());
item.SetDirty(); item.SetDirty();
return true; return true;
...@@ -291,8 +288,8 @@ void NGFragmentItems::LayoutObjectWillBeMoved( ...@@ -291,8 +288,8 @@ void NGFragmentItems::LayoutObjectWillBeMoved(
*container.GetPhysicalFragment(idx); *container.GetPhysicalFragment(idx);
DCHECK(fragment.Items()); DCHECK(fragment.Items());
for (const auto& item : fragment.Items()->Items()) { for (const auto& item : fragment.Items()->Items()) {
if (item->GetLayoutObject() == &layout_object) if (item.GetLayoutObject() == &layout_object)
item->LayoutObjectWillBeMoved(); item.LayoutObjectWillBeMoved();
} }
} }
return; return;
...@@ -318,8 +315,8 @@ void NGFragmentItems::LayoutObjectWillBeDestroyed( ...@@ -318,8 +315,8 @@ void NGFragmentItems::LayoutObjectWillBeDestroyed(
*container.GetPhysicalFragment(idx); *container.GetPhysicalFragment(idx);
DCHECK(fragment.Items()); DCHECK(fragment.Items());
for (const auto& item : fragment.Items()->Items()) { for (const auto& item : fragment.Items()->Items()) {
if (item->GetLayoutObject() == &layout_object) if (item.GetLayoutObject() == &layout_object)
item->LayoutObjectWillBeDestroyed(); item.LayoutObjectWillBeDestroyed();
} }
} }
return; return;
......
...@@ -24,7 +24,7 @@ class CORE_EXPORT NGFragmentItems { ...@@ -24,7 +24,7 @@ class CORE_EXPORT NGFragmentItems {
wtf_size_t Size() const { return size_; } wtf_size_t Size() const { return size_; }
using Span = base::span<const scoped_refptr<const NGFragmentItem>>; using Span = base::span<const NGFragmentItem>;
Span Items() const { return base::make_span(ItemsData(), size_); } Span Items() const { return base::make_span(ItemsData(), size_); }
bool Equals(const Span& span) const { bool Equals(const Span& span) const {
return ItemsData() == span.data() && Size() == span.size(); return ItemsData() == span.data() && Size() == span.size();
...@@ -33,7 +33,7 @@ class CORE_EXPORT NGFragmentItems { ...@@ -33,7 +33,7 @@ class CORE_EXPORT NGFragmentItems {
const NGFragmentItem& front() const { const NGFragmentItem& front() const {
CHECK_GE(size_, 1u); CHECK_GE(size_, 1u);
return *items_[0]; return items_[0];
} }
const String& Text(bool first_line) const { const String& Text(bool first_line) const {
...@@ -69,9 +69,7 @@ class CORE_EXPORT NGFragmentItems { ...@@ -69,9 +69,7 @@ class CORE_EXPORT NGFragmentItems {
wtf_size_t ByteSize() const { return ByteSizeFor(Size()); } wtf_size_t ByteSize() const { return ByteSizeFor(Size()); }
private: private:
const scoped_refptr<const NGFragmentItem>* ItemsData() const { const NGFragmentItem* ItemsData() const { return items_; }
return reinterpret_cast<const scoped_refptr<const NGFragmentItem>*>(items_);
}
static bool CanReuseAll(NGInlineCursor* cursor); static bool CanReuseAll(NGInlineCursor* cursor);
bool TryDirtyFirstLineFor(const LayoutObject& layout_object) const; bool TryDirtyFirstLineFor(const LayoutObject& layout_object) const;
...@@ -89,7 +87,7 @@ class CORE_EXPORT NGFragmentItems { ...@@ -89,7 +87,7 @@ class CORE_EXPORT NGFragmentItems {
static_assert( static_assert(
sizeof(NGFragmentItem*) == sizeof(scoped_refptr<const NGFragmentItem>), sizeof(NGFragmentItem*) == sizeof(scoped_refptr<const NGFragmentItem>),
"scoped_refptr must be the size of a pointer for |ItemsData()| to work"); "scoped_refptr must be the size of a pointer for |ItemsData()| to work");
NGFragmentItem* items_[]; NGFragmentItem items_[0];
}; };
} // namespace blink } // namespace blink
......
...@@ -60,15 +60,15 @@ void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line, ...@@ -60,15 +60,15 @@ void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
// Add an empty item so that the start of the line can be set later. // Add an empty item so that the start of the line can be set later.
const wtf_size_t line_start_index = items_.size(); 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. // 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; const wtf_size_t item_count = items_.size() - line_start_index;
DCHECK(!items_[line_start_index].item); DCHECK_EQ(line_item.DescendantsCount(), 1u);
items_[line_start_index].item = line_item.SetDescendantsCount(item_count);
base::MakeRefCounted<NGFragmentItem>(line, item_count);
// Keep children's offsets relative to |line|. They will be adjusted later in // Keep children's offsets relative to |line|. They will be adjusted later in
// |ConvertToPhysical()|. // |ConvertToPhysical()|.
...@@ -89,27 +89,23 @@ void NGFragmentItemsBuilder::AddItems(NGLogicalLineItem* child_begin, ...@@ -89,27 +89,23 @@ void NGFragmentItemsBuilder::AddItems(NGLogicalLineItem* child_begin,
NGLogicalLineItem& child = *child_iter; NGLogicalLineItem& child = *child_iter;
// OOF children should have been added to their parent box fragments. // OOF children should have been added to their parent box fragments.
DCHECK(!child.out_of_flow_positioned_box); DCHECK(!child.out_of_flow_positioned_box);
scoped_refptr<NGFragmentItem> item = if (!child.CanCreateFragmentItem()) {
NGFragmentItem::Create(std::move(child), writing_mode_);
if (!item) {
++child_iter; ++child_iter;
continue; continue;
} }
if (child.children_count <= 1) { if (child.children_count <= 1) {
items_.emplace_back(std::move(item), child.rect.offset); items_.emplace_back(child.rect.offset, std::move(child), writing_mode_);
++child_iter; ++child_iter;
continue; continue;
} }
DCHECK(item->IsContainer());
DCHECK(!item->IsFloating());
// Children of inline boxes are flattened and added to |items_|, with the // Children of inline boxes are flattened and added to |items_|, with the
// count of descendant items to preserve the tree structure. // count of descendant items to preserve the tree structure.
// //
// Add an empty item so that the start of the box can be set later. // Add an empty item so that the start of the box can be set later.
const wtf_size_t box_start_index = items_.size(); const wtf_size_t box_start_index = items_.size();
items_.emplace_back(child.rect.offset); items_.emplace_back(child.rect.offset, std::move(child), writing_mode_);
// Add all children, including their desendants, skipping this item. // Add all children, including their desendants, skipping this item.
CHECK_GE(child.children_count, 1u); // 0 will loop infinitely. CHECK_GE(child.children_count, 1u); // 0 will loop infinitely.
...@@ -121,9 +117,9 @@ void NGFragmentItemsBuilder::AddItems(NGLogicalLineItem* child_begin, ...@@ -121,9 +117,9 @@ void NGFragmentItemsBuilder::AddItems(NGLogicalLineItem* child_begin,
// All children are added. Compute how many items are actually added. The // All children are added. Compute how many items are actually added. The
// number of items added maybe different from |child.children_count|. // number of items added maybe different from |child.children_count|.
const wtf_size_t item_count = items_.size() - box_start_index; const wtf_size_t item_count = items_.size() - box_start_index;
item->SetDescendantsCount(item_count); NGFragmentItem& box_item = items_[box_start_index].item;
DCHECK(!items_[box_start_index].item); DCHECK_EQ(box_item.DescendantsCount(), 1u);
items_[box_start_index].item = std::move(item); box_item.SetDescendantsCount(item_count);
} }
} }
...@@ -135,9 +131,7 @@ void NGFragmentItemsBuilder::AddListMarker( ...@@ -135,9 +131,7 @@ void NGFragmentItemsBuilder::AddListMarker(
// Resolved direction matters only for inline items, and outside list markers // Resolved direction matters only for inline items, and outside list markers
// are not inline. // are not inline.
const TextDirection resolved_direction = TextDirection::kLtr; const TextDirection resolved_direction = TextDirection::kLtr;
items_.emplace_back( items_.emplace_back(offset, marker_fragment, resolved_direction);
base::MakeRefCounted<NGFragmentItem>(marker_fragment, resolved_direction),
offset);
} }
NGFragmentItemsBuilder::AddPreviousItemsResult NGFragmentItemsBuilder::AddPreviousItemsResult
...@@ -169,7 +163,7 @@ NGFragmentItemsBuilder::AddPreviousItems( ...@@ -169,7 +163,7 @@ NGFragmentItemsBuilder::AddPreviousItems(
const NGFragmentItem* const end_item = const NGFragmentItem* const end_item =
stop_at_dirty ? items.EndOfReusableItems() : nullptr; stop_at_dirty ? items.EndOfReusableItems() : nullptr;
const NGFragmentItem* last_line_start_item = nullptr; const NGPhysicalLineBoxFragment* last_line_fragment = nullptr;
LayoutUnit used_block_size; LayoutUnit used_block_size;
for (NGInlineCursor cursor(items); cursor;) { for (NGInlineCursor cursor(items); cursor;) {
...@@ -182,38 +176,43 @@ NGFragmentItemsBuilder::AddPreviousItems( ...@@ -182,38 +176,43 @@ NGFragmentItemsBuilder::AddPreviousItems(
const LogicalOffset item_offset = const LogicalOffset item_offset =
item.OffsetInContainerBlock().ConvertToLogical( item.OffsetInContainerBlock().ConvertToLogical(
writing_mode_, direction_, container_size, item.Size()); writing_mode_, direction_, container_size, item.Size());
items_.emplace_back(&item, item_offset);
if (item.Type() == NGFragmentItem::kLine) { if (item.Type() == NGFragmentItem::kLine) {
DCHECK(item.LineBoxFragment());
if (stop_at_dirty) {
last_line_fragment = item.LineBoxFragment();
container_builder->AddChild(*last_line_fragment, item_offset);
used_block_size +=
item.Size().ConvertToLogical(writing_mode_).block_size;
}
items_.emplace_back(item_offset,
std::move(const_cast<NGFragmentItem&>(item)));
const PhysicalRect line_box_bounds = item.RectInContainerBlock(); const PhysicalRect line_box_bounds = item.RectInContainerBlock();
for (NGInlineCursor line = cursor.CursorForDescendants(); line; for (NGInlineCursor line = cursor.CursorForDescendants(); line;
line.MoveToNext()) { line.MoveToNext()) {
const NGFragmentItem& line_child = *line.Current().Item(); const NGFragmentItem& line_child = *line.Current().Item();
DCHECK(line_child.CanReuse()); DCHECK(line_child.CanReuse());
items_.emplace_back( items_.emplace_back(
&line_child,
(line_child.OffsetInContainerBlock() - line_box_bounds.offset) (line_child.OffsetInContainerBlock() - line_box_bounds.offset)
.ConvertToLogical(line_writing_mode, TextDirection::kLtr, .ConvertToLogical(line_writing_mode, TextDirection::kLtr,
line_box_bounds.size, line_child.Size())); line_box_bounds.size, line_child.Size()),
std::move(const_cast<NGFragmentItem&>(line_child)));
} }
cursor.MoveToNextSkippingChildren(); 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; continue;
} }
DCHECK_NE(item.Type(), NGFragmentItem::kLine); DCHECK_NE(item.Type(), NGFragmentItem::kLine);
DCHECK(!stop_at_dirty); DCHECK(!stop_at_dirty);
items_.emplace_back(item_offset,
std::move(const_cast<NGFragmentItem&>(item)));
cursor.MoveToNext(); cursor.MoveToNext();
} }
if (stop_at_dirty && last_line_start_item) { if (stop_at_dirty && last_line_fragment) {
result.inline_break_token = last_line_start_item->InlineBreakToken(); result.inline_break_token =
To<NGInlineBreakToken>(last_line_fragment->BreakToken());
DCHECK(result.inline_break_token); DCHECK(result.inline_break_token);
DCHECK(!result.inline_break_token->IsFinished()); DCHECK(!result.inline_break_token->IsFinished());
result.used_block_size = used_block_size; result.used_block_size = used_block_size;
...@@ -241,7 +240,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(const PhysicalSize& outer_size) { ...@@ -241,7 +240,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(const PhysicalSize& outer_size) {
const WritingMode line_writing_mode = ToLineWritingMode(writing_mode_); const WritingMode line_writing_mode = ToLineWritingMode(writing_mode_);
for (ItemWithOffset* iter = items_.begin(); iter != items_.end(); ++iter) { for (ItemWithOffset* iter = items_.begin(); iter != items_.end(); ++iter) {
NGFragmentItem* item = const_cast<NGFragmentItem*>(iter->item.get()); NGFragmentItem* item = &iter->item;
item->SetOffset(iter->offset.ConvertToPhysical(writing_mode_, direction_, item->SetOffset(iter->offset.ConvertToPhysical(writing_mode_, direction_,
outer_size, item->Size())); outer_size, item->Size()));
...@@ -256,7 +255,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(const PhysicalSize& outer_size) { ...@@ -256,7 +255,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(const PhysicalSize& outer_size) {
while (--descendants_count) { while (--descendants_count) {
++iter; ++iter;
DCHECK_NE(iter, items_.end()); DCHECK_NE(iter, items_.end());
item = const_cast<NGFragmentItem*>(iter->item.get()); item = &iter->item;
// Use `kLtr` because inline items are after bidi-reoder, and that // Use `kLtr` because inline items are after bidi-reoder, and that
// their offset is visual, not logical. // their offset is visual, not logical.
item->SetOffset(iter->offset.ConvertToPhysical( item->SetOffset(iter->offset.ConvertToPhysical(
......
...@@ -87,15 +87,14 @@ class CORE_EXPORT NGFragmentItemsBuilder { ...@@ -87,15 +87,14 @@ class CORE_EXPORT NGFragmentItemsBuilder {
DISALLOW_NEW(); DISALLOW_NEW();
public: public:
ItemWithOffset(scoped_refptr<const NGFragmentItem> item, template <class... Args>
const LogicalOffset& offset) explicit ItemWithOffset(const LogicalOffset& offset, Args&&... args)
: item(std::move(item)), offset(offset) {} : item(std::forward<Args>(args)...), offset(offset) {}
explicit ItemWithOffset(const LogicalOffset& offset) : offset(offset) {}
const NGFragmentItem& operator*() const { return *item; } const NGFragmentItem& operator*() const { return item; }
const NGFragmentItem* operator->() const { return item.get(); } const NGFragmentItem* operator->() const { return &item; }
scoped_refptr<const NGFragmentItem> item; NGFragmentItem item;
LogicalOffset offset; LogicalOffset offset;
}; };
......
...@@ -120,7 +120,7 @@ const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const { ...@@ -120,7 +120,7 @@ const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const {
return layout_object->RootInlineFormattingContext(); return layout_object->RootInlineFormattingContext();
} }
if (IsItemCursor()) { if (IsItemCursor()) {
const NGFragmentItem& item = *fragment_items_->Items().front(); const NGFragmentItem& item = fragment_items_->front();
const LayoutObject* layout_object = item.GetLayoutObject(); const LayoutObject* layout_object = item.GetLayoutObject();
if (item.Type() == NGFragmentItem::kLine) if (item.Type() == NGFragmentItem::kLine)
return To<LayoutBlockFlow>(layout_object); return To<LayoutBlockFlow>(layout_object);
...@@ -916,7 +916,7 @@ NGInlineCursor::ItemsSpan::iterator NGInlineCursor::SlowFirstItemIteratorFor( ...@@ -916,7 +916,7 @@ NGInlineCursor::ItemsSpan::iterator NGInlineCursor::SlowFirstItemIteratorFor(
const LayoutObject& layout_object, const LayoutObject& layout_object,
const ItemsSpan& items) { const ItemsSpan& items) {
for (ItemsSpan::iterator iter = items.begin(); iter != items.end(); ++iter) { for (ItemsSpan::iterator iter = items.begin(); iter != items.end(); ++iter) {
if ((*iter)->GetLayoutObject() == &layout_object) if (iter->GetLayoutObject() == &layout_object)
return iter; return iter;
} }
return items.end(); return items.end();
...@@ -995,7 +995,7 @@ bool NGInlineCursor::IsAtFirst() const { ...@@ -995,7 +995,7 @@ bool NGInlineCursor::IsAtFirst() const {
if (const NGPaintFragment* paint_fragment = Current().PaintFragment()) if (const NGPaintFragment* paint_fragment = Current().PaintFragment())
return paint_fragment == root_paint_fragment_->FirstChild(); return paint_fragment == root_paint_fragment_->FirstChild();
if (const NGFragmentItem* item = Current().Item()) if (const NGFragmentItem* item = Current().Item())
return item == items_.front().get(); return item == &items_.front();
return false; return false;
} }
...@@ -1025,7 +1025,7 @@ void NGInlineCursor::MoveToFirstLine() { ...@@ -1025,7 +1025,7 @@ void NGInlineCursor::MoveToFirstLine() {
if (IsItemCursor()) { if (IsItemCursor()) {
auto iter = std::find_if( auto iter = std::find_if(
items_.begin(), items_.end(), items_.begin(), items_.end(),
[](const auto& item) { return item->Type() == NGFragmentItem::kLine; }); [](const auto& item) { return item.Type() == NGFragmentItem::kLine; });
if (iter != items_.end()) { if (iter != items_.end()) {
MoveToItem(iter); MoveToItem(iter);
return; return;
...@@ -1061,7 +1061,7 @@ void NGInlineCursor::MoveToLastLine() { ...@@ -1061,7 +1061,7 @@ void NGInlineCursor::MoveToLastLine() {
DCHECK(IsItemCursor()); DCHECK(IsItemCursor());
auto iter = std::find_if( auto iter = std::find_if(
items_.rbegin(), items_.rend(), items_.rbegin(), items_.rend(),
[](const auto& item) { return item->Type() == NGFragmentItem::kLine; }); [](const auto& item) { return item.Type() == NGFragmentItem::kLine; });
if (iter != items_.rend()) if (iter != items_.rend())
MoveToItem(std::next(iter).base()); MoveToItem(std::next(iter).base());
else else
...@@ -1229,7 +1229,7 @@ void NGInlineCursor::MoveToNextItem() { ...@@ -1229,7 +1229,7 @@ void NGInlineCursor::MoveToNextItem() {
return; return;
DCHECK(current_.item_iter_ != items_.end()); DCHECK(current_.item_iter_ != items_.end());
if (++current_.item_iter_ != items_.end()) { if (++current_.item_iter_ != items_.end()) {
current_.item_ = current_.item_iter_->get(); current_.item_ = &*current_.item_iter_;
return; return;
} }
MakeNull(); MakeNull();
...@@ -1253,7 +1253,7 @@ void NGInlineCursor::MoveToPreviousItem() { ...@@ -1253,7 +1253,7 @@ void NGInlineCursor::MoveToPreviousItem() {
if (current_.item_iter_ == items_.begin()) if (current_.item_iter_ == items_.begin())
return MakeNull(); return MakeNull();
--current_.item_iter_; --current_.item_iter_;
current_.item_ = current_.item_iter_->get(); current_.item_ = &*current_.item_iter_;
} }
void NGInlineCursor::MoveToParentPaintFragment() { void NGInlineCursor::MoveToParentPaintFragment() {
...@@ -1380,7 +1380,7 @@ void NGInlineCursor::MoveTo(const LayoutObject& layout_object) { ...@@ -1380,7 +1380,7 @@ void NGInlineCursor::MoveTo(const LayoutObject& layout_object) {
if (UNLIKELY(!fragment_items_->Equals(items_))) { if (UNLIKELY(!fragment_items_->Equals(items_))) {
const wtf_size_t span_begin_item_index = SpanBeginItemIndex(); const wtf_size_t span_begin_item_index = SpanBeginItemIndex();
while (UNLIKELY(item_index < span_begin_item_index)) { while (UNLIKELY(item_index < span_begin_item_index)) {
const NGFragmentItem& item = *fragment_items_->Items()[item_index]; const NGFragmentItem& item = fragment_items_->Items()[item_index];
const wtf_size_t next_delta = item.DeltaToNextForSameLayoutObject(); const wtf_size_t next_delta = item.DeltaToNextForSameLayoutObject();
if (!next_delta) { if (!next_delta) {
MakeNull(); MakeNull();
...@@ -1475,10 +1475,8 @@ NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor) ...@@ -1475,10 +1475,8 @@ NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor)
sibling.MoveToNextSkippingChildren()) sibling.MoveToNextSkippingChildren())
sibling_item_iterators_.push_back(sibling.Current().item_iter_); sibling_item_iterators_.push_back(sibling.Current().item_iter_);
current_index_ = sibling_item_iterators_.size(); current_index_ = sibling_item_iterators_.size();
if (current_index_) { if (current_index_)
current_.item_iter_ = sibling_item_iterators_[--current_index_]; current_.Set(sibling_item_iterators_[--current_index_]);
current_.item_ = current_.item_iter_->get();
}
return; return;
} }
DCHECK(!cursor); DCHECK(!cursor);
...@@ -1503,8 +1501,7 @@ void NGInlineBackwardCursor::MoveToPreviousSibling() { ...@@ -1503,8 +1501,7 @@ void NGInlineBackwardCursor::MoveToPreviousSibling() {
return; return;
} }
if (current_.item_) { if (current_.item_) {
current_.item_iter_ = sibling_item_iterators_[--current_index_]; current_.Set(sibling_item_iterators_[--current_index_]);
current_.item_ = current_.item_iter_->get();
return; return;
} }
NOTREACHED(); NOTREACHED();
......
...@@ -174,7 +174,7 @@ class CORE_EXPORT NGInlineCursorPosition { ...@@ -174,7 +174,7 @@ class CORE_EXPORT NGInlineCursorPosition {
void Set(const ItemsSpan::iterator& iter) { void Set(const ItemsSpan::iterator& iter) {
DCHECK(!paint_fragment_); DCHECK(!paint_fragment_);
item_iter_ = iter; item_iter_ = iter;
item_ = iter->get(); item_ = &*iter;
} }
void Clear() { void Clear() {
......
...@@ -106,6 +106,7 @@ struct NGLogicalLineItem { ...@@ -106,6 +106,7 @@ struct NGLogicalLineItem {
bool HasFragment() const { bool HasFragment() const {
return HasInFlowOrFloatingFragment() || HasOutOfFlowFragment(); return HasInFlowOrFloatingFragment() || HasOutOfFlowFragment();
} }
bool CanCreateFragmentItem() const { return HasInFlowOrFloatingFragment(); }
bool HasBidiLevel() const { return bidi_level != 0xff; } bool HasBidiLevel() const { return bidi_level != 0xff; }
bool IsPlaceholder() const { return !HasFragment() && !HasBidiLevel(); } bool IsPlaceholder() const { return !HasFragment() && !HasBidiLevel(); }
bool IsOpaqueToBidiReordering() const { bool IsOpaqueToBidiReordering() const {
......
...@@ -78,10 +78,8 @@ LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset( ...@@ -78,10 +78,8 @@ LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset(
unsigned offset, unsigned offset,
LayoutUnit (*round_function)(float), LayoutUnit (*round_function)(float),
AdjustMidCluster adjust_mid_cluster) const { AdjustMidCluster adjust_mid_cluster) const {
scoped_refptr<NGFragmentItem> item = return NGFragmentItem(*this).InlinePositionForOffset(
base::MakeRefCounted<NGFragmentItem>(*this); Text(), offset, round_function, adjust_mid_cluster);
return item->InlinePositionForOffset(Text(), offset, round_function,
adjust_mid_cluster);
} }
// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to // TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to
...@@ -125,17 +123,14 @@ LayoutUnit NGFragmentItem::InlinePositionForOffset(StringView text, ...@@ -125,17 +123,14 @@ LayoutUnit NGFragmentItem::InlinePositionForOffset(StringView text,
LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset( LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset(
unsigned offset) const { unsigned offset) const {
scoped_refptr<NGFragmentItem> item = return NGFragmentItem(*this).InlinePositionForOffset(Text(), offset);
base::MakeRefCounted<NGFragmentItem>(*this);
return item->InlinePositionForOffset(Text(), offset);
} }
std::pair<LayoutUnit, LayoutUnit> std::pair<LayoutUnit, LayoutUnit>
NGPhysicalTextFragment::LineLeftAndRightForOffsets(unsigned start_offset, NGPhysicalTextFragment::LineLeftAndRightForOffsets(unsigned start_offset,
unsigned end_offset) const { unsigned end_offset) const {
scoped_refptr<NGFragmentItem> item = return NGFragmentItem(*this).LineLeftAndRightForOffsets(Text(), start_offset,
base::MakeRefCounted<NGFragmentItem>(*this); end_offset);
return item->LineLeftAndRightForOffsets(Text(), start_offset, end_offset);
} }
// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to // TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to
...@@ -162,9 +157,7 @@ std::pair<LayoutUnit, LayoutUnit> NGFragmentItem::LineLeftAndRightForOffsets( ...@@ -162,9 +157,7 @@ std::pair<LayoutUnit, LayoutUnit> NGFragmentItem::LineLeftAndRightForOffsets(
PhysicalRect NGPhysicalTextFragment::LocalRect(unsigned start_offset, PhysicalRect NGPhysicalTextFragment::LocalRect(unsigned start_offset,
unsigned end_offset) const { unsigned end_offset) const {
scoped_refptr<NGFragmentItem> item = return NGFragmentItem(*this).LocalRect(Text(), start_offset, end_offset);
base::MakeRefCounted<NGFragmentItem>(*this);
return item->LocalRect(Text(), start_offset, end_offset);
} }
// TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to // TODO(yosin): We should move |NGFragmentItem::InlinePositionForOffset" to
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment