Changeset 256507 in webkit


Ignore:
Timestamp:
Feb 13, 2020 8:22:10 AM (4 years ago)
Author:
Alan Bujtas
Message:

[LFC][IFC] LineCandidateContent can have only one float item
https://bugs.webkit.org/show_bug.cgi?id=207681
<rdar://problem/59413044>

Reviewed by Antti Koivisto.

Floats should not be considered as inline content. They shrink the available space but we never
add them to the line. This patch decouples InlineContent and candidate floats. Also there can only be
one float box per candidate content (since there's always a soft wrap opportunity before/after the float box).

  • layout/inlineformatting/LineLayoutContext.cpp:

(WebCore::Layout::LineCandidate::InlineContent::runs const):
(WebCore::Layout::LineCandidate::InlineContent::logicalWidth const):
(WebCore::Layout::LineCandidate::InlineContent::trailingLineBreak const):
(WebCore::Layout::LineCandidate::InlineContent::appendLineBreak):
(WebCore::Layout::LineCandidate::InlineContent::setTrailingLineBreak):
(WebCore::Layout::LineCandidate::InlineContent::appendInlineItem):
(WebCore::Layout::LineCandidate::reset):
(WebCore::Layout::LineCandidate::InlineContent::reset):
(WebCore::Layout::LineLayoutContext::layoutLine):
(WebCore::Layout::LineLayoutContext::nextContentForLine):
(WebCore::Layout::LineLayoutContext::tryAddingFloatItem):
(WebCore::Layout::LineLayoutContext::tryAddingInlineItems):
(WebCore::Layout::LineCandidateContent::appendLineBreak): Deleted.
(WebCore::Layout::LineCandidateContent::appendFloat): Deleted.
(WebCore::Layout::LineCandidateContent::hasIntrusiveFloats const): Deleted.
(WebCore::Layout::LineCandidateContent::inlineRuns const): Deleted.
(WebCore::Layout::LineCandidateContent::inlineContentLogicalWidth const): Deleted.
(WebCore::Layout::LineCandidateContent::floats const): Deleted.
(WebCore::Layout::LineCandidateContent::trailingLineBreak const): Deleted.
(WebCore::Layout::LineCandidateContent::setTrailingLineBreak): Deleted.
(WebCore::Layout::LineCandidateContent::appendInlineContent): Deleted.
(WebCore::Layout::LineCandidateContent::reset): Deleted.
(WebCore::Layout::LineLayoutContext::tryAddingFloatItems): Deleted.

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

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r256505 r256507  
     12020-02-13  Zalan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] LineCandidateContent can have only one float item
     4        https://bugs.webkit.org/show_bug.cgi?id=207681
     5        <rdar://problem/59413044>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Floats should not be considered as inline content. They shrink the available space but we never
     10        add them to the line. This patch decouples InlineContent and candidate floats. Also there can only be
     11        one float box per candidate content (since there's always a soft wrap opportunity before/after the float box).
     12
     13        * layout/inlineformatting/LineLayoutContext.cpp:
     14        (WebCore::Layout::LineCandidate::InlineContent::runs const):
     15        (WebCore::Layout::LineCandidate::InlineContent::logicalWidth const):
     16        (WebCore::Layout::LineCandidate::InlineContent::trailingLineBreak const):
     17        (WebCore::Layout::LineCandidate::InlineContent::appendLineBreak):
     18        (WebCore::Layout::LineCandidate::InlineContent::setTrailingLineBreak):
     19        (WebCore::Layout::LineCandidate::InlineContent::appendInlineItem):
     20        (WebCore::Layout::LineCandidate::reset):
     21        (WebCore::Layout::LineCandidate::InlineContent::reset):
     22        (WebCore::Layout::LineLayoutContext::layoutLine):
     23        (WebCore::Layout::LineLayoutContext::nextContentForLine):
     24        (WebCore::Layout::LineLayoutContext::tryAddingFloatItem):
     25        (WebCore::Layout::LineLayoutContext::tryAddingInlineItems):
     26        (WebCore::Layout::LineCandidateContent::appendLineBreak): Deleted.
     27        (WebCore::Layout::LineCandidateContent::appendFloat): Deleted.
     28        (WebCore::Layout::LineCandidateContent::hasIntrusiveFloats const): Deleted.
     29        (WebCore::Layout::LineCandidateContent::inlineRuns const): Deleted.
     30        (WebCore::Layout::LineCandidateContent::inlineContentLogicalWidth const): Deleted.
     31        (WebCore::Layout::LineCandidateContent::floats const): Deleted.
     32        (WebCore::Layout::LineCandidateContent::trailingLineBreak const): Deleted.
     33        (WebCore::Layout::LineCandidateContent::setTrailingLineBreak): Deleted.
     34        (WebCore::Layout::LineCandidateContent::appendInlineContent): Deleted.
     35        (WebCore::Layout::LineCandidateContent::reset): Deleted.
     36        (WebCore::Layout::LineLayoutContext::tryAddingFloatItems): Deleted.
     37        * layout/inlineformatting/LineLayoutContext.h:
     38
    1392020-02-13  Chris Lord  <clord@igalia.com>
    240
  • trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.cpp

    r256499 r256507  
    172172}
    173173
    174 struct LineCandidateContent {
    175     void appendInlineContent(const InlineItem&, InlineLayoutUnit logicalWidth);
    176     void appendLineBreak(const InlineItem& inlineItem) { setTrailingLineBreak(inlineItem); }
    177     void appendFloat(const InlineItem& inlineItem) { m_floats.append(&inlineItem); }
    178 
    179     bool hasIntrusiveFloats() const { return !m_floats.isEmpty(); }
    180     const LineBreaker::RunList& inlineRuns() const { return m_inlineRuns; }
    181     InlineLayoutUnit inlineContentLogicalWidth() const { return m_inlineContentLogicalWidth; }
    182     const LineLayoutContext::FloatList& floats() const { return m_floats; }
    183 
    184     const InlineItem* trailingLineBreak() const { return m_trailingLineBreak; }
    185 
     174struct LineCandidate {
    186175    void reset();
    187176
    188 private:
    189     void setTrailingLineBreak(const InlineItem& lineBreakItem) { m_trailingLineBreak = &lineBreakItem; }
    190 
    191     InlineLayoutUnit m_inlineContentLogicalWidth { 0 };
    192     LineBreaker::RunList m_inlineRuns;
    193     LineLayoutContext::FloatList m_floats;
    194     const InlineItem* m_trailingLineBreak { nullptr };
     177    struct InlineContent {
     178        const LineBreaker::RunList& runs() const { return m_inlineRuns; }
     179        InlineLayoutUnit logicalWidth() const { return m_LogicalWidth; }
     180        const InlineItem* trailingLineBreak() const { return m_trailingLineBreak; }
     181
     182        void appendInlineItem(const InlineItem&, InlineLayoutUnit logicalWidth);
     183        void appendLineBreak(const InlineItem& inlineItem) { setTrailingLineBreak(inlineItem); }
     184        void reset();
     185
     186    private:
     187        void setTrailingLineBreak(const InlineItem& lineBreakItem) { m_trailingLineBreak = &lineBreakItem; }
     188
     189        InlineLayoutUnit m_LogicalWidth { 0 };
     190        LineBreaker::RunList m_inlineRuns;
     191        const InlineItem* m_trailingLineBreak { nullptr };
     192    };
     193    // Candidate content is either a collection of inline items or a float box.
     194    InlineContent inlineContent;
     195    const InlineItem* floatItem { nullptr };
    195196};
    196197
    197 inline void LineCandidateContent::appendInlineContent(const InlineItem& inlineItem, InlineLayoutUnit logicalWidth)
    198 {
    199     m_inlineContentLogicalWidth += logicalWidth;
     198inline void LineCandidate::InlineContent::appendInlineItem(const InlineItem& inlineItem, InlineLayoutUnit logicalWidth)
     199{
     200    m_LogicalWidth += logicalWidth;
    200201    m_inlineRuns.append({ inlineItem, logicalWidth });
    201202}
    202203
    203 inline void LineCandidateContent::reset()
    204 {
    205     m_inlineContentLogicalWidth = 0;
     204inline void LineCandidate::reset()
     205{
     206    floatItem = { };
     207    inlineContent.reset();
     208}
     209
     210inline void LineCandidate::InlineContent::reset()
     211{
     212    m_LogicalWidth = 0;
    206213    m_inlineRuns.clear();
    207     m_floats.clear();
    208214    m_trailingLineBreak = nullptr;
    209215}
     
    260266    auto currentItemIndex = layoutRange.start;
    261267    unsigned committedInlineItemCount = 0;
    262     auto candidateContent = LineCandidateContent { };
     268    auto lineCandidate = LineCandidate { };
    263269    while (currentItemIndex < layoutRange.end) {
    264270        // 1. Collect the set of runs that we can commit to the line as one entity e.g. <span>text_and_span_start_span_end</span>.
     
    266272        // 3. Check if the content fits the line and commit the content accordingly (full, partial or not commit at all).
    267273        // 4. Return if we are at the end of the line either by not being able to fit more content or because of an explicit line break.
    268         nextContentForLine(candidateContent, currentItemIndex, layoutRange, partialLeadingContentLength, line.lineBox().logicalWidth());
    269         if (candidateContent.hasIntrusiveFloats()) {
    270             // Add floats first because they shrink the available horizontal space for the rest of the content.
    271             auto result = tryAddingFloatItems(line, candidateContent.floats());
     274        nextContentForLine(lineCandidate, currentItemIndex, layoutRange, partialLeadingContentLength, line.lineBox().logicalWidth());
     275        if (lineCandidate.floatItem) {
     276            // Floats shrink the available horizontal space for the rest of the content, but they are not added on the line.
     277            auto result = tryAddingFloatItem(line, *lineCandidate.floatItem);
    272278            committedInlineItemCount += result.committedCount;
    273279            if (result.isEndOfLine == LineBreaker::IsEndOfLine::Yes) {
    274                 // Floats take up all the horizontal space.
     280                // This float takes up all the horizontal space.
    275281                return close(line, layoutRange, committedInlineItemCount, { });
    276282            }
    277         }
    278         if (!candidateContent.inlineRuns().isEmpty()) {
    279             // Now check if we can put this content on the current line.
    280             auto result = tryAddingInlineItems(lineBreaker, line, candidateContent);
    281             if (result.revertTo) {
    282                 ASSERT(!result.committedCount);
    283                 ASSERT(result.isEndOfLine == LineBreaker::IsEndOfLine::Yes);
    284                 // An earlier line wrapping opportunity turned out to be the final breaking position.
    285                 rebuildLineForRevert(line, *result.revertTo, layoutRange);
     283            ASSERT(lineCandidate.inlineContent.runs().isEmpty());
     284        } else {
     285            auto& inlineContent = lineCandidate.inlineContent;
     286            if (!inlineContent.runs().isEmpty()) {
     287                // 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;
     296                if (result.isEndOfLine == LineBreaker::IsEndOfLine::Yes) {
     297                    // We can't place any more items on the current line.
     298                    return close(line, layoutRange, committedInlineItemCount, result.partialContent);
     299                }
     300            } else if (auto* trailingLineBreak = inlineContent.trailingLineBreak()) {
     301                line.append(*trailingLineBreak, 0);
     302                return close(line, layoutRange, ++committedInlineItemCount, { });
    286303            }
    287             committedInlineItemCount += result.committedCount;
    288             if (result.isEndOfLine == LineBreaker::IsEndOfLine::Yes) {
    289                 // We can't place any more items on the current line.
    290                 return close(line, layoutRange, committedInlineItemCount, result.partialContent);
    291             }
    292         } else if (auto* trailingLineBreak = candidateContent.trailingLineBreak()) {
    293             line.append(*trailingLineBreak, 0);
    294             return close(line, layoutRange, ++committedInlineItemCount, { });
    295304        }
    296305        currentItemIndex = layoutRange.start + committedInlineItemCount;
     
    331340}
    332341
    333 void LineLayoutContext::nextContentForLine(LineCandidateContent& candidateContent, unsigned currentInlineItemIndex, const InlineItemRange layoutRange, Optional<unsigned> partialLeadingContentLength, InlineLayoutUnit currentLogicalRight)
     342void LineLayoutContext::nextContentForLine(LineCandidate& lineCandidate, unsigned currentInlineItemIndex, const InlineItemRange layoutRange, Optional<unsigned> partialLeadingContentLength, InlineLayoutUnit currentLogicalRight)
    334343{
    335344    ASSERT(currentInlineItemIndex < layoutRange.end);
    336     candidateContent.reset();
     345    lineCandidate.reset();
    337346    // 1. Simply add any overflow content from the previous line to the candidate content. It's always a text content.
    338347    // 2. Find the next soft wrap position or explicit line break.
     
    347356        m_partialLeadingTextItem = downcast<InlineTextItem>(m_inlineItems[currentInlineItemIndex]).right(*partialLeadingContentLength);
    348357        auto itemWidth = inlineItemWidth(*m_partialLeadingTextItem, currentLogicalRight);
    349         candidateContent.appendInlineContent(*m_partialLeadingTextItem, itemWidth);
     358        lineCandidate.inlineContent.appendInlineItem(*m_partialLeadingTextItem, itemWidth);
    350359        currentLogicalRight += itemWidth;
    351360        ++currentInlineItemIndex;
     
    355364        auto& inlineItem = m_inlineItems[index];
    356365        if (inlineItem.isText() || inlineItem.isContainerStart() || inlineItem.isContainerEnd()) {
     366            ASSERT(!lineCandidate.floatItem);
    357367            auto inlineItenmWidth = inlineItemWidth(inlineItem, currentLogicalRight);
    358             candidateContent.appendInlineContent(inlineItem, inlineItenmWidth);
     368            lineCandidate.inlineContent.appendInlineItem(inlineItem, inlineItenmWidth);
    359369            currentLogicalRight += inlineItenmWidth;
    360370            continue;
     
    363373            // Floats are not part of the line context.
    364374            // FIXME: Check if their width should be added to currentLogicalRight.
    365             candidateContent.appendFloat(inlineItem);
     375            ASSERT(!lineCandidate.floatItem);
     376            ASSERT(lineCandidate.inlineContent.runs().isEmpty());
     377            lineCandidate.floatItem = &inlineItem;
    366378            continue;
    367379        }
    368380        if (inlineItem.isLineBreak()) {
    369             candidateContent.appendLineBreak(inlineItem);
     381            lineCandidate.inlineContent.appendLineBreak(inlineItem);
    370382            continue;
    371383        }
     
    374386}
    375387
    376 LineLayoutContext::Result LineLayoutContext::tryAddingFloatItems(LineBuilder& line, const FloatList& floats)
    377 {
    378     size_t committedFloatItemCount = 0;
    379     for (auto& floatItem : floats) {
    380         auto logicalWidth = inlineItemWidth(*floatItem, { });
    381 
    382         auto lineIsConsideredEmpty = line.isVisuallyEmpty() && !line.hasIntrusiveFloat();
    383         if (LineBreaker().shouldWrapFloatBox(logicalWidth, line.availableWidth() + line.trimmableTrailingWidth(), lineIsConsideredEmpty))
    384             return { LineBreaker::IsEndOfLine::Yes, committedFloatItemCount };
    385         // This float can sit on the current line.
    386         ++committedFloatItemCount;
    387         auto& floatBox = floatItem->layoutBox();
    388         // Shrink available space for current line and move existing inline runs.
    389         line.setHasIntrusiveFloat();
    390         if (floatBox.isLeftFloatingPositioned())
    391             line.moveLogicalLeft(logicalWidth);
    392         else
    393             line.moveLogicalRight(logicalWidth);
    394         m_floats.append(floatItem);
    395     }
    396     return { LineBreaker::IsEndOfLine::No, committedFloatItemCount };
    397 }
    398 
    399 LineLayoutContext::Result LineLayoutContext::tryAddingInlineItems(LineBreaker& lineBreaker, LineBuilder& line, const LineCandidateContent& candidateContent)
     388LineLayoutContext::Result LineLayoutContext::tryAddingFloatItem(LineBuilder& line, const InlineItem& floatItem)
     389{
     390    auto logicalWidth = inlineItemWidth(floatItem, { });
     391
     392    auto lineIsConsideredEmpty = line.isVisuallyEmpty() && !line.hasIntrusiveFloat();
     393    if (LineBreaker().shouldWrapFloatBox(logicalWidth, line.availableWidth() + line.trimmableTrailingWidth(), lineIsConsideredEmpty))
     394        return { LineBreaker::IsEndOfLine::Yes };
     395    // This float can sit on the current line.
     396    auto& floatBox = floatItem.layoutBox();
     397    // Shrink available space for current line and move existing inline runs.
     398    line.setHasIntrusiveFloat();
     399    if (floatBox.isLeftFloatingPositioned())
     400        line.moveLogicalLeft(logicalWidth);
     401    else
     402        line.moveLogicalRight(logicalWidth);
     403    m_floats.append(&floatItem);
     404    return { LineBreaker::IsEndOfLine::No, 1 };
     405}
     406
     407LineLayoutContext::Result LineLayoutContext::tryAddingInlineItems(LineBreaker& lineBreaker, LineBuilder& line, const LineCandidate& lineCandidate)
    400408{
    401409    auto shouldDisableHyphenation = [&] {
     
    410418        lineBreaker.setHyphenationDisabled();
    411419
    412     auto& candidateRuns = candidateContent.inlineRuns();
    413     auto result = lineBreaker.shouldWrapInlineContent(candidateRuns, candidateContent.inlineContentLogicalWidth(), lineStatus);
     420    auto& inlineContent = lineCandidate.inlineContent;
     421    auto& candidateRuns = inlineContent.runs();
     422    auto result = lineBreaker.shouldWrapInlineContent(candidateRuns, inlineContent.logicalWidth(), lineStatus);
    414423    if (result.action == LineBreaker::Result::Action::Keep) {
    415424        // This continuous content can be fully placed on the current line.
     
    417426            line.append(run.inlineItem, run.logicalWidth);
    418427        // Consume trailing line break as well.
    419         if (auto* lineBreakItem = candidateContent.trailingLineBreak()) {
     428        if (auto* lineBreakItem = inlineContent.trailingLineBreak()) {
    420429            line.append(*lineBreakItem, 0);
    421430            return { LineBreaker::IsEndOfLine::Yes, candidateRuns.size() + 1 };
  • trunk/Source/WebCore/layout/inlineformatting/LineLayoutContext.h

    r256499 r256507  
    3434namespace Layout {
    3535
    36 struct LineCandidateContent;
     36struct LineCandidate;
    3737
    3838class LineLayoutContext {
     
    5757    };
    5858    LineContent layoutLine(LineBuilder&, const InlineItemRange, Optional<unsigned> partialLeadingContentLength);
    59     using FloatList = Vector<const InlineItem*>;
    6059
    6160private:
    62     void nextContentForLine(LineCandidateContent&, unsigned inlineItemIndex, const InlineItemRange layoutRange, Optional<unsigned> overflowLength, InlineLayoutUnit currentLogicalRight);
     61    void nextContentForLine(LineCandidate&, unsigned inlineItemIndex, const InlineItemRange layoutRange, Optional<unsigned> overflowLength, InlineLayoutUnit currentLogicalRight);
    6362    struct Result {
    6463        LineBreaker::IsEndOfLine isEndOfLine { LineBreaker::IsEndOfLine::No };
     
    6766        const InlineItem* revertTo { nullptr };
    6867    };
    69     Result tryAddingFloatItems(LineBuilder&, const FloatList&);
    70     Result tryAddingInlineItems(LineBreaker&, LineBuilder&, const LineCandidateContent&);
     68    Result tryAddingFloatItem(LineBuilder&, const InlineItem& floatItem);
     69    Result tryAddingInlineItems(LineBreaker&, LineBuilder&, const LineCandidate&);
    7170    void rebuildLineForRevert(LineBuilder&, const InlineItem& revertTo, const InlineItemRange layoutRange);
    7271    void commitPartialContent(LineBuilder&, const LineBreaker::RunList&, const LineBreaker::Result::PartialTrailingContent&);
     
    8180    const ContainerBox& m_formattingContextRoot;
    8281    const InlineItems& m_inlineItems;
     82    using FloatList = Vector<const InlineItem*>;
    8383    FloatList m_floats;
    8484    Optional<InlineTextItem> m_partialLeadingTextItem;
Note: See TracChangeset for help on using the changeset viewer.