Changeset 109799 in webkit


Ignore:
Timestamp:
Mar 5, 2012 1:59:10 PM (12 years ago)
Author:
tony@chromium.org
Message:

Implement flex-wrap: wrap
https://bugs.webkit.org/show_bug.cgi?id=79930

Reviewed by David Hyatt.

Source/WebCore:

Tests: css3/flexbox/multiline-align.html

css3/flexbox/multiline.html

  • rendering/RenderBox.cpp:

(WebCore::RenderBox::sizesToIntrinsicLogicalWidth): Don't apply column+stretch optimization to multiline.

  • rendering/RenderFlexibleBox.cpp:

(WebCore::RenderFlexibleBox::FlexOrderIterator::FlexOrderIterator):
(WebCore::RenderFlexibleBox::FlexOrderIterator::currentChild): Expose the current child so we can pause
in the middle of iteration and resume later.
(RenderFlexibleBox::FlexOrderIterator):
(WebCore::RenderFlexibleBox::isMultiline):
(WebCore):
(WebCore::RenderFlexibleBox::layoutFlexItems): Loop per line.
(WebCore::RenderFlexibleBox::availableAlignmentSpaceForChild): Use the line space, not the whole container space.
(WebCore::RenderFlexibleBox::computeFlexOrder): Return true for each line.
(WebCore::RenderFlexibleBox::layoutAndPlaceChildren): Use the line offset. Also compute the line height as we go.
(WebCore::RenderFlexibleBox::layoutColumnReverse): Use the line offset.
(WebCore::RenderFlexibleBox::alignChildren): Align based on the line height. For multiline + column, we have to relayout
since the width may change (same as the row case above). We'll have to do something smarter when we implement flex-line-pack.

  • rendering/RenderFlexibleBox.h:

(RenderFlexibleBox):

LayoutTests:

  • css3/flexbox/multiline-align-expected.txt: Added.
  • css3/flexbox/multiline-align.html: Added.
  • css3/flexbox/multiline-expected.txt: Added.
  • css3/flexbox/multiline.html: Added.
