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

Changeset 246114 in webkit


Ignore:
Timestamp:
Jun 5, 2019, 10:34:20 AM (7 years ago)
Author:
Alan Bujtas
Message:

[LFC][IFC] LineLayout::placeInlineItems should not apply float contraint.
https://bugs.webkit.org/show_bug.cgi?id=198565
<rdar://problem/51440718>

Reviewed by Antti Koivisto.

This patch moves float constraint handling from placeInlineItems() to LineLayout::layout().
When placeInlineItems() is called by the preferred width computation, intruding floats should be ignored
since they don't constrain the "min/max lines".

  • layout/inlineformatting/InlineFormattingContext.h:
  • layout/inlineformatting/InlineFormattingContextLineLayout.cpp:

(WebCore::Layout::InlineFormattingContext::LineLayout::LineInput::HorizontalConstraint::HorizontalConstraint):
(WebCore::Layout::InlineFormattingContext::LineLayout::LineInput::LineInput):
(WebCore::Layout::InlineFormattingContext::LineLayout::placeInlineItems const):
(WebCore::Layout::InlineFormattingContext::LineLayout::layout const):
(WebCore::Layout::constructLine): Deleted.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r246108 r246114  
     12019-06-05  Zalan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] LineLayout::placeInlineItems should not apply float contraint.
     4        https://bugs.webkit.org/show_bug.cgi?id=198565
     5        <rdar://problem/51440718>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        This patch moves float constraint handling from placeInlineItems() to LineLayout::layout().
     10        When placeInlineItems() is called by the preferred width computation, intruding floats should be ignored
     11        since they don't constrain the "min/max lines".
     12
     13        * layout/inlineformatting/InlineFormattingContext.h:
     14        * layout/inlineformatting/InlineFormattingContextLineLayout.cpp:
     15        (WebCore::Layout::InlineFormattingContext::LineLayout::LineInput::HorizontalConstraint::HorizontalConstraint):
     16        (WebCore::Layout::InlineFormattingContext::LineLayout::LineInput::LineInput):
     17        (WebCore::Layout::InlineFormattingContext::LineLayout::placeInlineItems const):
     18        (WebCore::Layout::InlineFormattingContext::LineLayout::layout const):
     19        (WebCore::Layout::constructLine): Deleted.
     20
    1212019-06-05  Truitt Savell  <tsavell@apple.com>
    222
  • trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h

    r246067 r246114  
    6767
    6868        struct LineInput {
    69             LineInput(LayoutUnit logicalTop, LayoutUnit availableLogicalWidth, unsigned firstInlineItemIndex, const InlineItems&);
     69            LineInput(LayoutPoint logicalTopLeft, LayoutUnit availableLogicalWidth, unsigned firstInlineItemIndex, const InlineItems&);
     70            struct HorizontalConstraint {
     71                HorizontalConstraint(LayoutPoint logicalTopLeft, LayoutUnit availableLogicalWidth);
    7072
    71             LayoutUnit logicalTop;
    72             LayoutUnit availableLogicalWidth;
     73                LayoutPoint logicalTopLeft;
     74                LayoutUnit availableLogicalWidth;
     75            };
     76            HorizontalConstraint horizontalConstraint;
    7377            unsigned firstInlineItemIndex { 0 };
    7478            const InlineItems& inlineItems;
  • trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp

    r246105 r246114  
    7373}
    7474
    75 InlineFormattingContext::LineLayout::LineInput::LineInput(LayoutUnit logicalTop, LayoutUnit availableLogicalWidth, unsigned firstInlineItemIndex, const InlineItems& inlineItems)
    76     : logicalTop(logicalTop)
     75InlineFormattingContext::LineLayout::LineInput::HorizontalConstraint::HorizontalConstraint(LayoutPoint logicalTopLeft, LayoutUnit availableLogicalWidth)
     76    : logicalTopLeft(logicalTopLeft)
    7777    , availableLogicalWidth(availableLogicalWidth)
     78{
     79}
     80
     81InlineFormattingContext::LineLayout::LineInput::LineInput(LayoutPoint logicalTopLeft, LayoutUnit availableLogicalWidth, unsigned firstInlineItemIndex, const InlineItems& inlineItems)
     82    : horizontalConstraint(logicalTopLeft, availableLogicalWidth)
    7883    , firstInlineItemIndex(firstInlineItemIndex)
    7984    , inlineItems(inlineItems)
     
    143148}
    144149
    145 static std::unique_ptr<Line> constructLine(const LayoutState& layoutState, const FloatingState& floatingState, const Box& formattingRoot,
    146     LayoutUnit lineLogicalTop, LayoutUnit availableWidth)
    147 {
    148     auto& formattingRootDisplayBox = layoutState.displayBoxForLayoutBox(formattingRoot);
     150InlineFormattingContext::LineLayout::LineContent InlineFormattingContext::LineLayout::placeInlineItems(const LineInput& lineInput) const
     151{
     152    auto mimimumLineHeight = m_formattingRoot.style().computedLineHeight();
     153    auto baselineOffset = Line::halfLeadingMetrics(m_formattingRoot.style().fontMetrics(), mimimumLineHeight).height;
     154    auto line = Line { layoutState(), lineInput.horizontalConstraint.logicalTopLeft, lineInput.horizontalConstraint.availableLogicalWidth, mimimumLineHeight, baselineOffset };
     155
     156    Vector<WeakPtr<InlineItem>> floats;
     157    unsigned committedInlineItemCount = 0;
     158
     159    UncommittedContent uncommittedContent;
     160    auto commitPendingContent = [&] {
     161        if (uncommittedContent.isEmpty())
     162            return;
     163        committedInlineItemCount += uncommittedContent.size();
     164        for (auto& uncommittedRun : uncommittedContent.runs()) {
     165            auto& inlineItem = uncommittedRun.inlineItem;
     166            if (inlineItem.isHardLineBreak())
     167                line.appendHardLineBreak(inlineItem);
     168            else if (is<InlineTextItem>(inlineItem))
     169                line.appendTextContent(downcast<InlineTextItem>(inlineItem), uncommittedRun.size);
     170            else if (inlineItem.isContainerStart())
     171                line.appendInlineContainerStart(inlineItem, uncommittedRun.size);
     172            else if (inlineItem.isContainerEnd())
     173                line.appendInlineContainerEnd(inlineItem, uncommittedRun.size);
     174            else if (inlineItem.layoutBox().isReplaced())
     175                line.appendReplacedInlineBox(inlineItem, uncommittedRun.size);
     176            else
     177                line.appendNonReplacedInlineBox(inlineItem, uncommittedRun.size);
     178        }
     179        uncommittedContent.reset();
     180    };
     181
     182    auto closeLine = [&] {
     183        // This might change at some point.
     184        ASSERT(committedInlineItemCount);
     185        return LineContent { lineInput.firstInlineItemIndex + (committedInlineItemCount - 1), WTFMove(floats), line.close() };
     186    };
     187    LineBreaker lineBreaker;
     188    // Iterate through the inline content and place the inline boxes on the current line.
     189    for (auto inlineItemIndex = lineInput.firstInlineItemIndex; inlineItemIndex < lineInput.inlineItems.size(); ++inlineItemIndex) {
     190        auto availableWidth = line.availableWidth() - uncommittedContent.width();
     191        auto currentLogicalRight = line.contentLogicalRight() + uncommittedContent.width();
     192        auto& inlineItem = lineInput.inlineItems[inlineItemIndex];
     193        auto itemLogicalWidth = inlineItemWidth(layoutState(), *inlineItem, currentLogicalRight);
     194
     195        // FIXME: Ensure LineContext::trimmableWidth includes uncommitted content if needed.
     196        auto breakingContext = lineBreaker.breakingContext(*inlineItem, itemLogicalWidth, { availableWidth, currentLogicalRight, line.trailingTrimmableWidth(), !line.hasContent() });
     197        if (breakingContext.isAtBreakingOpportunity)
     198            commitPendingContent();
     199
     200        // Content does not fit the current line.
     201        if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Wrap)
     202            return closeLine();
     203
     204        // Partial content stays on the current line.
     205        if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Split) {
     206            ASSERT(inlineItem->isText());
     207
     208            ASSERT_NOT_IMPLEMENTED_YET();
     209            return closeLine();
     210        }
     211
     212        ASSERT(breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Keep);
     213        if (inlineItem->isFloat()) {
     214            auto& floatBox = inlineItem->layoutBox();
     215            ASSERT(layoutState().hasDisplayBox(floatBox));
     216            // Shrink availble space for current line and move existing inline runs.
     217            auto floatBoxWidth = layoutState().displayBoxForLayoutBox(floatBox).marginBoxWidth();
     218            floatBox.isLeftFloatingPositioned() ? line.moveLogicalLeft(floatBoxWidth) : line.moveLogicalRight(floatBoxWidth);
     219            floats.append(makeWeakPtr(*inlineItem));
     220            ++committedInlineItemCount;
     221            continue;
     222        }
     223        if (inlineItem->isHardLineBreak()) {
     224            uncommittedContent.add(*inlineItem, { itemLogicalWidth, inlineItemHeight(layoutState(), *inlineItem) });
     225            commitPendingContent();
     226            return closeLine();
     227        }
     228
     229        uncommittedContent.add(*inlineItem, { itemLogicalWidth, inlineItemHeight(layoutState(), *inlineItem) });
     230        if (breakingContext.isAtBreakingOpportunity)
     231            commitPendingContent();
     232    }
     233    commitPendingContent();
     234    return closeLine();
     235}
     236
     237void InlineFormattingContext::LineLayout::layout(LayoutUnit widthConstraint) const
     238{
     239    ASSERT(!m_formattingState.inlineItems().isEmpty());
     240
     241    auto& formattingRootDisplayBox = layoutState().displayBoxForLayoutBox(m_formattingRoot);
     242    auto lineLogicalTop = formattingRootDisplayBox.contentBoxTop();
    149243    auto lineLogicalLeft = formattingRootDisplayBox.contentBoxLeft();
    150244
    151     // Check for intruding floats and adjust logical left/available width for this line accordingly.
    152     if (!floatingState.isEmpty()) {
    153         auto floatConstraints = floatingState.constraints({ lineLogicalTop }, formattingRoot);
     245    auto applyFloatConstraint = [&](auto& lineHorizontalConstraint) {
     246        // Check for intruding floats and adjust logical left/available width for this line accordingly.
     247        if (m_floatingState.isEmpty())
     248            return;
     249        auto availableWidth = lineHorizontalConstraint.availableLogicalWidth;
     250        auto lineLogicalLeft = lineHorizontalConstraint.logicalTopLeft.x();
     251        auto floatConstraints = m_floatingState.constraints({ lineLogicalTop }, m_formattingRoot);
    154252        // Check if these constraints actually put limitation on the line.
    155253        if (floatConstraints.left && *floatConstraints.left <= formattingRootDisplayBox.contentBoxLeft())
     
    171269            availableWidth = *floatConstraints.right - lineLogicalLeft;
    172270        }
    173     }
    174 
    175     auto& formattingRootStyle = formattingRoot.style();
    176     auto mimimumLineHeight = formattingRootStyle.computedLineHeight();
    177     auto baselineOffset = Line::halfLeadingMetrics(formattingRootStyle.fontMetrics(), mimimumLineHeight).height;
    178     return std::make_unique<Line>(layoutState, LayoutPoint { lineLogicalLeft, lineLogicalTop }, availableWidth, mimimumLineHeight, baselineOffset);
    179 }
    180 
    181 InlineFormattingContext::LineLayout::LineContent InlineFormattingContext::LineLayout::placeInlineItems(const LineInput& lineInput) const
    182 {
    183     auto line = constructLine(layoutState(), m_floatingState, m_formattingRoot, lineInput.logicalTop, lineInput.availableLogicalWidth);
    184     Vector<WeakPtr<InlineItem>> floats;
    185     unsigned committedInlineItemCount = 0;
    186 
    187     UncommittedContent uncommittedContent;
    188     auto commitPendingContent = [&] {
    189         if (uncommittedContent.isEmpty())
    190             return;
    191         committedInlineItemCount += uncommittedContent.size();
    192         for (auto& uncommittedRun : uncommittedContent.runs()) {
    193             auto& inlineItem = uncommittedRun.inlineItem;
    194             if (inlineItem.isHardLineBreak())
    195                 line->appendHardLineBreak(inlineItem);
    196             else if (is<InlineTextItem>(inlineItem))
    197                 line->appendTextContent(downcast<InlineTextItem>(inlineItem), uncommittedRun.size);
    198             else if (inlineItem.isContainerStart())
    199                 line->appendInlineContainerStart(inlineItem, uncommittedRun.size);
    200             else if (inlineItem.isContainerEnd())
    201                 line->appendInlineContainerEnd(inlineItem, uncommittedRun.size);
    202             else if (inlineItem.layoutBox().isReplaced())
    203                 line->appendReplacedInlineBox(inlineItem, uncommittedRun.size);
    204             else
    205                 line->appendNonReplacedInlineBox(inlineItem, uncommittedRun.size);
    206         }
    207         uncommittedContent.reset();
     271        lineHorizontalConstraint.availableLogicalWidth = availableWidth;
     272        lineHorizontalConstraint.logicalTopLeft.setX(lineLogicalLeft);
    208273    };
    209274
    210     auto closeLine = [&] {
    211         // This might change at some point.
    212         ASSERT(committedInlineItemCount);
    213         return LineContent { lineInput.firstInlineItemIndex + (committedInlineItemCount - 1), WTFMove(floats), line->close() };
    214     };
    215     LineBreaker lineBreaker;
    216     // Iterate through the inline content and place the inline boxes on the current line.
    217     for (auto inlineItemIndex = lineInput.firstInlineItemIndex; inlineItemIndex < lineInput.inlineItems.size(); ++inlineItemIndex) {
    218         auto availableWidth = line->availableWidth() - uncommittedContent.width();
    219         auto currentLogicalRight = line->contentLogicalRight() + uncommittedContent.width();
    220         auto& inlineItem = lineInput.inlineItems[inlineItemIndex];
    221         auto itemLogicalWidth = inlineItemWidth(layoutState(), *inlineItem, currentLogicalRight);
    222 
    223         // FIXME: Ensure LineContext::trimmableWidth includes uncommitted content if needed.
    224         auto breakingContext = lineBreaker.breakingContext(*inlineItem, itemLogicalWidth, { availableWidth, currentLogicalRight, line->trailingTrimmableWidth(), !line->hasContent() });
    225         if (breakingContext.isAtBreakingOpportunity)
    226             commitPendingContent();
    227 
    228         // Content does not fit the current line.
    229         if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Wrap)
    230             return closeLine();
    231 
    232         // Partial content stays on the current line.
    233         if (breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Split) {
    234             ASSERT(inlineItem->isText());
    235 
    236             ASSERT_NOT_IMPLEMENTED_YET();
    237             return closeLine();
    238         }
    239 
    240         ASSERT(breakingContext.breakingBehavior == LineBreaker::BreakingBehavior::Keep);
    241         if (inlineItem->isFloat()) {
    242             auto& floatBox = inlineItem->layoutBox();
    243             ASSERT(layoutState().hasDisplayBox(floatBox));
    244             // Shrink availble space for current line and move existing inline runs.
    245             auto floatBoxWidth = layoutState().displayBoxForLayoutBox(floatBox).marginBoxWidth();
    246             floatBox.isLeftFloatingPositioned() ? line->moveLogicalLeft(floatBoxWidth) : line->moveLogicalRight(floatBoxWidth);
    247             floats.append(makeWeakPtr(*inlineItem));
    248             ++committedInlineItemCount;
    249             continue;
    250         }
    251         if (inlineItem->isHardLineBreak()) {
    252             uncommittedContent.add(*inlineItem, { itemLogicalWidth, inlineItemHeight(layoutState(), *inlineItem) });
    253             commitPendingContent();
    254             return closeLine();
    255         }
    256 
    257         uncommittedContent.add(*inlineItem, { itemLogicalWidth, inlineItemHeight(layoutState(), *inlineItem) });
    258         if (breakingContext.isAtBreakingOpportunity)
    259             commitPendingContent();
    260     }
    261     commitPendingContent();
    262     return closeLine();
    263 }
    264 
    265 void InlineFormattingContext::LineLayout::layout(LayoutUnit widthConstraint) const
    266 {
    267     ASSERT(!m_formattingState.inlineItems().isEmpty());
    268 
    269     auto lineLogicalTop = layoutState().displayBoxForLayoutBox(m_formattingRoot).contentBoxTop();
    270275    auto& inlineItems = m_formattingState.inlineItems();
    271276    unsigned currentInlineItemIndex = 0;
    272277    while (currentInlineItemIndex < inlineItems.size()) {
    273         auto lineContent = placeInlineItems({ lineLogicalTop, widthConstraint, currentInlineItemIndex, inlineItems });
     278        auto lineInput = LineInput { { lineLogicalLeft, lineLogicalTop }, widthConstraint, currentInlineItemIndex, inlineItems };
     279        applyFloatConstraint(lineInput.horizontalConstraint);
     280        auto lineContent = placeInlineItems(lineInput);
    274281        createDisplayRuns(*lineContent.runs, lineContent.floats, widthConstraint);
    275282        // We should always put at least one run on the line atm. This might change later on though.
Note: See TracChangeset for help on using the changeset viewer.