Title: [283474] trunk/Source/WebCore
Revision
283474
Author
[email protected]
Date
2021-10-03 11:46:15 -0700 (Sun, 03 Oct 2021)

Log Message

[LFC][IFC] Moving hanging whitespace sequence handling to Line
https://bugs.webkit.org/show_bug.cgi?id=231126

Reviewed by Antti Koivisto.

Let the Line handle the whitespace hanging. Line::HangingTrailingContent will eventually gain more functionality.
This is also in preparation for fixing imported/w3c/web-platform-tests/css/css-text/white-space/textarea-pre-wrap-014.html

* layout/formattingContexts/inline/InlineLine.cpp:
(WebCore::Layout::Line::Line):
(WebCore::Layout::Line::visuallyCollapseHangingOverflow):
(WebCore::Layout::Line::HangingTrailingContent::HangingTrailingContent):
(WebCore::Layout::Line::HangingTrailingContent::width const):
* layout/formattingContexts/inline/InlineLine.h:
(WebCore::Layout::Line::hangingWhitespaceWidth const):
(WebCore::Layout::Line::Run::shouldTrailingWhitespaceHang const):
(WebCore::Layout::Line::Run::isOverflowWhitespaceHanging const): Deleted. shouldTrailingWhitespaceHang is a more descriptive name.
* layout/formattingContexts/inline/InlineLineBoxBuilder.cpp:
(WebCore::Layout::horizontalAlignmentOffset):
(WebCore::Layout::LineBoxBuilder::build):
(WebCore::Layout::hangingGlyphWidth): Deleted.
* layout/formattingContexts/inline/InlineLineBuilder.cpp:
(WebCore::Layout::LineBuilder::layoutInlineContent):
* layout/formattingContexts/inline/InlineLineBuilder.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (283473 => 283474)


--- trunk/Source/WebCore/ChangeLog	2021-10-03 18:41:35 UTC (rev 283473)
+++ trunk/Source/WebCore/ChangeLog	2021-10-03 18:46:15 UTC (rev 283474)
@@ -1,3 +1,30 @@
+2021-10-03  Alan Bujtas  <[email protected]>
+
+        [LFC][IFC] Moving hanging whitespace sequence handling to Line
+        https://bugs.webkit.org/show_bug.cgi?id=231126
+
+        Reviewed by Antti Koivisto.
+
+        Let the Line handle the whitespace hanging. Line::HangingTrailingContent will eventually gain more functionality.
+        This is also in preparation for fixing imported/w3c/web-platform-tests/css/css-text/white-space/textarea-pre-wrap-014.html
+
+        * layout/formattingContexts/inline/InlineLine.cpp:
+        (WebCore::Layout::Line::Line):
+        (WebCore::Layout::Line::visuallyCollapseHangingOverflow):
+        (WebCore::Layout::Line::HangingTrailingContent::HangingTrailingContent):
+        (WebCore::Layout::Line::HangingTrailingContent::width const):
+        * layout/formattingContexts/inline/InlineLine.h:
+        (WebCore::Layout::Line::hangingWhitespaceWidth const):
+        (WebCore::Layout::Line::Run::shouldTrailingWhitespaceHang const):
+        (WebCore::Layout::Line::Run::isOverflowWhitespaceHanging const): Deleted. shouldTrailingWhitespaceHang is a more descriptive name.
+        * layout/formattingContexts/inline/InlineLineBoxBuilder.cpp:
+        (WebCore::Layout::horizontalAlignmentOffset):
+        (WebCore::Layout::LineBoxBuilder::build):
+        (WebCore::Layout::hangingGlyphWidth): Deleted.
+        * layout/formattingContexts/inline/InlineLineBuilder.cpp:
+        (WebCore::Layout::LineBuilder::layoutInlineContent):
+        * layout/formattingContexts/inline/InlineLineBuilder.h:
+
 2021-10-03  Simon Fraser  <[email protected]>
 
         WebCore::Length incorrectly uses memcpy() for copy constructors/operator and IPC encoding/decoding

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp (283473 => 283474)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp	2021-10-03 18:41:35 UTC (rev 283473)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp	2021-10-03 18:46:15 UTC (rev 283474)
@@ -43,6 +43,7 @@
 Line::Line(const InlineFormattingContext& inlineFormattingContext)
     : m_inlineFormattingContext(inlineFormattingContext)
     , m_trimmableTrailingContent(m_runs)
+    , m_hangingTrailingContent(m_runs)
 {
 }
 
@@ -175,7 +176,7 @@
     // different set of white-space values and decide if the in-between pre-wrap content should be collapsed as well.)
     auto trimmedContentWidth = InlineLayoutUnit { };
     for (auto& run : WTF::makeReversedRange(m_runs)) {
-        if (!run.isOverflowWhitespaceHanging())
+        if (!run.shouldTrailingWhitespaceHang())
             break;
         auto visuallyCollapsibleInlineItem = run.isInlineBoxStart() || run.isInlineBoxEnd() || run.hasTrailingWhitespace();
         if (!visuallyCollapsibleInlineItem)
@@ -441,6 +442,29 @@
     return remove();
 }
 
+Line::HangingTrailingContent::HangingTrailingContent(const RunList& runs)
+    : m_runs(runs)
+{
+}
+
+InlineLayoutUnit Line::HangingTrailingContent::width() const
+{
+    // When a glyph at the start or end edge of a line hangs, it is not considered when measuring the line’s contents for fit, alignment, or justification.
+    // Depending on the line’s alignment/justification, this can result in the mark being placed outside the line box.
+    // https://drafts.csswg.org/css-text-3/#hanging
+    auto hangingWidth = InlineLayoutUnit { };
+    for (auto& run : WTF::makeReversedRange(m_runs)) {
+        if (run.isBox() || run.isLineBreak())
+            break;
+        if (run.isInlineBoxStart() || run.isInlineBoxEnd())
+            continue;
+        if (!run.hasTrailingWhitespace() || !run.shouldTrailingWhitespaceHang())
+            break;
+        hangingWidth += run.trailingWhitespaceWidth();
+    }
+    return hangingWidth;
+}
+
 Line::Run::Run(const InlineItem& inlineItem, const RenderStyle& style, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth)
     : m_type(inlineItem.type())
     , m_layoutBox(&inlineItem.layoutBox())

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h (283473 => 283474)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h	2021-10-03 18:41:35 UTC (rev 283473)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h	2021-10-03 18:46:15 UTC (rev 283474)
@@ -53,6 +53,8 @@
     InlineLayoutUnit trimmableTrailingWidth() const { return m_trimmableTrailingContent.width(); }
     bool isTrailingRunFullyTrimmable() const { return m_trimmableTrailingContent.isTrailingRunFullyTrimmable(); }
 
+    InlineLayoutUnit hangingWhitespaceWidth() const { return m_hangingTrailingContent.width(); }
+
     std::optional<InlineLayoutUnit> trailingSoftHyphenWidth() const { return m_trailingSoftHyphenWidth; }
     void addTrailingHyphen(InlineLayoutUnit hyphenLogicalWidth);
 
@@ -87,7 +89,7 @@
         bool hasTrailingWhitespace() const { return m_trailingWhitespaceType != TrailingWhitespace::None; }
         InlineLayoutUnit trailingWhitespaceWidth() const { return m_trailingWhitespaceWidth; }
 
-        bool isOverflowWhitespaceHanging() const;
+        bool shouldTrailingWhitespaceHang() const;
         TextDirection inlineDirection() const;
         InlineLayoutUnit letterSpacing() const;
         bool hasTextCombine() const;
@@ -131,7 +133,7 @@
         std::optional<Text> m_textContent;
         InlineDisplay::Box::Expansion m_expansion;
         struct Style {
-            bool isOverflowWhitespaceHanging { false };
+            bool shouldTrailingWhitespaceHang { false };
             TextDirection inlineDirection { TextDirection::RTL };
             InlineLayoutUnit letterSpacing { 0 };
             bool hasTextCombine { false };
@@ -179,9 +181,19 @@
         InlineLayoutUnit m_partiallyTrimmableWidth { 0 };
     };
 
