Commit 98377d31 authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[NGFragmentItem] Create NGFragmentItems in NGPhysicalBoxFragment

This patch implements more of |NGFragmentItemsBuilder|, so
that |NGFragmentItems| are created and stored to
|NGPhysicalBoxFragment|, except out-of-flow objects.

Not all necessary changes are in yet, but instantiations of
most objects and call flows are in place.

The new code still relies on |NGPhysicalLineBoxFragment| and
|NGPhysicalTextFragment|. |NGFragmentItem| is supposed to
deprecate them, but eliminating them is not very easy. After
some experiments, I'm planning to create |NGFragmentItem|
first from these fragments, but plan to eliminate them as the
code grows. |NGPhysicalTextFragment| is probably easy, but
|NGPhysicalLineBoxFragment| may take a while as it is used
for communication and propagation between
|NGBlockLayoutAlgorithm| and |NGInlineLayoutAlgorithm|.

Bug: 982194
Change-Id: Icc2d4716d4c351bd3b8810fbeac77ba48c118d3d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1739033
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Cr-Commit-Position: refs/heads/master@{#685449}
parent 5019a9a3
...@@ -9,6 +9,30 @@ ...@@ -9,6 +9,30 @@
namespace blink { namespace blink {
NGFragmentItem::NGFragmentItem(const NGPhysicalTextFragment& text)
: layout_object_(text.GetLayoutObject()),
text_({text.TextShapeResult()}),
size_(text.Size()),
type_(kText),
style_variant_(static_cast<unsigned>(text.StyleVariant())) {}
NGFragmentItem::NGFragmentItem(const NGPhysicalLineBoxFragment& line,
wtf_size_t item_count)
: layout_object_(nullptr),
line_({line.Metrics(), To<NGInlineBreakToken>(line.BreakToken()),
item_count}),
size_(line.Size()),
type_(kLine),
style_variant_(static_cast<unsigned>(line.StyleVariant())) {}
NGFragmentItem::NGFragmentItem(const NGPhysicalBoxFragment& box,
wtf_size_t item_count)
: layout_object_(box.GetLayoutObject()),
box_({&box, item_count}),
size_(box.Size()),
type_(kBox),
style_variant_(static_cast<unsigned>(box.StyleVariant())) {}
NGFragmentItem::~NGFragmentItem() { NGFragmentItem::~NGFragmentItem() {
switch (Type()) { switch (Type()) {
case kText: case kText:
......
...@@ -55,13 +55,10 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient { ...@@ -55,13 +55,10 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
enum ItemType { kText, kGeneratedText, kLine, kBox }; enum ItemType { kText, kGeneratedText, kLine, kBox };
NGFragmentItem(const LayoutObject& layout_object, // TODO(kojii): Should be able to create without once creating fragments.
NGStyleVariant style_variant, NGFragmentItem(const NGPhysicalTextFragment& text);
Text&& text) NGFragmentItem(const NGPhysicalBoxFragment& box, wtf_size_t item_count);
: layout_object_(&layout_object), NGFragmentItem(const NGPhysicalLineBoxFragment& line, wtf_size_t item_count);
text_(text),
type_(kText),
style_variant_(static_cast<unsigned>(style_variant)) {}
~NGFragmentItem() final; ~NGFragmentItem() final;
...@@ -109,10 +106,7 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient { ...@@ -109,10 +106,7 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
Box box_; Box box_;
}; };
union { PhysicalOffset offset_;
PhysicalOffset offset_;
LogicalOffset logical_offset_;
};
PhysicalSize size_; PhysicalSize size_;
struct NGInkOverflowModel { struct NGInkOverflowModel {
......
...@@ -5,40 +5,104 @@ ...@@ -5,40 +5,104 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
namespace blink { namespace blink {
void NGFragmentItemsBuilder::AddChildren(const ChildList& children) { void NGFragmentItemsBuilder::SetTextContent(const NGInlineNode& node) {
items_.ReserveCapacity(items_.size() + children.size()); const NGInlineItemsData& items_data = node.ItemsData(false);
offsets_.ReserveCapacity(items_.size() + children.size()); text_content_ = items_data.text_content;
const NGInlineItemsData& first_line = node.ItemsData(true);
if (&items_data != &first_line)
first_line_text_content_ = first_line.text_content;
}
void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
ChildList& children) {
DCHECK_EQ(items_.size(), offsets_.size());
#if DCHECK_IS_ON()
DCHECK(!is_converted_to_physical_);
#endif
// Reserve the capacity for (children + line box item).
wtf_size_t capacity = items_.size() + children.size() + 1;
items_.ReserveCapacity(capacity);
offsets_.ReserveCapacity(capacity);
// Add an empty item so that the start of the line can be set later.
wtf_size_t line_start_index = items_.size();
items_.Grow(line_start_index + 1);
offsets_.Grow(line_start_index + 1);
AddItems({children.begin(), children.size()});
// All children are added. Create an item for the start of the line.
wtf_size_t item_count = items_.size() - line_start_index;
items_[line_start_index] = std::make_unique<NGFragmentItem>(line, item_count);
// TODO(kojii): We probably need an end marker too for the reverse-order
// traversals.
}
void NGFragmentItemsBuilder::AddItems(base::span<Child> children) {
DCHECK_EQ(items_.size(), offsets_.size());
for (auto& child : children) { for (auto& child : children) {
if (child.fragment) { if (const NGPhysicalTextFragment* text = child.fragment.get()) {
items_.push_back(std::make_unique<NGFragmentItem>( DCHECK(text->TextShapeResult());
*child.fragment->GetLayoutObject(), child.fragment->StyleVariant(), DCHECK_EQ(text->StartOffset(), text->TextShapeResult()->StartIndex());
NGFragmentItem::Text{child.fragment->TextShapeResult()})); DCHECK_EQ(text->EndOffset(), text->TextShapeResult()->EndIndex());
items_.push_back(std::make_unique<NGFragmentItem>(*text));
offsets_.push_back(child.offset); offsets_.push_back(child.offset);
continue; continue;
} }
// TODO(kojii): Implement other cases. if (child.layout_result) {
// Add an empty item so that the start of the box can be set later.
wtf_size_t box_start_index = items_.size();
items_.Grow(box_start_index + 1);
offsets_.push_back(child.offset);
// TODO(kojii): Add children and update children_count.
// All children are added. Create an item for the start of the box.
wtf_size_t item_count = items_.size() - box_start_index;
const NGPhysicalBoxFragment& box =
To<NGPhysicalBoxFragment>(child.layout_result->PhysicalFragment());
items_[box_start_index] =
std::make_unique<NGFragmentItem>(box, item_count);
continue;
}
DCHECK(!child.out_of_flow_positioned_box);
} }
} }
// Convert internal logical offsets to physical. Items are kept with logical
// offset until outer box size is determined.
void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode, void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
TextDirection direction, TextDirection direction,
PhysicalSize outer_size) { const PhysicalSize& outer_size) {
CHECK_EQ(items_.size(), offsets_.size()); CHECK_EQ(items_.size(), offsets_.size());
#if DCHECK_IS_ON()
DCHECK(!is_converted_to_physical_);
#endif
const LogicalOffset* offset_iter = offsets_.begin(); const LogicalOffset* offset_iter = offsets_.begin();
for (auto& item : items_) { for (auto& item : items_) {
PhysicalOffset offset = offset_iter->ConvertToPhysical( item->SetOffset(offset_iter->ConvertToPhysical(writing_mode, direction,
writing_mode, direction, outer_size, item->Size()); outer_size, item->Size()));
item->SetOffset(offset);
++offset_iter; ++offset_iter;
} }
#if DCHECK_IS_ON()
is_converted_to_physical_ = true;
#endif
} }
void NGFragmentItemsBuilder::ToFragmentItems(void* data) { void NGFragmentItemsBuilder::ToFragmentItems(WritingMode writing_mode,
TextDirection direction,
const PhysicalSize& outer_size,
void* data) {
ConvertToPhysical(writing_mode, direction, outer_size);
new (data) NGFragmentItems(this); new (data) NGFragmentItems(this);
} }
......
...@@ -14,6 +14,7 @@ namespace blink { ...@@ -14,6 +14,7 @@ namespace blink {
class NGBoxFragmentBuilder; class NGBoxFragmentBuilder;
class NGFragmentItem; class NGFragmentItem;
class NGFragmentItems; class NGFragmentItems;
class NGInlineNode;
// This class builds |NGFragmentItems|. // This class builds |NGFragmentItems|.
// //
...@@ -24,22 +25,41 @@ class CORE_EXPORT NGFragmentItemsBuilder { ...@@ -24,22 +25,41 @@ class CORE_EXPORT NGFragmentItemsBuilder {
public: public:
NGFragmentItemsBuilder(NGBoxFragmentBuilder* box_builder) {} NGFragmentItemsBuilder(NGBoxFragmentBuilder* box_builder) {}
const String& TextContent(bool first_line) const {
return UNLIKELY(first_line && first_line_text_content_)
? first_line_text_content_
: text_content_;
}
void SetTextContent(const NGInlineNode& node);
// Add a line at once.
using Child = NGLineBoxFragmentBuilder::Child; using Child = NGLineBoxFragmentBuilder::Child;
using ChildList = NGLineBoxFragmentBuilder::ChildList; using ChildList = NGLineBoxFragmentBuilder::ChildList;
void AddChildren(const ChildList& children); void AddLine(const NGPhysicalLineBoxFragment& line, ChildList& children);
// Build a |NGFragmentItems|. The builder cannot build twice because data set
// to this builder may be cleared.
void ToFragmentItems(WritingMode writing_mode,
TextDirection direction,
const PhysicalSize& outer_size,
void* data);
private:
void AddItems(base::span<Child> children);
void ConvertToPhysical(WritingMode writing_mode, void ConvertToPhysical(WritingMode writing_mode,
TextDirection direction, TextDirection direction,
PhysicalSize outer_size); const PhysicalSize& outer_size);
void ToFragmentItems(void* data);
private:
Vector<std::unique_ptr<NGFragmentItem>> items_; Vector<std::unique_ptr<NGFragmentItem>> items_;
Vector<LogicalOffset> offsets_; Vector<LogicalOffset> offsets_;
String text_content_; String text_content_;
String first_line_text_content_; String first_line_text_content_;
#if DCHECK_IS_ON()
bool is_converted_to_physical_ = false;
#endif
friend class NGFragmentItems; friend class NGFragmentItems;
}; };
......
...@@ -365,7 +365,6 @@ void NGInlineLayoutAlgorithm::CreateLine( ...@@ -365,7 +365,6 @@ void NGInlineLayoutAlgorithm::CreateLine(
container_builder_.SetIsSelfCollapsing(); container_builder_.SetIsSelfCollapsing();
container_builder_.SetIsEmptyLineBox(); container_builder_.SetIsEmptyLineBox();
container_builder_.SetBaseDirection(line_info->BaseDirection()); container_builder_.SetBaseDirection(line_info->BaseDirection());
container_builder_.AddChildren(line_box_);
return; return;
} }
...@@ -379,7 +378,6 @@ void NGInlineLayoutAlgorithm::CreateLine( ...@@ -379,7 +378,6 @@ void NGInlineLayoutAlgorithm::CreateLine(
if (line_info->UseFirstLineStyle()) if (line_info->UseFirstLineStyle())
container_builder_.SetStyleVariant(NGStyleVariant::kFirstLine); container_builder_.SetStyleVariant(NGStyleVariant::kFirstLine);
container_builder_.SetBaseDirection(line_info->BaseDirection()); container_builder_.SetBaseDirection(line_info->BaseDirection());
container_builder_.AddChildren(line_box_);
container_builder_.SetInlineSize(inline_size); container_builder_.SetInlineSize(inline_size);
container_builder_.SetMetrics(line_box_metrics); container_builder_.SetMetrics(line_box_metrics);
container_builder_.SetBfcBlockOffset(line_info->BfcOffset().block_offset); container_builder_.SetBfcBlockOffset(line_info->BfcOffset().block_offset);
...@@ -957,6 +955,22 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() { ...@@ -957,6 +955,22 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
CHECK(is_line_created); CHECK(is_line_created);
container_builder_.SetExclusionSpace(std::move(exclusion_space)); container_builder_.SetExclusionSpace(std::move(exclusion_space));
if (NGFragmentItemsBuilder* items_builder = context_->ItemsBuilder()) {
DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
container_builder_.AddOutOfFlowChildren(line_box_);
scoped_refptr<const NGLayoutResult> layout_result =
container_builder_.ToLineBoxFragment();
if (items_builder->TextContent(false).IsNull())
items_builder->SetTextContent(Node());
items_builder->AddLine(
To<NGPhysicalLineBoxFragment>(layout_result->PhysicalFragment()),
line_box_);
return layout_result;
}
DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
container_builder_.AddChildren(line_box_);
container_builder_.MoveOutOfFlowDescendantCandidatesToDescendants(); container_builder_.MoveOutOfFlowDescendantCandidatesToDescendants();
return container_builder_.ToLineBoxFragment(); return container_builder_.ToLineBoxFragment();
} }
......
...@@ -108,6 +108,20 @@ void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) { ...@@ -108,6 +108,20 @@ void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) {
} }
} }
void NGLineBoxFragmentBuilder::AddOutOfFlowChildren(ChildList& children) {
for (auto& child : children) {
if (child.out_of_flow_positioned_box) {
AddOutOfFlowChildCandidate(
NGBlockNode(ToLayoutBox(child.out_of_flow_positioned_box)),
child.offset, child.container_direction);
child.out_of_flow_positioned_box = nullptr;
}
}
DCHECK(oof_positioned_descendants_.IsEmpty());
MoveOutOfFlowDescendantCandidatesToDescendants();
}
scoped_refptr<const NGLayoutResult> scoped_refptr<const NGLayoutResult>
NGLineBoxFragmentBuilder::ToLineBoxFragment() { NGLineBoxFragmentBuilder::ToLineBoxFragment() {
writing_mode_ = ToLineWritingMode(writing_mode_); writing_mode_ = ToLineWritingMode(writing_mode_);
......
...@@ -235,6 +235,11 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final ...@@ -235,6 +235,11 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
// Add all items in ChildList. Skips null Child if any. // Add all items in ChildList. Skips null Child if any.
void AddChildren(ChildList&); void AddChildren(ChildList&);
// Add only out-of-flow items in ChildList. TODO(kojii): When |NGFragmentItem|
// is on, all objects should go to |NGFragmentItems| but OOF still uses
// fragments to propagate while in transition.
void AddOutOfFlowChildren(ChildList&);
// Creates the fragment. Can only be called once. // Creates the fragment. Can only be called once.
scoped_refptr<const NGLayoutResult> ToLineBoxFragment(); scoped_refptr<const NGLayoutResult> ToLineBoxFragment();
......
...@@ -83,11 +83,14 @@ NGPhysicalBoxFragment::NGPhysicalBoxFragment( ...@@ -83,11 +83,14 @@ NGPhysicalBoxFragment::NGPhysicalBoxFragment(
builder->BoxType()), builder->BoxType()),
baselines_(builder->baselines_) { baselines_(builder->baselines_) {
DCHECK(GetLayoutObject() && GetLayoutObject()->IsBoxModelObject()); DCHECK(GetLayoutObject() && GetLayoutObject()->IsBoxModelObject());
has_fragment_items_ = !!builder->ItemsBuilder(); if (NGFragmentItemsBuilder* items_builder = builder->ItemsBuilder()) {
if (has_fragment_items_) { has_fragment_items_ = true;
NGFragmentItems* items = NGFragmentItems* items =
const_cast<NGFragmentItems*>(ComputeItemsAddress()); const_cast<NGFragmentItems*>(ComputeItemsAddress());
builder->ItemsBuilder()->ToFragmentItems(items); items_builder->ToFragmentItems(block_or_line_writing_mode,
builder->Direction(), Size(), items);
} else {
has_fragment_items_ = false;
} }
has_borders_ = !borders.IsZero(); has_borders_ = !borders.IsZero();
if (has_borders_) if (has_borders_)
......
...@@ -28,6 +28,8 @@ class CORE_EXPORT NGPhysicalBoxFragment final ...@@ -28,6 +28,8 @@ class CORE_EXPORT NGPhysicalBoxFragment final
scoped_refptr<const NGLayoutResult> CloneAsHiddenForPaint() const; scoped_refptr<const NGLayoutResult> CloneAsHiddenForPaint() const;
~NGPhysicalBoxFragment() { ~NGPhysicalBoxFragment() {
if (has_fragment_items_)
ComputeItemsAddress()->~NGFragmentItems();
for (const NGLink& child : Children()) for (const NGLink& child : Children())
child.fragment->Release(); child.fragment->Release();
} }
......
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