Changeset 256524 in webkit


Ignore:
Timestamp:
Feb 13, 2020 11:05:29 AM (4 years ago)
Author:
Alan Bujtas
Message:

[LFC][IFC] LineBreaker should not hold on to the lastWrapOpportunity inline item
https://bugs.webkit.org/show_bug.cgi?id=207707
<rdar://problem/59427376>

Reviewed by Antti Koivisto.

LineBreaker only needs a flag indicating that there's a wrapping opportunity on the line.
LineLayoutContext needs to know what the position is (as an InlineItem) so that it could initiate a revert if needed.

  • layout/inlineformatting/InlineLineBreaker.cpp:

(WebCore::Layout::LineBreaker::shouldWrapInlineContent):
(WebCore::Layout::LineBreaker::tryWrappingInlineContent const):
(WebCore::Layout::LineBreaker::wordBreakBehavior const):

  • layout/inlineformatting/InlineLineBreaker.h:
  • layout/inlineformatting/LineLayoutContext.cpp:

(WebCore::Layout::LineLayoutContext::layoutLine):
(WebCore::Layout::LineLayoutContext::tryAddingFloatItem):
(WebCore::Layout::LineLayoutContext::tryAddingInlineItems):
(WebCore::Layout::LineLayoutContext::rebuildLine):
(WebCore::Layout::LineLayoutContext::rebuildLineForRevert): Deleted.

  • layout/inlineformatting/LineLayoutContext.h:

