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

[LayoutNG] Support block content in list items

The first implementation of CSS list in LayoutNG adds the logic to
NGInlineLayoutAlgorithm, and supports only when content of the list
item is inline level. Extending this to when list items have block
level children wasn't easy. Making them as inline blocks is likely not
web-compatible when floats affect part of the blocks.

The most common case is nested lists, because a list is block level.
This patch renders basic nested lists correctly.

This patch supports list marker as an unpositioned object in
NGBlockLayoutAlgorithm, similar to floats or out-of-flow objects, and
positions them when it lays out the next block, relative to its first
line baseline. It is much simpler than floats or out-of-flow objects,
because it is contained only within the list item.

The approach is still being discussed with Francois (msft) and Cathie.
Also this patch still doesn't support images, and customized
positioning of markers by setting padding/margin. These will be in
following patches.

Two tests that were incorrectly rebaselined were re-rebaselined.
Some image failures turned to text failures that need manual reviews
to rebaseline.

Bug: 725277
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_layout_ng
Change-Id: I2e7f46fc6320c6986e4894a263ef99873db2f092
Reviewed-on: https://chromium-review.googlesource.com/919443
Commit-Queue: Koji Ishii <kojii@chromium.org>
Reviewed-by: default avatarEmil A Eklund <eae@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537584}
parent d703a382
......@@ -3772,7 +3772,6 @@ crbug.com/591099 fast/lists/003.html [ Failure ]
crbug.com/591099 fast/lists/004.html [ Failure ]
crbug.com/591099 fast/lists/005-vertical.html [ Failure ]
crbug.com/591099 fast/lists/006-vertical.html [ Failure ]
crbug.com/591099 fast/lists/006.html [ Failure ]
crbug.com/591099 fast/lists/007-vertical.html [ Failure ]
crbug.com/591099 fast/lists/007.html [ Failure ]
crbug.com/591099 fast/lists/008-vertical.html [ Failure ]
......@@ -3786,7 +3785,6 @@ crbug.com/591099 fast/lists/drag-into-marker.html [ Failure ]
crbug.com/591099 fast/lists/dynamic-marker-crash.html [ Failure ]
crbug.com/591099 fast/lists/inline-before-content-after-list-marker.html [ Failure ]
crbug.com/591099 fast/lists/list-and-grid.html [ Failure ]
crbug.com/591099 fast/lists/list-and-margin-collapse.html [ Failure ]
crbug.com/591099 fast/lists/list-color-change-no-layout.html [ Failure ]
crbug.com/591099 fast/lists/list-inside-columns-crash.html [ Crash ]
crbug.com/591099 fast/lists/list-item-line-height.html [ Failure ]
......@@ -3930,6 +3928,7 @@ crbug.com/591099 fast/multicol/fixedpos-child-becomes-static.html [ Crash Failur
crbug.com/591099 fast/multicol/fixedpos-in-transform-at-column-boundary.html [ Failure ]
crbug.com/591099 fast/multicol/flexbox-starts-at-column-boundary-with-block.html [ Failure ]
crbug.com/591099 fast/multicol/flexbox-starts-at-column-boundary.html [ Failure ]
crbug.com/591099 fast/multicol/flexbox-with-overflow-auto-child-crash.html [ Crash ]
crbug.com/591099 fast/multicol/flexbox.html [ Failure ]
crbug.com/591099 fast/multicol/flipped-blocks-border-after.html [ Failure ]
crbug.com/591099 fast/multicol/flipped-blocks-hit-test.html [ Failure ]
......
......@@ -38,8 +38,9 @@ layer at (0,0) size 785x849 backgroundClip at (0,0) size 785x600 clip at (0,0) s
text run at (0,0) width 189: "This list item should be blue..."
LayoutNGListItem {LI} at (40,20) size 729x80 [color=#0000FF]
LayoutNGBlockFlow (anonymous) at (0,0) size 729x20
LayoutNGListMarker (anonymous) at (0,15) size 0x0
LayoutText (anonymous) at (0,0) size 0x0
LayoutNGListMarker (anonymous) at (-18,0) size 10x20
LayoutText (anonymous) at (0,0) size 10x19
text run at (0,0) width 10: "\x{2022} "
LayoutText {#text} at (0,0) size 289x19
text run at (0,0) width 289: "...and so should this; neither should be purple."
LayoutNGBlockFlow {UL} at (0,20) size 729x60
......@@ -114,8 +115,9 @@ layer at (0,0) size 785x849 backgroundClip at (0,0) size 785x600 clip at (0,0) s
text run at (0,0) width 189: "This list item should be blue..."
LayoutNGListItem {LI} at (40,20) size 643x80 [color=#0000FF]
LayoutNGBlockFlow (anonymous) at (0,0) size 643x20
LayoutNGListMarker (anonymous) at (0,15) size 0x0
LayoutText (anonymous) at (0,0) size 0x0
LayoutNGListMarker (anonymous) at (-18,0) size 10x20
LayoutText (anonymous) at (0,0) size 10x19
text run at (0,0) width 10: "\x{2022} "
LayoutText {#text} at (0,0) size 289x19
text run at (0,0) width 289: "...and so should this; neither should be purple."
LayoutNGBlockFlow {UL} at (0,20) size 643x60
......
......@@ -321,7 +321,7 @@ In a bird's‐eye view, it consists of two parts:
[NGInlineItem]: ng_inline_item.h
[NGInlineItemResult]: ng_inline_item_result.h
[NGInlineNode]: ng_inline_node.h
[NGInlineLayoutAlgorithm]: ng_inlineLlayout_algorithm.h
[NGInlineLayoutAlgorithm]: ng_inline_layout_algorithm.h
[NGLayoutInputNode]: ../ng_layout_input_node.h
[NGLineBreaker]: ng_line_breaker.h
[NGPhysicalBoxFragment]: ../ng_physical_box_fragment.h
......
......@@ -85,6 +85,11 @@ void NGInlineItem::ComputeBoxProperties() {
return;
}
if (type_ == kListMarker) {
is_empty_item_ = false;
return;
}
is_empty_item_ = true;
}
......
......@@ -237,8 +237,8 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
if (list_marker_index.has_value()) {
NGListLayoutAlgorithm::SetListMarkerPosition(
constraint_space_, *line_info, inline_size, list_marker_index.value(),
&line_box_);
constraint_space_, *line_info, inline_size,
&line_box_[list_marker_index.value()]);
}
container_builder_.AddChildren(line_box_);
......
......@@ -94,7 +94,7 @@ void CollectInlinesInternal(
builder->AppendOpaque(NGInlineItem::kOutOfFlowPositioned, nullptr, node);
} else if (node->IsAtomicInlineLevel()) {
if (LayoutNGListItem::IsListMarker(node)) {
if (node->IsLayoutNGListMarker()) {
// LayoutNGListItem produces the 'outside' list marker as an inline
// block. This is an out-of-flow item whose position is computed
// automatically.
......
# LayoutNG list #
This directory contains the list implementation
of Blink's new layout engine "LayoutNG".
This README can be viewed in formatted form [here](https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/Source/core/layout/ng/list/README.md).
Other parts of LayoutNG is explained [here](../README.md).
## The box tree of outside list marker ##
The outside list marker is an in-flow, inline block in LayoutNG.
1. When the content is inline level and therefore generates line boxes,
[NGInlineLayoutAlgorithm] positions it relative to the first line box.
```html
<li>sample text</li>
```
generates a box tree of:
- LayoutNGListItem
- LayoutNGListMarker
- LayoutText (1.)
- LayoutText (sample text)
Since all boxes are inline level,
[NGInlineLayoutAlgorithm] handles this tree.
When it finds [LayoutNGListMarker],
it positions the list marker relative to the line box.
2. When the content is block level,
an anonymous block box is generated to make all children block level.
```html
<li><div>sample text</div></li>
```
- LayoutNGListItem
- LayoutNGBlockFlow (anonymous)
- LayoutNGListMarker
- LayoutText (1.)
- LayoutNGBlockFlow (div)
- LayoutText (sample text)
When [NGBlockLayoutAlgorithm] finds the anonymous block,
it positions the list marker relative to the first line baseline
of the next block.
3. When the content is mixed,
inline level boxes are wrapped in anonymous blocks.
```html
<li>
inline text
<div>block text</div>
</li>
```
- LayoutNGListItem
- LayoutNGBlockFlow (anonymous)
- LayoutNGListMarker
- LayoutText (1.)
- LayoutText (inline text)
- LayoutNGBlockFlow (div)
- LayoutText (block text)
[NGInlineLayoutAlgorithm] handles the first anonymous box,
and therefore positions the [LayoutNGListMarker] relative to the line box.
### The spec and other considerations
The [CSS Lists and Counters Module Level 3],
which is not ready for implementation as of now,
defines that a list marker is an out-of-flow box.
A discussion is going on to define this better
in [csswg-drafts/issues/1934].
Logically speaking,
making the list marker out-of-flow looks the most reasonable
and it can avoid anonymous blocks at all.
However, doing so has some technical difficulties, such as:
1. The containing block of the list marker is changed to
the nearest ancestor that has non-static position.
This change makes several changes in the code paths.
2. We create a layer for every absolutely positioned objects.
This not only consumes memory,
but also changes code paths and make things harder.
Making it not to create a layer is possible,
but it creates a new code path for absolutely positioned objects without layers,
and more efforts are needed to make it to work.
In [csswg-drafts/issues/1934],
Francois proposed zero-width in-flow inline block,
while Cathie proposed zero-height in-flow block box.
It will need further discussions to make this part interoperable
and still easy to implement across implementations.
[CSS Lists and Counters Module Level 3]: https://drafts.csswg.org/css-lists-3/
[csswg-drafts/issues/1934]: https://github.com/w3c/csswg-drafts/issues/1934
[LayoutNGListItem]: layout_ng_list_item.h
[LayoutNGListMarker]: layout_ng_list_marker.h
[NGBlockLayoutAlgorithm]: ../ng_block_layout_algorithm.h
[NGInlineItem]: ../inline/ng_inline_item.h
[NGInlineLayoutAlgorithm]: ../inline/ng_inline_layout_algorithm.h
......@@ -23,13 +23,6 @@ bool LayoutNGListItem::IsOfType(LayoutObjectType type) const {
return type == kLayoutObjectNGListItem || LayoutNGBlockFlow::IsOfType(type);
}
bool LayoutNGListItem::IsListMarker(LayoutObject* layout_object) {
DCHECK(layout_object);
LayoutObject* parent = layout_object->Parent();
return parent && parent->IsLayoutNGListItem() &&
ToLayoutNGListItem(parent)->marker_ == layout_object;
}
void LayoutNGListItem::WillBeDestroyed() {
DestroyMarker();
......@@ -65,8 +58,7 @@ void LayoutNGListItem::OrdinalValueChanged() {
}
void LayoutNGListItem::WillCollectInlines() {
if (marker_ && !is_marker_text_updated_)
UpdateMarkerText(ToLayoutText(marker_->SlowFirstChild()));
UpdateMarkerTextIfNeeded();
}
// Returns true if this is 'list-style-position: inside', or should be laid out
......@@ -92,6 +84,11 @@ void LayoutNGListItem::UpdateMarkerText(LayoutText* text) {
is_marker_text_updated_ = true;
}
void LayoutNGListItem::UpdateMarkerText() {
DCHECK(marker_);
UpdateMarkerText(ToLayoutText(marker_->SlowFirstChild()));
}
void LayoutNGListItem::UpdateMarker() {
const ComputedStyle& style = StyleRef();
if (style.ListStyleType() == EListStyleType::kNone) {
......
......@@ -21,12 +21,16 @@ class CORE_EXPORT LayoutNGListItem final : public LayoutNGBlockFlow {
int Value() const;
String MarkerTextWithoutSuffix() const;
LayoutObject* Marker() const { return marker_; }
void UpdateMarkerTextIfNeeded() {
if (marker_ && !is_marker_text_updated_)
UpdateMarkerText();
}
void OrdinalValueChanged();
void WillCollectInlines() override;
// Returns whether the LayoutObject is a list marker or not.
static bool IsListMarker(LayoutObject*);
const char* GetName() const override { return "LayoutNGListItem"; }
private:
......@@ -42,6 +46,7 @@ class CORE_EXPORT LayoutNGListItem final : public LayoutNGBlockFlow {
enum MarkerTextFormat { kWithSuffix, kWithoutSuffix };
enum MarkerType { kStatic, kOrdinalValue };
MarkerType MarkerText(StringBuilder*, MarkerTextFormat) const;
void UpdateMarkerText();
void UpdateMarkerText(LayoutText*);
void UpdateMarker();
void DestroyMarker();
......
......@@ -4,6 +4,8 @@
#include "core/layout/ng/list/layout_ng_list_marker.h"
#include "core/layout/ng/list/layout_ng_list_item.h"
namespace blink {
LayoutNGListMarker::LayoutNGListMarker(Element* element)
......@@ -20,4 +22,38 @@ bool LayoutNGListMarker::IsOfType(LayoutObjectType type) const {
LayoutNGMixin<LayoutBlockFlow>::IsOfType(type);
}
bool LayoutNGListMarker::IsListMarkerWrapperForBlockContent(
const LayoutObject& object) {
if (!object.IsAnonymous() || !object.IsLayoutBlockFlow())
return false;
const LayoutBlockFlow& block_flow = ToLayoutBlockFlow(object);
if (const LayoutObject* child = block_flow.FirstChild()) {
return child->IsLayoutNGListMarker() &&
// The anonymous box should not have other children.
// e.g., <li>text<div>block</div></li>
// In this case, inline layout can handle the list marker.
!child->NextSibling();
}
return false;
}
// The LayoutNGListItem this marker belongs to.
LayoutNGListItem* LayoutNGListMarker::ListItem() const {
for (LayoutObject* parent = Parent(); parent; parent = parent->Parent()) {
if (parent->IsLayoutNGListItem()) {
DCHECK(ToLayoutNGListItem(parent)->Marker() == this);
return ToLayoutNGListItem(parent);
}
// These DCHECKs are not critical but to ensure we cover all cases we know.
DCHECK(parent->IsAnonymous());
DCHECK(parent->IsLayoutBlockFlow() || parent->IsLayoutFlowThread());
}
return nullptr;
}
void LayoutNGListMarker::WillCollectInlines() {
if (LayoutNGListItem* list_item = ListItem())
list_item->UpdateMarkerTextIfNeeded();
}
} // namespace blink
......@@ -12,6 +12,7 @@
namespace blink {
class Document;
class LayoutNGListItem;
// A LayoutObject subclass for list markers in LayoutNG.
class CORE_EXPORT LayoutNGListMarker final
......@@ -20,10 +21,22 @@ class CORE_EXPORT LayoutNGListMarker final
explicit LayoutNGListMarker(Element*);
static LayoutNGListMarker* CreateAnonymous(Document*);
// True if the LayoutObject is a list marker wrapper for block content.
//
// Because a list marker in LayoutNG is an inline block, and because CSS
// defines all children of a box must be either inline level or block level,
// when the content of an list item is block level, the list marker is wrapped
// in an anonymous block box. This function determines such an anonymous box.
static bool IsListMarkerWrapperForBlockContent(const LayoutObject&);
void WillCollectInlines() override;
const char* GetName() const override { return "LayoutNGListMarker"; }
private:
bool IsOfType(LayoutObjectType) const override;
LayoutNGListItem* ListItem() const;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGListMarker, IsLayoutNGListMarker());
......
......@@ -7,31 +7,83 @@
#include "core/layout/LayoutListMarker.h"
#include "core/layout/ng/inline/ng_inline_box_state.h"
#include "core/layout/ng/inline/ng_inline_item_result.h"
#include "core/layout/ng/ng_box_fragment.h"
#include "core/layout/ng/ng_constraint_space.h"
#include "core/layout/ng/ng_fragment.h"
#include "core/layout/ng/ng_fragment_builder.h"
#include "core/layout/ng/ng_layout_result.h"
namespace blink {
namespace {
std::pair<LayoutUnit, LayoutUnit> InlineMarginsForOutside(
const NGFragment& list_marker,
const NGConstraintSpace& constraint_space) {
DCHECK(&list_marker);
bool is_image = false; // TODO(kojii): implement
return LayoutListMarker::InlineMarginsForOutside(
list_marker.Style(), is_image, list_marker.InlineSize());
}
} // namespace
void NGListLayoutAlgorithm::SetListMarkerPosition(
const NGConstraintSpace& constraint_space,
const NGLineInfo& line_info,
LayoutUnit line_width,
unsigned list_marker_index,
NGLineBoxFragmentBuilder::ChildList* line_box) {
const NGPhysicalFragment* physical_fragment =
(*line_box)[list_marker_index].PhysicalFragment();
DCHECK(physical_fragment);
NGFragment list_marker(constraint_space.GetWritingMode(), *physical_fragment);
// Compute the inline offset relative to the line.
bool is_image = false; // TODO(kojii): implement
auto margins = LayoutListMarker::InlineMarginsForOutside(
physical_fragment->Style(), is_image, list_marker.InlineSize());
NGLineBoxFragmentBuilder::Child* list_marker_child) {
DCHECK(list_marker_child->PhysicalFragment());
NGFragment list_marker_fragment(constraint_space.GetWritingMode(),
*list_marker_child->PhysicalFragment());
auto margins =
InlineMarginsForOutside(list_marker_fragment, constraint_space);
LayoutUnit line_offset = IsLtr(line_info.BaseDirection())
? margins.first
: line_width + margins.second;
(*line_box)[list_marker_index].offset.inline_offset = line_offset;
list_marker_child->offset.inline_offset = line_offset;
}
void NGListLayoutAlgorithm::AddListMarkerForBlockContent(
NGBlockNode list_marker_node,
const NGConstraintSpace& constraint_space,
const NGPhysicalBoxFragment& content,
NGLogicalOffset offset,
NGFragmentBuilder* container_builder) {
// Layout the list marker.
scoped_refptr<NGLayoutResult> list_marker_layout_result =
list_marker_node.LayoutAtomicInline(constraint_space,
constraint_space.UseFirstLineStyle());
DCHECK(list_marker_layout_result->PhysicalFragment());
NGBoxFragment list_marker_fragment(
constraint_space.GetWritingMode(),
ToNGPhysicalBoxFragment(*list_marker_layout_result->PhysicalFragment()));
// Compute the inline offset of the marker from its margins.
auto margins =
InlineMarginsForOutside(list_marker_fragment, constraint_space);
offset.inline_offset += margins.first;
// Compute the block offset of the marker by aligning the baseline of the
// marker to the first baseline of the content.
FontBaseline baseline_type =
IsHorizontalWritingMode(constraint_space.GetWritingMode())
? kAlphabeticBaseline
: kIdeographicBaseline;
NGLineHeightMetrics list_marker_metrics =
list_marker_fragment.BaselineMetrics(
{NGBaselineAlgorithmType::kAtomicInline, baseline_type},
constraint_space);
NGBoxFragment content_fragment(constraint_space.GetWritingMode(), content);
NGLineHeightMetrics content_metrics = content_fragment.BaselineMetrics(
{NGBaselineAlgorithmType::kFirstLine, baseline_type}, constraint_space);
// |offset.block_offset| is at the top of the content. Adjust it to the top of
// the list marker by adding the differences of the ascent between content's
// first line and the list marker.
offset.block_offset += content_metrics.ascent - list_marker_metrics.ascent;
DCHECK(container_builder);
container_builder->AddChild(std::move(list_marker_layout_result), offset);
}
} // namespace blink
......@@ -21,12 +21,19 @@ class NGLineInfo;
// or renaming.
class CORE_EXPORT NGListLayoutAlgorithm final {
public:
// Compute and set the list marker inline position.
// Compute and set the inline position to an outside list marker for a line
// box.
static void SetListMarkerPosition(const NGConstraintSpace&,
const NGLineInfo&,
LayoutUnit line_width,
unsigned list_marker_index,
NGLineBoxFragmentBuilder::ChildList*);
NGLineBoxFragmentBuilder::Child*);
// Add a fragment for an outside list marker for a block content.
static void AddListMarkerForBlockContent(NGBlockNode,
const NGConstraintSpace&,
const NGPhysicalBoxFragment&,
NGLogicalOffset,
NGFragmentBuilder*);
};
} // namespace blink
......
......@@ -11,6 +11,7 @@
#include "core/layout/LayoutObject.h"
#include "core/layout/ng/inline/ng_inline_node.h"
#include "core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "core/layout/ng/list/ng_list_layout_algorithm.h"
#include "core/layout/ng/ng_block_child_iterator.h"
#include "core/layout/ng/ng_box_fragment.h"
#include "core/layout/ng/ng_constraint_space.h"
......@@ -109,7 +110,8 @@ NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode node,
NGBlockBreakToken* break_token)
: NGLayoutAlgorithm(node, space, break_token),
is_resuming_(break_token && !break_token->IsBreakBefore()),
exclusion_space_(new NGExclusionSpace(space.ExclusionSpace())) {}
exclusion_space_(new NGExclusionSpace(space.ExclusionSpace())),
unpositioned_list_marker_(nullptr) {}
Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
const MinMaxSizeInput& input) const {
......@@ -373,6 +375,9 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
} else if (child.IsFloating()) {
HandleFloat(previous_inflow_position, ToNGBlockNode(child),
ToNGBlockBreakToken(child_break_token));
} else if (child.IsListMarkerWrapperForBlockContent()) {
DCHECK(!unpositioned_list_marker_);
unpositioned_list_marker_ = ToNGBlockNode(child);
} else {
// We need to propagate the initial break-before value up our container
// chain, until we reach a container that's not a first child. If we get
......@@ -706,6 +711,9 @@ bool NGBlockLayoutAlgorithm::HandleNewFormattingContext(
std::max(intrinsic_block_size_,
logical_offset.block_offset + fragment.BlockSize());
if (unpositioned_list_marker_)
PositionListMarker(physical_fragment, logical_offset);
container_builder_.AddChild(layout_result, logical_offset);
container_builder_.PropagateBreak(layout_result);
......@@ -1033,6 +1041,9 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
logical_offset.block_offset + fragment.BlockSize());
}
if (unpositioned_list_marker_)
PositionListMarker(physical_fragment, logical_offset);
container_builder_.AddChild(layout_result, logical_offset);
if (child.IsBlock())
container_builder_.PropagateBreak(layout_result);
......@@ -1567,6 +1578,15 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
.SetIsShrinkToFit(ShouldShrinkToFit(Style(), child_style))
.SetTextDirection(child_style.Direction());
writing_mode = child_style.GetWritingMode();
// PositionListMarker() requires a first line baseline.
if (unpositioned_list_marker_) {
space_builder.AddBaselineRequest(
{NGBaselineAlgorithmType::kFirstLine,
IsHorizontalWritingMode(constraint_space_.GetWritingMode())
? kAlphabeticBaseline
: kIdeographicBaseline});
}
}
LayoutUnit space_available;
......@@ -1759,4 +1779,16 @@ LayoutUnit NGBlockLayoutAlgorithm::CalculateMinimumBlockSize(
return NGSizeIndefinite;
}
void NGBlockLayoutAlgorithm::PositionListMarker(
const NGPhysicalFragment& content,
const NGLogicalOffset& content_offset) {
DCHECK(unpositioned_list_marker_);
NGListLayoutAlgorithm::AddListMarkerForBlockContent(
unpositioned_list_marker_, constraint_space_,
ToNGPhysicalBoxFragment(content), content_offset, &container_builder_);
unpositioned_list_marker_ = NGBlockNode(nullptr);
}
} // namespace blink
......@@ -188,6 +188,9 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
// Adds a set of positioned floats as children to the current fragment.
void AddPositionedFloats(const Vector<NGPositionedFloat>& positioned_floats);
// Positions a list marker for the specified block content.
void PositionListMarker(const NGPhysicalFragment&, const NGLogicalOffset&);
// Calculates logical offset for the current fragment using either {@code
// intrinsic_block_size_} when the fragment doesn't know it's offset or
// {@code known_fragment_offset} if the fragment knows it's offset
......@@ -230,6 +233,7 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
std::unique_ptr<NGExclusionSpace> exclusion_space_;
Vector<scoped_refptr<NGUnpositionedFloat>> unpositioned_floats_;
NGBlockNode unpositioned_list_marker_;
};
} // namespace blink
......
......@@ -36,6 +36,7 @@ class CORE_EXPORT NGFragment {
NGBorderEdges BorderEdges() const;
NGPhysicalFragment::NGFragmentType Type() const;
const ComputedStyle& Style() const { return physical_fragment_.Style(); }
protected:
const NGPhysicalFragment& physical_fragment_;
......
......@@ -9,6 +9,7 @@
#include "core/layout/MinMaxSize.h"
#include "core/layout/ng/geometry/ng_logical_size.h"
#include "core/layout/ng/inline/ng_inline_node.h"
#include "core/layout/ng/list/layout_ng_list_marker.h"
#include "core/layout/ng/ng_block_node.h"
#include "core/layout/ng/ng_layout_result.h"
#include "platform/wtf/text/StringBuilder.h"
......@@ -86,6 +87,15 @@ bool NGLayoutInputNode::ShouldBeConsideredAsReplaced() const {
return box_->ShouldBeConsideredAsReplaced();
}
bool NGLayoutInputNode::IsListMarker() const {
return IsBlock() && box_->IsLayoutNGListMarker();
}
bool NGLayoutInputNode::IsListMarkerWrapperForBlockContent() const {
return IsBlock() &&
LayoutNGListMarker::IsListMarkerWrapperForBlockContent(*box_);
}
bool NGLayoutInputNode::IsQuirkyContainer() const {
return box_->GetDocument().InQuirksMode() &&
(box_->IsBody() || box_->IsTableCell());
......
......@@ -57,6 +57,10 @@ class CORE_EXPORT NGLayoutInputNode {
bool IsBody() const;
bool IsDocumentElement() const;
bool ShouldBeConsideredAsReplaced() const;
bool IsListMarker() const;
// True for an anonymous block wrapper of a list marker. See
// LayoutNGListMarker::IsListMarkerWrapper() for more.
bool IsListMarkerWrapperForBlockContent() const;
// If the node is a quirky container for margin collapsing, see:
// https://html.spec.whatwg.org/#margin-collapsing-quirks
......
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