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 @@
#include "core/layout/ng/ng_break_token.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_inline_node.h"
#include "core/layout/ng/ng_length_utils.h"
#include "core/layout/ng/ng_physical_fragment.h"
#include "core/style/ComputedStyle.h"
......@@ -30,10 +32,63 @@ NGLayoutStatus NGInlineLayoutAlgorithm::Layout(
NGPhysicalFragmentBase*,
NGPhysicalFragmentBase** fragment_out,
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;
}
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) {
......@@ -41,6 +96,9 @@ DEFINE_TRACE(NGInlineLayoutAlgorithm) {
visitor->trace(first_child_);
visitor->trace(constraint_space_);
visitor->trace(break_token_);
visitor->trace(builder_);
visitor->trace(space_for_current_child_);
visitor->trace(current_child_);
}
} // namespace blink
......@@ -14,6 +14,7 @@ namespace blink {
class ComputedStyle;
class NGBreakToken;
class NGConstraintSpace;
class NGFragmentBuilder;
class NGInlineNode;
// A class for inline layout (e.g. a anonymous block with inline-level children
......@@ -45,10 +46,19 @@ class CORE_EXPORT NGInlineLayoutAlgorithm : public NGLayoutAlgorithm {
// Read-only Getters.
const ComputedStyle& Style() const { return *style_; }
bool LayoutCurrentChild();
NGConstraintSpace* CreateConstraintSpaceForCurrentChild() const;
enum State { kStateInit, kStateChildLayout, kStateFinalize };
State state_ = kStateInit;
RefPtr<const ComputedStyle> style_;
Member<NGInlineNode> first_child_;
Member<NGConstraintSpace> constraint_space_;
Member<NGBreakToken> break_token_;
Member<NGFragmentBuilder> builder_;
Member<NGConstraintSpace> space_for_current_child_;
Member<NGInlineNode> current_child_;
};
} // namespace blink
......
......@@ -7,9 +7,12 @@
#include "core/layout/LayoutObject.h"
#include "core/layout/LayoutText.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_text_layout_algorithm.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_text_fragment.h"
#include "core/style/ComputedStyle.h"
......@@ -26,7 +29,6 @@ NGInlineNode::NGInlineNode(LayoutObject* start_inline,
last_inline_(nullptr),
block_style_(block_style) {
DCHECK(start_inline);
PrepareLayout(); // TODO(layout-dev): Shouldn't be called here.
}
NGInlineNode::NGInlineNode()
......@@ -55,6 +57,8 @@ void NGInlineNode::PrepareLayout() {
// parent LayoutInline where possible, and joining all text content in a single
// string to allow bidi resolution and shaping of the entire block.
void NGInlineNode::CollectInlines(LayoutObject* start, LayoutObject* last) {
DCHECK(text_content_.isNull());
DCHECK(items_.isEmpty());
NGLayoutInlineItemsBuilder builder(&items_);
builder.EnterBlock(block_style_.get());
CollectInlines(start, last, &builder);
......@@ -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,
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
// inline.
......@@ -219,9 +249,9 @@ bool NGInlineNode::Layout(NGConstraintSpace* constraint_space,
// 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(),
toNGPhysicalTextFragment(fragment));
toNGPhysicalFragment(fragment));
// Reset algorithm for future use
layout_algorithm_ = nullptr;
......
......@@ -21,6 +21,7 @@ class ComputedStyle;
class LayoutObject;
class NGConstraintSpace;
class NGFragmentBase;
class NGFragmentBuilder;
class NGLayoutAlgorithm;
class NGLayoutInlineItem;
class NGLayoutInlineItemsBuilder;
......@@ -38,6 +39,8 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
// calling the Layout method.
void PrepareLayout();
unsigned CreateLine(unsigned start, NGConstraintSpace*, NGFragmentBuilder*);
String Text(unsigned start_offset, unsigned end_offset) const {
return text_content_.substring(start_offset, end_offset);
}
......
......@@ -6,6 +6,8 @@
#include "core/layout/ng/ng_break_token.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"
namespace blink {
......@@ -25,8 +27,23 @@ NGLayoutStatus NGTextLayoutAlgorithm::Layout(
NGPhysicalFragmentBase*,
NGPhysicalFragmentBase** fragment_out,
NGLayoutAlgorithm**) {
// TODO(layout-dev): implement.
*fragment_out = nullptr;
// TODO(kojii): What kind of fragment tree do we want for line boxes/root line
// 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;
}
......
......@@ -51,11 +51,13 @@ TEST_F(NGInlineLayoutTest, BlockWithSingleTextNode) {
NGInlineLayoutAlgorithm* layoutAlgorithm = new NGInlineLayoutAlgorithm(
blockFlow->style(), inlineBox, constraintSpace);
NGPhysicalFragmentBase* fragment;
while (layoutAlgorithm->Layout(nullptr, &fragment, nullptr) != kNewFragment) {
// Repeat until layout completes.
}
String expectedText("Hello World!");
EXPECT_EQ(expectedText, inlineBox->Text(0, 12));
NGPhysicalFragmentBase* fragment;
layoutAlgorithm->Layout(nullptr, &fragment, nullptr);
}
TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) {
......@@ -78,13 +80,15 @@ TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) {
NGInlineLayoutAlgorithm* layoutAlgorithm = new NGInlineLayoutAlgorithm(
blockFlow->style(), inlineBox, constraintSpace);
NGPhysicalFragmentBase* fragment;
while (layoutAlgorithm->Layout(nullptr, &fragment, nullptr) != kNewFragment) {
// Repeat until layout completes.
}
String expectedText("Hello ");
expectedText.append(objectReplacementCharacter);
expectedText.append(".");
EXPECT_EQ(expectedText, inlineBox->Text(0, 8));
NGPhysicalFragmentBase* fragment;
layoutAlgorithm->Layout(nullptr, &fragment, nullptr);
}
} // 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