summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc323
1 files changed, 252 insertions, 71 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index 8dde837c121..9795013bde1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -14,7 +14,6 @@
#include "third_party/blink/renderer/core/layout/layout_object_inlines.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
@@ -103,6 +102,7 @@ scoped_refptr<const NGPhysicalBoxFragment> NGPhysicalBoxFragment::Create(
bool has_rare_data =
builder->mathml_paint_info_ ||
!builder->oof_positioned_fragmentainer_descendants_.IsEmpty() ||
+ !builder->multicols_with_pending_oofs_.IsEmpty() ||
builder->table_grid_rect_ || builder->table_column_geometries_ ||
builder->table_collapsed_borders_ ||
builder->table_collapsed_borders_geometry_ ||
@@ -327,6 +327,10 @@ NGPhysicalBoxFragment::RareData::RareData(NGBoxFragmentBuilder* builder,
: PhysicalSize()),
descendant.containing_block_fragment);
}
+ if (builder->HasMulticolsWithPendingOOFs()) {
+ multicols_with_pending_oofs =
+ std::move(builder->multicols_with_pending_oofs_);
+ }
if (builder->table_grid_rect_)
table_grid_rect = *builder->table_grid_rect_;
if (builder->table_column_geometries_)
@@ -344,6 +348,7 @@ NGPhysicalBoxFragment::RareData::RareData(NGBoxFragmentBuilder* builder,
NGPhysicalBoxFragment::RareData::RareData(const RareData& other)
: oof_positioned_fragmentainer_descendants(
other.oof_positioned_fragmentainer_descendants),
+ multicols_with_pending_oofs(other.multicols_with_pending_oofs),
mathml_paint_info(other.mathml_paint_info
? new NGMathMLPaintInfo(*other.mathml_paint_info)
: nullptr),
@@ -370,6 +375,62 @@ NGPhysicalBoxFragment::CloneAsHiddenForPaint() const {
return builder.ToBoxFragment();
}
+const LayoutBox* NGPhysicalBoxFragment::OwnerLayoutBox() const {
+ const LayoutBox* owner_box =
+ DynamicTo<LayoutBox>(GetSelfOrContainerLayoutObject());
+ DCHECK(owner_box);
+ if (UNLIKELY(IsColumnBox())) {
+ owner_box = To<LayoutBox>(owner_box->SlowFirstChild());
+ DCHECK(owner_box && owner_box->IsLayoutFlowThread());
+ }
+ // Check |this| and the |LayoutBox| that produced it are in sync.
+ DCHECK(owner_box->PhysicalFragments().Contains(*this));
+ DCHECK_EQ(IsFirstForNode(), this == owner_box->GetPhysicalFragment(0));
+ return owner_box;
+}
+
+LayoutBox* NGPhysicalBoxFragment::MutableOwnerLayoutBox() const {
+ return const_cast<LayoutBox*>(OwnerLayoutBox());
+}
+
+PhysicalOffset NGPhysicalBoxFragment::OffsetFromOwnerLayoutBox() const {
+ // This function uses |FragmentData|, so must be |kPrePaintClean|.
+ DCHECK_GE(GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kPrePaintClean);
+
+ const LayoutBox* owner_box = OwnerLayoutBox();
+ DCHECK(owner_box);
+ DCHECK(owner_box->PhysicalFragments().Contains(*this));
+ if (owner_box->PhysicalFragmentCount() <= 1)
+ return PhysicalOffset();
+
+ // When LTR, compute the offset from the first fragment. The first fragment is
+ // at the left top of the |LayoutBox| regardless of the writing mode.
+ const auto* containing_block = owner_box->ContainingBlock();
+ const ComputedStyle& containing_block_style = containing_block->StyleRef();
+ if (IsLtr(containing_block_style.Direction())) {
+ DCHECK_EQ(IsFirstForNode(), this == owner_box->GetPhysicalFragment(0));
+ if (IsFirstForNode())
+ return PhysicalOffset();
+
+ const FragmentData* fragment_data =
+ owner_box->FragmentDataFromPhysicalFragment(*this);
+ DCHECK(fragment_data);
+ const FragmentData& first_fragment_data = owner_box->FirstFragment();
+ // All |FragmentData| for an NG block fragmented |LayoutObject| should be in
+ // the same transform node that their |PaintOffset()| are in the same
+ // coordinate system.
+ return fragment_data->PaintOffset() - first_fragment_data.PaintOffset();
+ }
+
+ // When RTL, compute the offset from the last fragment.
+ const FragmentData* fragment_data =
+ owner_box->FragmentDataFromPhysicalFragment(*this);
+ DCHECK(fragment_data);
+ const FragmentData& last_fragment_data = fragment_data->LastFragment();
+ return fragment_data->PaintOffset() - last_fragment_data.PaintOffset();
+}
+
const NGPhysicalBoxFragment* NGPhysicalBoxFragment::PostLayout() const {
const auto* layout_object = GetSelfOrContainerLayoutObject();
if (UNLIKELY(!layout_object)) {
@@ -523,7 +584,7 @@ PhysicalRect NGPhysicalBoxFragment::ScrollableOverflowFromChildren(
rect.offset.ConvertToLogical(writing_direction, container.Size(),
rect.size) +
rect.size.ConvertToLogical(writing_direction.GetWritingMode());
- return rect_logical_end.inline_offset > border_inline_start &&
+ return rect_logical_end.inline_offset > border_inline_start ||
rect_logical_end.block_offset > border_block_start;
}
@@ -559,7 +620,7 @@ PhysicalRect NGPhysicalBoxFragment::ScrollableOverflowFromChildren(
DCHECK_EQ(&child, cursor.CurrentItem());
DCHECK_EQ(child.Type(), NGFragmentItem::kLine);
if (padding_strut)
- AddLineBoxRect(child.RectInContainerBlock());
+ AddLineBoxRect(child.RectInContainerFragment());
const NGPhysicalLineBoxFragment* line_box = child.LineBoxFragment();
DCHECK(line_box);
PhysicalRect child_scrollable_overflow =
@@ -609,7 +670,7 @@ PhysicalRect NGPhysicalBoxFragment::ScrollableOverflowFromChildren(
item->PostLayoutBoxFragment()) {
if (child_box->IsFloatingOrOutOfFlowPositioned()) {
context.AddFloatingOrOutOfFlowPositionedChild(
- *child_box, item->OffsetInContainerBlock());
+ *child_box, item->OffsetInContainerFragment());
}
}
}
@@ -653,28 +714,58 @@ PhysicalSize NGPhysicalBoxFragment::ScrollSize() const {
return {box->ScrollWidth(), box->ScrollHeight()};
}
+const NGPhysicalBoxFragment*
+NGPhysicalBoxFragment::InlineContainerFragmentIfOutlineOwner() const {
+ DCHECK(IsInlineBox());
+ // In order to compute united outlines, collect all rectangles of inline
+ // fragments for |LayoutInline| if |this| is the first inline fragment.
+ // Otherwise return none.
+ const LayoutObject* layout_object = GetLayoutObject();
+ DCHECK(layout_object);
+ DCHECK(layout_object->IsLayoutInline());
+ NGInlineCursor cursor;
+ cursor.MoveTo(*layout_object);
+ DCHECK(cursor);
+ if (cursor.Current().BoxFragment() == this)
+ return &cursor.ContainerFragment();
+ if (!cursor.IsBlockFragmented())
+ return nullptr;
+
+ // When |LayoutInline| is block fragmented, unite rectangles for each block
+ // fragment. To do this, return |true| if |this| is the first inline fragment
+ // of a block fragment.
+ for (wtf_size_t previous_fragment_index = cursor.ContainerFragmentIndex();;) {
+ cursor.MoveToNextForSameLayoutObject();
+ DCHECK(cursor);
+ const wtf_size_t fragment_index = cursor.ContainerFragmentIndex();
+ if (cursor.Current().BoxFragment() == this) {
+ if (fragment_index != previous_fragment_index)
+ return &cursor.ContainerFragment();
+ return nullptr;
+ }
+ previous_fragment_index = fragment_index;
+ }
+}
+
PhysicalRect NGPhysicalBoxFragment::ComputeSelfInkOverflow() const {
DCHECK_EQ(PostLayout(), this);
CheckCanUpdateInkOverflow();
const ComputedStyle& style = Style();
- PhysicalRect ink_overflow({}, Size().ToLayoutSize());
+ if (!style.HasVisualOverflowingEffect())
+ return LocalRect();
DCHECK(GetLayoutObject());
- if (style.HasVisualOverflowingEffect()) {
- ink_overflow.Expand(style.BoxDecorationOutsets());
- if (NGOutlineUtils::HasPaintedOutline(style,
- GetLayoutObject()->GetNode()) &&
- NGOutlineUtils::ShouldPaintOutline(*this)) {
- Vector<PhysicalRect> outline_rects;
- // The result rects are in coordinates of this object's border box.
- AddSelfOutlineRects(
- PhysicalOffset(),
- GetLayoutObject()->OutlineRectsShouldIncludeBlockVisualOverflow(),
- &outline_rects);
- PhysicalRect rect = UnionRect(outline_rects);
- rect.Inflate(LayoutUnit(style.OutlineOutsetExtent()));
- ink_overflow.Unite(rect);
- }
+ PhysicalRect ink_overflow(LocalRect());
+ ink_overflow.Expand(style.BoxDecorationOutsets());
+ if (NGOutlineUtils::HasPaintedOutline(style, GetNode()) && IsOutlineOwner()) {
+ Vector<PhysicalRect> outline_rects;
+ // The result rects are in coordinates of this object's border box.
+ AddSelfOutlineRects(PhysicalOffset(),
+ style.OutlineRectsShouldIncludeBlockVisualOverflow(),
+ &outline_rects);
+ PhysicalRect rect = UnionRect(outline_rects);
+ rect.Inflate(LayoutUnit(style.OutlineOutsetExtent()));
+ ink_overflow.Unite(rect);
}
return ink_overflow;
}
@@ -683,33 +774,31 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects(
const PhysicalOffset& additional_offset,
NGOutlineType outline_type,
Vector<PhysicalRect>* outline_rects) const {
+ AddOutlineRects(additional_offset, outline_type,
+ /* container_relative */ false, outline_rects);
+}
+
+void NGPhysicalBoxFragment::AddOutlineRects(
+ const PhysicalOffset& additional_offset,
+ NGOutlineType outline_type,
+ Vector<PhysicalRect>* outline_rects) const {
+ AddOutlineRects(additional_offset, outline_type,
+ /* container_relative */ true, outline_rects);
+}
+
+void NGPhysicalBoxFragment::AddOutlineRects(
+ const PhysicalOffset& additional_offset,
+ NGOutlineType outline_type,
+ bool inline_container_relative,
+ Vector<PhysicalRect>* outline_rects) const {
DCHECK_EQ(PostLayout(), this);
- if (!NGOutlineUtils::ShouldPaintOutline(*this))
- return;
if (IsInlineBox()) {
- const LayoutObject* layout_object = GetLayoutObject();
- DCHECK(layout_object);
- DCHECK(layout_object->IsLayoutInline());
- Vector<PhysicalRect> blockflow_outline_rects =
- layout_object->OutlineRects(PhysicalOffset(), outline_type);
- // The rectangles returned are offset from the containing block. We need the
- // offset from this fragment.
- if (blockflow_outline_rects.size() > 0) {
- PhysicalOffset first_fragment_offset = blockflow_outline_rects[0].offset;
- PhysicalOffset corrected_offset =
- additional_offset - first_fragment_offset;
- for (auto& outline : blockflow_outline_rects) {
- // Skip if both width and height are zero. Containing blocks in empty
- // linebox is one such case.
- if (outline.size.IsZero())
- continue;
- outline.Move(corrected_offset);
- outline_rects->push_back(outline);
- }
- }
+ AddOutlineRectsForInlineBox(additional_offset, outline_type,
+ inline_container_relative, outline_rects);
return;
}
+ DCHECK(IsOutlineOwner());
// For anonymous blocks, the children add outline rects.
if (!IsAnonymousBlock())
@@ -739,6 +828,67 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects(
// LayoutBlockFlow::AddOutlineRects?
}
+void NGPhysicalBoxFragment::AddOutlineRectsForInlineBox(
+ PhysicalOffset additional_offset,
+ NGOutlineType outline_type,
+ bool container_relative,
+ Vector<PhysicalRect>* rects) const {
+ DCHECK_EQ(PostLayout(), this);
+ DCHECK(IsInlineBox());
+
+ const NGPhysicalBoxFragment* container =
+ InlineContainerFragmentIfOutlineOwner();
+ if (!container)
+ return;
+
+ // In order to compute united outlines, collect all rectangles of inline
+ // fragments for |LayoutInline| if |this| is the first inline fragment.
+ // Otherwise return none.
+ //
+ // When |LayoutInline| is block fragmented, unite rectangles for each block
+ // fragment.
+ DCHECK(GetLayoutObject());
+ DCHECK(GetLayoutObject()->IsLayoutInline());
+ const auto* layout_object = To<LayoutInline>(GetLayoutObject());
+ const wtf_size_t initial_rects_size = rects->size();
+ NGInlineCursor cursor(*container);
+ cursor.MoveTo(*layout_object);
+ DCHECK(cursor);
+#if DCHECK_IS_ON()
+ bool has_this_fragment = false;
+#endif
+ for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
+ const NGInlineCursorPosition& current = cursor.Current();
+#if DCHECK_IS_ON()
+ has_this_fragment = has_this_fragment || current.BoxFragment() == this;
+#endif
+ if (!current.Size().IsZero())
+ rects->push_back(current.RectInContainerFragment());
+
+ // Add descendants if any, in the container-relative coordinate.
+ if (!current.HasChildren())
+ continue;
+ NGInlineCursor descendants = cursor.CursorForDescendants();
+ AddOutlineRectsForCursor(rects, PhysicalOffset(), outline_type,
+ layout_object, &descendants);
+ }
+#if DCHECK_IS_ON()
+ DCHECK(has_this_fragment);
+#endif
+ DCHECK_GE(rects->size(), initial_rects_size);
+ if (rects->size() <= initial_rects_size)
+ return;
+
+ // Adjust the rectangles using |additional_offset| and |container_relative|.
+ if (!container_relative)
+ additional_offset -= (*rects)[initial_rects_size].offset;
+ if (additional_offset.IsZero())
+ return;
+ for (PhysicalRect& rect :
+ base::make_span(rects->begin() + initial_rects_size, rects->end()))
+ rect.offset += additional_offset;
+}
+
PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
PhysicalOffset point) const {
if (layout_object_->IsBox() && !layout_object_->IsLayoutNGObject()) {
@@ -757,8 +907,14 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
return layout_object_->CreatePositionWithAffinity(0);
}
+ if (!RuntimeEnabledFeatures::LayoutNGFullPositionForPointEnabled()) {
+ DCHECK(layout_object_->ChildrenInline());
+ return layout_object_->CreatePositionWithAffinity(0);
+ }
+
NGLink closest_child = {nullptr};
LayoutUnit shortest_distance = LayoutUnit::Max();
+ bool found_hit_test_candidate = false;
const PhysicalSize pixel_size(LayoutUnit(1), LayoutUnit(1));
PhysicalRect point_rect(point, pixel_size);
@@ -773,8 +929,18 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
// direction (column rows and spanners).
for (const NGLink& child : Children()) {
const auto& box_fragment = To<NGPhysicalBoxFragment>(*child.fragment);
- if (!IsHitTestCandidate(box_fragment))
- continue;
+ bool is_hit_test_candidate = IsHitTestCandidate(box_fragment);
+ if (!is_hit_test_candidate) {
+ if (found_hit_test_candidate)
+ continue;
+ // We prefer valid hit-test candidates, but if there are no such children,
+ // we'll lower our requirements somewhat. The exact reasoning behind the
+ // details here is unknown, but it is something that evolved during
+ // WebKit's early years.
+ if (box_fragment.Style().Visibility() != EVisibility::kVisible ||
+ (box_fragment.Children().empty() && !box_fragment.IsBlockFlow()))
+ continue;
+ }
PhysicalRect child_rect(child.offset, child->Size());
LayoutUnit horizontal_distance;
@@ -797,10 +963,13 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
const LayoutUnit distance = horizontal_distance * horizontal_distance +
vertical_distance * vertical_distance;
- if (shortest_distance > distance) {
- // This child is closer to the point than any previous child.
+ if (shortest_distance > distance ||
+ (is_hit_test_candidate && !found_hit_test_candidate)) {
+ // This child is either closer to the point than any previous child, or
+ // this is the first child that is an actual hit-test candidate.
shortest_distance = distance;
closest_child = child;
+ found_hit_test_candidate = is_hit_test_candidate;
}
}
@@ -808,7 +977,7 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
return layout_object_->CreatePositionWithAffinity(0);
const auto& child = To<NGPhysicalBoxFragment>(*closest_child);
- Node* child_node = child_node = child.NonPseudoNode();
+ Node* child_node = child.NonPseudoNode();
PhysicalOffset point_in_child = point - closest_child.offset;
if (!child.IsCSSBox() || !child_node)
return child.PositionForPoint(point_in_child);
@@ -835,9 +1004,8 @@ PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
LogicalSize child_logical_size = converter.ToLogical(child.Size());
LayoutUnit child_middle = child_logical_size.inline_size / 2;
if (logical_point_in_child.inline_offset < child_middle)
- return layout_object_->CreatePositionWithAffinity(child_node->NodeIndex());
- return layout_object_->CreatePositionWithAffinity(child_node->NodeIndex() + 1,
- TextAffinity::kUpstream);
+ return child.GetLayoutObject()->PositionBeforeThis();
+ return child.GetLayoutObject()->PositionAfterThis();
}
UBiDiLevel NGPhysicalBoxFragment::BidiLevel() const {
@@ -926,11 +1094,26 @@ void NGPhysicalBoxFragment::CheckSameForSimplifiedLayout(
.UseBlockEndMarginEdgeForInlineBlockBaseline());
}
- // TODO(atotic,ikilpatrick): Enable DCHECKs for:
- // - TableGridRect()
- // - TableColumnGeometries()
- // - TableCollapsedBorders()
- // - TableCollapsedBordersGeometry()
+ if (IsTableNG()) {
+ DCHECK_EQ(TableGridRect(), other.TableGridRect());
+
+ if (TableColumnGeometries()) {
+ DCHECK(other.TableColumnGeometries());
+ DCHECK(*TableColumnGeometries() == *other.TableColumnGeometries());
+ } else {
+ DCHECK(!other.TableColumnGeometries());
+ }
+
+ DCHECK_EQ(TableCollapsedBorders(), other.TableCollapsedBorders());
+
+ if (TableCollapsedBordersGeometry()) {
+ DCHECK(other.TableCollapsedBordersGeometry());
+ TableCollapsedBordersGeometry()->CheckSameForSimplifiedLayout(
+ *other.TableCollapsedBordersGeometry());
+ } else {
+ DCHECK(!other.TableCollapsedBordersGeometry());
+ }
+ }
if (IsTableNGCell())
DCHECK_EQ(TableCellColumnIndex(), other.TableCellColumnIndex());
@@ -972,23 +1155,21 @@ void NGPhysicalBoxFragment::CheckIntegrity() const {
if (layout_object_ && layout_object_->ChildPaintBlockedByDisplayLock())
return;
- if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) {
- if (has_line_boxes)
- DCHECK(HasItems());
- } else {
- DCHECK_EQ(HasItems(), has_line_boxes);
- }
+ if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) {
+ if (has_line_boxes)
+ DCHECK(HasItems());
+ } else {
+ DCHECK_EQ(HasItems(), has_line_boxes);
+ }
- if (has_line_boxes) {
- DCHECK(!has_inlines);
- DCHECK(!has_inflow_blocks);
- // The following objects should be in the items, not in the tree. One
- // exception is that floats may occur as regular fragments in the tree
- // after a fragmentainer break.
- DCHECK(!has_floats || !IsFirstForNode());
- DCHECK(!has_list_markers);
- }
+ if (has_line_boxes) {
+ DCHECK(!has_inlines);
+ DCHECK(!has_inflow_blocks);
+ // The following objects should be in the items, not in the tree. One
+ // exception is that floats may occur as regular fragments in the tree
+ // after a fragmentainer break.
+ DCHECK(!has_floats || !IsFirstForNode());
+ DCHECK(!has_list_markers);
}
}
#endif