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

Changeset 286782 in webkit


Ignore:
Timestamp:
Dec 9, 2021, 9:10:03 AM (5 years ago)
Author:
Alan Bujtas
Message:

[LFC][IFC] Make collectInkOverflowForInlineBoxes propagate ink overflow using the display box list
https://bugs.webkit.org/show_bug.cgi?id=233950

Reviewed by Antti Koivisto.

This is in preparation for supporting ink overflow across bidi boundaries.

The current HashMap<const Box*, size_t> approach does not work when a layout box could
produce multiple inline box type of display boxes on the same line (at bidi boundaries).
Instead let's propagate ink overflow by traversing the display box list starting
at the end and bubble up the inflated ink overflow rect to the parent inline boxes.

  • layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:

(WebCore::Layout::InlineDisplayContentBuilder::build):
(WebCore::Layout::computeBoxShadowInkOverflow):
(WebCore::Layout::InlineDisplayContentBuilder::appendAtomicInlineLevelDisplayBox):
(WebCore::Layout::InlineDisplayContentBuilder::appendInlineBoxDisplayBox):
(WebCore::Layout::InlineDisplayContentBuilder::appendSpanningInlineBoxDisplayBox):
(WebCore::Layout::InlineDisplayContentBuilder::collectInkOverflowForInlineBoxes):
(WebCore::Layout::addBoxShadowInkOverflow): Deleted.

  • layout/formattingContexts/inline/InlineDisplayContentBuilder.h:
Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r286780 r286782  
     12021-12-09  Alan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] Make collectInkOverflowForInlineBoxes propagate ink overflow using the display box list
     4        https://bugs.webkit.org/show_bug.cgi?id=233950
     5
     6        Reviewed by Antti Koivisto.
     7
     8        This is in preparation for supporting ink overflow across bidi boundaries.
     9
     10        The current HashMap<const Box*, size_t> approach does not work when a layout box could
     11        produce multiple inline box type of display boxes on the same line (at bidi boundaries).
     12        Instead let's propagate ink overflow by traversing the display box list starting
     13        at the end and bubble up the inflated ink overflow rect to the parent inline boxes.
     14
     15        * layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:
     16        (WebCore::Layout::InlineDisplayContentBuilder::build):
     17        (WebCore::Layout::computeBoxShadowInkOverflow):
     18        (WebCore::Layout::InlineDisplayContentBuilder::appendAtomicInlineLevelDisplayBox):
     19        (WebCore::Layout::InlineDisplayContentBuilder::appendInlineBoxDisplayBox):
     20        (WebCore::Layout::InlineDisplayContentBuilder::appendSpanningInlineBoxDisplayBox):
     21        (WebCore::Layout::InlineDisplayContentBuilder::collectInkOverflowForInlineBoxes):
     22        (WebCore::Layout::addBoxShadowInkOverflow): Deleted.
     23        * layout/formattingContexts/inline/InlineDisplayContentBuilder.h:
     24
    1252021-12-09  Tyler Wilcock  <tyler_w@apple.com>
    226
  • trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp

    r286541 r286782  
    7575        processNonBidiContent(lineContent, lineBox, lineBoxLogicalRect.topLeft(), boxes);
    7676    processOverflownRunsForEllipsis(boxes, lineBoxLogicalRect.right());
    77     collectInkOverflowForInlineBoxes(lineBox, boxes);
     77    collectInkOverflowForInlineBoxes(boxes);
    7878    return boxes;
    7979}
    8080
    81 static inline void addBoxShadowInkOverflow(const RenderStyle& style, InlineRect& inkOverflow)
     81static inline bool computeBoxShadowInkOverflow(const RenderStyle& style, InlineRect& inkOverflow)
    8282{
    8383    auto topBoxShadow = LayoutUnit { };
     
    8888    auto rightBoxShadow = LayoutUnit { };
    8989    style.getBoxShadowInlineDirectionExtent(leftBoxShadow, rightBoxShadow);
     90    if (!topBoxShadow && !bottomBoxShadow && !leftBoxShadow && !rightBoxShadow)
     91        return false;
    9092    inkOverflow.inflate(InlineLayoutUnit { topBoxShadow }, InlineLayoutUnit { rightBoxShadow }, InlineLayoutUnit { bottomBoxShadow }, InlineLayoutUnit { leftBoxShadow });
     93    return true;
    9194}
    9295
     
    169172
    170173    auto& layoutBox = lineRun.layoutBox();
    171     // FIXME: Add ink overflow support for atomic inline level boxes (e.g. box shadow).
     174    auto inkOverflow = [&] {
     175        auto inkOverflow = borderBoxRect;
     176        computeBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow);
     177        // Atomic inline box contribute to their inline box parents ink overflow at all times (e.g. <span><img></span>).
     178        m_contentHasInkOverflow = m_contentHasInkOverflow || &layoutBox.parent() != &root();
     179        return inkOverflow;
     180    };
    172181    boxes.append({ m_lineIndex
    173182        , InlineDisplay::Box::Type::AtomicInlineLevelBox
     
    175184        , lineRun.bidiLevel()
    176185        , borderBoxRect
    177         , borderBoxRect
     186        , inkOverflow()
    178187        , lineRun.expansion()
    179188        , { } });
    180 
    181189    // Note that inline boxes are relative to the line and their top position can be negative.
    182190    // Atomic inline boxes are all set. Their margin/border/content box geometries are already computed. We just have to position them here.
    183     auto& boxGeometry = formattingState().boxGeometry(layoutBox);
    184     boxGeometry.setLogicalTopLeft(toLayoutPoint(borderBoxRect.topLeft()));
    185 
    186     auto adjustParentInlineBoxInkOverflow = [&] {
    187         auto& parentInlineBox = layoutBox.parent();
    188         if (&parentInlineBox == &root()) {
    189             // We don't collect ink overflow for the root inline box.
    190             return;
    191         }
    192         RELEASE_ASSERT(m_inlineBoxIndexMap.contains(&parentInlineBox));
    193 
    194         auto boxInkOverflow = borderBoxRect;
    195         addBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), boxInkOverflow);
    196         boxes[m_inlineBoxIndexMap.get(&parentInlineBox)].adjustInkOverflow(boxInkOverflow);
    197     };
    198     adjustParentInlineBoxInkOverflow();
     191    formattingState().boxGeometry(layoutBox).setLogicalTopLeft(toLayoutPoint(borderBoxRect.topLeft()));
    199192}
    200193
     
    221214
    222215    auto& layoutBox = lineRun.layoutBox();
    223     if (linehasContent) {
    224         auto inkOverflow = [&] {
    225             auto inkOverflow = inlineBoxBorderBox;
    226             addBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow);
    227             return inkOverflow;
    228         };
     216
     217    if (!linehasContent) {
    229218        // FIXME: It's expected to not have any boxes on empty lines. We should reconsider this.
    230         m_inlineBoxIndexMap.add(&layoutBox, boxes.size());
    231 
    232         ASSERT(inlineBox.isInlineBox());
    233         ASSERT(inlineBox.isFirstBox());
    234         boxes.append({ m_lineIndex
    235             , InlineDisplay::Box::Type::NonRootInlineBox
    236             , layoutBox
    237             , lineRun.bidiLevel()
    238             , inlineBoxBorderBox
    239             , inkOverflow()
    240             , { }
    241             , { }
    242             , inlineBox.hasContent()
    243             , isFirstLastBox(inlineBox) });
     219        setInlineBoxGeometry(layoutBox, inlineBoxBorderBox, true);
     220        return;
    244221    }
    245222
     223    auto inkOverflow = [&] {
     224        auto inkOverflow = inlineBoxBorderBox;
     225        m_contentHasInkOverflow = computeBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow) || m_contentHasInkOverflow;
     226        return inkOverflow;
     227    };
     228    ASSERT(inlineBox.isInlineBox());
     229    ASSERT(inlineBox.isFirstBox());
     230    boxes.append({ m_lineIndex
     231        , InlineDisplay::Box::Type::NonRootInlineBox
     232        , layoutBox
     233        , lineRun.bidiLevel()
     234        , inlineBoxBorderBox
     235        , inkOverflow()
     236        , { }
     237        , { }
     238        , inlineBox.hasContent()
     239        , isFirstLastBox(inlineBox) });
    246240    // This inline box showed up first on this line.
    247241    setInlineBoxGeometry(layoutBox, inlineBoxBorderBox, true);
     
    253247
    254248    auto& layoutBox = lineRun.layoutBox();
    255     m_inlineBoxIndexMap.add(&layoutBox, boxes.size());
    256 
    257249    auto inkOverflow = [&] {
    258250        auto inkOverflow = inlineBoxBorderBox;
    259         addBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow);
     251        m_contentHasInkOverflow = computeBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow) || m_contentHasInkOverflow;
    260252        return inkOverflow;
    261253    };
     
    271263        , inlineBox.hasContent()
    272264        , isFirstLastBox(inlineBox) });
    273 
    274265    // Middle or end of the inline box. Let's stretch the box as needed.
    275266    setInlineBoxGeometry(layoutBox, inlineBoxBorderBox, false);
     
    628619}
    629620
    630 void InlineDisplayContentBuilder::collectInkOverflowForInlineBoxes(const LineBox& lineBox, DisplayBoxes& boxes)
    631 {
    632     if (m_inlineBoxIndexMap.isEmpty() || !lineBox.hasContent()) {
    633         // This line has no inline box (only root, but we don't collect ink overflow for the root inline box atm)
     621void InlineDisplayContentBuilder::collectInkOverflowForInlineBoxes(DisplayBoxes& boxes)
     622{
     623    if (!m_contentHasInkOverflow)
    634624        return;
    635     }
    636 
    637     auto& nonRootInlineLevelBoxes = lineBox.nonRootInlineLevelBoxes();
    638625    // Visit the inline boxes and propagate ink overflow to their parents -except to the root inline box.
    639626    // (e.g. <span style="font-size: 10px;">Small font size<span style="font-size: 300px;">Larger font size. This overflows the top most span.</span></span>).
    640     for (size_t index = nonRootInlineLevelBoxes.size(); index--;) {
    641         if (!nonRootInlineLevelBoxes[index].isInlineBox())
    642             continue;
    643         auto& inlineBox = nonRootInlineLevelBoxes[index].layoutBox();
    644         auto& parentInlineBox = inlineBox.parent();
    645         if (&parentInlineBox == &root())
    646             continue;
    647         RELEASE_ASSERT(m_inlineBoxIndexMap.contains(&inlineBox) && m_inlineBoxIndexMap.contains(&parentInlineBox));
    648         auto& inkOverflow = boxes[m_inlineBoxIndexMap.get(&inlineBox)].inkOverflow();
    649         auto& parentDisplayBox = boxes[m_inlineBoxIndexMap.get(&parentInlineBox)];
    650         parentDisplayBox.adjustInkOverflow(inkOverflow);
     627    auto accumulatedInkOverflowRect = InlineRect { { }, { } };
     628    for (size_t index = boxes.size(); index--;) {
     629        auto& displayBox = boxes[index];
     630
     631        auto mayHaveInkOverflow = displayBox.isAtomicInlineLevelBox() || displayBox.isGenericInlineLevelBox() || displayBox.isNonRootInlineBox();
     632        if (!mayHaveInkOverflow)
     633            continue;
     634        if (displayBox.isNonRootInlineBox() && !accumulatedInkOverflowRect.isEmpty())
     635            displayBox.adjustInkOverflow(accumulatedInkOverflowRect);
     636
     637        // We stop collecting ink overflow for at root inline box (i.e. don't inflate the root inline box with the inline content here).
     638        auto parentBoxIsRoot = &displayBox.layoutBox().parent() == &root();
     639        if (parentBoxIsRoot)
     640            accumulatedInkOverflowRect = InlineRect { { }, { } };
     641        else if (accumulatedInkOverflowRect.isEmpty())
     642            accumulatedInkOverflowRect = displayBox.inkOverflow();
     643        else
     644            accumulatedInkOverflowRect.expandToContain(displayBox.inkOverflow());
    651645    }
    652646}
  • trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.h

    r286534 r286782  
    5050    void processBidiContent(const LineBuilder::LineContent&, const LineBox&, const InlineLayoutPoint& lineBoxLogicalTopLeft, DisplayBoxes&);
    5151    void processOverflownRunsForEllipsis(DisplayBoxes&, InlineLayoutUnit lineBoxLogicalRight);
    52     void collectInkOverflowForInlineBoxes(const LineBox&, DisplayBoxes&);
     52    void collectInkOverflowForInlineBoxes(DisplayBoxes&);
    5353
    5454    void appendTextDisplayBox(const Line::Run&, const InlineRect&, DisplayBoxes&);
     
    6868    const ContainerBox& m_formattingContextRoot;
    6969    InlineFormattingState& m_formattingState;
    70     HashMap<const Box*, size_t> m_inlineBoxIndexMap;
    7170    size_t m_lineIndex { 0 };
     71    bool m_contentHasInkOverflow { false };
    7272};
    7373
  • trunk/Source/WebCore/layout/formattingContexts/inline/InlineRect.h

    r286178 r286782  
    7272    void inflate(InlineLayoutUnit top, InlineLayoutUnit right, InlineLayoutUnit bottom, InlineLayoutUnit left);
    7373
     74    bool isEmpty() const;
     75
    7476    operator InlineLayoutRect() const;
    7577
     
    309311}
    310312
     313inline bool InlineRect::isEmpty() const
     314{
     315    ASSERT(hasValidGeometry());
     316    return m_rect.isEmpty();
     317}
     318
    311319inline InlineRect::operator InlineLayoutRect() const
    312320{
Note: See TracChangeset for help on using the changeset viewer.