summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc100
1 files changed, 67 insertions, 33 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index c8c01e84f7c..f3d4a644b8c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -96,8 +96,10 @@ NGInlineBoxState* NGInlineLayoutAlgorithm::HandleCloseTag(
box->EnsureTextMetrics(*item.Style(), baseline_type_);
box = box_states_->OnCloseTag(&line_box_, box, baseline_type_,
item.HasEndEdge());
- item.GetLayoutObject()->SetShouldDoFullPaintInvalidation();
- ClearNeedsLayoutIfNeeded(item.GetLayoutObject());
+ // Just clear |NeedsLayout| flags. Culled inline boxes do not need paint
+ // invalidations. If this object produces box fragments,
+ // |NGInlineBoxStateStack| takes care of invalidations.
+ item.GetLayoutObject()->ClearNeedsLayoutWithoutPaintInvalidation();
return box;
}
@@ -239,7 +241,8 @@ void NGInlineLayoutAlgorithm::CreateLine(
}
line_box_.AddChild(text_builder.ToTextFragment(), box->text_top,
item_result.inline_size, item.BidiLevel());
- ClearNeedsLayoutIfNeeded(item.GetLayoutObject());
+ // Text boxes always need full paint invalidations.
+ item.GetLayoutObject()->ClearNeedsLayoutWithFullPaintInvalidation();
} else if (item.Type() == NGInlineItem::kControl) {
PlaceControlItem(item, *line_info, &item_result, box);
} else if (item.Type() == NGInlineItem::kOpenTag) {
@@ -290,6 +293,14 @@ void NGInlineLayoutAlgorithm::CreateLine(
box_states_->UpdateAfterReorder(&line_box_);
}
LayoutUnit inline_size = box_states_->ComputeInlinePositions(&line_box_);
+ if (LayoutUnit hang_width = line_info->HangWidth()) {
+ inline_size -= hang_width;
+ container_builder_.SetHangInlineSize(hang_width);
+
+ if (IsRtl(line_info->BaseDirection())) {
+ line_box_.MoveInInlineDirection(-hang_width);
+ }
+ }
// Truncate the line if 'text-overflow: ellipsis' is set.
if (UNLIKELY(inline_size > line_info->AvailableWidth() &&
@@ -346,6 +357,7 @@ void NGInlineLayoutAlgorithm::CreateLine(
// Even if we have something in-flow, it may just be empty items that
// shouldn't trigger creation of a line. Exit now if that's the case.
if (line_info->IsEmptyLine()) {
+ container_builder_.SetIsSelfCollapsing();
container_builder_.SetIsEmptyLineBox();
container_builder_.SetBaseDirection(line_info->BaseDirection());
container_builder_.AddChildren(line_box_);
@@ -413,7 +425,7 @@ void NGInlineLayoutAlgorithm::PlaceControlItem(const NGInlineItem& item,
// Place a generated content that does not exist in DOM nor in LayoutObject
// tree.
void NGInlineLayoutAlgorithm::PlaceGeneratedContent(
- scoped_refptr<const NGPhysicalFragment> fragment,
+ scoped_refptr<const NGPhysicalTextFragment> fragment,
UBiDiLevel bidi_level,
NGInlineBoxState* box) {
LayoutUnit inline_size = IsHorizontalWritingMode() ? fragment->Size().width
@@ -466,7 +478,7 @@ void NGInlineLayoutAlgorithm::PlaceLayoutResult(NGInlineItemResult* item_result,
NGBoxFragment fragment(ConstraintSpace().GetWritingMode(),
ConstraintSpace().Direction(),
To<NGPhysicalBoxFragment>(
- *item_result->layout_result->PhysicalFragment()));
+ item_result->layout_result->PhysicalFragment()));
NGLineHeightMetrics metrics = fragment.BaselineMetrics(
{NGBaselineAlgorithmType::kAtomicInline, baseline_type_},
ConstraintSpace());
@@ -475,7 +487,7 @@ void NGInlineLayoutAlgorithm::PlaceLayoutResult(NGInlineItemResult* item_result,
LayoutUnit line_top = item_result->margins.line_over - metrics.ascent;
line_box_.AddChild(std::move(item_result->layout_result),
- NGLogicalOffset{inline_offset, line_top},
+ LogicalOffset{inline_offset, line_top},
item_result->inline_size, item.BidiLevel());
}
@@ -486,6 +498,8 @@ void NGInlineLayoutAlgorithm::PlaceOutOfFlowObjects(
DCHECK(line_info.IsEmptyLine() || !line_box_metrics.IsEmpty())
<< "Non-empty lines must have a valid set of linebox metrics.";
+ bool is_empty_inline = Node().IsEmptyInline();
+
// All children within the linebox are positioned relative to the baseline,
// then shifted later using NGLineBoxFragmentBuilder::MoveInBlockDirection.
LayoutUnit baseline_adjustment =
@@ -516,25 +530,34 @@ void NGInlineLayoutAlgorithm::PlaceOutOfFlowObjects(
// To correctly determine which "line" block-level out-of-flow positioned
// object is placed on, we need to keep track of if there is any inline-level
// content preceeding it.
- bool has_preceeding_inline_level_content = false;
+ bool has_preceding_inline_level_content = false;
for (NGLineBoxFragmentBuilder::Child& child : line_box_) {
- has_preceeding_inline_level_content |= child.HasInFlowFragment();
+ has_preceding_inline_level_content |= child.HasInFlowFragment();
LayoutObject* box = child.out_of_flow_positioned_box;
if (!box)
continue;
- NGLogicalOffset static_offset(LayoutUnit(), baseline_adjustment);
+ LogicalOffset static_offset(LayoutUnit(), baseline_adjustment);
if (box->StyleRef().IsOriginalDisplayInlineType()) {
// An inline-level OOF element positions itself within the line, at the
// position it would have been if it was in-flow.
static_offset.inline_offset = child.offset.inline_offset;
+
+ // The static-position of inline-level OOF-positioned nodes depends on
+ // previous floats (if any).
+ //
+ // If we are an empty-inline we may not have the correct BFC block-offset
+ // yet. Due to this we need to mark this node as having adjoining
+ // objects, and perform a re-layout if our position shifts.
+ if (is_empty_inline)
+ container_builder_.AddAdjoiningFloatTypes(kAdjoiningInlineOutOfFlow);
} else {
// A block-level OOF element positions itself on the "next" line. However
// only shifts down if there is inline-level content.
static_offset.inline_offset = block_level_inline_offset;
- if (has_preceeding_inline_level_content)
+ if (has_preceding_inline_level_content)
static_offset.block_offset += line_height;
}
@@ -566,9 +589,8 @@ void NGInlineLayoutAlgorithm::PlaceFloatingObjects(
bool is_empty_inline = Node().IsEmptyInline();
LayoutUnit bfc_block_offset = line_info.BfcOffset().block_offset;
- if (is_empty_inline && ConstraintSpace().FloatsBfcBlockOffset()) {
- bfc_block_offset = *ConstraintSpace().FloatsBfcBlockOffset();
- }
+ if (is_empty_inline && ConstraintSpace().ForcedBfcBlockOffset())
+ bfc_block_offset = *ConstraintSpace().ForcedBfcBlockOffset();
LayoutUnit bfc_line_offset = container_builder_.BfcLineOffset();
@@ -587,7 +609,7 @@ void NGInlineLayoutAlgorithm::PlaceFloatingObjects(
// Skip any children which aren't positioned floats.
if (!child.layout_result ||
- !child.layout_result->PhysicalFragment()->IsFloating())
+ !child.layout_result->PhysicalFragment().IsFloating())
continue;
LayoutUnit block_offset =
@@ -595,9 +617,8 @@ void NGInlineLayoutAlgorithm::PlaceFloatingObjects(
// We need to manually account for the flipped-lines writing mode here :(.
if (IsFlippedLinesWritingMode(ConstraintSpace().GetWritingMode())) {
- NGFragment fragment(
- ConstraintSpace().GetWritingMode(),
- To<NGPhysicalBoxFragment>(*child.layout_result->PhysicalFragment()));
+ NGFragment fragment(ConstraintSpace().GetWritingMode(),
+ child.layout_result->PhysicalFragment());
block_offset = -fragment.BlockSize() - block_offset;
}
@@ -629,10 +650,7 @@ bool NGInlineLayoutAlgorithm::ApplyJustify(LayoutUnit space,
return false;
// Justify the end of visible text, ignoring preserved trailing spaces.
- unsigned end_offset;
- LayoutUnit trailing_spaces_width =
- line_info->ComputeTrailingSpaceWidth(&end_offset);
- space += trailing_spaces_width;
+ unsigned end_offset = line_info->EndOffsetForJustify();
// If this line overflows, fallback to 'text-align: start'.
if (space <= 0)
@@ -700,8 +718,7 @@ LayoutUnit NGInlineLayoutAlgorithm::ApplyTextAlign(NGLineInfo* line_info) {
LayoutUnit space =
line_info->AvailableWidth() - line_info->WidthForAlignment();
- const ComputedStyle& line_style = line_info->LineStyle();
- ETextAlign text_align = line_style.GetTextAlign(line_info->IsLastLine());
+ ETextAlign text_align = line_info->TextAlign();
if (text_align == ETextAlign::kJustify) {
// If justification succeeds, no offset is needed. Expansions are set to
// each |NGInlineItemResult| in |line_info|.
@@ -781,16 +798,22 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
unsigned handled_leading_floats_index =
PositionLeadingFloats(&initial_exclusion_space, &leading_floats);
+ // Only empty-inlines should have the "forced" BFC block-offset set.
+ DCHECK(is_empty_inline || !ConstraintSpace().ForcedBfcBlockOffset());
+
// We query all the layout opportunities on the initial exclusion space up
// front, as if the line breaker may add floats and change the opportunities.
const LayoutOpportunityVector opportunities =
initial_exclusion_space.AllLayoutOpportunities(
- ConstraintSpace().BfcOffset(),
+ {ConstraintSpace().BfcOffset().line_offset,
+ ConstraintSpace().ForcedBfcBlockOffset().value_or(
+ ConstraintSpace().BfcOffset().block_offset)},
ConstraintSpace().AvailableSize().inline_size);
NGExclusionSpace exclusion_space;
const NGInlineBreakToken* break_token = BreakToken();
+ bool is_line_created = false;
LayoutUnit line_block_size;
LayoutUnit block_delta;
const auto* opportunities_it = opportunities.begin();
@@ -818,6 +841,7 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// Reset any state that may have been modified in a previous pass.
container_builder_.Reset();
exclusion_space = initial_exclusion_space;
+ is_line_created = false;
NGLineLayoutOpportunity line_opportunity =
opportunity.ComputeLineLayoutOpportunity(ConstraintSpace(),
@@ -834,8 +858,8 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// *and* the opportunity is smaller than the available inline-size, and the
// container autowraps, continue to the next opportunity.
if (line_info.HasOverflow() &&
- ConstraintSpace().AvailableSize().inline_size !=
- line_opportunity.AvailableFloatInlineSize() &&
+ !line_opportunity.IsEqualToAvailableFloatInlineSize(
+ ConstraintSpace().AvailableSize().inline_size) &&
Node().Style().AutoWrap()) {
// Shapes are *special*. We need to potentially increment the block-delta
// by 1px each loop to properly test each potential position of the line.
@@ -851,11 +875,15 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
line_block_size = LayoutUnit();
++opportunities_it;
}
+ // There must be at least one more opportunity, or we fail to call
+ // |CreateLine()|.
+ DCHECK_NE(opportunities_it, opportunities.end());
continue;
}
PrepareBoxStates(line_info, break_token);
CreateLine(line_opportunity, &line_info, &exclusion_space);
+ is_line_created = true;
// We now can check the block-size of the fragment, and it fits within the
// opportunity.
@@ -894,10 +922,6 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
continue;
}
- if (opportunity.rect.BlockStartOffset() >
- ConstraintSpace().BfcOffset().block_offset)
- container_builder_.SetIsPushedByFloats();
-
// Success!
container_builder_.SetBreakToken(line_breaker.CreateBreakToken(line_info));
@@ -909,10 +933,20 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// TODO(ikilpatrick): Move this into ng_block_layout_algorithm.
container_builder_.SetBlockSize(
ComputeContentSize(line_info, exclusion_space, line_height));
+
+ // As we aren't an empty inline we should have correctly placed all
+ // our adjoining floats, and shouldn't propagate this information
+ // to siblings.
+ container_builder_.ResetAdjoiningFloatTypes();
+
+ if (opportunity.rect.BlockStartOffset() >
+ ConstraintSpace().BfcOffset().block_offset)
+ container_builder_.SetIsPushedByFloats();
}
break;
}
+ CHECK(is_line_created);
container_builder_.SetExclusionSpace(std::move(exclusion_space));
container_builder_.MoveOutOfFlowDescendantCandidatesToDescendants();
return container_builder_.ToLineBoxFragment();
@@ -948,13 +982,13 @@ unsigned NGInlineLayoutAlgorithm::PositionLeadingFloats(
? kFloatTypeLeft
: kFloatTypeRight);
- // If we are an empty inline, and don't have the special floats BFC
+ // If we are an empty inline, and don't have the special forced BFC
// block-offset yet, there is no way to position any floats.
- if (is_empty_inline && !ConstraintSpace().FloatsBfcBlockOffset())
+ if (is_empty_inline && !ConstraintSpace().ForcedBfcBlockOffset())
continue;
LayoutUnit origin_bfc_block_offset =
- is_empty_inline ? *ConstraintSpace().FloatsBfcBlockOffset()
+ is_empty_inline ? *ConstraintSpace().ForcedBfcBlockOffset()
: ConstraintSpace().BfcOffset().block_offset;
NGPositionedFloat positioned_float = PositionFloat(