Changeset 250487 in webkit


Ignore:
Timestamp:
Sep 28, 2019, 6:59:27 PM (6 years ago)
Author:
Alan Bujtas
Message:

[LFC][IFC] Move horizontal alignment to Line
https://bugs.webkit.org/show_bug.cgi?id=202351
<rdar://problem/55810139>

Reviewed by Antti Koivisto.

Line should be able to finalize the run placement including horizontal alignment.

  • layout/Verification.cpp:

(WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded):

  • layout/inlineformatting/InlineFormattingContextLineLayout.cpp:

(WebCore::Layout::LineInput::LineInput):
(WebCore::Layout::LineLayout::LineLayout):
(WebCore::Layout::InlineFormattingContext::InlineLayout::layout):
(WebCore::Layout::InlineFormattingContext::InlineLayout::computedIntrinsicWidth const):

  • layout/inlineformatting/InlineLine.cpp:

(WebCore::Layout::Line::Line):
(WebCore::Layout::Line::isVisuallyEmpty const):
(WebCore::Layout::Line::close):
(WebCore::Layout::Line::verticalAlignContent):
(WebCore::Layout::Line::horizontalAlignContent):
(WebCore::Layout::Line::appendInlineContainerStart):
(WebCore::Layout::Line::appendTextContent):
(WebCore::Layout::Line::appendNonReplacedInlineBox):
(WebCore::Layout::Line::appendHardLineBreak):
(WebCore::Layout::Line::inlineItemContentHeight const):

  • layout/inlineformatting/InlineLine.h:
