diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 15:05:36 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:33:47 +0000 |
commit | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch) | |
tree | d55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/third_party/blink/renderer/core/layout/layout_inline.cc | |
parent | 2b94bfe47ccb6c08047959d1c26e392919550e86 (diff) | |
download | qtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz |
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/layout_inline.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/core/layout/layout_inline.cc | 238 |
1 files changed, 183 insertions, 55 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc index 828d0821aad..b3c2a8bfec3 100644 --- a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc +++ b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc @@ -35,6 +35,7 @@ #include "third_party/blink/renderer/core/layout/line/inline_text_box.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h" #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h" +#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h" #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" #include "third_party/blink/renderer/core/paint/box_painter.h" #include "third_party/blink/renderer/core/paint/inline_painter.h" @@ -52,11 +53,24 @@ namespace { // TODO(layout-dev): Once we generate fragment for all inline element, we should // use |LayoutObject::EnclosingBlockFlowFragment()|. -const NGPhysicalBoxFragment* EnclosingBlockFlowFragmentOf( +const NGPhysicalBoxFragment* ContainingBlockFlowFragmentOf( const LayoutInline& node) { if (!RuntimeEnabledFeatures::LayoutNGEnabled()) return nullptr; - return node.EnclosingBlockFlowFragment(); + return node.ContainingBlockFlowFragment(); +} + +// TODO(xiaochengh): Deduplicate with a similar function in ng_paint_fragment.cc +// ::before, ::after and ::first-letter can be hit test targets. +bool CanBeHitTestTargetPseudoNodeStyle(const ComputedStyle& style) { + switch (style.StyleType()) { + case kPseudoIdBefore: + case kPseudoIdAfter: + case kPseudoIdFirstLetter: + return true; + default: + return false; + } } } // anonymous namespace @@ -230,40 +244,92 @@ void LayoutInline::StyleDidChange(StyleDifference diff, // before and after the block share the same style, but the block doesn't need // to pass its style on to anyone else. const ComputedStyle& new_style = StyleRef(); - LayoutInline* continuation = InlineElementContinuation(); - LayoutInline* end_of_continuation = nullptr; - for (LayoutInline* curr_cont = continuation; curr_cont; - curr_cont = curr_cont->InlineElementContinuation()) { - LayoutBoxModelObject* next_cont = curr_cont->Continuation(); - curr_cont->SetContinuation(nullptr); - curr_cont->SetStyle(MutableStyle()); - curr_cont->SetContinuation(next_cont); - end_of_continuation = curr_cont; - } + if (LayoutInline* continuation = InlineElementContinuation()) { + bool position_type_changed = + old_style && (new_style.GetPosition() != old_style->GetPosition()) && + (new_style.HasInFlowPosition() || old_style->HasInFlowPosition()); + + // An inline that establishes a continuation is normally wrapped inside an + // anonymous block, of course, but if the continuation chain has been + // partially torn down (read comment further below), this is not the + // case. Here we want to find the nearest containing block that's an + // ancestor of all the continuations. + const LayoutBlock* boundary = ContainingBlock(); + if (boundary->IsAnonymousBlock()) + boundary = boundary->ContainingBlock(); + LayoutInline* previous_part = this; + LayoutInline* end_of_continuation = nullptr; + bool needs_anon_block_position_update = false; + for (LayoutInline* curr_cont = continuation; curr_cont; + curr_cont = curr_cont->InlineElementContinuation()) { + if (position_type_changed && !needs_anon_block_position_update) { + // When we have a continuation chain, and the block child that was the + // reason for creating that in the first place is removed, we don't + // clean up the continuation chain. Previously split inlines should + // ideally be joined when this happens, but we don't do that, but rather + // leave the mess around. We'll end up with LayoutInline siblings or + // cousins for the same Node (that form a bogus continuation chain), + // without any blocks in-between. Here we check that we're NOT in such a + // situation, and that the Node actually forms a real continuation + // chain. This matters when it comes to marking the anonymous + // container(s) of block children as relatively positioned (further + // below). We should only do that if the Node is an ancestor of the + // blocks. Otherwise out-of-flow positioned descendants will use the + // wrong containing block. + for (LayoutObject* walker = previous_part->NextInPreOrder(boundary); + walker;) { + if (walker == curr_cont) + break; + if (walker->IsAnonymousBlock()) { + needs_anon_block_position_update = true; + break; + } + if (walker->IsLayoutInline()) + walker = walker->NextInPreOrder(boundary); + else + walker = walker->NextInPreOrderAfterChildren(boundary); + } + } + previous_part = curr_cont; + + LayoutBoxModelObject* next_cont = curr_cont->Continuation(); + curr_cont->SetContinuation(nullptr); + curr_cont->SetStyle(MutableStyle()); + curr_cont->SetContinuation(next_cont); + end_of_continuation = curr_cont; + } - if (continuation && old_style) { - DCHECK(end_of_continuation); - LayoutObject* block = ContainingBlock()->NextSibling(); - // If an inline's in-flow positioning has changed then any descendant blocks - // will need to change their styles accordingly. - if (block && block->IsAnonymousBlock() && - new_style.GetPosition() != old_style->GetPosition() && - (new_style.HasInFlowPosition() || old_style->HasInFlowPosition())) - UpdateInFlowPositionOfAnonymousBlockContinuations( - block, new_style, *old_style, end_of_continuation->ContainingBlock()); + if (needs_anon_block_position_update) { + DCHECK(old_style); + DCHECK(end_of_continuation); + LayoutObject* block = ContainingBlock()->NextSibling(); + // If an inline's in-flow positioning has changed then any descendant + // blocks will need to change their styles accordingly. + if (block && block->IsAnonymousBlock()) { + UpdateInFlowPositionOfAnonymousBlockContinuations( + block, new_style, *old_style, + end_of_continuation->ContainingBlock()); + } + } } - if (!AlwaysCreateLineBoxes()) { - bool always_create_line_boxes_new = - HasSelfPaintingLayer() || HasBoxDecorationBackground() || - new_style.HasPadding() || new_style.HasMargin() || - new_style.HasOutline(); - if (old_style && always_create_line_boxes_new) { - DirtyLineBoxes(false); - SetNeedsLayoutAndFullPaintInvalidation( - LayoutInvalidationReason::kStyleChange); + if (!IsInLayoutNGInlineFormattingContext()) { + if (!AlwaysCreateLineBoxes()) { + bool always_create_line_boxes_new = + HasSelfPaintingLayer() || HasBoxDecorationBackground() || + new_style.HasPadding() || new_style.HasMargin() || + new_style.HasOutline(); + if (old_style && always_create_line_boxes_new) { + DirtyLineBoxes(false); + SetNeedsLayoutAndFullPaintInvalidation( + layout_invalidation_reason::kStyleChange); + } + SetAlwaysCreateLineBoxes(always_create_line_boxes_new); + } + } else { + if (!ShouldCreateBoxFragment()) { + UpdateShouldCreateBoxFragment(); } - SetAlwaysCreateLineBoxes(always_create_line_boxes_new); } // If we are changing to/from static, we need to reposition @@ -290,6 +356,8 @@ void LayoutInline::StyleDidChange(StyleDifference diff, } void LayoutInline::UpdateAlwaysCreateLineBoxes(bool full_layout) { + DCHECK(!IsInLayoutNGInlineFormattingContext()); + // Once we have been tainted once, just assume it will happen again. This way // effects like hover highlighting that change the background color will only // cause a layout on the first rollover. @@ -329,6 +397,49 @@ void LayoutInline::UpdateAlwaysCreateLineBoxes(bool full_layout) { } } +bool LayoutInline::ComputeInitialShouldCreateBoxFragment( + const ComputedStyle& style) const { + if (style.HasBoxDecorationBackground() || style.HasPadding() || + style.HasMargin()) + return true; + + return style.CanContainAbsolutePositionObjects() || + style.CanContainFixedPositionObjects(false) || + NGOutlineUtils::HasPaintedOutline(style, GetNode()) || + CanBeHitTestTargetPseudoNodeStyle(style); +} + +bool LayoutInline::ComputeInitialShouldCreateBoxFragment() const { + const ComputedStyle& style = StyleRef(); + if (HasSelfPaintingLayer() || ComputeInitialShouldCreateBoxFragment(style) || + ShouldApplyPaintContainment() || ShouldApplyLayoutContainment()) + return true; + + const ComputedStyle& first_line_style = FirstLineStyleRef(); + if (UNLIKELY(&style != &first_line_style && + ComputeInitialShouldCreateBoxFragment(first_line_style))) + return true; + + return false; +} + +void LayoutInline::UpdateShouldCreateBoxFragment() { + // Once we have been tainted once, just assume it will happen again. This way + // effects like hover highlighting that change the background color will only + // cause a layout on the first rollover. + if (IsInLayoutNGInlineFormattingContext()) { + if (ShouldCreateBoxFragment()) + return; + } else { + SetIsInLayoutNGInlineFormattingContext(true); + SetShouldCreateBoxFragment(false); + } + + if (ComputeInitialShouldCreateBoxFragment()) { + SetShouldCreateBoxFragment(); + } +} + LayoutRect LayoutInline::LocalCaretRect( const InlineBox* inline_box, int, @@ -449,12 +560,17 @@ void LayoutInline::AddChildIgnoringContinuation(LayoutObject* new_child, LayoutBoxModelObject::AddChild(new_child, before_child); new_child->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( - LayoutInvalidationReason::kChildChanged); + layout_invalidation_reason::kChildChanged); } LayoutInline* LayoutInline::Clone() const { - LayoutInline* clone_inline = new LayoutInline(GetNode()); - DCHECK(!IsAnonymous()); + LayoutInline* clone_inline = nullptr; + if (UNLIKELY(IsFirstLineAnonymous())) { + clone_inline = CreateAnonymousForFirstLine(&GetDocument()); + } else { + DCHECK(!IsAnonymous()); + clone_inline = new LayoutInline(GetNode()); + } clone_inline->SetStyle(MutableStyle()); clone_inline->SetIsInsideFlowThread(IsInsideFlowThread()); return clone_inline; @@ -463,8 +579,8 @@ LayoutInline* LayoutInline::Clone() const { void LayoutInline::MoveChildrenToIgnoringContinuation( LayoutInline* to, LayoutObject* start_child) { - DCHECK(!IsAnonymous()); - DCHECK(!to->IsAnonymous()); + DCHECK(!IsAnonymous() || IsFirstLineAnonymous()); + DCHECK(!to->IsAnonymous() || to->IsFirstLineAnonymous()); LayoutObject* child = start_child; while (child) { LayoutObject* current_child = child; @@ -480,7 +596,7 @@ void LayoutInline::SplitInlines(LayoutBlockFlow* from_block, LayoutObject* before_child, LayoutBoxModelObject* old_cont) { DCHECK(IsDescendantOf(from_block)); - DCHECK(!IsAnonymous()); + DCHECK(!IsAnonymous() || IsFirstLineAnonymous()); // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the // depth at which we're willing to clone. @@ -602,7 +718,7 @@ void LayoutInline::SplitFlow(LayoutObject* before_child, pre->Children()->AppendChildNode( pre, block->Children()->RemoveChildNode(block, no)); no->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( - LayoutInvalidationReason::kAnonymousBlockChange); + layout_invalidation_reason::kAnonymousBlockChange); } } @@ -620,11 +736,11 @@ void LayoutInline::SplitFlow(LayoutObject* before_child, // pre block into the post block, we want to make new line boxes instead of // leaving the old line boxes around. pre->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( - LayoutInvalidationReason::kAnonymousBlockChange); + layout_invalidation_reason::kAnonymousBlockChange); block->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( - LayoutInvalidationReason::kAnonymousBlockChange); + layout_invalidation_reason::kAnonymousBlockChange); post->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation( - LayoutInvalidationReason::kAnonymousBlockChange); + layout_invalidation_reason::kAnonymousBlockChange); } void LayoutInline::AddChildToContinuation(LayoutObject* new_child, @@ -678,8 +794,11 @@ void LayoutInline::Paint(const PaintInfo& paint_info) const { template <typename GeneratorContext> void LayoutInline::GenerateLineBoxRects(GeneratorContext& yield) const { - if (const NGPhysicalBoxFragment* box_fragment = - EnclosingBlockFlowFragmentOf(*this)) { + if (IsInLayoutNGInlineFormattingContext()) { + const NGPhysicalBoxFragment* box_fragment = + ContainingBlockFlowFragmentOf(*this); + if (!box_fragment) + return; const auto& descendants = NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this); const LayoutBlock* block_for_flipping = nullptr; @@ -883,8 +1002,11 @@ LayoutPoint LayoutInline::FirstLineBoxTopLeft() const { // hand, sets the block-axis coordinate relatively to the block-start border // edge, which means that offsetLeft will be wrong when writing-mode is // vertical-rl. - if (const NGPhysicalBoxFragment* box_fragment = - EnclosingBlockFlowFragmentOf(*this)) { + if (IsInLayoutNGInlineFormattingContext()) { + const NGPhysicalBoxFragment* box_fragment = + ContainingBlockFlowFragmentOf(*this); + if (!box_fragment) + return LayoutPoint(); const auto& fragments = NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this); if (fragments.IsEmpty()) @@ -936,7 +1058,7 @@ bool LayoutInline::NodeAtPoint(HitTestResult& result, const HitTestLocation& location_in_container, const LayoutPoint& accumulated_offset, HitTestAction hit_test_action) { - if (EnclosingNGBlockFlow()) { + if (ContainingNGBlockFlow()) { // In LayoutNG, we reach here only when called from // PaintLayer::HitTestContents() without going through any ancestor, in // which case the element must have self painting layer. @@ -1004,9 +1126,9 @@ bool LayoutInline::HitTestCulledInline( // offset on the rectangles relatively to the block-start. NG is doing the // right thing. Legacy is wrong. if (container_fragment) { - DCHECK(EnclosingNGBlockFlow()); + DCHECK(ContainingNGBlockFlow()); DCHECK(container_fragment->IsDescendantOfNotSelf( - *EnclosingNGBlockFlow()->PaintFragment())); + *ContainingNGBlockFlow()->PaintFragment())); const NGPhysicalContainerFragment& traversal_root = ToNGPhysicalContainerFragment(container_fragment->PhysicalFragment()); DCHECK(traversal_root.IsInline() || traversal_root.IsLineBox()); @@ -1020,7 +1142,7 @@ bool LayoutInline::HitTestCulledInline( context(rect); } } else { - DCHECK(!EnclosingNGBlockFlow()); + DCHECK(!ContainingNGBlockFlow()); GenerateCulledLineBoxRects(context, this); } @@ -1048,7 +1170,7 @@ PositionWithAffinity LayoutInline::PositionForPoint( continuation = ToLayoutBlockFlow(continuation)->InlineElementContinuation(); } - if (const LayoutBlockFlow* ng_block_flow = EnclosingNGBlockFlow()) + if (const LayoutBlockFlow* ng_block_flow = ContainingNGBlockFlow()) return ng_block_flow->PositionForPoint(point); DCHECK(CanUseInlineBox(*this)); @@ -1078,8 +1200,11 @@ class LinesBoundingBoxGeneratorContext { } // unnamed namespace LayoutRect LayoutInline::LinesBoundingBox() const { - if (const NGPhysicalBoxFragment* box_fragment = - EnclosingBlockFlowFragmentOf(*this)) { + if (IsInLayoutNGInlineFormattingContext()) { + const NGPhysicalBoxFragment* box_fragment = + ContainingBlockFlowFragmentOf(*this); + if (!box_fragment) + return LayoutRect(); NGPhysicalOffsetRect bounding_box; auto children = NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this); @@ -1223,8 +1348,11 @@ LayoutRect LayoutInline::CulledInlineVisualOverflowBoundingBox() const { } LayoutRect LayoutInline::LinesVisualOverflowBoundingBox() const { - if (const NGPhysicalBoxFragment* box_fragment = - EnclosingBlockFlowFragmentOf(*this)) { + if (IsInLayoutNGInlineFormattingContext()) { + const NGPhysicalBoxFragment* box_fragment = + ContainingBlockFlowFragmentOf(*this); + if (!box_fragment) + return LayoutRect(); NGPhysicalOffsetRect result; auto children = NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this); |