Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(299)

Unified Diff: third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc

Issue 2898413002: [LayoutNG] Add box fragments to line boxes when needed (Closed)
Patch Set: x64 build fix Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
index 4d27613e7d9b0ff58deac025b3e974eaa468241a..64cdfd1c7d16995848abbe47921e0aee80b733df 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_box_state.cc
@@ -7,6 +7,8 @@
#include "core/layout/ng/inline/ng_inline_node.h"
#include "core/layout/ng/inline/ng_line_box_fragment_builder.h"
#include "core/layout/ng/inline/ng_text_fragment_builder.h"
+#include "core/layout/ng/ng_fragment_builder.h"
+#include "core/layout/ng/ng_layout_result.h"
#include "core/style/ComputedStyle.h"
namespace blink {
@@ -36,6 +38,16 @@ void NGInlineBoxState::AccumulateUsedFonts(const NGInlineItem& item,
}
}
+void NGInlineBoxState::SetNeedsBoxFragment(
+ LayoutUnit position,
+ LayoutUnit borders_paddings_block_start,
+ LayoutUnit borders_paddings_block_height) {
+ needs_box_fragment = true;
+ line_left_position = position;
+ this->borders_paddings_block_start = borders_paddings_block_start;
+ this->borders_paddings_block_height = borders_paddings_block_height;
+}
+
NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
const ComputedStyle* line_style,
FontBaseline baseline_type) {
@@ -67,13 +79,12 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
const NGInlineItem& item,
- NGLineBoxFragmentBuilder* line_box,
- NGTextFragmentBuilder* text_builder) {
+ NGLineBoxFragmentBuilder* line_box) {
stack_.resize(stack_.size() + 1);
NGInlineBoxState* box = &stack_.back();
box->fragment_start = line_box->Children().size();
+ box->item = &item;
box->style = item.Style();
- text_builder->SetDirection(box->style->Direction());
return box;
}
@@ -81,8 +92,9 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag(
const NGInlineItem& item,
NGLineBoxFragmentBuilder* line_box,
NGInlineBoxState* box,
- FontBaseline baseline_type) {
- EndBoxState(box, line_box, baseline_type);
+ FontBaseline baseline_type,
+ LayoutUnit position) {
+ EndBoxState(box, line_box, baseline_type, position);
// TODO(kojii): When the algorithm restarts from a break token, the stack may
// underflow. We need either synthesize a missing box state, or push all
// parents on initialize.
@@ -92,19 +104,27 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag(
void NGInlineLayoutStateStack::OnEndPlaceItems(
NGLineBoxFragmentBuilder* line_box,
- FontBaseline baseline_type) {
+ FontBaseline baseline_type,
+ LayoutUnit position) {
for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) {
NGInlineBoxState* box = &(*it);
- EndBoxState(box, line_box, baseline_type);
+ EndBoxState(box, line_box, baseline_type, position);
}
+ if (!box_placeholders_.IsEmpty())
+ CreateBoxFragments(line_box);
+
DCHECK(!LineBoxState().metrics.IsEmpty());
line_box->SetMetrics(LineBoxState().metrics);
}
void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box,
NGLineBoxFragmentBuilder* line_box,
- FontBaseline baseline_type) {
+ FontBaseline baseline_type,
+ LayoutUnit position) {
+ if (box->needs_box_fragment)
+ AddBoxFragmentPlaceholder(box, line_box, baseline_type, position);
+
PositionPending position_pending =
ApplyBaselineShift(box, line_box, baseline_type);
@@ -114,6 +134,106 @@ void NGInlineLayoutStateStack::EndBoxState(NGInlineBoxState* box,
}
}
+// Crete a placeholder for a box fragment.
+// We keep a flat list of fragments because it is more suitable for operations
+// such as ApplyBaselineShift. Later, CreateBoxFragments() creates box fragments
+// from placeholders.
+void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
+ NGInlineBoxState* box,
+ NGLineBoxFragmentBuilder* line_box,
+ FontBaseline baseline_type,
+ LayoutUnit position) {
+ if (box->fragment_start == line_box->Children().size()) {
+ // Don't create a placeholder if the inline box is empty.
+ // Whether to create this box or not affects layout when the line contains
+ // only this box, since this box participates the line height.
+ // TODO(kojii): Testing indicates that we should create a box if it has
+ // borders, but not for backgrounds. But creating such a RootInlineBox needs
+ // additional code. The plan is to enable such line box when NG paint is
+ // enabled.
+ return;
+ }
+
+ // The inline box should have the height of the font metrics without the
+ // line-height property. Compute from style because |box->metrics| includes
+ // the line-height property.
+ DCHECK(box->style);
+ const ComputedStyle& style = *box->style;
+ NGLineHeightMetrics metrics(style, baseline_type);
+
+ // Extend the block direction of the box by borders and paddings. Inline
+ // direction is already included into positions in NGLineBreaker.
+ NGLogicalRect bounds(
+ box->line_left_position,
+ -metrics.ascent - box->borders_paddings_block_start,
+ position - box->line_left_position,
+ metrics.LineHeight() + box->borders_paddings_block_height);
+
+ // The start is marked only in BoxFragmentPlaceholder, while end is marked
+ // in both BoxFragmentPlaceholder and the list itself.
+ // With a list of 4 text fragments:
+ // | 0 | 1 | 2 | 3 |
+ // |text0|text1|text2|text3|
+ // By adding a BoxFragmentPlaceholder(2,4) (end is exclusive), it becomes:
+ // | 0 | 1 | 2 | 3 | 4 |
+ // |text0|text1|text2|text3|null |
+ // The "null" is added to the list to compute baseline shift of the box
+ // separately from text fragments.
+ unsigned fragment_end = line_box->Children().size();
+ box_placeholders_.push_back(BoxFragmentPlaceholder{
+ box->fragment_start, fragment_end, box->item, bounds.size});
+ line_box->AddChild(nullptr, bounds.offset);
+}
+
+// Create box fragments and construct a tree from the placeholders.
+void NGInlineLayoutStateStack::CreateBoxFragments(
+ NGLineBoxFragmentBuilder* line_box) {
+ DCHECK(!box_placeholders_.IsEmpty());
+
+ Vector<RefPtr<NGPhysicalFragment>> children =
+ std::move(line_box->MutableChildren());
+ Vector<NGLogicalOffset> offsets = std::move(line_box->MutableOffsets());
+ DCHECK(line_box->Children().IsEmpty() && line_box->Offsets().IsEmpty());
+
+ // At this point, children is a list of text fragments and box placeholders.
+ // | 0 | 1 | 2 | 3 | 4 | 5 |
+ // |text0|text1|text2|text3|null1|text5|
+ // When there is a BoxFragmentPlaceholder(2,4), this loop creates a box
+ // fragment with text2 and text3 as its children and changes the list to:
+ // | 0 | 1 | 2 | 3 | 4 | 5 |
+ // |text0|text1|null |null | box |text5|
+ for (const BoxFragmentPlaceholder& placeholder : box_placeholders_) {
+ NGFragmentBuilder box(NGPhysicalFragment::kFragmentBox,
+ placeholder.item->GetLayoutObject());
+ const NGLogicalOffset& box_offset = offsets[placeholder.fragment_end];
+ for (unsigned i = placeholder.fragment_start; i < placeholder.fragment_end;
+ i++) {
+ if (RefPtr<NGPhysicalFragment>& child = children[i]) {
+ box.AddChild(std::move(child), offsets[i] - box_offset);
+ DCHECK(!children[i]);
+ }
+ }
+
+ box.SetWritingMode(line_box->WritingMode());
+ box.SetDirection(placeholder.item->Direction());
+ box.SetSize(placeholder.size);
+ // TODO(kojii): Overflow size should be computed from children.
+ box.SetOverflowSize(placeholder.size);
+ RefPtr<NGLayoutResult> layout_result = box.ToBoxFragment();
+ DCHECK(!children[placeholder.fragment_end]);
+ children[placeholder.fragment_end] =
+ std::move(layout_result->MutablePhysicalFragment());
+ }
+ box_placeholders_.clear();
+
+ // Add the list to line_box by skipping null fragments; i.e., fragments added
+ // to box children.
+ for (unsigned i = 0; i < children.size(); i++) {
+ if (children[i])
+ line_box->AddChild(children[i], offsets[i]);
+ }
+}
+
NGInlineLayoutStateStack::PositionPending
NGInlineLayoutStateStack::ApplyBaselineShift(NGInlineBoxState* box,
NGLineBoxFragmentBuilder* line_box,

Powered by Google App Engine
This is Rietveld 408576698