(WebCore::Layout::LineLayoutContext::InlineItemRange::size const):

Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r256514 r256524  
     12020-02-13  Zalan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] LineBreaker should not hold on to the lastWrapOpportunity inline item
     4        https://bugs.webkit.org/show_bug.cgi?id=207707
     5        <rdar://problem/59427376>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        LineBreaker only needs a flag indicating that there's a wrapping opportunity on the line.
     10        LineLayoutContext needs to know what the position is (as an InlineItem) so that it could initiate a revert if needed.
     11
     12        * layout/inlineformatting/InlineLineBreaker.cpp:
     13        (WebCore::Layout::LineBreaker::shouldWrapInlineContent):
     14        (WebCore::Layout::LineBreaker::tryWrappingInlineContent const):
     15        (WebCore::Layout::LineBreaker::wordBreakBehavior const):
     16        * layout/inlineformatting/InlineLineBreaker.h:
     17        * layout/inlineformatting/LineLayoutContext.cpp:
     18        (WebCore::Layout::LineLayoutContext::layoutLine):
     19        (WebCore::Layout::LineLayoutContext::tryAddingFloatItem):
     20        (WebCore::Layout::LineLayoutContext::tryAddingInlineItems):
     21        (WebCore::Layout::LineLayoutContext::rebuildLine):
     22        (WebCore::Layout::LineLayoutContext::rebuildLineForRevert): Deleted.
     23        * layout/inlineformatting/LineLayoutContext.h:
     24        (WebCore::Layout::LineLayoutContext::InlineItemRange::size const):
     25
    1262020-02-13  Adrian Perez de Castro  <aperez@igalia.com>
    227
  • trunk/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp

    r256304 r256524  
    140140                return shouldKeepBeginningOfLineWhitespace(candidateItem.style());
    141141            };
    142             auto& inlineItem = candidateRuns[*lastLineWrapOpportunityIndex].inlineItem;
    143             if (isEligibleLineWrapOpportunity(inlineItem))
    144                 m_lastWrapOpportunity = &inlineItem;
     142            auto& lastWrapOpportunityCandidateItem = candidateRuns[*lastLineWrapOpportunityIndex].inlineItem;
     143            if (isEligibleLineWrapOpportunity(lastWrapOpportunityCandidateItem)) {
     144                result.lastWrapOpportunityItem = &lastWrapOpportunityCandidateItem;
     145                m_hasWrapOpportunityAtPreviousPosition = true;
     146            }
    145147        }
    146148    }
     
    201203    // If we are not allowed to break this overflowing content, we still need to decide whether keep it or push it to the next line.
    202204    if (lineStatus.lineIsEmpty) {
    203         ASSERT(!m_lastWrapOpportunity);
     205        ASSERT(!m_hasWrapOpportunityAtPreviousPosition);
    204206        return { Result::Action::Keep, IsEndOfLine::No };
    205207    }
     
    207209    if (isContentWrappingAllowed(candidateContent))
    208210        return { Result::Action::Push, IsEndOfLine::Yes };
    209     if (m_lastWrapOpportunity)
    210         return { Result::Action::Revert, IsEndOfLine::Yes, { }, m_lastWrapOpportunity };
     211    if (m_hasWrapOpportunityAtPreviousPosition)
     212        return { Result::Action::RevertToLastWrapOpportunity, IsEndOfLine::Yes };
    211213    return { Result::Action::Keep, IsEndOfLine::No };
    212214}
     
    287289    // For compatibility with legacy content, the word-break property also supports a deprecated break-word keyword.
    288290    // When specified, this has the same effect as word-break: normal and overflow-wrap: anywhere, regardless of the actual value of the overflow-wrap property.
    289     if (style.wordBreak() == WordBreak::BreakWord && !m_lastWrapOpportunity)
     291    if (style.wordBreak() == WordBreak::BreakWord && !m_hasWrapOpportunityAtPreviousPosition)
    290292        return WordBreakRule::AtArbitraryPosition;
    291293    // OverflowWrap::Break: An otherwise unbreakable sequence of characters may be broken at an arbitrary point if there are no otherwise-acceptable break points in the line.
    292     if (style.overflowWrap() == OverflowWrap::Break && !m_lastWrapOpportunity)
     294    if (style.overflowWrap() == OverflowWrap::Break && !m_hasWrapOpportunityAtPreviousPosition)
    293295        return WordBreakRule::AtArbitraryPosition;
    294296
  • trunk/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h

    r254721 r256524  
    5454            Split, // Partial content is on the current line.
    5555            Push, // Content is pushed to the next line.
    56             Revert // The current content overflows and can't get wrapped. The line needs to be reverted back to the last line wrapping opportunity.
     56            RevertToLastWrapOpportunity // The current content overflows and can't get wrapped. The line needs to be reverted back to the last line wrapping opportunity.
    5757        };
    5858        struct PartialTrailingContent {
     
    6464        IsEndOfLine isEndOfLine { IsEndOfLine::No };
    6565        Optional<PartialTrailingContent> partialTrailingContent { };
    66         const InlineItem* revertTo { nullptr };
     66        const InlineItem* lastWrapOpportunityItem { nullptr };
    6767    };
    6868
     
    112112
    113113    bool n_hyphenationIsDisabled { false };
    114     const InlineItem* m_lastWrapOpportunity { nullptr };
     114    bool m_hasWrapOpportunityAtPreviousPosition { false };
    115115};
    116116
  • trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp

    r256507 r256524  
    263263    ASSERT(m_floats.isEmpty());
    264264    m_partialLeadingTextItem = { };
     265    m_lastWrapOpportunityItem = { };
    265266    auto lineBreaker = LineBreaker { };
    266267    auto currentItemIndex = layoutRange.start;
     
    276277            // Floats shrink the available horizontal space for the rest of the content, but they are not added on the line.
    277278            auto result = tryAddingFloatItem(line, *lineCandidate.floatItem);
    278             committedInlineItemCount += result.committedCount;
     279            committedInlineItemCount += result.committedCount.value;
    279280            if (result.isEndOfLine == LineBreaker::IsEndOfLine::Yes) {
    280281                // This float takes up all the horizontal space.
     
    286287            if (!inlineContent.runs().isEmpty()) {
    287288                // Now check if we can put this content on the current line.
    288                 auto result = tryAddingInlineItems(lineBreaker, line, lineCandidate);
    289                 if (result.revertTo) {
    290                     ASSERT(!result.committedCount);
    291                     ASSERT(result.isEndOfLine == LineBreaker::IsEndOfLine::Yes);
    292                     // An earlier line wrapping opportunity turned out to be the final breaking position.
    293                     rebuildLineForRevert(line, *result.revertTo, layoutRange);
    294                 }
    295                 committedInlineItemCount += result.committedCount;
     289                auto result = tryAddingInlineItems(lineBreaker, line, layoutRange, lineCandidate);
     290                committedInlineItemCount = result.committedCount.isRevert ? result.committedCount.value : committedInlineItemCount + result.committedCount.value; 
    296291                if (result.isEndOfLine == LineBreaker::IsEndOfLine::Yes) {
    297292                    // We can't place any more items on the current line.
     
    402397        line.moveLogicalRight(logicalWidth);
    403398    m_floats.append(&floatItem);
    404     return { LineBreaker::IsEndOfLine::No, 1 };
    405 }
    406 
    407 LineLayoutContext::Result LineLayoutContext::tryAddingInlineItems(LineBreaker& lineBreaker, LineBuilder& line, const LineCandidate& lineCandidate)
     399    return { LineBreaker::IsEndOfLine::No, { 1, false } };
     400}
     401
     402LineLayoutContext::Result LineLayoutContext::tryAddingInlineItems(LineBreaker& lineBreaker, LineBuilder& line, const InlineItemRange& layoutRange, const LineCandidate& lineCandidate)
    408403{
    409404    auto shouldDisableHyphenation = [&] {
     
    421416    auto& candidateRuns = inlineContent.runs();
    422417    auto result = lineBreaker.shouldWrapInlineContent(candidateRuns, inlineContent.logicalWidth(), lineStatus);
     418    if (result.lastWrapOpportunityItem)
     419        m_lastWrapOpportunityItem = result.lastWrapOpportunityItem;
    423420    if (result.action == LineBreaker::Result::Action::Keep) {
    424421        // This continuous content can be fully placed on the current line.
     
    428425        if (auto* lineBreakItem = inlineContent.trailingLineBreak()) {
    429426            line.append(*lineBreakItem, 0);
    430             return { LineBreaker::IsEndOfLine::Yes, candidateRuns.size() + 1 };
    431         }
    432         return { result.isEndOfLine, candidateRuns.size() };
     427            return { LineBreaker::IsEndOfLine::Yes, { candidateRuns.size() + 1, false } };
     428        }
     429        return { result.isEndOfLine, { candidateRuns.size(), false } };
    433430    }
    434431    if (result.action == LineBreaker::Result::Action::Push) {
     432        ASSERT(result.isEndOfLine == LineBreaker::IsEndOfLine::Yes);
    435433        // This continuous content can't be placed on the current line. Nothing to commit at this time.
    436434        return { result.isEndOfLine };
    437435    }
    438     if (result.action == LineBreaker::Result::Action::Revert) {
     436    if (result.action == LineBreaker::Result::Action::RevertToLastWrapOpportunity) {
     437        ASSERT(result.isEndOfLine == LineBreaker::IsEndOfLine::Yes);
    439438        // Not only this content can't be placed on the current line, but we even need to revert the line back to an earlier position.
    440         return { result.isEndOfLine, 0, { }, result.revertTo };
     439        ASSERT(m_lastWrapOpportunityItem);
     440        return { result.isEndOfLine, { rebuildLine(line, layoutRange), true } };
    441441    }
    442442    if (result.action == LineBreaker::Result::Action::Split) {
     443        ASSERT(result.isEndOfLine == LineBreaker::IsEndOfLine::Yes);
    443444        // Commit the combination of full and partial content on the current line.
    444445        ASSERT(result.partialTrailingContent);
     
    449450        auto committedInlineItemCount = trailingRunIndex + 1;
    450451        if (!result.partialTrailingContent->partialRun)
    451             return { result.isEndOfLine, committedInlineItemCount };
     452            return { result.isEndOfLine, { committedInlineItemCount, false } };
    452453
    453454        auto partialRun = *result.partialTrailingContent->partialRun;
    454455        auto& trailingInlineTextItem = downcast<InlineTextItem>(candidateRuns[trailingRunIndex].inlineItem);
    455456        auto overflowLength = trailingInlineTextItem.length() - partialRun.length;
    456         return { result.isEndOfLine, committedInlineItemCount, LineContent::PartialContent { partialRun.needsHyphen, overflowLength } };
     457        return { result.isEndOfLine, { committedInlineItemCount, false }, LineContent::PartialContent { partialRun.needsHyphen, overflowLength } };
    457458    }
    458459    ASSERT_NOT_REACHED();
     
    481482}
    482483
    483 void LineLayoutContext::rebuildLineForRevert(LineBuilder& line, const InlineItem& revertTo, const InlineItemRange layoutRange)
    484 {
    485     // This is the rare case when the line needs to be reverted to an earlier position.
     484size_t LineLayoutContext::rebuildLine(LineBuilder& line, const InlineItemRange& layoutRange)
     485{
     486    // Clear the line and start appending the inline items closing with the last wrap opportunity run.
    486487    line.resetContent();
    487     auto inlineItemIndex = layoutRange.start;
    488     InlineLayoutUnit logicalRight = { };
     488    auto currentItemIndex = layoutRange.start;
     489    auto logicalRight = InlineLayoutUnit { };
    489490    if (m_partialLeadingTextItem) {
    490491        auto logicalWidth = inlineItemWidth(*m_partialLeadingTextItem, logicalRight);
    491492        line.append(*m_partialLeadingTextItem, logicalWidth);
    492493        logicalRight += logicalWidth;
    493         if (&revertTo == &m_partialLeadingTextItem.value())
    494             return;
    495         ++inlineItemIndex;
    496     }
    497 
    498     for (; inlineItemIndex < layoutRange.end; ++inlineItemIndex) {
    499         auto& inlineItem = m_inlineItems[inlineItemIndex];
     494        if (&m_partialLeadingTextItem.value() == m_lastWrapOpportunityItem)
     495            return 1;
     496        ++currentItemIndex;
     497    }
     498    for (; currentItemIndex < layoutRange.end; ++currentItemIndex) {
     499        auto& inlineItem = m_inlineItems[currentItemIndex];
    500500        auto logicalWidth = inlineItemWidth(inlineItem, logicalRight);
    501501        line.append(inlineItem, logicalWidth);
    502502        logicalRight += logicalWidth;
    503         if (&inlineItem == &revertTo)
    504             break;
    505     }
     503        if (&inlineItem == m_lastWrapOpportunityItem)
     504            return currentItemIndex - layoutRange.start + 1;
     505    }
     506    return layoutRange.size();
    506507}
    507508
  • trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.h

    r256507 r256524  
    5353    struct InlineItemRange {
    5454        bool isEmpty() const { return start == end; }
     55        size_t size() const { return end - start; }
    5556        size_t start { 0 };
    5657        size_t end { 0 };
     
    6263    struct Result {
    6364        LineBreaker::IsEndOfLine isEndOfLine { LineBreaker::IsEndOfLine::No };
    64         size_t committedCount { 0 };
     65        struct CommittedContentCount {
     66            size_t value { 0 };
     67            bool isRevert { false };
     68        };
     69        CommittedContentCount committedCount { };
    6570        Optional <LineContent::PartialContent> partialContent { };
    66         const InlineItem* revertTo { nullptr };
    6771    };
    6872    Result tryAddingFloatItem(LineBuilder&, const InlineItem& floatItem);
    69     Result tryAddingInlineItems(LineBreaker&, LineBuilder&, const LineCandidate&);
    70     void rebuildLineForRevert(LineBuilder&, const InlineItem& revertTo, const InlineItemRange layoutRange);
     73    Result tryAddingInlineItems(LineBreaker&, LineBuilder&, const InlineItemRange& layoutRange, const LineCandidate&);
     74    size_t rebuildLine(LineBuilder&, const InlineItemRange& layoutRange);
    7175    void commitPartialContent(LineBuilder&, const LineBreaker::RunList&, const LineBreaker::Result::PartialTrailingContent&);
    7276    LineContent close(LineBuilder&, const InlineItemRange layoutRange, unsigned committedInlineItemCount, Optional<LineContent::PartialContent>);
     
    8387    FloatList m_floats;
    8488    Optional<InlineTextItem> m_partialLeadingTextItem;
     89    const InlineItem* m_lastWrapOpportunityItem { nullptr };
    8590    unsigned m_successiveHyphenatedLineCount { 0 };
    8691};
Note: See TracChangeset for help on using the changeset viewer.