Commit 47a1c9c8 authored by Morten Stenshorne's avatar Morten Stenshorne Committed by Commit Bot

[LayoutNG] Support column rules in fragment painting.

And enable fragment painting for multicol containers.

Rules are to be painted "just above the border of the multicol
container" [1]. At the same time, "the rules need to scroll along with
the columns" [1]. Hence, we'll paint it as the first item in the
foreground phase, so that we get scroll offsets applied.

[1] https://drafts.csswg.org/css-multicol/#column-gaps-and-rules

By enabling fragment painting for multicol containers, we break one
outline test. The fix is easy, but I'd rather deal with that in a
follow-up.

Bug: 829028
Change-Id: Ie5e4ac267967f185a588bfc36f1902a2b1659413
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1899784
Commit-Queue: Ian Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#714376}
parent 2c8a7607
......@@ -205,6 +205,9 @@ bool LayoutNGBlockFlowMixin<
if (PaintFragment())
return false;
if (Base::StyleRef().HasColumnRule())
return false;
return Base::PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
}
......@@ -283,12 +286,6 @@ void LayoutNGBlockFlowMixin<Base>::Paint(const PaintInfo& paint_info) const {
}
}
// |NGBoxFragmentPainter| currently doesn't support column rules.
if (UNLIKELY(Base::MultiColumnFlowThread())) {
Base::Paint(paint_info);
return;
}
if (const NGPaintFragment* paint_fragment = PaintFragment()) {
NGBoxFragmentPainter(*paint_fragment).Paint(paint_info);
return;
......
......@@ -841,6 +841,7 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
}
LayoutBlock* block = DynamicTo<LayoutBlock>(box_);
bool needs_full_invalidation = false;
if (LIKELY(block && is_last_fragment)) {
LayoutUnit intrinsic_block_size =
layout_result.UnconstrainedIntrinsicBlockSize();
......@@ -854,6 +855,11 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
if (UNLIKELY(flow_thread)) {
UpdateLegacyMultiColumnFlowThread(*this, flow_thread, constraint_space,
physical_fragment);
// Issue full invalidation, in case the number of column rules have
// changed.
if (Style().HasColumnRule())
needs_full_invalidation = true;
}
BoxLayoutExtraInput input(*block);
......@@ -867,7 +873,11 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
}
box_->UpdateAfterLayout();
box_->ClearNeedsLayout();
if (needs_full_invalidation)
box_->ClearNeedsLayoutWithFullPaintInvalidation();
else
box_->ClearNeedsLayout();
// Overflow computation depends on this being set.
if (LIKELY(block_flow))
......
......@@ -383,6 +383,12 @@ void NGBoxFragmentPainter::PaintObject(
(!physical_box_fragment.Children().empty() ||
physical_box_fragment.HasItems()) &&
!paint_info.DescendantPaintingBlocked()) {
if (RuntimeEnabledFeatures::LayoutNGFragmentPaintEnabled()) {
if (UNLIKELY(paint_phase == PaintPhase::kForeground &&
box_fragment_.Style().HasColumnRule()))
PaintColumnRules(paint_info, paint_offset);
}
if (paint_phase != PaintPhase::kFloat) {
if (physical_box_fragment.ChildrenInline()) {
DCHECK(paint_fragment_ || PhysicalFragment().HasItems());
......@@ -844,6 +850,106 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackgroundWithRect(
paint_info.context.EndLayer();
}
void NGBoxFragmentPainter::PaintColumnRules(
const PaintInfo& paint_info,
const PhysicalOffset& paint_offset) {
const ComputedStyle& style = box_fragment_.Style();
DCHECK(style.HasColumnRule());
// TODO(crbug.com/792437): Certain rule styles should be converted.
EBorderStyle rule_style = style.ColumnRuleStyle();
if (DrawingRecorder::UseCachedDrawingIfPossible(paint_info.context,
GetDisplayItemClient(),
DisplayItem::kColumnRules))
return;
DrawingRecorder recorder(paint_info.context, GetDisplayItemClient(),
DisplayItem::kColumnRules);
const Color& rule_color =
LayoutObject::ResolveColor(style, GetCSSPropertyColumnRuleColor());
LayoutUnit rule_thickness(style.ColumnRuleWidth());
PhysicalRect previous_column;
bool past_first_column_in_row = false;
for (const NGLink& child : box_fragment_.Children()) {
if (!child->IsColumnBox()) {
// Column spanner. Continue in the next row, if there are 2 columns or
// more there.
past_first_column_in_row = false;
previous_column = PhysicalRect();
continue;
}
PhysicalRect current_column(child.offset, child->Size());
if (!past_first_column_in_row) {
// Rules are painted *between* columns. Need to see if we have a second
// one before painting anything.
past_first_column_in_row = true;
previous_column = current_column;
continue;
}
PhysicalRect rule;
BoxSide box_side;
if (previous_column.Y() == current_column.Y() ||
previous_column.Bottom() == current_column.Bottom()) {
// Horizontal writing-mode.
DCHECK(style.IsHorizontalWritingMode());
LayoutUnit center;
if (previous_column.X() < current_column.X()) {
// Left to right.
center = (previous_column.X() + current_column.Right()) / 2;
box_side = BoxSide::kLeft;
} else {
// Right to left.
center = (current_column.X() + previous_column.Right()) / 2;
box_side = BoxSide::kRight;
}
// The last column may be shorter than the previous ones, but otherwise
// they should be the same.
LayoutUnit rule_length = previous_column.Height();
DCHECK_GE(rule_length, current_column.Height());
rule.offset.top = previous_column.offset.top;
rule.size.height = rule_length;
rule.offset.left = center - rule_thickness / 2;
rule.size.width = rule_thickness;
} else {
// Vertical writing-mode.
LayoutUnit center;
if (previous_column.Y() < current_column.Y()) {
// Top to bottom.
center = (previous_column.Y() + current_column.Bottom()) / 2;
box_side = BoxSide::kTop;
} else {
// Bottom to top.
center = (current_column.Y() + previous_column.Bottom()) / 2;
box_side = BoxSide::kBottom;
}
// The last column may be shorter than the previous ones, but otherwise
// they should be the same.
LayoutUnit rule_length = previous_column.Width();
DCHECK_GE(rule_length, current_column.Width());
rule.offset.left = previous_column.offset.left;
rule.size.width = rule_length;
rule.offset.top = center - rule_thickness / 2;
rule.size.height = rule_thickness;
}
// TODO(crbug.com/792435): The spec actually kind of says that the rules
// should be as tall as the entire multicol container, not just as tall as
// the column fragments (this difference matters when block-size is
// specified and columns are balanced).
rule.Move(paint_offset);
ObjectPainter::DrawLineForBoxSide(paint_info.context, rule.X(), rule.Y(),
rule.Right(), rule.Bottom(), box_side,
rule_color, rule_style, 0, 0, true);
previous_column = current_column;
}
}
// TODO(kojii): This logic is kept in sync with BoxPainter. Not much efforts to
// eliminate LayoutObject dependency were done yet.
void NGBoxFragmentPainter::PaintBackground(
......
......@@ -79,6 +79,7 @@ class NGBoxFragmentPainter : public BoxPainterBase {
void PaintBoxDecorationBackgroundWithRect(const PaintInfo&,
const PhysicalRect&,
const DisplayItemClient&);
void PaintColumnRules(const PaintInfo&, const PhysicalOffset& paint_offset);
bool BackgroundIsKnownToBeOpaque(const PaintInfo&);
void PaintInternal(const PaintInfo&);
......
......@@ -1261,6 +1261,12 @@ class ComputedStyle : public ComputedStyleBase,
!ColumnRuleColorInternal().Alpha();
}
bool ColumnRuleEquivalent(const ComputedStyle& other_style) const;
bool HasColumnRule() const {
if (LIKELY(!SpecifiesColumns()))
return false;
return ColumnRuleWidth() && !ColumnRuleIsTransparent() &&
BorderStyleIsVisible(ColumnRuleStyle());
}
// Flex utility functions.
bool ResolvedIsColumnFlexDirection() const {
......
......@@ -1024,7 +1024,6 @@ crbug.com/988015 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/mult
crbug.com/988015 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-003.html [ Failure ]
crbug.com/994172 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-007.html [ Failure Crash ]
crbug.com/924142 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-010.html [ Crash Pass ]
crbug.com/988015 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-013.html [ Failure ]
crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-001.html [ Failure ]
crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html [ Failure ]
crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html [ Failure ]
......@@ -1141,6 +1140,7 @@ crbug.com/954171 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-mo
crbug.com/954171 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-line-and-unbreakable.html [ Failure Crash ]
crbug.com/954171 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-line.html [ Failure Crash ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-unbreakable.html [ Failure ]
crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/focus-outline.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/forced-break-after-block-with-spanner.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/forced-break-after-empty-block-after-spanner.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/forced-break-after-last-block-before-spanner.html [ Failure ]
......@@ -1208,7 +1208,6 @@ crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/positioned-split.htm
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/positive-leading.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/pushed-line-affected-by-float.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/relayout-and-push-float.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/rule-in-nested-with-too-tall-line.html [ Failure ]
crbug.com/714962 virtual/layout_ng_block_frag/fast/multicol/scale-transform-text.html [ Failure ]
crbug.com/874506 virtual/layout_ng_block_frag/fast/multicol/scrollable-basic.html [ Failure ]
crbug.com/591099 virtual/layout_ng_block_frag/fast/multicol/scrolling-overflow.html [ Failure ]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment