⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 283474 in webkit


Ignore:
Timestamp:
Oct 3, 2021, 11:46:15 AM (5 years ago)
Author:
Alan Bujtas
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:
Location:
trunk/Source/WebCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r283470 r283474  
     12021-10-03  Alan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] Moving hanging whitespace sequence handling to Line
     4        https://bugs.webkit.org/show_bug.cgi?id=231126
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Let the Line handle the whitespace hanging. Line::HangingTrailingContent will eventually gain more functionality.
     9        This is also in preparation for fixing imported/w3c/web-platform-tests/css/css-text/white-space/textarea-pre-wrap-014.html
     10
     11        * layout/formattingContexts/inline/InlineLine.cpp:
     12        (WebCore::Layout::Line::Line):
     13        (WebCore::Layout::Line::visuallyCollapseHangingOverflow):
     14        (WebCore::Layout::Line::HangingTrailingContent::HangingTrailingContent):
     15        (WebCore::Layout::Line::HangingTrailingContent::width const):
     16        * layout/formattingContexts/inline/InlineLine.h:
     17        (WebCore::Layout::Line::hangingWhitespaceWidth const):
     18        (WebCore::Layout::Line::Run::shouldTrailingWhitespaceHang const):
     19        (WebCore::Layout::Line::Run::isOverflowWhitespaceHanging const): Deleted. shouldTrailingWhitespaceHang is a more descriptive name.
     20        * layout/formattingContexts/inline/InlineLineBoxBuilder.cpp:
     21        (WebCore::Layout::horizontalAlignmentOffset):
     22        (WebCore::Layout::LineBoxBuilder::build):
     23        (WebCore::Layout::hangingGlyphWidth): Deleted.
     24        * layout/formattingContexts/inline/InlineLineBuilder.cpp:
     25        (WebCore::Layout::LineBuilder::layoutInlineContent):
     26        * layout/formattingContexts/inline/InlineLineBuilder.h:
     27
    1282021-10-03  Simon Fraser  <simon.fraser@apple.com>
    229
  • trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp

    r283059 r283474  
    4444    : m_inlineFormattingContext(inlineFormattingContext)
    4545    , m_trimmableTrailingContent(m_runs)
     46    , m_hangingTrailingContent(m_runs)
    4647{
    4748}
     
    176177    auto trimmedContentWidth = InlineLayoutUnit { };
    177178    for (auto& run : WTF::makeReversedRange(m_runs)) {
    178         if (!run.isOverflowWhitespaceHanging())
     179        if (!run.shouldTrailingWhitespaceHang())
    179180            break;
    180181        auto visuallyCollapsibleInlineItem = run.isInlineBoxStart() || run.isInlineBoxEnd() || run.hasTrailingWhitespace();
     
    442443}
    443444
     445Line::HangingTrailingContent::HangingTrailingContent(const RunList& runs)
     446    : m_runs(runs)
     447{
     448}
     449
     450InlineLayoutUnit Line::HangingTrailingContent::width() const
     451{
     452    // 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.
     453    // Depending on the line’s alignment/justification, this can result in the mark being placed outside the line box.
     454    // https://drafts.csswg.org/css-text-3/#hanging
     455    auto hangingWidth = InlineLayoutUnit { };
     456    for (auto& run : WTF::makeReversedRange(m_runs)) {
     457        if (run.isBox() || run.isLineBreak())
     458            break;
     459        if (run.isInlineBoxStart() || run.isInlineBoxEnd())
     460            continue;
     461        if (!run.hasTrailingWhitespace() || !run.shouldTrailingWhitespaceHang())
     462            break;
     463        hangingWidth += run.trailingWhitespaceWidth();
     464    }
     465    return hangingWidth;
     466}
     467
    444468Line::Run::Run(const InlineItem& inlineItem, const RenderStyle& style, InlineLayoutUnit logicalLeft, InlineLayoutUnit logicalWidth)
    445469    : m_type(inlineItem.type())
  • trunk/Source/WebCore/layout/formattingContexts/inline/InlineLine.h

    r283059 r283474  
    5454    bool isTrailingRunFullyTrimmable() const { return m_trimmableTrailingContent.isTrailingRunFullyTrimmable(); }
    5555
     56    InlineLayoutUnit hangingWhitespaceWidth() const { return m_hangingTrailingContent.width(); }
     57
    5658    std::optional<InlineLayoutUnit> trailingSoftHyphenWidth() const { return m_trailingSoftHyphenWidth; }
    5759    void addTrailingHyphen(InlineLayoutUnit hyphenLogicalWidth);
     
    8890        InlineLayoutUnit trailingWhitespaceWidth() const { return m_trailingWhitespaceWidth; }
    8991
    90         bool isOverflowWhitespaceHanging() const;
     92        bool shouldTrailingWhitespaceHang() const;
    9193        TextDirection inlineDirection() const;
    9294        InlineLayoutUnit letterSpacing() const;
     
    132134        InlineDisplay::Box::Expansion m_expansion;
    133135        struct Style {
    134             bool isOverflowWhitespaceHanging { false };
     136            bool shouldTrailingWhitespaceHang { false };
    135137            TextDirection inlineDirection { TextDirection::RTL };
    136138            InlineLayoutUnit letterSpacing { 0 };
     
    180182    };
    181183
     184    struct HangingTrailingContent {
     185        HangingTrailingContent(const RunList&);
     186
     187        InlineLayoutUnit width() const;
     188
     189    private:
     190        const RunList& m_runs;
     191    };
     192
    182193    const InlineFormattingContext& m_inlineFormattingContext;
    183194    RunList m_runs;
    184195    TrimmableTrailingContent m_trimmableTrailingContent;
     196    HangingTrailingContent m_hangingTrailingContent;
    185197    InlineLayoutUnit m_contentLogicalWidth { 0 };
    186198    size_t m_nonSpanningInlineLevelBoxCount { 0 };
     
    214226}
    215227
    216 inline bool Line::Run::isOverflowWhitespaceHanging() const
    217 {
    218     return m_style.isOverflowWhitespaceHanging;
     228inline bool Line::Run::shouldTrailingWhitespaceHang() const
     229{
     230    return m_style.shouldTrailingWhitespaceHang;
    219231}
    220232
  • trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp

    r283390 r283474  
    3737namespace Layout {
    3838
    39 static InlineLayoutUnit hangingGlyphWidth(InlineLayoutUnit extraHorizontalSpace, const Line::RunList& runs, bool isLastLineWithInlineContent)
    40 {
    41     // 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.
    42     // Depending on the line’s alignment/justification, this can result in the mark being placed outside the line box.
    43     // https://drafts.csswg.org/css-text-3/#hanging
    44     auto isConditional = isLastLineWithInlineContent;
    45     auto hangingWidth = InlineLayoutUnit { };
    46     for (auto& run : WTF::makeReversedRange(runs)) {
    47         if (run.isInlineBoxStart() || run.isInlineBoxEnd())
    48             continue;
    49         if (run.isLineBreak()) {
    50             isConditional = true;
    51             continue;
    52         }
    53         if (!run.hasTrailingWhitespace())
    54             break;
    55         // Check if we have a preserved or hung whitespace.
    56         if (!run.isOverflowWhitespaceHanging())
    57             break;
    58         // This is either a normal or conditionally hanging trailing whitespace.
    59         hangingWidth += run.trailingWhitespaceWidth();
     39static std::optional<InlineLayoutUnit> horizontalAlignmentOffset(TextAlignMode textAlign, const LineBuilder::LineContent& lineContent)
     40{
     41    // Depending on the line’s alignment/justification, the hanging glyph can be placed outside the line box.
     42    auto& runs = lineContent.runs;
     43    auto contentLogicalWidth = lineContent.contentLogicalWidth;
     44    if (lineContent.hangingWhitespaceWidth) {
     45        ASSERT(!runs.isEmpty());
     46        // If white-space is set to pre-wrap, the UA must (unconditionally) hang this sequence, unless the sequence is followed
     47        // by a forced line break, in which case it must conditionally hang the sequence is instead.
     48        // Note that end of last line in a paragraph is considered a forced break.
     49        auto isConditionalHanging = runs.last().isLineBreak() || lineContent.isLastLineWithInlineContent;
     50        // 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.
     51        // FIXME: Only the overflowing glyphs should be considered for hanging.
     52        if (isConditionalHanging)
     53            contentLogicalWidth = std::min(contentLogicalWidth, lineContent.lineLogicalWidth);
     54        else
     55            contentLogicalWidth -= lineContent.hangingWhitespaceWidth;
    6056    }
    61     // 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.
    62     return !isConditional || extraHorizontalSpace < 0 ? hangingWidth : InlineLayoutUnit { };
    63 }
    64 
    65 static std::optional<InlineLayoutUnit> horizontalAlignmentOffset(const Line::RunList& runs, TextAlignMode textAlign, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, bool isLastLine)
    66 {
    67     auto extraHorizontalSpace = lineLogicalWidth - contentLogicalWidth;
    68     // Depending on the line’s alignment/justification, the hanging glyph can be placed outside the line box.
    69     extraHorizontalSpace += hangingGlyphWidth(extraHorizontalSpace, runs, isLastLine);
     57    auto extraHorizontalSpace = lineContent.lineLogicalWidth - contentLogicalWidth;
    7058    if (extraHorizontalSpace <= 0)
    7159        return { };
     
    7765        // in order to exactly fill the line box. Unless otherwise specified by text-align-last,
    7866        // the last line before a forced break or the end of the block is start-aligned.
    79         if (isLastLine || (!runs.isEmpty() && runs.last().isLineBreak()))
     67        if (lineContent.isLastLineWithInlineContent || (!runs.isEmpty() && runs.last().isLineBreak()))
    8068            return TextAlignMode::Start;
    8169        return TextAlignMode::Justify;
     
    112100LineBoxBuilder::LineAndLineBox LineBoxBuilder::build(const LineBuilder::LineContent& lineContent, size_t lineIndex)
    113101{
    114     auto& runs = lineContent.runs;
    115     auto contentLogicalWidth = lineContent.contentLogicalWidth;
    116102    auto textAlign = !lineIndex ? rootBox().firstLineStyle().textAlign() : rootBox().style().textAlign();
    117     auto contentLogicalLeft = Layout::horizontalAlignmentOffset(runs, textAlign, lineContent.lineLogicalWidth, contentLogicalWidth, lineContent.isLastLineWithInlineContent).value_or(InlineLayoutUnit { });
    118     auto lineBox = LineBox { rootBox(), contentLogicalLeft, contentLogicalWidth, lineIndex, lineContent.nonSpanningInlineLevelBoxCount };
    119 
    120     auto lineBoxLogicalHeight = constructAndAlignInlineLevelBoxes(lineBox, runs, lineIndex);
     103    auto contentLogicalLeft = Layout::horizontalAlignmentOffset(textAlign, lineContent).value_or(InlineLayoutUnit { });
     104    auto lineBox = LineBox { rootBox(), contentLogicalLeft, lineContent.contentLogicalWidth, lineIndex, lineContent.nonSpanningInlineLevelBoxCount };
     105
     106    auto lineBoxLogicalHeight = constructAndAlignInlineLevelBoxes(lineBox, lineContent.runs, lineIndex);
    121107
    122108    auto line = [&] {
  • trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp

    r283442 r283474  
    279279        , m_lineLogicalRect.width()
    280280        , m_line.contentLogicalWidth()
     281        , m_line.hangingWhitespaceWidth()
    281282        , isLastLine
    282283        , m_line.nonSpanningInlineLevelBoxCount()
  • trunk/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h

    r283255 r283474  
    5757        bool hasIntrusiveFloat { false };
    5858        InlineLayoutPoint logicalTopLeft;
    59         InlineLayoutUnit lineLogicalWidth;
    60         InlineLayoutUnit contentLogicalWidth;
     59        InlineLayoutUnit lineLogicalWidth { 0 };
     60        InlineLayoutUnit contentLogicalWidth { 0 };
     61        InlineLayoutUnit hangingWhitespaceWidth { 0 };
    6162        bool isLastLineWithInlineContent { true };
    6263        size_t nonSpanningInlineLevelBoxCount { 0 };
Note: See TracChangeset for help on using the changeset viewer.