summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 15:05:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:33:47 +0000
commite684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch)
treed55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/third_party/blink/renderer/core/layout/layout_inline.cc
parent2b94bfe47ccb6c08047959d1c26e392919550e86 (diff)
downloadqtwebengine-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.cc238
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);