Commit ea0ed30f authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

[LayoutNG] Support the '-webkit-box-decoration-break' property

This patch supports the rendering of the
'-webkit-box-decoration-break' property. This property is
used by 0.73% of pages according to UMA.

Also cleanup how NGLineBreaker commmunicates margins/borders/
padding to NGInlineLayoutAlgorithm through NGInlineItemResult.

The work for line breaker to take this property into account
is deferred to future work. Gecko (unprefixed) supports it,
while Blink and WebKit (prefixed) takes only the start edge
into account, ignoring the end edge. Edge does not support
this property yet. Also CSS WG resolved a change in its
behavior recently when used in bidi context. It will need a
bit more investigations.

Bug: 636993
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng
Change-Id: I8d87db5cd35441133a73fcead67901763026155d
Reviewed-on: https://chromium-review.googlesource.com/1146125Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Commit-Queue: Koji Ishii <kojii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577306}
parent 028b3b68
......@@ -495,7 +495,6 @@ crbug.com/591099 fast/borders/border-image-border-radius.html [ Failure ]
crbug.com/714962 fast/borders/border-image-outset-split-inline.html [ Failure ]
crbug.com/714962 fast/borders/border-styles-split.html [ Failure ]
crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
crbug.com/591099 fast/box-decoration-break/box-decoration-break-rendering.html [ Failure ]
crbug.com/591099 fast/box-shadow/box-shadow.html [ Failure ]
crbug.com/591099 fast/box-shadow/inset-subpixel.html [ Failure ]
crbug.com/591099 fast/box-shadow/inset.html [ Failure ]
......
......@@ -108,6 +108,7 @@ struct CORE_EXPORT NGLineBoxStrut {
NGLineBoxStrut(const NGBoxStrut&, bool is_flipped_lines);
LayoutUnit InlineSum() const { return inline_start + inline_end; }
LayoutUnit BlockSum() const { return line_over + line_under; }
LayoutUnit inline_start;
LayoutUnit inline_end;
......
......@@ -119,10 +119,9 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
box.metrics = box.text_metrics = NGLineHeightMetrics();
if (box.needs_box_fragment) {
// Existing box states are wrapped before they were closed, and hence
// they do not have start edges.
box.has_start_edge = false;
box.margin_inline_start = LayoutUnit();
box.margin_border_padding_inline_start = LayoutUnit();
// they do not have start edges, unless 'box-decoration-break: clone'.
box.has_start_edge =
box.style->BoxDecorationBreak() == EBoxDecorationBreak::kClone;
}
DCHECK(box.pending_descendants.IsEmpty());
}
......@@ -155,18 +154,11 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
// Compute box properties regardless of needs_box_fragment since close tag may
// also set needs_box_fragment.
box->padding = item_result.padding;
box->has_start_edge = item_result.has_edge;
if (box->has_start_edge) {
box->margin_inline_start = item_result.margins.inline_start;
// The open tag item has the start margin+border+padding in |inline_size|.
box->margin_border_padding_inline_start = item_result.inline_size;
} else {
DCHECK_EQ(item_result.margins.inline_start, LayoutUnit());
DCHECK_EQ(item_result.inline_size, LayoutUnit());
}
box->border_padding_line_over = item_result.borders_paddings_line_over;
box->border_padding_line_under = item_result.borders_paddings_line_under;
box->margin_inline_start = item_result.margins.inline_start;
box->margin_inline_end = item_result.margins.inline_end;
box->borders = item_result.borders;
box->padding = item_result.padding;
return box;
}
......@@ -183,7 +175,10 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
NGInlineBoxState* NGInlineLayoutStateStack::OnCloseTag(
NGLineBoxFragmentBuilder::ChildList* line_box,
NGInlineBoxState* box,
FontBaseline baseline_type) {
FontBaseline baseline_type,
bool has_end_edge) {
DCHECK_EQ(box, &stack_.back());
box->has_end_edge = has_end_edge;
EndBoxState(box, line_box, baseline_type);
// TODO(kojii): When the algorithm restarts from a break token, the stack may
// underflow. We need either synthesize a missing box state, or push all
......@@ -197,6 +192,9 @@ void NGInlineLayoutStateStack::OnEndPlaceItems(
FontBaseline baseline_type) {
for (auto it = stack_.rbegin(); it != stack_.rend(); ++it) {
NGInlineBoxState* box = &(*it);
if (!box->has_end_edge && box->needs_box_fragment &&
box->style->BoxDecorationBreak() == EBoxDecorationBreak::kClone)
box->has_end_edge = true;
EndBoxState(box, line_box, baseline_type);
}
}
......@@ -233,28 +231,14 @@ void NGInlineBoxState::SetNeedsBoxFragment() {
needs_box_fragment = true;
}
void NGInlineBoxState::SetLineRightForBoxFragment(
const NGInlineItem& item,
const NGInlineItemResult& item_result) {
DCHECK(needs_box_fragment);
has_end_edge = item_result.has_edge;
if (has_end_edge) {
margin_inline_end = item_result.margins.inline_end;
// The close tag item has the end margin+border+padding in |inline_size|.
margin_border_padding_inline_end = item_result.inline_size;
} else {
DCHECK_EQ(item_result.margins.inline_end, LayoutUnit());
DCHECK_EQ(item_result.inline_size, LayoutUnit());
}
}
bool NGInlineBoxState::ParentNeedsBoxFragment(
const NGInlineBoxState& parent) const {
if (!parent.item)
return false;
// Below are the known cases where parent rect may not equal the union of
// its child rects.
if (margin_inline_start || margin_inline_end)
if ((has_start_edge && margin_inline_start) ||
(has_end_edge && margin_inline_end))
return true;
// Inline box height is determined by font metrics, which can be different
// from the height of its child atomic inline.
......@@ -284,11 +268,12 @@ void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
// Extend the block direction of the box by borders and paddings. Inline
// direction is already included into positions in NGLineBreaker.
NGLogicalOffset offset(LayoutUnit(),
-metrics.ascent - box->border_padding_line_over);
NGLogicalSize size(LayoutUnit(), metrics.LineHeight() +
box->border_padding_line_over +
box->border_padding_line_under);
NGLogicalOffset offset(
LayoutUnit(),
-metrics.ascent - (box->borders.line_over + box->padding.line_over));
NGLogicalSize size(
LayoutUnit(),
metrics.LineHeight() + box->borders.BlockSum() + box->padding.BlockSum());
unsigned fragment_end = line_box->size();
DCHECK(box->item);
......@@ -299,14 +284,16 @@ void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
if (box->has_start_edge) {
box_data.has_line_left_edge = true;
box_data.margin_line_left = box->margin_inline_start;
box_data.margin_border_padding_line_left =
box->margin_border_padding_inline_start;
box_data.margin_border_padding_line_left = box->margin_inline_start +
box->borders.inline_start +
box->padding.inline_start;
}
if (box->has_end_edge) {
box_data.has_line_right_edge = true;
box_data.margin_line_right = box->margin_inline_end;
box_data.margin_border_padding_line_right =
box->margin_border_padding_inline_end;
box_data.margin_border_padding_line_right = box->margin_inline_end +
box->borders.inline_end +
box->padding.inline_end;
}
if (IsRtl(style.Direction())) {
std::swap(box_data.has_line_left_edge, box_data.has_line_right_edge);
......
......@@ -57,14 +57,10 @@ struct NGInlineBoxState {
// is set.
bool has_start_edge = false;
bool has_end_edge = false;
NGLineBoxStrut padding;
// |CreateBoxFragment()| needs margin, border+padding, and the sum of them.
LayoutUnit margin_inline_start;
LayoutUnit margin_inline_end;
LayoutUnit margin_border_padding_inline_start;
LayoutUnit margin_border_padding_inline_end;
LayoutUnit border_padding_line_over;
LayoutUnit border_padding_line_under;
NGLineBoxStrut borders;
NGLineBoxStrut padding;
Vector<NGPendingPositions> pending_descendants;
bool include_used_fonts = false;
......@@ -88,8 +84,6 @@ struct NGInlineBoxState {
// Create a box fragment for this box.
void SetNeedsBoxFragment();
void SetLineRightForBoxFragment(const NGInlineItem&,
const NGInlineItemResult&);
// In certain circumstances, the parent's rects is not a simple union of its
// children fragments' rects, e.g., when children have margin. In such cases,
......@@ -126,7 +120,8 @@ class CORE_EXPORT NGInlineLayoutStateStack {
// Pop a box state stack.
NGInlineBoxState* OnCloseTag(NGLineBoxFragmentBuilder::ChildList*,
NGInlineBoxState*,
FontBaseline);
FontBaseline,
bool has_end_edge = true);
// Compute all the pending positioning at the end of a line.
void OnEndPlaceItems(NGLineBoxFragmentBuilder::ChildList*, FontBaseline);
......
......@@ -50,14 +50,11 @@ struct CORE_EXPORT NGInlineItemResult {
// NGLayoutResult for atomic inline items.
scoped_refptr<NGLayoutResult> layout_result;
// Margins and padding for atomic inline items and open/close tags.
// Margins, borders, and padding for atomic inline items and open tags.
NGLineBoxStrut margins;
NGLineBoxStrut borders;
NGLineBoxStrut padding;
// Borders/padding for open tags.
LayoutUnit borders_paddings_line_over;
LayoutUnit borders_paddings_line_under;
// Has start/end edge for open/close tags.
bool has_edge = false;
......
......@@ -231,12 +231,10 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
} else if (item.Type() == NGInlineItem::kCloseTag) {
if (!box->needs_box_fragment && item_result.inline_size)
box->SetNeedsBoxFragment();
if (box->needs_box_fragment) {
box->SetLineRightForBoxFragment(item, item_result);
if (quirks_mode_)
box->EnsureTextMetrics(*item.Style(), baseline_type_);
}
box = box_states_->OnCloseTag(&line_box_, box, baseline_type_);
if (quirks_mode_ && box->needs_box_fragment)
box->EnsureTextMetrics(*item.Style(), baseline_type_);
box = box_states_->OnCloseTag(&line_box_, box, baseline_type_,
item.HasEndEdge());
} else if (item.Type() == NGInlineItem::kAtomicInline) {
box = PlaceAtomicInline(item, &item_result, *line_info);
} else if (item.Type() == NGInlineItem::kListMarker) {
......
......@@ -913,19 +913,15 @@ bool NGLineBreaker::ComputeOpenTagResult(
(style.HasBorder() || style.HasPadding() ||
(style.HasMargin() && item_result->has_edge))) {
bool is_flipped_lines = style.IsFlippedLinesWritingMode();
NGLineBoxStrut borders = NGLineBoxStrut(
item_result->borders = NGLineBoxStrut(
ComputeBorders(constraint_space, style), is_flipped_lines);
item_result->padding = NGLineBoxStrut(
ComputePadding(constraint_space, style), is_flipped_lines);
item_result->borders_paddings_line_over =
borders.line_over + item_result->padding.line_over;
item_result->borders_paddings_line_under =
borders.line_under + item_result->padding.line_under;
if (item_result->has_edge) {
item_result->margins = NGLineBoxStrut(
ComputeMarginsForSelf(constraint_space, style), is_flipped_lines);
item_result->inline_size = item_result->margins.inline_start +
borders.inline_start +
item_result->borders.inline_start +
item_result->padding.inline_start;
return true;
}
......@@ -962,18 +958,16 @@ void NGLineBreaker::HandleCloseTag(const NGInlineItem& item) {
if (item_result->has_edge) {
DCHECK(item.Style());
const ComputedStyle& style = *item.Style();
bool is_flipped_lines = style.IsFlippedLinesWritingMode();
item_result->margins = NGLineBoxStrut(
ComputeMarginsForSelf(constraint_space_, style), is_flipped_lines);
NGBoxStrut margins = ComputeMarginsForSelf(constraint_space_, style);
NGBoxStrut borders = ComputeBorders(constraint_space_, style);
NGBoxStrut paddings = ComputePadding(constraint_space_, style);
item_result->inline_size = item_result->margins.inline_end +
borders.inline_end + paddings.inline_end;
item_result->inline_size =
margins.inline_end + borders.inline_end + paddings.inline_end;
position_ += item_result->inline_size;
if (!item_result->should_create_line_box &&
(item_result->inline_size ||
(item_result->margins.inline_end && !in_line_height_quirks_mode_)))
(margins.inline_end && !in_line_height_quirks_mode_)))
item_result->should_create_line_box = true;
}
DCHECK(item.GetLayoutObject() && item.GetLayoutObject()->Parent());
......
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