Changeset 292973 in webkit


Ignore:
Timestamp:
Apr 18, 2022 2:44:04 PM (3 months ago)
Author:
Matt Woodrow
Message:

Implement support for aligning baselines through subgrids
https://bugs.webkit.org/show_bug.cgi?id=238643

Reviewed by Javier Fernandez.

LayoutTests/imported/w3c:

  • web-platform-tests/css/css-grid/subgrid/baseline-002-expected.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-002.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-003-expected.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-003.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-004-expected.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-004.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-005-expected.html: Added.
  • web-platform-tests/css/css-grid/subgrid/baseline-005.html: Added.

Added new WPT variants of the baseline tests, for the case where the introspected subgrid
has padding that affects the baseline position, and for the case where the subgrid uses an
orthogonal writing mode.

Source/WebCore:

Implement baseline sharing recursion into subgrids

Tests: imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-002.html

imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-003.html
imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-004.html
imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-005.html

  • rendering/GridBaselineAlignment.cpp:

(WebCore::GridBaselineAlignment::ascentForChild const):
(WebCore::GridBaselineAlignment::descentForChild const):
(WebCore::GridBaselineAlignment::updateBaselineAlignmentContext):
(WebCore::BaselineGroup::BaselineGroup):
(WebCore::BaselineGroup::update):
(WebCore::BaselineContext::BaselineContext):
(WebCore::BaselineContext::updateSharedGroup):

  • rendering/GridBaselineAlignment.h:

(WebCore::BaselineGroup::maxAscent const):
(WebCore::BaselineGroup::maxDescent const): Deleted.

  • rendering/GridLayoutFunctions.h:
  • rendering/GridTrackSizingAlgorithm.cpp:

(WebCore::GridTrackSizingAlgorithm::canParticipateInBaselineAlignment const):
(WebCore::GridTrackSizingAlgorithm::updateBaselineAlignmentContext):
(WebCore::GridTrackSizingAlgorithm::baselineOffsetForChild const):
(WebCore::GridTrackSizingAlgorithm::cacheBaselineAlignedItem):

  • rendering/GridTrackSizingAlgorithm.h:
  • rendering/RenderGrid.cpp:

(WebCore::cacheBaselineAlignedChildren):
(WebCore::RenderGrid::computeIntrinsicLogicalWidths const):
(WebCore::RenderGrid::performGridItemsPreLayout const):
(WebCore::RenderGrid::alignSelfForChild const):
(WebCore::RenderGrid::justifySelfForChild const):
(WebCore::RenderGrid::columnAxisBaselineOffsetForChild const):
(WebCore::RenderGrid::rowAxisBaselineOffsetForChild const):

Moves the code for collecting baseline aligned children into a shared helper function, and adds
support for recursing into subgrid children (restricted to the axes that subgrid was applied).

Fixes align/justifySelfForChild to check if the child is a subgrid and overrides the result to 'stretch', so
that we're correctly stretching subgrids, not the children of subgrids (covered by new tests).