+    struct HangingTrailingContent {
+        HangingTrailingContent(const RunList&);
+
+        InlineLayoutUnit width() const;
+
+    private:
+        const RunList& m_runs;
+    };
+
     const InlineFormattingContext& m_inlineFormattingContext;
     RunList m_runs;
     TrimmableTrailingContent m_trimmableTrailingContent;
+    HangingTrailingContent m_hangingTrailingContent;
     InlineLayoutUnit m_contentLogicalWidth { 0 };
     size_t m_nonSpanningInlineLevelBoxCount { 0 };
     std::optional<InlineLayoutUnit> m_trailingSoftHyphenWidth { 0 };
@@ -213,9 +225,9 @@
     m_logicalWidth += hyphenLogicalWidth;
 }
 
-inline bool Line::Run::isOverflowWhitespaceHanging() const
+inline bool Line::Run::shouldTrailingWhitespaceHang() const
 {
-    return m_style.isOverflowWhitespaceHanging;
+    return m_style.shouldTrailingWhitespaceHang;
 }
 
 inline TextDirection Line::Run::inlineDirection() const

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp (283473 => 283474)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp	2021-10-03 18:41:35 UTC (rev 283473)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp	2021-10-03 18:46:15 UTC (rev 283474)
@@ -36,37 +36,25 @@
 namespace WebCore {
 namespace Layout {
 
-static InlineLayoutUnit hangingGlyphWidth(InlineLayoutUnit extraHorizontalSpace, const Line::RunList& runs, bool isLastLineWithInlineContent)
+static std::optional<InlineLayoutUnit> horizontalAlignmentOffset(TextAlignMode textAlign, const LineBuilder::LineContent& lineContent)
 {
-    // When a glyph at the start or end edge of a line hangs, it is not considered when measuring the line’s contents for fit, alignment, or justification.
-    // Depending on the line’s alignment/justification, this can result in the mark being placed outside the line box.
-    // https://drafts.csswg.org/css-text-3/#hanging
-    auto isConditional = isLastLineWithInlineContent;
-    auto hangingWidth = InlineLayoutUnit { };
-    for (auto& run : WTF::makeReversedRange(runs)) {
-        if (run.isInlineBoxStart() || run.isInlineBoxEnd())
-            continue;
-        if (run.isLineBreak()) {
-            isConditional = true;
-            continue;
-        }
-        if (!run.hasTrailingWhitespace())
-            break;
-        // Check if we have a preserved or hung whitespace.
-        if (!run.isOverflowWhitespaceHanging())
-            break;
-        // This is either a normal or conditionally hanging trailing whitespace.
-        hangingWidth += run.trailingWhitespaceWidth();
+    // Depending on the line’s alignment/justification, the hanging glyph can be placed outside the line box.
+    auto& runs = lineContent.runs;
+    auto contentLogicalWidth = lineContent.contentLogicalWidth;
+    if (lineContent.hangingWhitespaceWidth) {
+        ASSERT(!runs.isEmpty());
+        // If white-space is set to pre-wrap, the UA must (unconditionally) hang this sequence, unless the sequence is followed
+        // by a forced line break, in which case it must conditionally hang the sequence is instead.
+        // Note that end of last line in a paragraph is considered a forced break.
+        auto isConditionalHanging = runs.last().isLineBreak() || lineContent.isLastLineWithInlineContent;
+        // In some cases, a glyph at the end of a line can conditionally hang: it hangs only if it does not otherwise fit in the line prior to justification.
+        // FIXME: Only the overflowing glyphs should be considered for hanging.
+        if (isConditionalHanging)
+            contentLogicalWidth = std::min(contentLogicalWidth, lineContent.lineLogicalWidth);
+        else
+            contentLogicalWidth -= lineContent.hangingWhitespaceWidth;
     }
-    // In some cases, a glyph at the end of a line can conditionally hang: it hangs only if it does not otherwise fit in the line prior to justification.
-    return !isConditional || extraHorizontalSpace < 0 ? hangingWidth : InlineLayoutUnit { };
-}
-
-static std::optional<InlineLayoutUnit> horizontalAlignmentOffset(const Line::RunList& runs, TextAlignMode textAlign, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, bool isLastLine)
-{
-    auto extraHorizontalSpace = lineLogicalWidth - contentLogicalWidth;
-    // Depending on the line’s alignment/justification, the hanging glyph can be placed outside the line box.
-    extraHorizontalSpace += hangingGlyphWidth(extraHorizontalSpace, runs, isLastLine);
+    auto extraHorizontalSpace = lineContent.lineLogicalWidth - contentLogicalWidth;
     if (extraHorizontalSpace <= 0)
         return { };
 
@@ -76,7 +64,7 @@
         // Text is justified according to the method specified by the text-justify property,
         // in order to exactly fill the line box. Unless otherwise specified by text-align-last,
         // the last line before a forced break or the end of the block is start-aligned.
-        if (isLastLine || (!runs.isEmpty() && runs.last().isLineBreak()))
+        if (lineContent.isLastLineWithInlineContent || (!runs.isEmpty() && runs.last().isLineBreak()))
             return TextAlignMode::Start;
         return TextAlignMode::Justify;
     };
@@ -111,13 +99,11 @@
 
 LineBoxBuilder::LineAndLineBox LineBoxBuilder::build(const LineBuilder::LineContent& lineContent, size_t lineIndex)
 {
-    auto& runs = lineContent.runs;
-    auto contentLogicalWidth = lineContent.contentLogicalWidth;
     auto textAlign = !lineIndex ? rootBox().firstLineStyle().textAlign() : rootBox().style().textAlign();
-    auto contentLogicalLeft = Layout::horizontalAlignmentOffset(runs, textAlign, lineContent.lineLogicalWidth, contentLogicalWidth, lineContent.isLastLineWithInlineContent).value_or(InlineLayoutUnit { });
-    auto lineBox = LineBox { rootBox(), contentLogicalLeft, contentLogicalWidth, lineIndex, lineContent.nonSpanningInlineLevelBoxCount };
+    auto contentLogicalLeft = Layout::horizontalAlignmentOffset(textAlign, lineContent).value_or(InlineLayoutUnit { });
+    auto lineBox = LineBox { rootBox(), contentLogicalLeft, lineContent.contentLogicalWidth, lineIndex, lineContent.nonSpanningInlineLevelBoxCount };
 
-    auto lineBoxLogicalHeight = constructAndAlignInlineLevelBoxes(lineBox, runs, lineIndex);
+    auto lineBoxLogicalHeight = constructAndAlignInlineLevelBoxes(lineBox, lineContent.runs, lineIndex);
 
     auto line = [&] {
         auto lineBoxLogicalRect = InlineRect { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, lineBoxLogicalHeight };

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp (283473 => 283474)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp	2021-10-03 18:41:35 UTC (rev 283473)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp	2021-10-03 18:46:15 UTC (rev 283474)
@@ -278,6 +278,7 @@
         , m_lineLogicalRect.topLeft()
         , m_lineLogicalRect.width()
         , m_line.contentLogicalWidth()
+        , m_line.hangingWhitespaceWidth()
         , isLastLine
         , m_line.nonSpanningInlineLevelBoxCount()
         , m_line.runs()};

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h (283473 => 283474)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h	2021-10-03 18:41:35 UTC (rev 283473)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h	2021-10-03 18:46:15 UTC (rev 283474)
@@ -56,8 +56,9 @@
         const FloatList& floats;
         bool hasIntrusiveFloat { false };
         InlineLayoutPoint logicalTopLeft;
-        InlineLayoutUnit lineLogicalWidth;
-        InlineLayoutUnit contentLogicalWidth;
+        InlineLayoutUnit lineLogicalWidth { 0 };
+        InlineLayoutUnit contentLogicalWidth { 0 };
+        InlineLayoutUnit hangingWhitespaceWidth { 0 };
         bool isLastLineWithInlineContent { true };
         size_t nonSpanningInlineLevelBoxCount { 0 };
         const Line::RunList& runs;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to