Ignore:
Timestamp:
Oct 14, 2013, 3:36:39 AM (12 years ago)
Author:
[email protected]
Message:

[CSS Grid Layout] Implement support for <flex>
https://bugs.webkit.org/show_bug.cgi?id=115362

Reviewed by Andreas Kling.

From Blink r149134, r149480, r149532, r150287 and r156127 by <[email protected]>
From Blink r157820 by <[email protected]>

Source/WebCore:

Added support for flexible lengths ('fr' unit) in CSS Grid Layout
code. This requires the addition of GridLength class to
encapsulate the knowledge of <flex> to the grid layout code.

Also updated the algorithm that computes the layout. It increases
the value of 1fr based on the grid tracks' usedBreath to fraction
ratio (called normalizedFractionValue). This enables increasing
the fraction value while updating the available space to account
for processed grid tracks. The algorithm stops when we run out of
grid tracks or available space (one grid item has an intrinsic
size too big). This matches the specs to the letter for the known
available space case (both the unknown case and the interaction
with 'span' are left out of this patch).

Tests: fast/css-grid-layout/flex-and-minmax-content-resolution-columns.html

fast/css-grid-layout/flex-and-minmax-content-resolution-rows.html
fast/css-grid-layout/flex-content-resolution-columns.html
fast/css-grid-layout/flex-content-resolution-rows.html

  • GNUmakefile.list.am: Added GridLength.h to the build system.
  • Target.pri: Ditto.
  • WebCore.vcxproj/WebCore.vcxproj: Ditto.
  • WebCore.vcxproj/WebCore.vcxproj.filters: Ditto.
  • WebCore.xcodeproj/project.pbxproj: Ditto.
  • css/CSSComputedStyleDeclaration.cpp:

(WebCore::valueForGridTrackBreadth): Replace Length by GridLength.

  • css/CSSGrammar.y.in: Added FR support.
  • css/CSSParser.cpp: Ditto.

(WebCore::CSSParser::parseGridBreadth):
(WebCore::CSSParser::detectNumberToken):

  • css/CSSParserValues.cpp: Added FR support.

(WebCore::CSSParserValue::createCSSValue):

  • css/CSSParserValues.h:

(WebCore::CSSParserString::operator[]):
(WebCore::CSSParserString::equalIgnoringCase):

  • css/CSSPrimitiveValue.cpp: Added FR support.

(WebCore::isValidCSSUnitTypeForDoubleConversion):
(WebCore::CSSPrimitiveValue::cleanup):
(WebCore::CSSPrimitiveValue::customCSSText):
(WebCore::CSSPrimitiveValue::cloneForCSSOM):
(WebCore::CSSPrimitiveValue::equals):

  • css/CSSPrimitiveValue.h: Added a couple of missing const.

(WebCore::CSSPrimitiveValue::isFlex):

  • css/StyleResolver.cpp: Added FR support.

(WebCore::createGridTrackBreadth):
(WebCore::createGridTrackSize):

  • rendering/RenderGrid.cpp:

(WebCore::GridTrackForNormalization::GridTrackForNormalization):
New helper struct to ease the computation of track breadths with
flexible lengths.
(WebCore::GridTrackForNormalization::operator=):
(WebCore::RenderGrid::computePreferredTrackWidth): Replaced Length by GridLength.
(WebCore::RenderGrid::computedUsedBreadthOfGridTracks): Grow grid lines
having a fraction as the MaxTrackSizingFunction.
(WebCore::RenderGrid::computeUsedBreadthOfMinLength): Replaced Length by GridLength.
(WebCore::RenderGrid::computeUsedBreadthOfMaxLength): Ditto.
(WebCore::sortByGridNormalizedFlexValue):
(WebCore::RenderGrid::computeNormalizedFractionBreadth): Increase
the fraction value while updating the available space to account
for processed grid tracks.
(WebCore::RenderGrid::resolveContentBasedTrackSizingFunctions):
(WebCore::RenderGrid::distributeSpaceToTracks): Never shrink track sizes.
(WebCore::RenderGrid::tracksAreWiderThanMinTrackBreadth):

  • rendering/RenderGrid.h:
  • rendering/style/GridLength.h: Added.

