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

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

Issue 2930963002: [LayoutNG] Refactor of NGLineBreaker. (Closed)
Patch Set: rebase Created 3 years, 6 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_line_breaker.cc
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
index dd34fb3ac047cf4ab227f148ca66663b7004a38b..3bb0c2081a51fc0ae3908f6e86d4e5f74033545f 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
@@ -8,6 +8,7 @@
#include "core/layout/ng/inline/ng_inline_layout_algorithm.h"
#include "core/layout/ng/inline/ng_inline_node.h"
#include "core/layout/ng/inline/ng_text_fragment.h"
+#include "core/layout/ng/ng_block_layout_algorithm.h"
#include "core/layout/ng/ng_box_fragment.h"
#include "core/layout/ng/ng_break_token.h"
#include "core/layout/ng/ng_constraint_space.h"
@@ -56,10 +57,12 @@ std::pair<unsigned, LayoutUnit> ShapeLineMock(
} // namespace
NGLineBreaker::NGLineBreaker(NGInlineNode node,
- const NGConstraintSpace* space,
- NGInlineBreakToken* break_token)
+ NGConstraintSpace* space,
+ NGFragmentBuilder* container_builder,
+ const NGInlineBreakToken* break_token)
: node_(node),
constraint_space_(space),
+ container_builder_(container_builder),
item_index_(0),
offset_(0),
break_iterator_(node.Text()),
@@ -72,8 +75,8 @@ NGLineBreaker::NGLineBreaker(NGInlineNode node,
}
bool NGLineBreaker::NextLine(NGLineInfo* line_info,
- NGInlineLayoutAlgorithm* algorithm) {
- BreakLine(line_info, algorithm);
+ const NGLogicalOffset& content_offset) {
+ BreakLine(line_info, content_offset);
// TODO(kojii): When editing, or caret is enabled, trailing spaces at wrap
// point should not be removed. For other cases, we can a) remove, b) leave
@@ -85,16 +88,21 @@ bool NGLineBreaker::NextLine(NGLineInfo* line_info,
}
void NGLineBreaker::BreakLine(NGLineInfo* line_info,
- NGInlineLayoutAlgorithm* algorithm) {
+ const NGLogicalOffset& content_offset) {
NGInlineItemResults* item_results = &line_info->Results();
item_results->clear();
const Vector<NGInlineItem>& items = node_.Items();
line_info->SetLineStyle(node_, !item_index_ && !offset_);
UpdateBreakIterator(line_info->LineStyle());
- available_width_ = algorithm->AvailableWidth();
position_ = LayoutUnit(0);
LineBreakState state = LineBreakState::kNotBreakable;
+ // We are only able to calculate our available_width if our container has
+ // been positioned in the BFC coordinate space yet.
+ WTF::Optional<LayoutUnit> available_width;
+ if (container_builder_->BfcOffset())
+ available_width = ComputeAvailableWidth(content_offset);
+
while (item_index_ < items.size()) {
// CloseTag prohibits to break before.
const NGInlineItem& item = items[item_index_];
@@ -109,14 +117,32 @@ void NGLineBreaker::BreakLine(NGLineInfo* line_info,
line_info->SetIsLastLine(false);
return;
}
- if (state == LineBreakState::kIsBreakable && position_ > available_width_)
- return HandleOverflow(line_info);
+ if (state == LineBreakState::kIsBreakable && available_width &&
+ position_ > available_width.value())
+ return HandleOverflow(available_width.value(), line_info);
+
+ // We resolve the BFC-offset of the container if this line has an item with
+ // inline-size. Floats, and tags do not allow us to resolve the BFC-offset.
+ //
+ // If this line just has a float we place it in the unpositioned float list
+ // which will be positioned later.
+ bool should_resolve_bfc_offset =
+ !container_builder_->BfcOffset() &&
+ (item.Type() == NGInlineItem::kText ||
+ item.Type() == NGInlineItem::kAtomicInline ||
+ item.Type() == NGInlineItem::kControl);
+
+ if (should_resolve_bfc_offset) {
+ ResolveBFCOffset();
+ available_width = ComputeAvailableWidth(content_offset);
+ }
item_results->push_back(
NGInlineItemResult(item_index_, offset_, item.EndOffset()));
NGInlineItemResult* item_result = &item_results->back();
if (item.Type() == NGInlineItem::kText) {
- state = HandleText(item, item_result);
+ DCHECK(available_width);
+ state = HandleText(item, available_width.value(), item_result);
} else if (item.Type() == NGInlineItem::kAtomicInline) {
state = HandleAtomicInline(item, item_result);
} else if (item.Type() == NGInlineItem::kControl) {
@@ -129,18 +155,44 @@ void NGLineBreaker::BreakLine(NGLineInfo* line_info,
HandleOpenTag(item, item_result);
state = LineBreakState::kNotBreakable;
} else if (item.Type() == NGInlineItem::kFloating) {
- HandleFloat(item, item_results, algorithm);
+ HandleFloat(item, content_offset, &available_width, item_results);
} else {
MoveToNextOf(item);
}
}
- if (state == LineBreakState::kIsBreakable && position_ > available_width_)
- return HandleOverflow(line_info);
+ if (state == LineBreakState::kIsBreakable && available_width &&
+ position_ > available_width.value())
+ return HandleOverflow(available_width.value(), line_info);
line_info->SetIsLastLine(true);
}
+// Resolves the BFC offset for the container, and positions any pending floats.
+void NGLineBreaker::ResolveBFCOffset() {
+ LayoutUnit container_bfc_block_offset =
+ constraint_space_->BfcOffset().block_offset +
+ constraint_space_->MarginStrut().Sum();
+ MaybeUpdateFragmentBfcOffset(*constraint_space_, container_bfc_block_offset,
+ container_builder_);
+ PositionPendingFloats(container_bfc_block_offset, container_builder_,
+ constraint_space_);
+}
+
+// Returns the inline size of the first layout opportunity from the given
+// content_offset.
+LayoutUnit NGLineBreaker::ComputeAvailableWidth(
+ const NGLogicalOffset& content_offset) const {
+ NGLogicalOffset offset = container_builder_->BfcOffset().value();
+ offset += content_offset;
+
+ NGLayoutOpportunityIterator iter(constraint_space_->Exclusions().get(),
+ constraint_space_->AvailableSize(), offset);
+ NGLayoutOpportunity opportunity = iter.Next();
+ return opportunity.InlineSize();
+};
+
NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
const NGInlineItem& item,
+ LayoutUnit available_width,
NGInlineItemResult* item_result) {
DCHECK_EQ(item.Type(), NGInlineItem::kText);
@@ -148,7 +200,7 @@ NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
if (offset_ == item.StartOffset()) {
item_result->inline_size = item.InlineSize();
LayoutUnit next_position = position_ + item_result->inline_size;
- if (!auto_wrap_ || next_position <= available_width_) {
+ if (!auto_wrap_ || next_position <= available_width) {
position_ = next_position;
MoveToNextOf(item);
if (auto_wrap_ && break_iterator_.IsBreakable(item.EndOffset()))
@@ -160,10 +212,10 @@ NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
if (auto_wrap_) {
// Try to break inside of this text item.
- BreakText(item_result, item, available_width_ - position_);
+ BreakText(item_result, item, available_width - position_);
position_ += item_result->inline_size;
- bool is_overflow = position_ > available_width_;
+ bool is_overflow = position_ > available_width;
item_result->no_break_opportunities_inside = is_overflow;
if (item_result->end_offset < item.EndOffset()) {
offset_ = item_result->end_offset;
@@ -284,12 +336,73 @@ NGLineBreaker::LineBreakState NGLineBreaker::HandleAtomicInline(
return LineBreakState::kNotBreakable;
}
+// Performs layout and positions a float.
+//
+// If there is a known available_width (e.g. something has resolved the
+// container BFC offset) it will attempt to position the float on the current
+// line.
+// Additionally updates the available_width for the line as the float has
+// (probably) consumed space.
+//
+// If the float is too wide *or* we already have UnpositionedFloats we add it
+// as an UnpositionedFloat. This should be positioned *immediately* after we
+// are done with the current line.
+// We have this check if there are already UnpositionedFloats as we aren't
+// allowed to position a float "above" another float which has come before us
+// in the document.
+//
+// TODO(glebl): Add the support of clearance for inline floats.
void NGLineBreaker::HandleFloat(const NGInlineItem& item,
- NGInlineItemResults* item_results,
- NGInlineLayoutAlgorithm* algorithm) {
- algorithm->LayoutAndPositionFloat(position_, item.GetLayoutObject());
- // Floats may change the available width if they fit.
- available_width_ = algorithm->AvailableWidth();
+ const NGLogicalOffset& content_offset,
+ WTF::Optional<LayoutUnit>* available_width,
+ NGInlineItemResults* item_results) {
+ NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
+
+ const ComputedStyle& float_style = node.Style();
+ NGBoxStrut margins = ComputeMargins(*constraint_space_, float_style,
+ constraint_space_->WritingMode(),
+ constraint_space_->Direction());
+
+ // TODO(ikilpatrick): Add support for float break tokens inside an inline
+ // layout context.
+ RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create(
+ constraint_space_->AvailableSize(),
+ constraint_space_->PercentageResolutionSize(),
+ constraint_space_->BfcOffset(), constraint_space_->BfcOffset(), margins,
+ node, /* break_token */ nullptr);
+
+ LayoutUnit inline_size = ComputeInlineSizeForUnpositionedFloat(
+ constraint_space_, unpositioned_float.Get());
+
+ // We can only determine if our float will fit if we have an available_width
+ // I.e. we may not have come across any text yet, in order to be able to
+ // resolve the BFC position.
+ bool float_does_not_fit =
+ !available_width->has_value() ||
+ position_ + inline_size + margins.InlineSum() > available_width->value();
+
+ // Check if we already have a pending float. That's because a float cannot be
+ // higher than any block or floated box generated before.
+ if (!container_builder_->UnpositionedFloats().IsEmpty() ||
+ float_does_not_fit) {
+ container_builder_->AddUnpositionedFloat(unpositioned_float);
+ } else {
+ NGLogicalOffset container_bfc_offset =
+ container_builder_->BfcOffset().value();
+ unpositioned_float->origin_offset = container_bfc_offset + content_offset;
+ unpositioned_float->from_offset.block_offset =
+ container_bfc_offset.block_offset;
+ unpositioned_float->parent_bfc_block_offset =
+ container_bfc_offset.block_offset;
+
+ container_builder_->AddPositionedFloat(
+ PositionFloat(unpositioned_float.Get(), constraint_space_));
+
+ // We need to recalculate the available_width as the float probably
+ // consumed space on the line.
+ *available_width = ComputeAvailableWidth(content_offset);
+ }
+
// Floats are already positioned in the container_builder.
item_results->pop_back();
MoveToNextOf(item);
@@ -341,10 +454,11 @@ void NGLineBreaker::HandleCloseTag(const NGInlineItem& item,
// Handles when the last item overflows.
// At this point, item_results does not fit into the current line, and there
// are no break opportunities in item_results.back().
-void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) {
+void NGLineBreaker::HandleOverflow(LayoutUnit available_width,
+ NGLineInfo* line_info) {
NGInlineItemResults* item_results = &line_info->Results();
const Vector<NGInlineItem>& items = node_.Items();
- LayoutUnit rewind_width = available_width_ - position_;
+ LayoutUnit rewind_width = available_width - position_;
DCHECK_LT(rewind_width, 0);
// Search for a break opportunity that can fit.

Powered by Google App Engine
This is Rietveld 408576698