Location:
trunk/Source/WebCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r250485 r250487  
     12019-09-28  Zalan Bujtas  <zalan@apple.com>
     2
     3        [LFC][IFC] Move horizontal alignment to Line
     4        https://bugs.webkit.org/show_bug.cgi?id=202351
     5        <rdar://problem/55810139>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        Line should be able to finalize the run placement including horizontal alignment.
     10
     11        * layout/Verification.cpp:
     12        (WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded):
     13        * layout/inlineformatting/InlineFormattingContextLineLayout.cpp:
     14        (WebCore::Layout::LineInput::LineInput):
     15        (WebCore::Layout::LineLayout::LineLayout):
     16        (WebCore::Layout::InlineFormattingContext::InlineLayout::layout):
     17        (WebCore::Layout::InlineFormattingContext::InlineLayout::computedIntrinsicWidth const):
     18        * layout/inlineformatting/InlineLine.cpp:
     19        (WebCore::Layout::Line::Line):
     20        (WebCore::Layout::Line::isVisuallyEmpty const):
     21        (WebCore::Layout::Line::close):
     22        (WebCore::Layout::Line::verticalAlignContent):
     23        (WebCore::Layout::Line::horizontalAlignContent):
     24        (WebCore::Layout::Line::appendInlineContainerStart):
     25        (WebCore::Layout::Line::appendTextContent):
     26        (WebCore::Layout::Line::appendNonReplacedInlineBox):
     27        (WebCore::Layout::Line::appendHardLineBreak):
     28        (WebCore::Layout::Line::inlineItemContentHeight const):
     29        * layout/inlineformatting/InlineLine.h:
     30
    1312019-09-28  Wenson Hsieh  <wenson_hsieh@apple.com>
    232
  • trunk/Source/WebCore/layout/Verification.cpp

    r250429 r250487  
    100100            continue;
    101101
    102         stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ") layout run(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->end() << ") (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalRight() << ")";
     102        stream << "Mismatching: simple run(" << simpleRun.start << ", " << simpleRun.end << ") (" << simpleRun.logicalLeft << ", " << simpleRun.logicalRight << ")";
     103        stream << " inline run";
     104        if (inlineRun.textContext())
     105            stream << " (" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->end() << ")";
     106        stream << " (" << inlineRun.logicalLeft() << ", " << inlineRun.logicalTop() << ") (" << inlineRun.logicalWidth() << "x" << inlineRun.logicalHeight() << ")";
    103107        stream.nextLine();
    104108        mismatched = true;
  • trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h

    r250439 r250487  
    6969        LineContent placeInlineItems(const LineInput&) const;
    7070        void setupDisplayBoxes(const LineContent&);
    71         void alignRuns(TextAlignMode, InlineRuns&, unsigned firstRunIndex, LayoutUnit availableWidth) const;
    7271
    7372    private:
  • trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextLineLayout.cpp

    r250484 r250487  
    8282
    8383struct LineInput {
    84     LineInput(const Line::InitialConstraints& initialLineConstraints, Line::SkipVerticalAligment, IndexAndRange firstToProcess, const InlineItems&);
     84    LineInput(const Line::InitialConstraints&, TextAlignMode, IndexAndRange firstToProcess, const InlineItems&);
     85    LineInput(const Line::InitialConstraints&, IndexAndRange firstToProcess, const InlineItems&);
    8586
    8687    Line::InitialConstraints initialConstraints;
     88    TextAlignMode horizontalAlignment;
    8789    // FIXME Alternatively we could just have a second pass with vertical positioning (preferred width computation opts out)
    88     Line::SkipVerticalAligment skipVerticalAligment;
     90    Line::SkipAlignment skipAlignment { Line::SkipAlignment::No };
    8991    IndexAndRange firstInlineItem;
    9092    const InlineItems& inlineItems;
     
    9294};
    9395
    94 LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, Line::SkipVerticalAligment skipVerticalAligment, IndexAndRange firstToProcess, const InlineItems& inlineItems)
     96LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, TextAlignMode horizontalAlignment, IndexAndRange firstToProcess, const InlineItems& inlineItems)
    9597    : initialConstraints(initialLineConstraints)
    96     , skipVerticalAligment(skipVerticalAligment)
     98    , horizontalAlignment(horizontalAlignment)
     99    , firstInlineItem(firstToProcess)
     100    , inlineItems(inlineItems)
     101{
     102}
     103
     104LineInput::LineInput(const Line::InitialConstraints& initialLineConstraints, IndexAndRange firstToProcess, const InlineItems& inlineItems)
     105    : initialConstraints(initialLineConstraints)
     106    , skipAlignment(Line::SkipAlignment::Yes)
    97107    , firstInlineItem(firstToProcess)
    98108    , inlineItems(inlineItems)
     
    165175    : m_inlineFormattingContext(inlineFormattingContext)
    166176    , m_lineInput(lineInput)
    167     , m_line(inlineFormattingContext, lineInput.initialConstraints, lineInput.skipVerticalAligment)
     177    , m_line(inlineFormattingContext, lineInput.initialConstraints, lineInput.horizontalAlignment, lineInput.skipAlignment)
    168178    , m_lineHasIntrusiveFloat(lineInput.initialConstraints.lineIsConstrainedByFloat)
    169179{
     
    282292    IndexAndRange currentInlineItem;
    283293    while (currentInlineItem.index < inlineItems.size()) {
    284         auto lineInput = LineInput { initialConstraintsForLine(lineLogicalTop), Line::SkipVerticalAligment::No, currentInlineItem, inlineItems };
     294        auto lineInput = LineInput { initialConstraintsForLine(lineLogicalTop), formattingRoot().style().textAlign(), currentInlineItem, inlineItems };
    285295        auto lineLayout = LineLayout { formattingContext(), lineInput };
    286296
     
    350360        // Only the horiztonal available width is constrained when computing intrinsic width.
    351361        auto initialLineConstraints = Line::InitialConstraints { { }, widthConstraint(), false, { } };
    352         auto lineInput = LineInput { initialLineConstraints, Line::SkipVerticalAligment::Yes, currentInlineItem, inlineItems };
     362        auto lineInput = LineInput { initialLineConstraints, currentInlineItem, inlineItems };
    353363
    354364        auto lineContent = LineLayout(formattingContext, lineInput).layout();
     
    381391    }
    382392
    383     auto& inlineDisplayRuns = formattingState.inlineRuns();
    384     auto previousLineLastRunIndex = Optional<unsigned> { inlineDisplayRuns.isEmpty() ? Optional<unsigned>() : inlineDisplayRuns.size() - 1 };
    385     // 9.4.2 Inline formatting contexts
    386     // A line box is always tall enough for all of the boxes it contains.
    387 
    388393    // Add final display runs to state.
    389394    for (auto& lineRun : lineContent.runList) {
     
    394399    }
    395400
     401    // Compute box final geometry.
    396402    auto geometry = formattingContext.geometry();
    397403    auto& lineRuns = lineContent.runList;
     
    457463        ASSERT_NOT_REACHED();
    458464    }
    459     // FIXME linebox needs to be ajusted after content alignment.
    460465    formattingState.addLineBox(lineContent.lineBox);
    461     alignRuns(formattingRoot().style().textAlign(), inlineDisplayRuns, previousLineLastRunIndex.valueOr(-1) + 1, widthConstraint() - lineContent.lineBox.logicalWidth());
    462 }
    463 
    464 static Optional<LayoutUnit> horizontalAdjustmentForAlignment(TextAlignMode align, LayoutUnit remainingWidth)
    465 {
    466     switch (align) {
    467     case TextAlignMode::Left:
    468     case TextAlignMode::WebKitLeft:
    469     case TextAlignMode::Start:
    470         return { };
    471     case TextAlignMode::Right:
    472     case TextAlignMode::WebKitRight:
    473     case TextAlignMode::End:
    474         return std::max(remainingWidth, 0_lu);
    475     case TextAlignMode::Center:
    476     case TextAlignMode::WebKitCenter:
    477         return std::max(remainingWidth / 2, 0_lu);
    478     case TextAlignMode::Justify:
    479         ASSERT_NOT_REACHED();
    480         break;
    481     }
    482     ASSERT_NOT_REACHED();
    483     return { };
    484 }
    485 
    486 void InlineFormattingContext::InlineLayout::alignRuns(TextAlignMode textAlign, InlineRuns& inlineDisplayRuns, unsigned firstRunIndex, LayoutUnit availableWidth) const
    487 {
    488     auto adjustment = horizontalAdjustmentForAlignment(textAlign, availableWidth);
    489     if (!adjustment)
    490         return;
    491 
    492     for (unsigned index = firstRunIndex; index < inlineDisplayRuns.size(); ++index)
    493         inlineDisplayRuns[index].moveHorizontally(*adjustment);
    494466}
    495467
  • trunk/Source/WebCore/layout/inlineformatting/InlineLine.cpp

    r250484 r250487  
    5858}
    5959
    60 Line::Line(const InlineFormattingContext& inlineFormattingContext, const InitialConstraints& initialConstraints, SkipVerticalAligment skipVerticalAligment)
     60Line::Line(const InlineFormattingContext& inlineFormattingContext, const InitialConstraints& initialConstraints, Optional<TextAlignMode> horizontalAlignment, SkipAlignment skipAlignment)
    6161    : m_inlineFormattingContext(inlineFormattingContext)
    6262    , m_initialStrut(initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->strut : WTF::nullopt)
    6363    , m_lineLogicalWidth(initialConstraints.availableLogicalWidth)
    64     , m_skipVerticalAligment(skipVerticalAligment == SkipVerticalAligment::Yes)
    65 {
    66     ASSERT(m_skipVerticalAligment || initialConstraints.heightAndBaseline);
     64    , m_horizontalAlignment(horizontalAlignment)
     65    , m_skipAlignment(skipAlignment == SkipAlignment::Yes)
     66{
     67    ASSERT(m_skipAlignment || initialConstraints.heightAndBaseline);
    6768    auto initialLineHeight = initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->height : LayoutUnit();
    6869    auto initialBaselineOffset = initialConstraints.heightAndBaseline ? initialConstraints.heightAndBaseline->baselineOffset : LayoutUnit();
     
    9798            if (!boxGeometry.width())
    9899                continue;
    99             if (m_skipVerticalAligment || boxGeometry.height())
     100            if (m_skipAlignment || boxGeometry.height())
    100101                return false;
    101102            continue;
     
    110111{
    111112    removeTrailingTrimmableContent();
    112     if (!m_skipVerticalAligment) {
    113         if (isVisuallyEmpty()) {
    114             m_lineBox.baseline().reset();
    115             m_lineBox.setBaselineOffset({ });
    116             m_lineBox.setLogicalHeight({ });
    117         }
    118 
    119         // Remove descent when all content is baseline aligned but none of them have descent.
    120         if (formattingContext().quirks().lineDescentNeedsCollapsing(m_runList)) {
    121             m_lineBox.shrinkVertically(m_lineBox.baseline().descent());
    122             m_lineBox.baseline().setDescent({ });
    123         }
    124 
    125         auto& layoutState = this->layoutState();
    126         auto& formattingContext = this->formattingContext();
    127         for (auto& run : m_runList) {
    128             LayoutUnit logicalTop;
    129             auto& layoutBox = run->layoutBox();
    130             auto verticalAlign = layoutBox.style().verticalAlign();
    131             auto ascent = layoutBox.style().fontMetrics().ascent();
    132 
    133             switch (verticalAlign) {
    134             case VerticalAlign::Baseline:
    135                 if (run->isLineBreak() || run->isText())
    136                     logicalTop = baselineOffset() - ascent;
    137                 else if (run->isContainerStart()) {
    138                     auto& boxGeometry = formattingContext.geometryForBox(layoutBox);
    139                     logicalTop = baselineOffset() - ascent - boxGeometry.borderTop() - boxGeometry.paddingTop().valueOr(0);
    140                 } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
    141                     auto& formattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(downcast<Container>(layoutBox)));
    142                     // Spec makes us generate at least one line -even if it is empty.
    143                     ASSERT(!formattingState.lineBoxes().isEmpty());
    144                     auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline();
    145                     logicalTop = baselineOffset() - inlineBlockBaseline.ascent();
    146                 } else
    147                     logicalTop = baselineOffset() - run->logicalRect().height();
    148                 break;
    149             case VerticalAlign::Top:
    150                 logicalTop = { };
    151                 break;
    152             case VerticalAlign::Bottom:
    153                 logicalTop = logicalBottom() - run->logicalRect().height();
    154                 break;
    155             default:
    156                 ASSERT_NOT_IMPLEMENTED_YET();
    157                 break;
    158             }
    159             run->adjustLogicalTop(logicalTop);
    160             // Convert runs from relative to the line top/left to the formatting root's border box top/left.
    161             run->moveVertically(this->logicalTop());
    162             run->moveHorizontally(this->logicalLeft());
    163         }
    164     }
    165 
    166     // Let's join text runs together when possible.
    167     // FIXME: Check if we can do it as part of the loop above.
     113    // Join text runs together when possible.
    168114    unsigned index = 1;
    169115    while (index < m_runList.size()) {
     
    185131        m_runList.remove(index);
    186132    }
     133
     134    if (!m_skipAlignment) {
     135        alignContentVertically();
     136        alignContentHorizontally();
     137    }
     138
    187139    return WTFMove(m_runList);
     140}
     141
     142void Line::alignContentVertically()
     143{
     144    ASSERT(!m_skipAlignment);
     145
     146    if (isVisuallyEmpty()) {
     147        m_lineBox.baseline().reset();
     148        m_lineBox.setBaselineOffset({ });
     149        m_lineBox.setLogicalHeight({ });
     150    }
     151
     152    // Remove descent when all content is baseline aligned but none of them have descent.
     153    if (formattingContext().quirks().lineDescentNeedsCollapsing(m_runList)) {
     154        m_lineBox.shrinkVertically(m_lineBox.baseline().descent());
     155        m_lineBox.baseline().setDescent({ });
     156    }
     157
     158    auto& layoutState = this->layoutState();
     159    auto& formattingContext = this->formattingContext();
     160    for (auto& run : m_runList) {
     161        LayoutUnit logicalTop;
     162        auto& layoutBox = run->layoutBox();
     163        auto verticalAlign = layoutBox.style().verticalAlign();
     164        auto ascent = layoutBox.style().fontMetrics().ascent();
     165
     166        switch (verticalAlign) {
     167        case VerticalAlign::Baseline:
     168            if (run->isLineBreak() || run->isText())
     169                logicalTop = baselineOffset() - ascent;
     170            else if (run->isContainerStart()) {
     171                auto& boxGeometry = formattingContext.geometryForBox(layoutBox);
     172                logicalTop = baselineOffset() - ascent - boxGeometry.borderTop() - boxGeometry.paddingTop().valueOr(0);
     173            } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
     174                auto& formattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(downcast<Container>(layoutBox)));
     175                // Spec makes us generate at least one line -even if it is empty.
     176                ASSERT(!formattingState.lineBoxes().isEmpty());
     177                auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline();
     178                logicalTop = baselineOffset() - inlineBlockBaseline.ascent();
     179            } else
     180                logicalTop = baselineOffset() - run->logicalRect().height();
     181            break;
     182        case VerticalAlign::Top:
     183            logicalTop = { };
     184            break;
     185        case VerticalAlign::Bottom:
     186            logicalTop = logicalBottom() - run->logicalRect().height();
     187            break;
     188        default:
     189            ASSERT_NOT_IMPLEMENTED_YET();
     190            break;
     191        }
     192        run->adjustLogicalTop(logicalTop);
     193        // Convert runs from relative to the line top/left to the formatting root's border box top/left.
     194        run->moveVertically(this->logicalTop());
     195        run->moveHorizontally(this->logicalLeft());
     196    }
     197}
     198
     199void Line::alignContentHorizontally()
     200{
     201    ASSERT(!m_skipAlignment);
     202
     203    auto adjustmentForAlignment = [&]() -> Optional<LayoutUnit> {
     204        switch (*m_horizontalAlignment) {
     205        case TextAlignMode::Left:
     206        case TextAlignMode::WebKitLeft:
     207        case TextAlignMode::Start:
     208            return { };
     209        case TextAlignMode::Right:
     210        case TextAlignMode::WebKitRight:
     211        case TextAlignMode::End:
     212            return std::max(availableWidth(), 0_lu);
     213        case TextAlignMode::Center:
     214        case TextAlignMode::WebKitCenter:
     215            return std::max(availableWidth() / 2, 0_lu);
     216        case TextAlignMode::Justify:
     217            ASSERT_NOT_REACHED();
     218            break;
     219        }
     220        ASSERT_NOT_REACHED();
     221        return { };
     222    };
     223
     224    auto adjustment = adjustmentForAlignment();
     225    if (!adjustment)
     226        return;
     227
     228    for (auto& run : m_runList)
     229        run->moveHorizontally(*adjustment);
     230    // FIXME: Find out if m_lineBox needs adjustmnent as well.
    188231}
    189232
     
    252295    logicalRect.setWidth(logicalWidth);
    253296
    254     if (!m_skipVerticalAligment) {
     297    if (!m_skipAlignment) {
    255298        auto logicalHeight = inlineItemContentHeight(inlineItem);
    256299        adjustBaselineAndLineHeight(inlineItem, logicalHeight);
     
    299342    logicalRect.setLeft(contentLogicalWidth());
    300343    logicalRect.setWidth(logicalWidth);
    301     if (!m_skipVerticalAligment) {
     344    if (!m_skipAlignment) {
    302345        auto runHeight = inlineItemContentHeight(inlineItem);
    303346        logicalRect.setHeight(runHeight);
     
    326369    logicalRect.setLeft(contentLogicalWidth() + horizontalMargin.start);
    327370    logicalRect.setWidth(logicalWidth);
    328     if (!m_skipVerticalAligment) {
     371    if (!m_skipAlignment) {
    329372        adjustBaselineAndLineHeight(inlineItem, boxGeometry.marginBoxHeight());
    330373        logicalRect.setHeight(inlineItemContentHeight(inlineItem));
     
    347390    logicalRect.setLeft(contentLogicalWidth());
    348391    logicalRect.setWidth({ });
    349     if (!m_skipVerticalAligment) {
     392    if (!m_skipAlignment) {
    350393        adjustBaselineAndLineHeight(inlineItem, { });
    351394        logicalRect.setHeight(logicalHeight());
     
    427470LayoutUnit Line::inlineItemContentHeight(const InlineItem& inlineItem) const
    428471{
    429     ASSERT(!m_skipVerticalAligment);
     472    ASSERT(!m_skipAlignment);
    430473    auto& fontMetrics = inlineItem.style().fontMetrics();
    431474    if (inlineItem.isLineBreak() || is<InlineTextItem>(inlineItem))
  • trunk/Source/WebCore/layout/inlineformatting/InlineLine.h

    r250484 r250487  
    5252        Optional<HeightAndBaseline> heightAndBaseline;
    5353    };
    54     enum class SkipVerticalAligment { No, Yes };
    55     Line(const InlineFormattingContext&, const InitialConstraints&, SkipVerticalAligment);
     54    enum class SkipAlignment { No, Yes };
     55    Line(const InlineFormattingContext&, const InitialConstraints&, Optional<TextAlignMode>, SkipAlignment);
    5656
    5757    void append(const InlineItem&, LayoutUnit logicalWidth);
     
    126126
    127127    void removeTrailingTrimmableContent();
     128    void alignContentHorizontally();
     129    void alignContentVertically();
    128130
    129131    void adjustBaselineAndLineHeight(const InlineItem&, LayoutUnit runHeight);
     
    140142    Optional<LineBox::Baseline> m_initialStrut;
    141143    LayoutUnit m_lineLogicalWidth;
    142     bool m_skipVerticalAligment { false };
     144    Optional<TextAlignMode> m_horizontalAlignment;
     145    bool m_skipAlignment { false };
    143146    LineBox m_lineBox;
    144147};
Note: See TracChangeset for help on using the changeset viewer.