Changeset 246457 in webkit


Ignore:
Timestamp:
Jun 15, 2019 7:03:23 AM (5 years ago)
Author:
Alan Bujtas
Message:

[LFC][IFC] Add support for vertical-align: top and bottom
https://bugs.webkit.org/show_bug.cgi?id=198697
<rdar://problem/51556188>

Reviewed by Antti Koivisto.

Use the layout box's vertical alignment to adjust line baseline and height and set the run's logical top when the line is being closed.

  • layout/inlineformatting/InlineLine.cpp:

(WebCore::Layout::Line::isVisuallyEmpty const):
(WebCore::Layout::Line::close):
(WebCore::Layout::Line::appendInlineContainerStart):
(WebCore::Layout::Line::appendTextContent):
(WebCore::Layout::Line::appendNonReplacedInlineBox):
(WebCore::Layout::Line::appendHardLineBreak):
(WebCore::Layout::Line::adjustBaselineAndLineHeight):
(WebCore::Layout::Line::inlineItemHeight const):
(WebCore::Layout::Line::Content::isVisuallyEmpty const): Deleted.

  • layout/inlineformatting/InlineLine.h:

(WebCore::Layout::Line::Content::isVisuallyEmpty const):
(WebCore::Layout::Line::Content::setIsVisuallyEmpty):
(WebCore::Layout::Line::hasContent const):

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r246445 r246457  
     12019-06-15  Zalan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] Add support for vertical-align: top and bottom
     4        https://bugs.webkit.org/show_bug.cgi?id=198697
     5        <rdar://problem/51556188>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Use the layout box's vertical alignment to adjust line baseline and height and set the run's logical top when the line is being closed.
     10
     11        * layout/inlineformatting/InlineLine.cpp:
     12        (WebCore::Layout::Line::isVisuallyEmpty const):
     13        (WebCore::Layout::Line::close):
     14        (WebCore::Layout::Line::appendInlineContainerStart):
     15        (WebCore::Layout::Line::appendTextContent):
     16        (WebCore::Layout::Line::appendNonReplacedInlineBox):
     17        (WebCore::Layout::Line::appendHardLineBreak):
     18        (WebCore::Layout::Line::adjustBaselineAndLineHeight):
     19        (WebCore::Layout::Line::inlineItemHeight const):
     20        (WebCore::Layout::Line::Content::isVisuallyEmpty const): Deleted.
     21        * layout/inlineformatting/InlineLine.h:
     22        (WebCore::Layout::Line::Content::isVisuallyEmpty const):
     23        (WebCore::Layout::Line::Content::setIsVisuallyEmpty):
     24        (WebCore::Layout::Line::hasContent const):
     25
    1262019-06-14  Antoine Quint  <graouts@apple.com>
    227
  • trunk/Source/WebCore/layout/inlineformatting/InlineLine.cpp

    r246234 r246457  
    3636WTF_MAKE_ISO_ALLOCATED_IMPL(Line);
    3737
    38 bool Line::Content::isVisuallyEmpty() const
    39 {
    40     // Return true for empty inline containers like <span></span>.
    41     for (auto& run : m_runs) {
    42         if (run->inlineItem.isContainerStart() || run->inlineItem.isContainerEnd())
    43             continue;
    44         if (!run->isCollapsed)
    45             return false;
    46     }
    47     return true;
    48 }
    49 
    5038Line::Content::Run::Run(const InlineItem& inlineItem, const Display::Rect& logicalRect, TextContext textContext, bool isCollapsed, bool canBeExtended)
    5139    : inlineItem(inlineItem)
     
    7664}
    7765
     66bool Line::isVisuallyEmpty() const
     67{
     68    // FIXME: This should be cached instead -as the inline items are being added.
     69    // Return true for empty inline containers like <span></span>.
     70    for (auto& run : m_content->runs()) {
     71        if (run->inlineItem.isContainerStart()) {
     72            auto& displayBox = m_layoutState.displayBoxForLayoutBox(run->inlineItem.layoutBox());
     73            if (displayBox.horizontalBorder() || (displayBox.horizontalPadding() && displayBox.horizontalPadding().value()))
     74                return false;
     75            continue;
     76        }
     77        if (run->inlineItem.isContainerEnd())
     78            continue;
     79        if (!run->isCollapsed)
     80            return false;
     81    }
     82    return true;
     83}
     84
    7885std::unique_ptr<Line::Content> Line::close()
    7986{
    8087    removeTrailingTrimmableContent();
    8188    if (!m_skipVerticalAligment) {
    82         // Convert inline run geometry from relative to the baseline to relative to logical top.
    8389        for (auto& run : m_content->runs()) {
    84             auto adjustedLogicalTop = run->logicalRect.top() + baselineOffset();
    85             run->logicalRect.setTop(adjustedLogicalTop);
    86         }
    87     }
     90            LayoutUnit logicalTop;
     91            auto& inlineItem = run->inlineItem;
     92            auto& layoutBox = inlineItem.layoutBox();
     93            auto ascent = inlineItem.style().fontMetrics().ascent();
     94
     95            switch (inlineItem.style().verticalAlign()) {
     96            case VerticalAlign::Baseline:
     97                if (inlineItem.isLineBreak() || inlineItem.isText())
     98                    logicalTop = baselineOffset() - ascent;
     99                else if (inlineItem.isContainerStart()) {
     100                    auto& displayBox = m_layoutState.displayBoxForLayoutBox(layoutBox);
     101                    logicalTop = baselineOffset() - ascent - displayBox.borderTop() - displayBox.paddingTop().valueOr(0);
     102                } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
     103                    auto& formattingState = downcast<InlineFormattingState>(m_layoutState.establishedFormattingState(layoutBox));
     104                    // Spec makes us generate at least one line -even if it is empty.
     105                    ASSERT(!formattingState.lineBoxes().isEmpty());
     106                    auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline();
     107                    logicalTop = baselineOffset() - inlineBlockBaseline.ascent;
     108                } else
     109                    logicalTop = baselineOffset() - run->logicalRect.height();
     110                break;
     111            case VerticalAlign::Top:
     112                logicalTop = { };
     113                break;
     114            case VerticalAlign::Bottom:
     115                logicalTop = logicalBottom() - run->logicalRect.height();
     116                break;
     117            default:
     118                ASSERT_NOT_IMPLEMENTED_YET();
     119                break;
     120            }
     121            run->logicalRect.setTop(logicalTop);
     122        }
     123    }
     124    m_content->setIsVisuallyEmpty(isVisuallyEmpty());
    88125    m_content->setLogicalRect({ logicalTop(), logicalLeft(), contentLogicalWidth(), logicalHeight() });
    89126    m_content->setBaseline(m_baseline);
     
    143180        auto logicalHeight = inlineItemHeight(inlineItem);
    144181        adjustBaselineAndLineHeight(inlineItem, logicalHeight);
    145 
    146         auto& displayBox = m_layoutState.displayBoxForLayoutBox(inlineItem.layoutBox());
    147         auto logicalTop = -inlineItem.style().fontMetrics().ascent() - displayBox.borderTop() - displayBox.paddingTop().valueOr(0);
    148         logicalRect.setTop(logicalTop);
    149182        logicalRect.setHeight(logicalHeight);
    150183    }
     
    191224    logicalRect.setLeft(contentLogicalRight());
    192225    logicalRect.setWidth(logicalWidth);
    193     if (!m_skipVerticalAligment) {
    194         logicalRect.setTop(-inlineItem.style().fontMetrics().ascent());
     226    if (!m_skipVerticalAligment)
    195227        logicalRect.setHeight(inlineItemHeight(inlineItem));
    196     }
    197228
    198229    auto textContext = Content::Run::TextContext { inlineItem.start(), inlineItem.isCollapsed() ? 1 : inlineItem.length() };
     
    216247        auto logicalHeight = inlineItemHeight(inlineItem);
    217248        adjustBaselineAndLineHeight(inlineItem, logicalHeight);
    218 
    219         logicalRect.setTop(-logicalHeight);
    220249        logicalRect.setHeight(logicalHeight);
    221250    }
     
    234263void Line::appendHardLineBreak(const InlineItem& inlineItem)
    235264{
    236     auto ascent = inlineItem.layoutBox().style().fontMetrics().ascent();
    237     auto logicalRect = Display::Rect { -ascent, contentLogicalRight(), { }, logicalHeight() };
     265    auto logicalRect = Display::Rect { };
     266    logicalRect.setLeft(contentLogicalRight());
     267    logicalRect.setWidth({ });
     268    if (!m_skipVerticalAligment)
     269        logicalRect.setHeight(logicalHeight());
    238270    m_content->runs().append(std::make_unique<Content::Run>(inlineItem, logicalRect, Content::Run::TextContext { }, false, false));
    239271}
     
    256288    }
    257289    // Replaced and non-replaced inline level box.
    258     // FIXME: We need to look inside the inline-block's formatting context and check the lineboxes (if any) to be able to baseline align.
    259     if (layoutBox.establishesInlineFormattingContext()) {
    260         if (runHeight == logicalHeight())
    261             return;
    262         // FIXME: This fails when the line height difference comes from font-size diff.
     290    switch (inlineItem.style().verticalAlign()) {
     291    case VerticalAlign::Baseline:
     292        if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
     293            // Inline-blocks with inline content always have baselines.
     294            auto& formattingState = downcast<InlineFormattingState>(m_layoutState.establishedFormattingState(layoutBox));
     295            // Spec makes us generate at least one line -even if it is empty.
     296            ASSERT(!formattingState.lineBoxes().isEmpty());
     297            auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline();
     298            m_baseline.descent = std::max(inlineBlockBaseline.descent, m_baseline.descent);
     299            m_baseline.ascent = std::max(inlineBlockBaseline.ascent, m_baseline.ascent);
     300            m_contentLogicalHeight = std::max(std::max(m_contentLogicalHeight, runHeight), baselineAlignedContentHeight());
     301            break;
     302        }
    263303        m_baseline.descent = std::max<LayoutUnit>(0, m_baseline.descent);
    264304        m_baseline.ascent = std::max(runHeight, m_baseline.ascent);
    265305        m_contentLogicalHeight = std::max(m_contentLogicalHeight, baselineAlignedContentHeight());
    266         return;
    267     }
    268     // 0 descent -> baseline aligment for now.
    269     m_baseline.descent = std::max<LayoutUnit>(0, m_baseline.descent);
    270     m_baseline.ascent = std::max(runHeight, m_baseline.ascent);
    271     m_contentLogicalHeight = std::max(m_contentLogicalHeight, baselineAlignedContentHeight());
     306        break;
     307    case VerticalAlign::Top:
     308        // Top align content never changes the baseline offset, it only pushes the bottom of the line further down.
     309        m_contentLogicalHeight = std::max(runHeight, m_contentLogicalHeight);
     310        break;
     311    case VerticalAlign::Bottom:
     312        if (m_contentLogicalHeight < runHeight) {
     313            m_baseline.offset = m_baseline.offset + (runHeight - m_contentLogicalHeight);
     314            m_contentLogicalHeight = runHeight;
     315        }
     316        break;
     317    default:
     318        ASSERT_NOT_IMPLEMENTED_YET();
     319        break;
     320    }
    272321}
    273322
     
    293342
    294343    // Non-replaced inline box (e.g. inline-block)
    295     return displayBox.height();
     344    return displayBox.marginBox().height();
    296345}
    297346
  • trunk/Source/WebCore/layout/inlineformatting/InlineLine.h

    r246234 r246457  
    5252
    5353            const InlineItem& inlineItem;
    54             // Relative to the baseline.
    5554            Display::Rect logicalRect;
     55            LayoutUnit baseline;
    5656            Optional<TextContext> textContext;
    5757            bool isCollapsed { false };
     
    6262        bool isEmpty() const { return m_runs.isEmpty(); }
    6363        // Not in painting sense though.
    64         bool isVisuallyEmpty() const;
     64        bool isVisuallyEmpty() const { return m_isVisuallyEmpty; }
    6565
    6666        LayoutUnit logicalTop() const { return m_logicalRect.top(); }
     
    7777        void setLogicalRect(const Display::Rect& logicalRect) { m_logicalRect = logicalRect; }
    7878        void setBaseline(LineBox::Baseline baseline) { m_baseline = baseline; }
     79        void setIsVisuallyEmpty(bool isVisuallyEmpty) { m_isVisuallyEmpty = isVisuallyEmpty; }
    7980        Runs& runs() { return m_runs; }
    8081
     
    8283        LineBox::Baseline m_baseline;
    8384        Runs m_runs;
     85        bool m_isVisuallyEmpty { true };
    8486    };
    8587    std::unique_ptr<Content> close();
     
    9294    void appendHardLineBreak(const InlineItem&);
    9395
    94     bool hasContent() const { return !m_content->isVisuallyEmpty(); }
     96    bool hasContent() const { return !isVisuallyEmpty(); }
    9597
    9698    LayoutUnit trailingTrimmableWidth() const;
     
    122124    void adjustBaselineAndLineHeight(const InlineItem&, LayoutUnit runHeight);
    123125    LayoutUnit inlineItemHeight(const InlineItem&) const;
     126    bool isVisuallyEmpty() const;
    124127
    125128    const LayoutState& m_layoutState;
Note: See TracChangeset for help on using the changeset viewer.