Changeset 253928 in webkit


Ignore:
Timestamp:
Dec 28, 2019 4:19:44 PM (4 years ago)
Author:
Alan Bujtas
Message:

[LFC][IFC] Keep track of last line wrap opportunity
https://bugs.webkit.org/show_bug.cgi?id=205619
<rdar://problem/58227112>

Reviewed by Antti Koivisto.

This is in preparation for being able to revert back to an earlier position
of the current line as the line wrapping opportunity.
(actually the m_lastWrapOpportunity is already taken into use at LineBreaker::wordBreakBehavior)

  • layout/inlineformatting/InlineLineBreaker.cpp:

(WebCore::Layout::shouldKeepBeginningOfLineWhitespace):
(WebCore::Layout::LineBreaker::shouldWrapInlineContent):
(WebCore::Layout::LineBreaker::shouldWrapFloatBox):
(WebCore::Layout::LineBreaker::tryWrappingInlineContent const):
(WebCore::Layout::LineBreaker::wrapTextContent const):
(WebCore::Layout::LineBreaker::wordBreakBehavior const):
(WebCore::Layout::LineBreaker::tryBreakingTextRun const):
(WebCore::Layout::LineBreaker::ContinousContent::lastWrapOpportunityIndex const):

  • layout/inlineformatting/InlineLineBreaker.h:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r253926 r253928  
     12019-12-28  Zalan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] Keep track of last line wrap opportunity
     4        https://bugs.webkit.org/show_bug.cgi?id=205619
     5        <rdar://problem/58227112>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        This is in preparation for being able to revert back to an earlier position
     10        of the current line as the line wrapping opportunity.
     11        (actually the m_lastWrapOpportunity is already taken into use at LineBreaker::wordBreakBehavior)
     12
     13        * layout/inlineformatting/InlineLineBreaker.cpp:
     14        (WebCore::Layout::shouldKeepBeginningOfLineWhitespace):
     15        (WebCore::Layout::LineBreaker::shouldWrapInlineContent):
     16        (WebCore::Layout::LineBreaker::shouldWrapFloatBox):
     17        (WebCore::Layout::LineBreaker::tryWrappingInlineContent const):
     18        (WebCore::Layout::LineBreaker::wrapTextContent const):
     19        (WebCore::Layout::LineBreaker::wordBreakBehavior const):
     20        (WebCore::Layout::LineBreaker::tryBreakingTextRun const):
     21        (WebCore::Layout::LineBreaker::ContinousContent::lastWrapOpportunityIndex const):
     22        * layout/inlineformatting/InlineLineBreaker.h:
     23
    1242019-12-25  Dean Jackson  <dino@apple.com>
    225
  • trunk/Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp

    r253924 r253928  
    4444}
    4545
     46static inline bool shouldKeepBeginningOfLineWhitespace(const RenderStyle& style)
     47{
     48    auto whitespace = style.whiteSpace();
     49    return whitespace == WhiteSpace::Pre || whitespace == WhiteSpace::PreWrap || whitespace == WhiteSpace::BreakSpaces;
     50}
     51
    4652bool LineBreaker::isContentWrappingAllowed(const ContinousContent& candidateRuns) const
    4753{
     
    6571    auto candidateContent = ContinousContent { candidateRuns };
    6672    ASSERT(!candidateContent.isEmpty());
     73    auto result = tryWrappingInlineContent(candidateContent, lineStatus);
     74    // If this is not the end of the line, hold on to the last eligible line wrap opportunity so that we could revert back
     75    // to this position if no other line breaking opportunity exists in this content.
     76    if (result.isEndOfLine == IsEndOfLine::Yes)
     77        return result;
     78    if (auto lastLineWrapOpportunityIndex = candidateContent.lastWrapOpportunityIndex()) {
     79        auto isEligibleLineWrapOpportunity = [&] (auto& candidateItem) {
     80            // Just check for leading collapsible whitespace for now.
     81            if (!lineStatus.lineIsEmpty || !candidateItem.isText() || !downcast<InlineTextItem>(candidateItem).isWhitespace())
     82                return true;
     83            return shouldKeepBeginningOfLineWhitespace(candidateItem.style());
     84        };
     85        auto& inlineItem = candidateContent.runs()[*lastLineWrapOpportunityIndex].inlineItem;
     86        if (isEligibleLineWrapOpportunity(inlineItem))
     87            m_lastWrapOpportunity = &inlineItem;
     88    }
     89    return result;
     90}
     91
     92LineBreaker::Result LineBreaker::tryWrappingInlineContent(const ContinousContent& candidateContent, const LineStatus& lineStatus) const
     93{
    6794    if (candidateContent.width() <= lineStatus.availableWidth)
    6895        return { Result::Action::Keep, IsEndOfLine::No, { } };
     
    114141    // If we are not allowed to break this content, we still need to decide whether keep it or push it to the next line.
    115142    auto isWrappingAllowed = isContentWrappingAllowed(candidateContent);
    116     auto contentOverflows = lineStatus.lineIsEmpty || !isWrappingAllowed;
    117     if (!contentOverflows)
     143    auto letContentOverflow = lineStatus.lineIsEmpty || !isWrappingAllowed;
     144    if (!letContentOverflow)
    118145        return { Result::Action::Push, IsEndOfLine::Yes, { } };
    119146    return { Result::Action::Keep, isWrappingAllowed ? IsEndOfLine::Yes : IsEndOfLine::No, { } };
     
    149176            // When the first span computes longer than the available space, by the time we get to the second span, the adjusted available space becomes negative.
    150177            auto adjustedAvailableWidth = std::max<InlineLayoutUnit>(0, lineStatus.availableWidth - accumulatedRunWidth);
    151              if (auto partialRun = tryBreakingTextRun(run, adjustedAvailableWidth, lineStatus.lineIsEmpty)) {
     178            if (auto partialRun = tryBreakingTextRun(run, adjustedAvailableWidth)) {
    152179                 if (partialRun->length)
    153180                     return WrappedTextContent { index, false, partialRun };
     
    170197        if (isContentSplitAllowed(run)) {
    171198            ASSERT(run.inlineItem.isText());
    172             if (auto partialRun = tryBreakingTextRun(run, maxInlineLayoutUnit(), lineStatus.lineIsEmpty)) {
     199            if (auto partialRun = tryBreakingTextRun(run, maxInlineLayoutUnit())) {
    173200                 // We know this run fits, so if wrapping is allowed on the run, it should return a non-empty left-side.
    174201                 ASSERT(partialRun->length);
     
    181208}
    182209
    183 LineBreaker::WordBreakRule LineBreaker::wordBreakBehavior(const RenderStyle& style, bool lineIsEmpty) const
     210LineBreaker::WordBreakRule LineBreaker::wordBreakBehavior(const RenderStyle& style) const
    184211{
    185212    // Disregard any prohibition against line breaks mandated by the word-break property.
     
    195222    // For compatibility with legacy content, the word-break property also supports a deprecated break-word keyword.
    196223    // 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.
    197     if (style.wordBreak() == WordBreak::BreakWord && lineIsEmpty)
     224    if (style.wordBreak() == WordBreak::BreakWord && !m_lastWrapOpportunity)
    198225        return WordBreakRule::AtArbitraryPosition;
    199226    // 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.
    200     if (style.overflowWrap() == OverflowWrap::Break && lineIsEmpty)
     227    if (style.overflowWrap() == OverflowWrap::Break && !m_lastWrapOpportunity)
    201228        return WordBreakRule::AtArbitraryPosition;
    202229
     
    207234}
    208235
    209 Optional<LineBreaker::PartialRun> LineBreaker::tryBreakingTextRun(const Run& overflowRun, InlineLayoutUnit availableWidth, bool lineIsEmpty) const
     236Optional<LineBreaker::PartialRun> LineBreaker::tryBreakingTextRun(const Run& overflowRun, InlineLayoutUnit availableWidth) const
    210237{
    211238    ASSERT(overflowRun.inlineItem.isText());
     
    214241    auto findLastBreakablePosition = availableWidth == maxInlineLayoutUnit();
    215242
    216     auto breakRule = wordBreakBehavior(style, lineIsEmpty);
     243    auto breakRule = wordBreakBehavior(style);
    217244    if (breakRule == WordBreakRule::AtArbitraryPosition) {
    218245        if (findLastBreakablePosition) {
     
    498525}
    499526
     527Optional<size_t> LineBreaker::ContinousContent::lastWrapOpportunityIndex() const
     528{
     529    // <span style="white-space: pre">no_wrap</span><span>yes_wrap</span><span style="white-space: pre">no_wrap</span>.
     530    // [container start][no_wrap][container end][container start][yes_wrap][container end][container start][no_wrap][container end]
     531    // Return #5 as the index where this content can wrap at last.
     532    for (auto index = m_runs.size(); index--;) {
     533        if (isWrappingAllowed(m_runs[index].inlineItem.style()))
     534            return index;
     535    }
     536    return { };
     537}
     538
    500539void LineBreaker::ContinousContent::TrailingCollapsibleContent::reset()
    501540{
     
    504543}
    505544
    506 
    507545}
    508546}
  • trunk/Source/WebCore/layout/inlineformatting/InlineLineBreaker.h

    r253924 r253928  
    105105        bool hasTrailingCollapsibleContent() const { return !!m_trailingCollapsibleContent.width; }
    106106        bool isTrailingContentFullyCollapsible() const { return m_trailingCollapsibleContent.isFullyCollapsible; }
     107        Optional<size_t> lastWrapOpportunityIndex() const;
    107108
    108109        Optional<unsigned> firstTextRunIndex() const;
     
    127128    };
    128129    Optional<WrappedTextContent> wrapTextContent(const RunList&, const LineStatus&) const;
    129     Optional<PartialRun> tryBreakingTextRun(const Run& overflowRun, InlineLayoutUnit availableWidth, bool lineIsEmpty) const;
     130    Result tryWrappingInlineContent(const ContinousContent&, const LineStatus&) const;
     131    Optional<PartialRun> tryBreakingTextRun(const Run& overflowRun, InlineLayoutUnit availableWidth) const;
    130132
    131133    enum class WordBreakRule {
     
    134136        OnlyHyphenationAllowed
    135137    };
    136     WordBreakRule wordBreakBehavior(const RenderStyle&, bool lineIsEmpty) const;
     138    WordBreakRule wordBreakBehavior(const RenderStyle&) const;
    137139    bool shouldKeepEndOfLineWhitespace(const ContinousContent&) const;
    138140    bool isContentWrappingAllowed(const ContinousContent&) const;
    139141
    140142    bool n_hyphenationIsDisabled { false };
     143    const InlineItem* m_lastWrapOpportunity { nullptr };
    141144};
    142145
Note: See TracChangeset for help on using the changeset viewer.