(WebCore::GridLength::GridLength):
(WebCore::GridLength::isLength):
(WebCore::GridLength::isFlex):
(WebCore::GridLength::length):
(WebCore::GridLength::flex):
(WebCore::GridLength::setFlex):
(WebCore::GridLength::operator==):

  • rendering/style/GridTrackSize.h: Replaced Length by GridLength.

(WebCore::GridTrackSize::length):
(WebCore::GridTrackSize::setLength):
(WebCore::GridTrackSize::minTrackBreadth):
(WebCore::GridTrackSize::maxTrackBreadth):
(WebCore::GridTrackSize::setMinMax):
(WebCore::GridTrackSize::hasMinOrMaxContentMinTrackBreadth):
(WebCore::GridTrackSize::hasMaxContentMinTrackBreadth):
(WebCore::GridTrackSize::hasMinOrMaxContentMaxTrackBreadth):
(WebCore::GridTrackSize::hasMaxContentMaxTrackBreadth):

LayoutTests:

Added 4 new test cases to test the support for <flex> in CSS Grid
Layout code. Also updated some of the existing ones to check the
support for 'fr' units.

  • fast/css-grid-layout/flex-and-minmax-content-resolution-columns-expected.txt: Added.
  • fast/css-grid-layout/flex-and-minmax-content-resolution-columns.html: Added.
  • fast/css-grid-layout/flex-and-minmax-content-resolution-rows-expected.txt: Added.
  • fast/css-grid-layout/flex-and-minmax-content-resolution-rows.html: Added.
  • fast/css-grid-layout/flex-content-resolution-columns-expected.txt: Added.
  • fast/css-grid-layout/flex-content-resolution-columns.html: Added.
  • fast/css-grid-layout/flex-content-resolution-rows-expected.txt: Added.
  • fast/css-grid-layout/flex-content-resolution-rows.html: Added.
  • fast/css-grid-layout/grid-columns-rows-get-set-expected.txt:
  • fast/css-grid-layout/grid-columns-rows-get-set-multiple-expected.txt:
  • fast/css-grid-layout/grid-columns-rows-get-set-multiple.html:
  • fast/css-grid-layout/grid-columns-rows-get-set.html:
  • fast/css-grid-layout/grid-dynamic-updates-relayout-expected.txt:
  • fast/css-grid-layout/grid-dynamic-updates-relayout.html:
  • fast/css-grid-layout/resources/grid-columns-rows-get-set-multiple.js:
  • fast/css-grid-layout/resources/grid-columns-rows-get-set.js:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/rendering/RenderGrid.cpp

    r157389 r157393  
    11/*
    22 * Copyright (C) 2011 Apple Inc. All rights reserved.
     3 * Copyright (C) 2013 Igalia S.L.
    34 *
    45 * Redistribution and use in source and binary forms, with or without
     
    6869};
    6970
     71struct GridTrackForNormalization {
     72    GridTrackForNormalization(const GridTrack& track, double flex)
     73        : m_track(&track)
     74        , m_flex(flex)
     75        , m_normalizedFlexValue(track.m_usedBreadth / flex)
     76    {
     77    }
     78
     79    const GridTrack* m_track;
     80    double m_flex;
     81    LayoutUnit m_normalizedFlexValue;
     82};
     83
    7084class RenderGrid::GridIterator {
    7185    WTF_MAKE_NONCOPYABLE(GridIterator);
     
    230244}
    231245
    232 LayoutUnit RenderGrid::computePreferredTrackWidth(const Length& length, size_t trackIndex) const
    233 {
     246LayoutUnit RenderGrid::computePreferredTrackWidth(const GridLength& gridLength, size_t trackIndex) const
     247{
     248    if (gridLength.isFlex())
     249        return 0;
     250
     251    const Length& length = gridLength.length();
     252
    234253    if (length.isFixed()) {
    235254        // Grid areas don't have borders, margins or paddings so we don't need to account for them.
     
    269288        GridTrack& track = tracks[i];
    270289        const GridTrackSize& trackSize = gridTrackSize(direction, i);
    271         const Length& minTrackBreadth = trackSize.minTrackBreadth();
    272         const Length& maxTrackBreadth = trackSize.maxTrackBreadth();
     290        const GridLength& minTrackBreadth = trackSize.minTrackBreadth();
     291        const GridLength& maxTrackBreadth = trackSize.maxTrackBreadth();
    273292
    274293        track.m_usedBreadth = computeUsedBreadthOfMinLength(direction, minTrackBreadth);
    275         track.m_maxBreadth = computeUsedBreadthOfMaxLength(direction, maxTrackBreadth);
     294        track.m_maxBreadth = computeUsedBreadthOfMaxLength(direction, maxTrackBreadth, track.m_usedBreadth);
    276295
    277296        track.m_maxBreadth = std::max(track.m_maxBreadth, track.m_usedBreadth);
     
    290309
    291310    distributeSpaceToTracks(tracksForDistribution, 0, &GridTrack::usedBreadth, &GridTrack::growUsedBreadth, availableLogicalSpace);
    292 }
    293 
    294 LayoutUnit RenderGrid::computeUsedBreadthOfMinLength(TrackSizingDirection direction, const Length& trackLength) const
    295 {
     311
     312    // 4. Grow all Grid tracks having a fraction as the MaxTrackSizingFunction.
     313
     314    // FIXME: Handle the case where RemainingSpace is not defined.
     315    double normalizedFractionBreadth = computeNormalizedFractionBreadth(tracks, direction, availableLogicalSpace);
     316    for (size_t i = 0; i < tracksSize; ++i) {
     317        const GridTrackSize& trackSize = gridTrackSize(direction, i);
     318        if (!trackSize.maxTrackBreadth().isFlex())
     319            continue;
     320
     321        tracks[i].m_usedBreadth = std::max<LayoutUnit>(tracks[i].m_usedBreadth, normalizedFractionBreadth * trackSize.maxTrackBreadth().flex());
     322    }
     323}
     324
     325LayoutUnit RenderGrid::computeUsedBreadthOfMinLength(TrackSizingDirection direction, const GridLength& gridLength) const
     326{
     327    if (gridLength.isFlex())
     328        return 0;
     329
     330    const Length& trackLength = gridLength.length();
     331    ASSERT(!trackLength.isAuto());
    296332    if (trackLength.isFixed() || trackLength.isPercent() || trackLength.isViewportPercentage())
    297333        return computeUsedBreadthOfSpecifiedLength(direction, trackLength);
    298334
    299     ASSERT(trackLength.isMinContent() || trackLength.isMaxContent() || trackLength.isAuto());
     335    ASSERT(trackLength.isMinContent() || trackLength.isMaxContent());
    300336    return 0;
    301337}
    302338
    303 LayoutUnit RenderGrid::computeUsedBreadthOfMaxLength(TrackSizingDirection direction, const Length& trackLength) const
    304 {
     339LayoutUnit RenderGrid::computeUsedBreadthOfMaxLength(TrackSizingDirection direction, const GridLength& gridLength, LayoutUnit usedBreadth) const
     340{
     341    if (gridLength.isFlex())
     342        return usedBreadth;
     343
     344    const Length& trackLength = gridLength.length();
     345    ASSERT(!trackLength.isAuto());
    305346    if (trackLength.isFixed() || trackLength.isPercent() || trackLength.isViewportPercentage()) {
    306347        LayoutUnit computedBreadth = computeUsedBreadthOfSpecifiedLength(direction, trackLength);
     
    309350    }
    310351
    311     ASSERT(trackLength.isMinContent() || trackLength.isMaxContent() || trackLength.isAuto());
     352    ASSERT(trackLength.isMinContent() || trackLength.isMaxContent());
    312353    return infinity;
    313354}
     
    318359    ASSERT(trackLength.isFixed() || trackLength.isPercent() || trackLength.isViewportPercentage());
    319360    return valueForLength(trackLength, direction == ForColumns ? logicalWidth() : computeContentLogicalHeight(style()->logicalHeight()));
     361}
     362
     363double RenderGrid::computeNormalizedFractionBreadth(Vector<GridTrack>& tracks, TrackSizingDirection direction, LayoutUnit availableLogicalSpace) const
     364{
     365    // |availableLogicalSpace| already accounts for the used breadths so no need to remove it here.
     366
     367    Vector<GridTrackForNormalization> tracksForNormalization;
     368    for (size_t i = 0; i < tracks.size(); ++i) {
     369        const GridTrackSize& trackSize = gridTrackSize(direction, i);
     370        if (!trackSize.maxTrackBreadth().isFlex())
     371            continue;
     372
     373        tracksForNormalization.append(GridTrackForNormalization(tracks[i], trackSize.maxTrackBreadth().flex()));
     374    }
     375
     376    // FIXME: Ideally we shouldn't come here without any <flex> grid track.
     377    if (tracksForNormalization.isEmpty())
     378        return LayoutUnit();
     379
     380    std::sort(tracksForNormalization.begin(), tracksForNormalization.end(),
     381              [](const GridTrackForNormalization& track1, const GridTrackForNormalization& track2) {
     382                  return track1.m_normalizedFlexValue < track2.m_normalizedFlexValue;
     383              });
     384
     385    // These values work together: as we walk over our grid tracks, we increase fractionValueBasedOnGridItemsRatio
     386    // to match a grid track's usedBreadth to <flex> ratio until the total fractions sized grid tracks wouldn't
     387    // fit into availableLogicalSpaceIgnoringFractionTracks.
     388    double accumulatedFractions = 0;
     389    LayoutUnit fractionValueBasedOnGridItemsRatio = 0;
     390    LayoutUnit availableLogicalSpaceIgnoringFractionTracks = availableLogicalSpace;
     391
     392    for (size_t i = 0; i < tracksForNormalization.size(); ++i) {
     393        const GridTrackForNormalization& track = tracksForNormalization[i];
     394        if (track.m_normalizedFlexValue > fractionValueBasedOnGridItemsRatio) {
     395            // If the normalized flex value (we ordered |tracksForNormalization| by increasing normalized flex value)
     396            // will make us overflow our container, then stop. We have the previous step's ratio is the best fit.
     397            if (track.m_normalizedFlexValue * accumulatedFractions > availableLogicalSpaceIgnoringFractionTracks)
     398                break;
     399
     400            fractionValueBasedOnGridItemsRatio = track.m_normalizedFlexValue;
     401        }
     402
     403        accumulatedFractions += track.m_flex;
     404        // This item was processed so we re-add its used breadth to the available space to accurately count the remaining space.
     405        availableLogicalSpaceIgnoringFractionTracks += track.m_track->m_usedBreadth;
     406    }
     407
     408    return availableLogicalSpaceIgnoringFractionTracks / accumulatedFractions;
    320409}
    321410
     
    413502void RenderGrid::resolveContentBasedTrackSizingFunctions(TrackSizingDirection direction, Vector<GridTrack>& columnTracks, Vector<GridTrack>& rowTracks, LayoutUnit& availableLogicalSpace)
    414503{
    415     // FIXME: Split the grid tracks once we support fractions (step 1 of the algorithm).
     504    // FIXME: Split the grid tracks into groups that doesn't overlap a <flex> grid track.
    416505
    417506    Vector<GridTrack>& tracks = (direction == ForColumns) ? columnTracks : rowTracks;
     
    476565        LayoutUnit availableLogicalSpaceShare = availableLogicalSpace / (tracksSize - i);
    477566        LayoutUnit trackBreadth = (tracks[i]->*trackGetter)();
    478         LayoutUnit growthShare = std::min(availableLogicalSpaceShare, track.m_maxBreadth - trackBreadth);
     567        LayoutUnit growthShare = std::max(LayoutUnit(), std::min(availableLogicalSpaceShare, track.m_maxBreadth - trackBreadth));
     568        // We should never shrink any grid track or else we can't guarantee we abide by our min-sizing function.
    479569        updatedTrackBreadths[i] = trackBreadth + growthShare;
    480570        availableLogicalSpace -= growthShare;
     
    502592    for (size_t i = 0; i < tracks.size(); ++i) {
    503593        const GridTrackSize& trackSize = gridTrackSize(direction, i);
    504         const Length& minTrackBreadth = trackSize.minTrackBreadth();
     594        const GridLength& minTrackBreadth = trackSize.minTrackBreadth();
    505595        if (computeUsedBreadthOfMinLength(direction, minTrackBreadth) > tracks[i].m_usedBreadth)
    506596            return false;
Note: See TracChangeset for help on using the changeset viewer.