Location:
trunk
Files:
4 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r109797 r109799  
     12012-03-05  Tony Chang  <tony@chromium.org>
     2
     3        Implement flex-wrap: wrap
     4        https://bugs.webkit.org/show_bug.cgi?id=79930
     5
     6        Reviewed by David Hyatt.
     7
     8        * css3/flexbox/multiline-align-expected.txt: Added.
     9        * css3/flexbox/multiline-align.html: Added.
     10        * css3/flexbox/multiline-expected.txt: Added.
     11        * css3/flexbox/multiline.html: Added.
     12
    1132012-03-05  Stephen White  <senorblanco@chromium.org>
    214
  • trunk/Source/WebCore/ChangeLog

    r109798 r109799  
     12012-03-05  Tony Chang  <tony@chromium.org>
     2
     3        Implement flex-wrap: wrap
     4        https://bugs.webkit.org/show_bug.cgi?id=79930
     5
     6        Reviewed by David Hyatt.
     7
     8        Tests: css3/flexbox/multiline-align.html
     9               css3/flexbox/multiline.html
     10
     11        * rendering/RenderBox.cpp:
     12        (WebCore::RenderBox::sizesToIntrinsicLogicalWidth): Don't apply column+stretch optimization to multiline.
     13        * rendering/RenderFlexibleBox.cpp:
     14        (WebCore::RenderFlexibleBox::FlexOrderIterator::FlexOrderIterator):
     15        (WebCore::RenderFlexibleBox::FlexOrderIterator::currentChild): Expose the current child so we can pause
     16        in the middle of iteration and resume later.
     17        (RenderFlexibleBox::FlexOrderIterator):
     18        (WebCore::RenderFlexibleBox::isMultiline):
     19        (WebCore):
     20        (WebCore::RenderFlexibleBox::layoutFlexItems): Loop per line.
     21        (WebCore::RenderFlexibleBox::availableAlignmentSpaceForChild): Use the line space, not the whole container space.
     22        (WebCore::RenderFlexibleBox::computeFlexOrder): Return true for each line.
     23        (WebCore::RenderFlexibleBox::layoutAndPlaceChildren): Use the line offset. Also compute the line height as we go.
     24        (WebCore::RenderFlexibleBox::layoutColumnReverse): Use the line offset.
     25        (WebCore::RenderFlexibleBox::alignChildren): Align based on the line height. For multiline + column, we have to relayout
     26        since the width may change (same as the row case above). We'll have to do something smarter when we implement flex-line-pack.
     27        * rendering/RenderFlexibleBox.h:
     28        (RenderFlexibleBox):
     29
    1302012-03-05  Ben Vanik  <benvanik@google.com>
    231
  • trunk/Source/WebCore/rendering/RenderBox.cpp

    r109785 r109799  
    18421842    // stretched size to avoid an extra layout when applying alignment.
    18431843    if (parent()->isFlexibleBox()) {
    1844         if (!parent()->style()->isColumnFlexDirection())
     1844        // For multiline columns, we need to apply the flex-line-pack first, so we can't stretch now.
     1845        if (!parent()->style()->isColumnFlexDirection() || parent()->style()->flexWrap() != FlexWrapNone)
    18451846            return true;
    18461847        EFlexAlign itemAlign = style()->flexItemAlign();
  • trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp

    r109785 r109799  
    5757        copyToVector(flexOrderValues, m_orderValues);
    5858        std::sort(m_orderValues.begin(), m_orderValues.end());
    59     }
     59        first();
     60    }
     61
     62    RenderBox* currentChild() { return m_currentChild; }
    6063
    6164    RenderBox* first()
     
    280283}
    281284
     285bool RenderFlexibleBox::isMultiline() const
     286{
     287    return style()->flexWrap() != FlexWrapNone;
     288}
     289
    282290Length RenderFlexibleBox::mainAxisLengthForChild(RenderBox* child) const
    283291{
     
    510518    float totalNegativeFlexibility;
    511519    FlexOrderIterator flexIterator(this, flexOrderValues);
    512     computeFlexOrder(flexIterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility);
    513 
    514     LayoutUnit availableFreeSpace = mainAxisContentExtent() - preferredMainAxisExtent;
    515     InflexibleFlexItemSize inflexibleItems;
    516     WTF::Vector<LayoutUnit> childSizes;
    517     while (!runFreeSpaceAllocationAlgorithm(orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) {
    518         ASSERT(totalPositiveFlexibility >= 0 && totalNegativeFlexibility >= 0);
    519         ASSERT(inflexibleItems.size() > 0);
    520     }
    521 
    522     layoutAndPlaceChildren(orderedChildren, childSizes, availableFreeSpace);
     520
     521    LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
     522    LayoutUnit mainAxisFlexibleSpace = mainAxisContentExtent();
     523    while (computeNextFlexLine(flexIterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility)) {
     524        LayoutUnit availableFreeSpace = mainAxisFlexibleSpace - preferredMainAxisExtent;
     525        InflexibleFlexItemSize inflexibleItems;
     526        WTF::Vector<LayoutUnit> childSizes;
     527        while (!runFreeSpaceAllocationAlgorithm(orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) {
     528            ASSERT(totalPositiveFlexibility >= 0 && totalNegativeFlexibility >= 0);
     529            ASSERT(inflexibleItems.size() > 0);
     530        }
     531
     532        layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace);
     533    }
    523534
    524535    // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
     
    536547}
    537548
    538 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(RenderBox* child)
    539 {
    540     LayoutUnit crossContentExtent = crossAxisContentExtent();
     549LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
     550{
    541551    LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
    542     return crossContentExtent - childCrossExtent;
     552    return lineCrossAxisExtent - childCrossExtent;
    543553}
    544554
     
    580590}
    581591
    582 void RenderFlexibleBox::computeFlexOrder(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility)
     592bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility)
    583593{
    584594    orderedChildren.clear();
    585595    preferredMainAxisExtent = 0;
    586596    totalPositiveFlexibility = totalNegativeFlexibility = 0;
    587     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
    588         orderedChildren.append(child);
    589         if (child->isPositioned())
     597
     598    if (!iterator.currentChild())
     599        return false;
     600
     601    for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) {
     602        if (child->isPositioned()) {
     603            orderedChildren.append(child);
    590604            continue;
     605        }
    591606
    592607        LayoutUnit childMainAxisExtent = mainAxisBorderAndPaddingExtentForChild(child) + preferredMainAxisContentExtentForChild(child);
     
    596611            childMainAxisExtent += child->marginTop() + child->marginBottom();
    597612
    598         // FIXME: When implementing multiline, we would return here if adding
    599         // the child's main axis extent would cause us to overflow.
     613        if (isMultiline() && preferredMainAxisExtent + childMainAxisExtent > mainAxisContentExtent() && orderedChildren.size() > 0)
     614            break;
     615        orderedChildren.append(child);
    600616        preferredMainAxisExtent += childMainAxisExtent;
    601617        totalPositiveFlexibility += positiveFlexForChild(child);
    602618        totalNegativeFlexibility += negativeFlexForChild(child);
    603619    }
     620    return true;
    604621}
    605622
     
    715732}
    716733
    717 void RenderFlexibleBox::layoutAndPlaceChildren(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace)
     734void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace)
    718735{
    719736    LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
     
    722739        mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
    723740
    724     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
    725741    LayoutUnit totalMainExtent = mainAxisExtent();
    726742    LayoutUnit maxAscent = 0, maxDescent = 0; // Used when flex-align: baseline.
     743    LayoutUnit maxChildCrossAxisExtent = 0;
    727744    bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
    728745    for (size_t i = 0; i < children.size(); ++i) {
     
    750767            childCrossAxisExtent =  crossAxisExtentForChild(child);
    751768        if (crossAxisLength().isAuto())
    752             setCrossAxisExtent(std::max(crossAxisExtent(), crossAxisBorderAndPaddingExtent() + crossAxisMarginExtentForChild(child) + childCrossAxisExtent + crossAxisScrollbarExtent()));
     769            setCrossAxisExtent(std::max(crossAxisExtent(), crossAxisOffset - flowAwareBorderBefore() - flowAwarePaddingBefore() + crossAxisBorderAndPaddingExtent() + crossAxisMarginExtentForChild(child) + childCrossAxisExtent + crossAxisScrollbarExtent()));
     770        maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisExtent + crossAxisMarginExtentForChild(child));
    753771
    754772        mainAxisOffset += flowAwareMarginStartForChild(child);
     
    772790        // on the height of the flexbox, which we only know after we've positioned all the flex items.
    773791        computeLogicalHeight();
    774         layoutColumnReverse(children, childSizes, availableFreeSpace);
    775     }
    776 
    777     alignChildren(children, maxAscent);
    778 }
    779 
    780 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace)
     792        layoutColumnReverse(children, childSizes, crossAxisOffset, availableFreeSpace);
     793    }
     794
     795    LayoutUnit lineCrossAxisExtent = isMultiline() ? maxChildCrossAxisExtent : crossAxisContentExtent();
     796    alignChildren(children, lineCrossAxisExtent, maxAscent);
     797
     798    crossAxisOffset += lineCrossAxisExtent;
     799}
     800
     801void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
    781802{
    782803    // This is similar to the logic in layoutAndPlaceChildren, except we place the children
     
    787808    mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
    788809
    789     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
    790810    for (size_t i = 0; i < children.size(); ++i) {
    791811        RenderBox* child = children[i];
     
    820840}
    821841
    822 void RenderFlexibleBox::alignChildren(const OrderedFlexItemList& children, LayoutUnit maxAscent)
     842void RenderFlexibleBox::alignChildren(const OrderedFlexItemList& children, LayoutUnit lineCrossAxisExtent, LayoutUnit maxAscent)
    823843{
    824844    for (size_t i = 0; i < children.size(); ++i) {
     
    831851            if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
    832852                LayoutUnit logicalHeightBefore = child->logicalHeight();
    833                 LayoutUnit stretchedLogicalHeight = child->logicalHeight() + RenderFlexibleBox::availableAlignmentSpaceForChild(child);
     853                LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
    834854                child->setLogicalHeight(stretchedLogicalHeight);
    835855                child->computeLogicalHeight();
     
    841861                    child->layoutIfNeeded();
    842862                }
     863            } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) {
     864                // FIXME: Handle min-width and max-width.
     865                LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child);
     866                child->setOverrideWidth(std::max(0, childWidth));
     867                child->setChildNeedsLayout(true);
     868                child->layoutIfNeeded();
    843869            }
    844870            break;
     
    847873            break;
    848874        case AlignEnd:
    849             adjustAlignmentForChild(child, RenderFlexibleBox::availableAlignmentSpaceForChild(child));
     875            adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
    850876            break;
    851877        case AlignCenter:
    852             adjustAlignmentForChild(child, RenderFlexibleBox::availableAlignmentSpaceForChild(child) / 2);
     878            adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
    853879            break;
    854880        case AlignBaseline: {
  • trunk/Source/WebCore/rendering/RenderFlexibleBox.h

    r108876 r109799  
    6060    bool isColumnFlow() const;
    6161    bool isLeftToRightFlow() const;
     62    bool isMultiline() const;
    6263    Length crossAxisLength() const;
    6364    Length mainAxisLengthForChild(RenderBox* child) const;
     
    9697    float negativeFlexForChild(RenderBox* child) const;
    9798
    98     LayoutUnit availableAlignmentSpaceForChild(RenderBox*);
     99    LayoutUnit availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox*);
    99100    LayoutUnit marginBoxAscent(RenderBox*);
    100101
    101102    void computeMainAxisPreferredSizes(bool relayoutChildren, FlexOrderHashSet&);
    102     void computeFlexOrder(FlexOrderIterator&, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility);
     103    bool computeNextFlexLine(FlexOrderIterator&, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility);
    103104    bool runFreeSpaceAllocationAlgorithm(const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize&, WTF::Vector<LayoutUnit>& childSizes);
    104105    void setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize);
    105106    void prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset);
    106     void layoutAndPlaceChildren(const OrderedFlexItemList&, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace);
    107     void layoutColumnReverse(const OrderedFlexItemList&, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace);
    108     void alignChildren(const OrderedFlexItemList&, LayoutUnit maxAscent);
     107    void layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList&, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace);
     108    void layoutColumnReverse(const OrderedFlexItemList&, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace);
     109    void alignChildren(const OrderedFlexItemList&, LayoutUnit lineCrossAxisExtent, LayoutUnit maxAscent);
    109110    void flipForRightToLeftColumn(FlexOrderIterator&);
    110111};
Note: See TracChangeset for help on using the changeset viewer.