Skip to content
Permalink
Browse files
[LFC][IFC] Support each-line keyword in text-indent
https://bugs.webkit.org/show_bug.cgi?id=240731

Patch by Kiet Ho <tho22@apple.com> on 2022-05-25
Reviewed by Alan Bujtas.

Normally, text-indent only affects the first line. When 'each-line' is specified,
subsequent lines where the previous line ends with a hard break are also indented.
This is supported in the legacy layout engine but not in LFC. Adds support for
'each-line' to bring LFC to parity with the legacy engine.

Test: imported/w3c/web-platform-tests/css/css-text/text-indent/text-indent-each-line-hanging.html

* LayoutTests/TestExpectations: Remove ImageOnlyFailure expectation.
* Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp:
(WebCore::Layout::LineBuilder::layoutInlineContent):
(WebCore::Layout::LineBuilder::computedIntrinsicWidth):
(WebCore::Layout::LineBuilder::initialConstraintsForLine const): Add logic to
indent line when 'each-line' is specified, and the previous line ends with a
hard break.
* Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h:
* Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h: Modify
initialConstraintsForLine to accept information about the previous line,
not just whether there's one or not.

Canonical link: https://commits.webkit.org/250978@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@294828 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
tuankiet65 authored and webkit-commit-queue committed May 25, 2022
1 parent d66b227 commit 8ac6fb0edfc973c9a39344b26a62b0f74f2d9d2b
Showing 3 changed files with 26 additions and 26 deletions.
@@ -2651,7 +2651,6 @@ webkit.org/b/214290 imported/w3c/web-platform-tests/css/css-text/text-encoding/s
webkit.org/b/214290 imported/w3c/web-platform-tests/css/css-text/text-indent/text-indent-tab-positions-001.html [ ImageOnlyFailure ]
webkit.org/b/240837 imported/w3c/web-platform-tests/css/css-text/text-indent/anonymous-flex-item-001.html [ ImageOnlyFailure ]
webkit.org/b/240837 imported/w3c/web-platform-tests/css/css-text/text-indent/anonymous-grid-item-001.html [ ImageOnlyFailure ]
webkit.org/b/240731 imported/w3c/web-platform-tests/css/css-text/text-indent/text-indent-each-line-hanging.html [ ImageOnlyFailure ]
webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/text-justify/text-justify-001.html [ ImageOnlyFailure ]
webkit.org/b/214290 imported/w3c/web-platform-tests/css/css-text/text-justify/text-justify-006.html [ ImageOnlyFailure ]
webkit.org/b/183258 imported/w3c/web-platform-tests/css/css-text/text-transform/text-transform-capitalize-018.html [ ImageOnlyFailure Pass ]
@@ -321,7 +321,7 @@ struct UsedConstraints {
};
LineBuilder::LineContent LineBuilder::layoutInlineContent(const InlineItemRange& needsLayoutRange, const InlineRect& lineLogicalRect, const std::optional<PreviousLine>& previousLine)
{
initialize(initialConstraintsForLine(lineLogicalRect, !previousLine), needsLayoutRange.start, previousLine);
initialize(initialConstraintsForLine(lineLogicalRect, previousLine), needsLayoutRange.start, previousLine);

auto committedContent = placeInlineContent(needsLayoutRange);
auto committedRange = close(needsLayoutRange, committedContent);
@@ -400,7 +400,7 @@ LineBuilder::IntrinsicContent LineBuilder::computedIntrinsicWidth(const InlineIt
{
ASSERT(isInIntrinsicWidthMode());
auto lineLogicalWidth = *intrinsicWidthMode() == IntrinsicWidthMode::Maximum ? maxInlineLayoutUnit() : 0.f;
auto lineConstraints = initialConstraintsForLine({ 0, 0, lineLogicalWidth, 0 }, !previousLine);
auto lineConstraints = initialConstraintsForLine({ 0, 0, lineLogicalWidth, 0 }, previousLine);
initialize(lineConstraints, needsLayoutRange.start, previousLine);

auto committedContent = placeInlineContent(needsLayoutRange);
@@ -627,7 +627,7 @@ std::optional<HorizontalConstraints> LineBuilder::floatConstraints(const InlineR
return HorizontalConstraints { toLayoutUnit(lineLogicalLeft), toLayoutUnit(lineLogicalRight - lineLogicalLeft) };
}

UsedConstraints LineBuilder::initialConstraintsForLine(const InlineRect& initialLineLogicalRect, bool isFirstLine) const
UsedConstraints LineBuilder::initialConstraintsForLine(const InlineRect& initialLineLogicalRect, const std::optional<PreviousLine>& previousLine) const
{
auto lineLogicalLeft = initialLineLogicalRect.left();
auto lineLogicalRight = initialLineLogicalRect.right();
@@ -640,31 +640,32 @@ UsedConstraints LineBuilder::initialConstraintsForLine(const InlineRect& initial
}

auto computedTextIndent = [&]() -> InlineLayoutUnit {
auto& root = this->root();

// text-indent property specifies the indentation applied to lines of inline content in a block.
// The indent is treated as a margin applied to the start edge of the line box.
// Unless otherwise specified, only lines that are the first formatted line of an element are affected.
// For example, the first line of an anonymous block box is only affected if it is the first child of its parent element.
// FIXME: Add support for each-line.
// The first formatted line of an element is always indented. For example, the first line of an anonymous block box
// is only affected if it is the first child of its parent element.
// If 'each-line' is specified, indentation also applies to all lines where the previous line ends with a hard break.
// [Integration] root()->parent() would normally produce a valid layout box.
auto& root = this->root();
auto isFormattingContextRootCandidateToTextIndent = !root.isAnonymous();
if (root.isAnonymous()) {
// Unless otherwise specified by the each-line and/or hanging keywords, only lines that are the first formatted line
// of an element are affected.
// For example, the first line of an anonymous block box is only affected if it is the first child of its parent element.
auto isIntegratedRootBoxFirstChild = layoutState().isIntegratedRootBoxFirstChild();
if (isIntegratedRootBoxFirstChild == LayoutState::IsIntegratedRootBoxFirstChild::NotApplicable)
isFormattingContextRootCandidateToTextIndent = root.parent().firstInFlowChild() == &root;
else
isFormattingContextRootCandidateToTextIndent = isIntegratedRootBoxFirstChild == LayoutState::IsIntegratedRootBoxFirstChild::Yes;
bool shouldIndent = false;
if (!previousLine) {
shouldIndent = !root.isAnonymous();
if (root.isAnonymous()) {
auto isIntegratedRootBoxFirstChild = layoutState().isIntegratedRootBoxFirstChild();
if (isIntegratedRootBoxFirstChild == LayoutState::IsIntegratedRootBoxFirstChild::NotApplicable)
shouldIndent = root.parent().firstInFlowChild() == &root;
else
shouldIndent = isIntegratedRootBoxFirstChild == LayoutState::IsIntegratedRootBoxFirstChild::Yes;
}
} else {
shouldIndent = root.style().textIndentLine() == TextIndentLine::EachLine && previousLine->endsWithLineBreak;
}
if (!isFormattingContextRootCandidateToTextIndent)
return { };
auto invertLineRange = root.style().textIndentType() == TextIndentType::Hanging;
// text-indent: hanging inverts which lines are affected.
// inverted line range -> all the lines except the first one.
// !inverted line range -> first line gets the indent.
auto shouldIndent = invertLineRange != isFirstLine;

// Specifying 'hanging' inverts whether the line should be indented or not.
if (root.style().textIndentType() == TextIndentType::Hanging)
shouldIndent = !shouldIndent;

if (!shouldIndent)
return { };

@@ -107,7 +107,7 @@ class LineBuilder {
size_t partialTrailingContentLength { 0 };
std::optional<InlineLayoutUnit> overflowLogicalWidth { };
};
UsedConstraints initialConstraintsForLine(const InlineRect& initialLineLogicalRect, bool isFirstLine) const;
UsedConstraints initialConstraintsForLine(const InlineRect& initialLineLogicalRect, const std::optional<PreviousLine>&) const;
std::optional<HorizontalConstraints> floatConstraints(const InlineRect& lineLogicalRect) const;

void handleFloatContent(const InlineItem&);

0 comments on commit 8ac6fb0

Please sign in to comment.