Location:
trunk
Files:
8 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r292953 r292973  
     12022-04-18  Matt Woodrow  <mattwoodrow@apple.com>
     2
     3        Implement support for aligning baselines through subgrids
     4        https://bugs.webkit.org/show_bug.cgi?id=238643
     5
     6        Reviewed by Javier Fernandez.
     7
     8        * web-platform-tests/css/css-grid/subgrid/baseline-002-expected.html: Added.
     9        * web-platform-tests/css/css-grid/subgrid/baseline-002.html: Added.
     10        * web-platform-tests/css/css-grid/subgrid/baseline-003-expected.html: Added.
     11        * web-platform-tests/css/css-grid/subgrid/baseline-003.html: Added.
     12        * web-platform-tests/css/css-grid/subgrid/baseline-004-expected.html: Added.
     13        * web-platform-tests/css/css-grid/subgrid/baseline-004.html: Added.
     14        * web-platform-tests/css/css-grid/subgrid/baseline-005-expected.html: Added.
     15        * web-platform-tests/css/css-grid/subgrid/baseline-005.html: Added.
     16
     17        Added new WPT variants of the baseline tests, for the case where the introspected subgrid
     18        has padding that affects the baseline position, and for the case where the subgrid uses an
     19        orthogonal writing mode.
     20
    1212022-04-18  Martin Robinson  <mrobinson@webkit.org>
    222
  • trunk/Source/WebCore/ChangeLog

    r292967 r292973  
     12022-04-18  Matt Woodrow  <mattwoodrow@apple.com>
     2
     3        Implement support for aligning baselines through subgrids
     4        https://bugs.webkit.org/show_bug.cgi?id=238643
     5
     6        Reviewed by Javier Fernandez.
     7
     8        Implement baseline sharing recursion into subgrids
     9
     10        Tests: imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-002.html
     11               imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-003.html
     12               imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-004.html
     13               imported/w3c/web-platform-tests/css/css-grid/subgrid/baseline-005.html
     14
     15        * rendering/GridBaselineAlignment.cpp:
     16        (WebCore::GridBaselineAlignment::ascentForChild const):
     17        (WebCore::GridBaselineAlignment::descentForChild const):
     18        (WebCore::GridBaselineAlignment::updateBaselineAlignmentContext):
     19        (WebCore::BaselineGroup::BaselineGroup):
     20        (WebCore::BaselineGroup::update):
     21        (WebCore::BaselineContext::BaselineContext):
     22        (WebCore::BaselineContext::updateSharedGroup):
     23        * rendering/GridBaselineAlignment.h:
     24        (WebCore::BaselineGroup::maxAscent const):
     25        (WebCore::BaselineGroup::maxDescent const): Deleted.
     26        * rendering/GridLayoutFunctions.h:
     27        * rendering/GridTrackSizingAlgorithm.cpp:
     28        (WebCore::GridTrackSizingAlgorithm::canParticipateInBaselineAlignment const):
     29        (WebCore::GridTrackSizingAlgorithm::updateBaselineAlignmentContext):
     30        (WebCore::GridTrackSizingAlgorithm::baselineOffsetForChild const):
     31        (WebCore::GridTrackSizingAlgorithm::cacheBaselineAlignedItem):
     32        * rendering/GridTrackSizingAlgorithm.h:
     33        * rendering/RenderGrid.cpp:
     34        (WebCore::cacheBaselineAlignedChildren):
     35        (WebCore::RenderGrid::computeIntrinsicLogicalWidths const):
     36        (WebCore::RenderGrid::performGridItemsPreLayout const):
     37        (WebCore::RenderGrid::alignSelfForChild const):
     38        (WebCore::RenderGrid::justifySelfForChild const):
     39        (WebCore::RenderGrid::columnAxisBaselineOffsetForChild const):
     40        (WebCore::RenderGrid::rowAxisBaselineOffsetForChild const):
     41
     42        Moves the code for collecting baseline aligned children into a shared helper function, and adds
     43        support for recursing into subgrid children (restricted to the axes that subgrid was applied).
     44
     45        Fixes align/justifySelfForChild to check if the child is a subgrid and overrides the result to 'stretch', so
     46        that we're correctly stretching subgrids, not the children of subgrids (covered by new tests).
     47
    1482022-04-18  Tyler Wilcock  <tyler_w@apple.com>
    249
  • trunk/Source/WebCore/rendering/GridBaselineAlignment.cpp

    r278185 r292973  
    6969    // We take border-box's under edge if no valid baseline.
    7070    if (baseline == -1) {
     71        ASSERT(!child.needsLayout());
    7172        if (isHorizontalBaselineAxis(baselineAxis))
    7273            return isFlippedWritingMode(m_blockFlow) ? child.size().width().toInt() + margin : margin;
     
    7879LayoutUnit GridBaselineAlignment::descentForChild(const RenderBox& child, LayoutUnit ascent, GridAxis baselineAxis) const
    7980{
     81    ASSERT(!child.needsLayout());
    8082    if (isParallelToBaselineAxisForChild(child, baselineAxis))
    8183        return child.marginLogicalHeight() + child.logicalHeight() - ascent;
     
    123125    // its grid container.
    124126    LayoutUnit ascent = ascentForChild(child, baselineAxis);
    125     LayoutUnit descent = descentForChild(child, ascent, baselineAxis);
    126127    if (isDescentBaselineForChild(child, baselineAxis))
    127         std::swap(ascent, descent);
     128        ascent = descentForChild(child, ascent, baselineAxis);
    128129
    129130    // Looking up for a shared alignment context perpendicular to the
     
    135136    // Looking for a compatible baseline-sharing group.
    136137    if (addResult.isNewEntry)
    137         addResult.iterator->value = makeUnique<BaselineContext>(child, preference, ascent, descent);
     138        addResult.iterator->value = makeUnique<BaselineContext>(child, preference, ascent);
    138139    else {
    139140        auto* context = addResult.iterator->value.get();
    140         context->updateSharedGroup(child, preference, ascent, descent);
     141        context->updateSharedGroup(child, preference, ascent);
    141142    }
    142143}
     
    160161
    161162BaselineGroup::BaselineGroup(WritingMode blockFlow, ItemPosition childPreference)
    162     : m_maxAscent(0), m_maxDescent(0), m_items()
     163    : m_maxAscent(0), m_items()
    163164{
    164165    m_blockFlow = blockFlow;
     
    166167}
    167168
    168 void BaselineGroup::update(const RenderBox& child, LayoutUnit ascent, LayoutUnit descent)
     169void BaselineGroup::update(const RenderBox& child, LayoutUnit ascent)
    169170{
    170171    if (m_items.add(&child).isNewEntry) {
    171172        m_maxAscent = std::max(m_maxAscent, ascent);
    172         m_maxDescent = std::max(m_maxDescent, descent);
    173173    }
    174174}
     
    210210}
    211211
    212 BaselineContext::BaselineContext(const RenderBox& child, ItemPosition preference, LayoutUnit ascent, LayoutUnit descent)
    213 {
    214     ASSERT(isBaselinePosition(preference));
    215     updateSharedGroup(child, preference, ascent, descent);
     212BaselineContext::BaselineContext(const RenderBox& child, ItemPosition preference, LayoutUnit ascent)
     213{
     214    ASSERT(isBaselinePosition(preference));
     215    updateSharedGroup(child, preference, ascent);
    216216}
    217217
     
    222222}
    223223
    224 void BaselineContext::updateSharedGroup(const RenderBox& child, ItemPosition preference, LayoutUnit ascent, LayoutUnit descent)
     224void BaselineContext::updateSharedGroup(const RenderBox& child, ItemPosition preference, LayoutUnit ascent)
    225225{
    226226    ASSERT(isBaselinePosition(preference));
    227227    BaselineGroup& group = findCompatibleSharedGroup(child, preference);
    228     group.update(child, ascent, descent);
     228    group.update(child, ascent);
    229229}
    230230
  • trunk/Source/WebCore/rendering/GridBaselineAlignment.h

    r276356 r292973  
    5050class BaselineGroup {
    5151public:
    52     // It stores an item (if not already present) and update the max_ascent and max_descent associated to this
     52    // It stores an item (if not already present) and update the max_ascent associated to this
    5353    // baseline-sharing group.
    54     void update(const RenderBox&, LayoutUnit ascent, LayoutUnit descent);
     54    void update(const RenderBox&, LayoutUnit ascent);
    5555    LayoutUnit maxAscent() const { return m_maxAscent; }
    56     LayoutUnit maxDescent() const { return m_maxDescent; }
    5756    int size() const { return m_items.size(); }
    5857
     
    7675    ItemPosition m_preference;
    7776    LayoutUnit m_maxAscent;
    78     LayoutUnit m_maxDescent;
    7977    HashSet<const RenderBox*> m_items;
    8078};
     
    10098    WTF_MAKE_FAST_ALLOCATED;
    10199public:
    102     BaselineContext(const RenderBox& child, ItemPosition preference, LayoutUnit ascent, LayoutUnit descent);
     100    BaselineContext(const RenderBox& child, ItemPosition preference, LayoutUnit ascent);
    103101    const BaselineGroup& sharedGroup(const RenderBox& child, ItemPosition preference) const;
    104102
     
    106104    // We pass the item's baseline-preference to avoid dependencies with the LayoutGrid class, which is the one
    107105    // managing the alignment behavior of the Grid Items.
    108     void updateSharedGroup(const RenderBox& child, ItemPosition preference, LayoutUnit ascent, LayoutUnit descent);
     106    void updateSharedGroup(const RenderBox& child, ItemPosition preference, LayoutUnit ascent);
    109107
    110108private:
  • trunk/Source/WebCore/rendering/GridLayoutFunctions.h

    r290879 r292973  
    3535class RenderGrid;
    3636
    37 enum GridAxis { GridRowAxis, GridColumnAxis };
     37enum GridAxis {
     38    GridRowAxis = 1 << 0,
     39    GridColumnAxis = 1 << 1
     40};
    3841
    3942namespace GridLayoutFunctions {
  • trunk/Source/WebCore/rendering/GridTrackSizingAlgorithm.cpp

    r292465 r292973  
    910910        return true;
    911911
     912    // FIXME: We don't currently allow items within subgrids that need to
     913    // synthesize a baseline, since we need a layout to have been completed
     914    // and performGridItemsPreLayout on the outer grid doesn't layout subgrid
     915    // items.
     916    if (child.parent() != renderGrid())
     917        return false;
     918
    912919    // Baseline cyclic dependencies only happen in grid areas with
    913920    // intrinsically-sized tracks.
     
    927934    ASSERT(wasSetup());
    928935    ASSERT(canParticipateInBaselineAlignment(child, baselineAxis));
    929     ASSERT(!child.needsLayout());
    930936
    931937    ItemPosition align = m_renderGrid->selfAlignmentForChild(baselineAxis, child).position();
     
    936942LayoutUnit GridTrackSizingAlgorithm::baselineOffsetForChild(const RenderBox& child, GridAxis baselineAxis) const
    937943{
     944    // If we haven't yet initialized this axis (which can be the case if we're doing
     945    // prelayout of a subgrid), then we can't know the baseline offset.
     946    if (tracks(gridDirectionForAxis(baselineAxis)).isEmpty())
     947        return LayoutUnit();
     948
    938949    if (!participateInBaselineAlignment(child, baselineAxis))
    939950        return LayoutUnit();
     
    952963void GridTrackSizingAlgorithm::cacheBaselineAlignedItem(const RenderBox& item, GridAxis axis)
    953964{
    954     ASSERT(m_renderGrid->isBaselineAlignmentForChild(item, axis));
     965    ASSERT(downcast<RenderGrid>(item.parent())->isBaselineAlignmentForChild(item, axis));
     966
     967    if (GridLayoutFunctions::isOrthogonalParent(*m_renderGrid, *item.parent()))
     968        axis = axis == GridColumnAxis ? GridRowAxis : GridColumnAxis;
     969
    955970    if (axis == GridColumnAxis)
    956971        m_columnBaselineItemsMap.add(&item, true);
  • trunk/Source/WebCore/rendering/GridTrackSizingAlgorithm.h

    r292465 r292973  
    123123    Grid& mutableGrid() const { return m_grid; }
    124124
    125     const RenderGrid* renderGrid() { return m_renderGrid; };
     125    const RenderGrid* renderGrid() const { return m_renderGrid; };
    126126
    127127    LayoutUnit minContentSize() const { return m_minContentSize; };
  • trunk/Source/WebCore/rendering/RenderGrid.cpp

    r292524 r292973  
    193193}
    194194
     195template<typename F>
     196static void cacheBaselineAlignedChildren(const RenderGrid& grid, GridTrackSizingAlgorithm& algorithm, uint32_t axes, F& callback)
     197{
     198    for (auto* child = grid.firstChildBox(); child; child = child->nextSiblingBox()) {
     199        if (child->isOutOfFlowPositioned() || child->isLegend())
     200            continue;
     201
     202        callback(child);
     203
     204        // We keep a cache of items with baseline as alignment values so that we only compute the baseline shims for
     205        // such items. This cache is needed for performance related reasons due to the cost of evaluating the item's
     206        // participation in a baseline context during the track sizing algorithm.
     207        uint32_t innerAxes = 0;
     208        RenderGrid* inner = is<RenderGrid>(child) ? downcast<RenderGrid>(child) : nullptr;
     209
     210        if (axes & GridColumnAxis) {
     211            if (inner && inner->isSubgridInParentDirection(ForRows))
     212                innerAxes |= GridLayoutFunctions::isOrthogonalChild(grid, *child) ? GridRowAxis : GridColumnAxis;
     213            else if (grid.isBaselineAlignmentForChild(*child, GridColumnAxis))
     214                algorithm.cacheBaselineAlignedItem(*child, GridColumnAxis);
     215        }
     216
     217        if (axes & GridRowAxis) {
     218            if (inner && inner->isSubgridInParentDirection(ForColumns))
     219                innerAxes |= GridLayoutFunctions::isOrthogonalChild(grid, *child) ? GridColumnAxis : GridRowAxis;
     220            else if (grid.isBaselineAlignmentForChild(*child, GridRowAxis))
     221                algorithm.cacheBaselineAlignedItem(*child, GridRowAxis);
     222        }
     223
     224        if (innerAxes)
     225            cacheBaselineAlignedChildren(*inner, algorithm, innerAxes, callback);
     226    }
     227}
     228
    195229Vector<RenderBox*> RenderGrid::computeAspectRatioDependentAndBaselineItems()
    196230{
     
    201235    m_hasAspectRatioBlockSizeDependentItem = false;
    202236
    203     for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
    204         if (child->isOutOfFlowPositioned() || child->isLegend())
    205             continue;
    206 
    207         // Grid's layout logic controls the grid item's override height, hence we need to
    208         // clear any override height set previously, so it doesn't interfere in current layout
    209         // execution. Grid never uses the override width, that's why we don't need to clear  it.
    210         child->clearOverridingLogicalHeight();
    211 
     237    auto computeOrthogonalAndDependentItems = [&](RenderBox* child) {
    212238        // Grid's layout logic controls the grid item's override height, hence we need to
    213239        // clear any override height set previously, so it doesn't interfere in current layout
     
    225251            m_hasAspectRatioBlockSizeDependentItem = true;
    226252        }
    227 
    228         // We keep a cache of items with baseline as aligcnment values so that we only compute the baseline shims for
    229         // such items. This cache is needed for performance related reasons due to the cost of evaluating the item's
    230         // participation in a baseline context during the track sizing algorithm.
    231         if (isBaselineAlignmentForChild(*child, GridColumnAxis))
    232             m_trackSizingAlgorithm.cacheBaselineAlignedItem(*child, GridColumnAxis);
    233         if (isBaselineAlignmentForChild(*child, GridRowAxis))
    234             m_trackSizingAlgorithm.cacheBaselineAlignedItem(*child, GridRowAxis);
    235     }
    236 
     253    };
     254
     255    cacheBaselineAlignedChildren(*this, m_trackSizingAlgorithm, GridRowAxis | GridColumnAxis, computeOrthogonalAndDependentItems);
    237256    return dependentGridItems;
    238257}
     
    478497            algorithm.copyBaselineItemsCache(m_trackSizingAlgorithm, GridRowAxis);
    479498        else {
    480             for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
    481                 if (child->isOutOfFlowPositioned())
    482                     continue;
    483                 if (isBaselineAlignmentForChild(*child, GridRowAxis))
    484                     algorithm.cacheBaselineAlignedItem(*child, GridRowAxis);
    485             }
     499            auto emptyCallback = [](RenderBox*) { };
     500            cacheBaselineAlignedChildren(*this, algorithm, GridRowAxis, emptyCallback);
    486501        }
    487502
     
    784799        // baseline or not, which may imply a cyclic sizing dependency.
    785800        // FIXME: Can we avoid it ?
     801        // FIXME: We also want to layout baseline aligned items within subgrids, but
     802        // we don't currently have a way to do that here.
    786803        if (isBaselineAlignmentForChild(*child)) {
    787804            updateGridAreaLogicalSize(*child, algorithm.estimatedGridAreaBreadthForChild(*child, ForColumns), algorithm.estimatedGridAreaBreadthForChild(*child, ForRows));
     
    12271244StyleSelfAlignmentData RenderGrid::alignSelfForChild(const RenderBox& child, StretchingMode stretchingMode, const RenderStyle* gridStyle) const
    12281245{
    1229     if (isSubgridInParentDirection(ForRows))
     1246    if (is<RenderGrid>(child) && downcast<RenderGrid>(child).isSubgridInParentDirection(ForRows))
    12301247        return { ItemPosition::Stretch, OverflowAlignment::Default };
    12311248    if (!gridStyle)
     
    12371254StyleSelfAlignmentData RenderGrid::justifySelfForChild(const RenderBox& child, StretchingMode stretchingMode, const RenderStyle* gridStyle) const
    12381255{
    1239     if (isSubgridInParentDirection(ForColumns))
     1256    if (is<RenderGrid>(child) && downcast<RenderGrid>(child).isSubgridInParentDirection(ForColumns))
    12401257        return { ItemPosition::Stretch, OverflowAlignment::Default };
    12411258    if (!gridStyle)
     
    14581475LayoutUnit RenderGrid::columnAxisBaselineOffsetForChild(const RenderBox& child) const
    14591476{
     1477    if (isSubgridRows()) {
     1478        RenderGrid* outer = downcast<RenderGrid>(parent());
     1479        if (GridLayoutFunctions::isOrthogonalChild(*outer, *this))
     1480            return outer->rowAxisBaselineOffsetForChild(child);
     1481        return outer->columnAxisBaselineOffsetForChild(child);
     1482    }
    14601483    return m_trackSizingAlgorithm.baselineOffsetForChild(child, GridColumnAxis);
    14611484}
     
    14631486LayoutUnit RenderGrid::rowAxisBaselineOffsetForChild(const RenderBox& child) const
    14641487{
     1488    if (isSubgridColumns()) {
     1489        RenderGrid* outer = downcast<RenderGrid>(parent());
     1490        if (GridLayoutFunctions::isOrthogonalChild(*outer, *this))
     1491            return outer->columnAxisBaselineOffsetForChild(child);
     1492        return outer->rowAxisBaselineOffsetForChild(child);
     1493    }
    14651494    return m_trackSizingAlgorithm.baselineOffsetForChild(child, GridRowAxis);
    14661495}
Note: See TracChangeset for help on using the changeset viewer.