Commit 73b62a1f authored by kojii's avatar kojii Committed by Commit bot

[LayoutNG] NGInlineLayoutAlgorithm and NGTextLayoutAlgorithm

This patch is an initial try to setup call flows and produces fragment
tree for inline layout, a step towards to NG inline layout to produce
LayoutObject tree.

Most of the necessary logic are still missing. For sizing the block
container, the logic should be shared with NGBlockLayoutAlgorithm using
composition. This will be filled in future patches.

For more steps of inline layout (e.g., line breaking, bidi reordering),
making the fragment tree meaningful, copying the fragment tree to
LayoutObject tree, etc. will be in future patches too.

NGInlineLayoutTest is changed to test the result after layout completes,
as NGInlineBox collects inline text during the layout in this patch.

BUG=636993

Review-Url: https://codereview.chromium.org/2551793002
Cr-Commit-Position: refs/heads/master@{#437828}
parent b1728927
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#include "core/layout/ng/ng_break_token.h" #include "core/layout/ng/ng_break_token.h"
#include "core/layout/ng/ng_constraint_space.h" #include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_constraint_space_builder.h"
#include "core/layout/ng/ng_fragment_builder.h" #include "core/layout/ng/ng_fragment_builder.h"
#include "core/layout/ng/ng_inline_node.h" #include "core/layout/ng/ng_inline_node.h"
#include "core/layout/ng/ng_length_utils.h"
#include "core/layout/ng/ng_physical_fragment.h" #include "core/layout/ng/ng_physical_fragment.h"
#include "core/style/ComputedStyle.h" #include "core/style/ComputedStyle.h"
...@@ -30,17 +32,73 @@ NGLayoutStatus NGInlineLayoutAlgorithm::Layout( ...@@ -30,17 +32,73 @@ NGLayoutStatus NGInlineLayoutAlgorithm::Layout(
NGPhysicalFragmentBase*, NGPhysicalFragmentBase*,
NGPhysicalFragmentBase** fragment_out, NGPhysicalFragmentBase** fragment_out,
NGLayoutAlgorithm**) { NGLayoutAlgorithm**) {
NGFragmentBuilder builder(NGPhysicalFragmentBase::kFragmentBox); // TODO(kojii): Implement sizing and child constraint spaces. Share common
// logic with NGBlockLayoutAlgorithm using composition.
switch (state_) {
case kStateInit: {
builder_ = new NGFragmentBuilder(NGPhysicalFragmentBase::kFragmentBox);
builder_->SetWritingMode(constraint_space_->WritingMode());
builder_->SetDirection(constraint_space_->Direction());
// builder_->SetInlineSize(inline_size).SetBlockSize(block_size);
current_child_ = first_child_;
if (current_child_)
space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
*fragment_out = builder.ToFragment(); state_ = kStateChildLayout;
return kNotFinished;
}
case kStateChildLayout: {
if (current_child_) {
if (!LayoutCurrentChild())
return kNotFinished;
current_child_ = current_child_->NextSibling();
if (current_child_) {
space_for_current_child_ = CreateConstraintSpaceForCurrentChild();
return kNotFinished;
}
}
state_ = kStateFinalize;
return kNotFinished;
}
case kStateFinalize:
// TODO(kojii): Compute content size and set to the builder.
*fragment_out = builder_->ToFragment();
state_ = kStateInit;
return kNewFragment;
};
NOTREACHED();
*fragment_out = nullptr;
return kNewFragment; return kNewFragment;
} }
bool NGInlineLayoutAlgorithm::LayoutCurrentChild() {
NGFragmentBase* fragment;
if (!current_child_->Layout(space_for_current_child_, &fragment))
return false;
builder_->AddChild(fragment, NGLogicalOffset());
return true;
}
NGConstraintSpace*
NGInlineLayoutAlgorithm::CreateConstraintSpaceForCurrentChild() const {
DCHECK(current_child_);
// TODO(kojii): Implement child constraint space.
NGConstraintSpace* child_space =
NGConstraintSpaceBuilder(constraint_space_->WritingMode())
.SetTextDirection(constraint_space_->Direction())
.ToConstraintSpace();
return child_space;
}
DEFINE_TRACE(NGInlineLayoutAlgorithm) { DEFINE_TRACE(NGInlineLayoutAlgorithm) {
NGLayoutAlgorithm::trace(visitor); NGLayoutAlgorithm::trace(visitor);
visitor->trace(first_child_); visitor->trace(first_child_);
visitor->trace(constraint_space_); visitor->trace(constraint_space_);
visitor->trace(break_token_); visitor->trace(break_token_);
visitor->trace(builder_);
visitor->trace(space_for_current_child_);
visitor->trace(current_child_);
} }
} // namespace blink } // namespace blink
...@@ -14,6 +14,7 @@ namespace blink { ...@@ -14,6 +14,7 @@ namespace blink {
class ComputedStyle; class ComputedStyle;
class NGBreakToken; class NGBreakToken;
class NGConstraintSpace; class NGConstraintSpace;
class NGFragmentBuilder;
class NGInlineNode; class NGInlineNode;
// A class for inline layout (e.g. a anonymous block with inline-level children // A class for inline layout (e.g. a anonymous block with inline-level children
...@@ -45,10 +46,19 @@ class CORE_EXPORT NGInlineLayoutAlgorithm : public NGLayoutAlgorithm { ...@@ -45,10 +46,19 @@ class CORE_EXPORT NGInlineLayoutAlgorithm : public NGLayoutAlgorithm {
// Read-only Getters. // Read-only Getters.
const ComputedStyle& Style() const { return *style_; } const ComputedStyle& Style() const { return *style_; }
bool LayoutCurrentChild();
NGConstraintSpace* CreateConstraintSpaceForCurrentChild() const;
enum State { kStateInit, kStateChildLayout, kStateFinalize };
State state_ = kStateInit;
RefPtr<const ComputedStyle> style_; RefPtr<const ComputedStyle> style_;
Member<NGInlineNode> first_child_; Member<NGInlineNode> first_child_;
Member<NGConstraintSpace> constraint_space_; Member<NGConstraintSpace> constraint_space_;
Member<NGBreakToken> break_token_; Member<NGBreakToken> break_token_;
Member<NGFragmentBuilder> builder_;
Member<NGConstraintSpace> space_for_current_child_;
Member<NGInlineNode> current_child_;
}; };
} // namespace blink } // namespace blink
......
...@@ -7,9 +7,12 @@ ...@@ -7,9 +7,12 @@
#include "core/layout/LayoutObject.h" #include "core/layout/LayoutObject.h"
#include "core/layout/LayoutText.h" #include "core/layout/LayoutText.h"
#include "core/layout/ng/ng_bidi_paragraph.h" #include "core/layout/ng/ng_bidi_paragraph.h"
#include "core/layout/ng/ng_fragment.h"
#include "core/layout/ng/ng_fragment_builder.h"
#include "core/layout/ng/ng_layout_inline_items_builder.h" #include "core/layout/ng/ng_layout_inline_items_builder.h"
#include "core/layout/ng/ng_text_layout_algorithm.h" #include "core/layout/ng/ng_text_layout_algorithm.h"
#include "core/layout/ng/ng_constraint_space_builder.h" #include "core/layout/ng/ng_constraint_space_builder.h"
#include "core/layout/ng/ng_physical_fragment.h"
#include "core/layout/ng/ng_physical_text_fragment.h" #include "core/layout/ng/ng_physical_text_fragment.h"
#include "core/layout/ng/ng_text_fragment.h" #include "core/layout/ng/ng_text_fragment.h"
#include "core/style/ComputedStyle.h" #include "core/style/ComputedStyle.h"
...@@ -26,7 +29,6 @@ NGInlineNode::NGInlineNode(LayoutObject* start_inline, ...@@ -26,7 +29,6 @@ NGInlineNode::NGInlineNode(LayoutObject* start_inline,
last_inline_(nullptr), last_inline_(nullptr),
block_style_(block_style) { block_style_(block_style) {
DCHECK(start_inline); DCHECK(start_inline);
PrepareLayout(); // TODO(layout-dev): Shouldn't be called here.
} }
NGInlineNode::NGInlineNode() NGInlineNode::NGInlineNode()
...@@ -55,6 +57,8 @@ void NGInlineNode::PrepareLayout() { ...@@ -55,6 +57,8 @@ void NGInlineNode::PrepareLayout() {
// parent LayoutInline where possible, and joining all text content in a single // parent LayoutInline where possible, and joining all text content in a single
// string to allow bidi resolution and shaping of the entire block. // string to allow bidi resolution and shaping of the entire block.
void NGInlineNode::CollectInlines(LayoutObject* start, LayoutObject* last) { void NGInlineNode::CollectInlines(LayoutObject* start, LayoutObject* last) {
DCHECK(text_content_.isNull());
DCHECK(items_.isEmpty());
NGLayoutInlineItemsBuilder builder(&items_); NGLayoutInlineItemsBuilder builder(&items_);
builder.EnterBlock(block_style_.get()); builder.EnterBlock(block_style_.get());
CollectInlines(start, last, &builder); CollectInlines(start, last, &builder);
...@@ -198,9 +202,35 @@ void NGInlineNode::ShapeText() { ...@@ -198,9 +202,35 @@ void NGInlineNode::ShapeText() {
} }
} }
unsigned NGInlineNode::CreateLine(unsigned start,
NGConstraintSpace* constraint_space,
NGFragmentBuilder* builder) {
// TODO(kojii): |unsigned start| should be BreakToken.
// TODO(kojii): implement line breaker and bidi reordering.
for (unsigned i = start; i < items_.size(); i++) {
const NGLayoutInlineItem& item = items_[i];
// TODO(kojii): handle bidi controls and atomic inlines properly.
if (!item.style_)
continue;
// TODO(kojii): There should be only one oof descendants list for a
// NGInlineNode. Attach to the first NGPhysicalTextFragment and leave the
// rest empty, or attach to line box/root line box fragment?
HeapLinkedHashSet<WeakMember<NGBlockNode>> out_of_flow_descendants;
Vector<NGStaticPosition> out_of_flow_positions;
// TODO(kojii): Create NGTextFragment from |item|.
NGPhysicalTextFragment* fragment = new NGPhysicalTextFragment(
NGPhysicalSize(), NGPhysicalSize(), out_of_flow_descendants,
out_of_flow_positions);
builder->AddChild(new NGTextFragment(constraint_space->WritingMode(),
item.Direction(), fragment),
NGLogicalOffset());
}
return 0; // All items are consumed.
}
bool NGInlineNode::Layout(NGConstraintSpace* constraint_space, bool NGInlineNode::Layout(NGConstraintSpace* constraint_space,
NGFragmentBase** out) { NGFragmentBase** out) {
// TODO(layout-dev): Perform pre-layout text step. PrepareLayout();
// NOTE: We don't need to change the coordinate system here as we are an // NOTE: We don't need to change the coordinate system here as we are an
// inline. // inline.
...@@ -219,9 +249,9 @@ bool NGInlineNode::Layout(NGConstraintSpace* constraint_space, ...@@ -219,9 +249,9 @@ bool NGInlineNode::Layout(NGConstraintSpace* constraint_space,
// TODO(layout-dev): Implement copying of fragment data to LayoutObject tree. // TODO(layout-dev): Implement copying of fragment data to LayoutObject tree.
*out = new NGTextFragment(constraint_space->WritingMode(), *out = new NGFragment(constraint_space->WritingMode(),
constraint_space->Direction(), constraint_space->Direction(),
toNGPhysicalTextFragment(fragment)); toNGPhysicalFragment(fragment));
// Reset algorithm for future use // Reset algorithm for future use
layout_algorithm_ = nullptr; layout_algorithm_ = nullptr;
......
...@@ -21,6 +21,7 @@ class ComputedStyle; ...@@ -21,6 +21,7 @@ class ComputedStyle;
class LayoutObject; class LayoutObject;
class NGConstraintSpace; class NGConstraintSpace;
class NGFragmentBase; class NGFragmentBase;
class NGFragmentBuilder;
class NGLayoutAlgorithm; class NGLayoutAlgorithm;
class NGLayoutInlineItem; class NGLayoutInlineItem;
class NGLayoutInlineItemsBuilder; class NGLayoutInlineItemsBuilder;
...@@ -38,6 +39,8 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode { ...@@ -38,6 +39,8 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
// calling the Layout method. // calling the Layout method.
void PrepareLayout(); void PrepareLayout();
unsigned CreateLine(unsigned start, NGConstraintSpace*, NGFragmentBuilder*);
String Text(unsigned start_offset, unsigned end_offset) const { String Text(unsigned start_offset, unsigned end_offset) const {
return text_content_.substring(start_offset, end_offset); return text_content_.substring(start_offset, end_offset);
} }
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include "core/layout/ng/ng_break_token.h" #include "core/layout/ng/ng_break_token.h"
#include "core/layout/ng/ng_constraint_space.h" #include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_fragment.h"
#include "core/layout/ng/ng_fragment_builder.h"
#include "core/layout/ng/ng_inline_node.h" #include "core/layout/ng/ng_inline_node.h"
namespace blink { namespace blink {
...@@ -25,8 +27,23 @@ NGLayoutStatus NGTextLayoutAlgorithm::Layout( ...@@ -25,8 +27,23 @@ NGLayoutStatus NGTextLayoutAlgorithm::Layout(
NGPhysicalFragmentBase*, NGPhysicalFragmentBase*,
NGPhysicalFragmentBase** fragment_out, NGPhysicalFragmentBase** fragment_out,
NGLayoutAlgorithm**) { NGLayoutAlgorithm**) {
// TODO(layout-dev): implement. // TODO(kojii): What kind of fragment tree do we want for line boxes/root line
*fragment_out = nullptr; // boxes? Just text, box, or new type of fragment?
NGFragmentBuilder root_line_box_builder(NGPhysicalFragmentBase::kFragmentBox);
root_line_box_builder.SetWritingMode(constraint_space_->WritingMode());
root_line_box_builder.SetDirection(constraint_space_->Direction());
unsigned start = 0;
do {
NGFragmentBuilder line_box_builder(NGPhysicalFragmentBase::kFragmentBox);
start =
inline_box_->CreateLine(start, constraint_space_, &line_box_builder);
root_line_box_builder.AddChild(
new NGFragment(constraint_space_->WritingMode(),
constraint_space_->Direction(),
line_box_builder.ToFragment()),
NGLogicalOffset());
} while (start);
*fragment_out = root_line_box_builder.ToFragment();
return kNewFragment; return kNewFragment;
} }
......
...@@ -51,11 +51,13 @@ TEST_F(NGInlineLayoutTest, BlockWithSingleTextNode) { ...@@ -51,11 +51,13 @@ TEST_F(NGInlineLayoutTest, BlockWithSingleTextNode) {
NGInlineLayoutAlgorithm* layoutAlgorithm = new NGInlineLayoutAlgorithm( NGInlineLayoutAlgorithm* layoutAlgorithm = new NGInlineLayoutAlgorithm(
blockFlow->style(), inlineBox, constraintSpace); blockFlow->style(), inlineBox, constraintSpace);
NGPhysicalFragmentBase* fragment;
while (layoutAlgorithm->Layout(nullptr, &fragment, nullptr) != kNewFragment) {
// Repeat until layout completes.
}
String expectedText("Hello World!"); String expectedText("Hello World!");
EXPECT_EQ(expectedText, inlineBox->Text(0, 12)); EXPECT_EQ(expectedText, inlineBox->Text(0, 12));
NGPhysicalFragmentBase* fragment;
layoutAlgorithm->Layout(nullptr, &fragment, nullptr);
} }
TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) { TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) {
...@@ -78,13 +80,15 @@ TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) { ...@@ -78,13 +80,15 @@ TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) {
NGInlineLayoutAlgorithm* layoutAlgorithm = new NGInlineLayoutAlgorithm( NGInlineLayoutAlgorithm* layoutAlgorithm = new NGInlineLayoutAlgorithm(
blockFlow->style(), inlineBox, constraintSpace); blockFlow->style(), inlineBox, constraintSpace);
NGPhysicalFragmentBase* fragment;
while (layoutAlgorithm->Layout(nullptr, &fragment, nullptr) != kNewFragment) {
// Repeat until layout completes.
}
String expectedText("Hello "); String expectedText("Hello ");
expectedText.append(objectReplacementCharacter); expectedText.append(objectReplacementCharacter);
expectedText.append("."); expectedText.append(".");
EXPECT_EQ(expectedText, inlineBox->Text(0, 8)); EXPECT_EQ(expectedText, inlineBox->Text(0, 8));
NGPhysicalFragmentBase* fragment;
layoutAlgorithm->Layout(nullptr, &fragment, nullptr);
} }
} // namespace blink } // namespace blink
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