Title: [150087] trunk
Revision
150087
Author
hy...@apple.com
Date
2013-05-14 13:37:13 -0700 (Tue, 14 May 2013)

Log Message

Source/WebCore: REGRESSION: united.com has overlapping elements and is broken by flex box changes.
https://bugs.webkit.org/show_bug.cgi?id=115329
<rdar://problem/13690610>
        
The new flexbox spec says that flex-basis omitted in the flex shorthand defaults to
0 when flex-grow/shrink are set. This has undesirable behavior when objects don't
end up flexing at all, and it's something the spec is going to eventually address.
        
For now, though, to fix the regression, I'm making a targeted "hack" to deliberately
violate the spec, but to do so as minimally as possible. This hack detects if there
is infinite available space on a line, and if so, it treats a flex-basis of 0 like
auto.
        
This means that when height is constrained and set by a container, flexing will do
the right thing. Basically any time you end up actually flexing, the spec behavior
should happen. If you're just laying out at intrinsic sizes, though, and no flexing
is going to occur, we ignore a flex-basis of 0 and just use the child's normal size.
        
Note that widths don't have to be patched because the preferred logical widths
algorithm is broken right now and not checking flex-basis. If it did, we'd have seen
the same bug in the width direction.
        
This width issue is covered by https://bugs.webkit.org/show_bug.cgi?id=116117
        
Reviewed by Simon Fraser.

Added fast/flexbox/auto-height-with-flex.html

* rendering/RenderFlexibleBox.cpp:
(WebCore::RenderFlexibleBox::mainAxisContentExtent):
Make sure we return LayoutUnit::max when you have infinite free space and not
max - borderPadding.

(WebCore::RenderFlexibleBox::preferredMainAxisContentExtentForChild):
Only clear override size if it was set. Only mark for relayout if we did
an override size clear (i.e., if we were actually flexed). Add a new parameter,
hasInfiniteLineLength, that - if set - causes us to special case flex-basis:0
and treat it like flex-basis:auto.

(WebCore::RenderFlexibleBox::layoutFlexItems):
Define hasInfiniteLineLength and pass it to all the functions that need it.

(WebCore::RenderFlexibleBox::computeMainAxisPreferredSizes):
Remove the code that marks for layout and does a layout so early. This code
is moving (and changing) to preferredMainAxisContentExtentForChild.

(WebCore::RenderFlexibleBox::computeNextFlexLine):
Computes whether or not we have infinite line length now.

(WebCore::RenderFlexibleBox::freezeViolations):
(WebCore::RenderFlexibleBox::resolveFlexibleLengths):
Propagate hasInfiniteLineLength through to preferredMainAxisContentExtentForChild.

* rendering/RenderFlexibleBox.h:
(RenderFlexibleBox):
Add hasInfiniteLineLength parameter to a bunch of functions.

LayoutTests: REGRESSION (r147261): Many overlaid elements on united.com's account page
https://bugs.webkit.org/show_bug.cgi?id=116107
<rdar://problem/13690610> 

Reviewed by Simon Fraser.

* fast/flexbox/auto-height-with-flex-expected.html: Added.
* fast/flexbox/auto-height-with-flex.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (150086 => 150087)


--- trunk/LayoutTests/ChangeLog	2013-05-14 20:37:09 UTC (rev 150086)
+++ trunk/LayoutTests/ChangeLog	2013-05-14 20:37:13 UTC (rev 150087)
@@ -1,3 +1,14 @@
+2013-05-14  David Hyatt  <hy...@apple.com>
+
+        REGRESSION (r147261): Many overlaid elements on united.com's account page
+        https://bugs.webkit.org/show_bug.cgi?id=116107
+        <rdar://problem/13690610> 
+
+        Reviewed by Simon Fraser.
+
+        * fast/flexbox/auto-height-with-flex-expected.html: Added.
+        * fast/flexbox/auto-height-with-flex.html: Added.
+
 2013-05-14  Bem Jones-Bey  <bjone...@adobe.com>
 
         Heap-use-after-free in WebCore::RenderBox::exclusionShapeOutsideInfo

Modified: trunk/LayoutTests/css3/flexbox/columns-auto-size.html (150086 => 150087)


--- trunk/LayoutTests/css3/flexbox/columns-auto-size.html	2013-05-14 20:37:09 UTC (rev 150086)
+++ trunk/LayoutTests/css3/flexbox/columns-auto-size.html	2013-05-14 20:37:13 UTC (rev 150087)
@@ -54,7 +54,7 @@
   <div data-expected-height="0" data-offset-y="0" style="-webkit-flex: 1; -moz-flex: 1"></div>
   <div data-expected-height="10" data-offset-y="0" style="height: 10px;"></div>
   <div data-expected-height="10" data-offset-y="10" style="-webkit-flex: 1 auto; -moz-flex: 1 auto"><div style="height: 10px"></div></div>
-  <div data-expected-height="0" data-offset-y="20" style="min-height: 0; -webkit-flex: 1; -moz-flex: 1"><div data-expected-height="10" data-offset-y="20" class="child-div" style="height: 10px"></div></div>
+  <div data-expected-height="10" data-offset-y="20" style="min-height: 0; -webkit-flex: 1; -moz-flex: 1"><div data-expected-height="10" data-offset-y="20" class="child-div" style="height: 10px"></div></div>
 </div>
 
 <div class="flexbox column horizontal">
@@ -103,7 +103,7 @@
 
 <!-- The first div overflows to the left, so give it a margin-left so we can see box it paints. -->
 <div class="flexbox column vertical" style="margin-left: 100px;">
-  <div data-expected-width="0" data-offset-x="20" style="min-width: 0; -webkit-flex: 1; -moz-flex: 1"><div data-expected-width="50" data-offset-x="-30" class="child-div" style="width: 50px"></div></div>
+  <div data-expected-width="50" data-offset-x="20" style="min-width: 0; -webkit-flex: 1; -moz-flex: 1"><div data-expected-width="50" data-offset-x="20" class="child-div" style="width: 50px"></div></div>
   <div data-expected-width="0" data-offset-x="20" style="-webkit-flex: 1; -moz-flex: 1"></div>
   <div data-expected-width="10" data-offset-x="10" style="width: 10px;"></div>
   <div data-expected-width="10" data-offset-x="0" style="-webkit-flex: 1 auto; -moz-flex: 1 auto"><div style="width: 10px"></div></div>

Added: trunk/LayoutTests/fast/flexbox/auto-height-with-flex-expected.html (0 => 150087)


--- trunk/LayoutTests/fast/flexbox/auto-height-with-flex-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/flexbox/auto-height-with-flex-expected.html	2013-05-14 20:37:13 UTC (rev 150087)
@@ -0,0 +1,5 @@
+<div style="border:1px solid purple;">
+<div>Header</div>
+<div>Flexible content<br>
+</div>
+</div>

Added: trunk/LayoutTests/fast/flexbox/auto-height-with-flex.html (0 => 150087)


--- trunk/LayoutTests/fast/flexbox/auto-height-with-flex.html	                        (rev 0)
+++ trunk/LayoutTests/fast/flexbox/auto-height-with-flex.html	2013-05-14 20:37:13 UTC (rev 150087)
@@ -0,0 +1,5 @@
+<div style="display:-webkit-flex; -webkit-flex-direction:column; border:1px solid purple;">
+<div>Header</div>
+<div style="-webkit-flex:1">Flexible content<br>
+</div>
+</div>

Modified: trunk/Source/WebCore/ChangeLog (150086 => 150087)


--- trunk/Source/WebCore/ChangeLog	2013-05-14 20:37:09 UTC (rev 150086)
+++ trunk/Source/WebCore/ChangeLog	2013-05-14 20:37:13 UTC (rev 150087)
@@ -1,3 +1,62 @@
+2013-05-14  David Hyatt  <hy...@apple.com>
+
+        REGRESSION: united.com has overlapping elements and is broken by flex box changes.
+        https://bugs.webkit.org/show_bug.cgi?id=115329
+        <rdar://problem/13690610>
+        
+        The new flexbox spec says that flex-basis omitted in the flex shorthand defaults to
+        0 when flex-grow/shrink are set. This has undesirable behavior when objects don't
+        end up flexing at all, and it's something the spec is going to eventually address.
+        
+        For now, though, to fix the regression, I'm making a targeted "hack" to deliberately
+        violate the spec, but to do so as minimally as possible. This hack detects if there
+        is infinite available space on a line, and if so, it treats a flex-basis of 0 like
+        auto.
+        
+        This means that when height is constrained and set by a container, flexing will do
+        the right thing. Basically any time you end up actually flexing, the spec behavior
+        should happen. If you're just laying out at intrinsic sizes, though, and no flexing
+        is going to occur, we ignore a flex-basis of 0 and just use the child's normal size.
+        
+        Note that widths don't have to be patched because the preferred logical widths
+        algorithm is broken right now and not checking flex-basis. If it did, we'd have seen
+        the same bug in the width direction.
+        
+        This width issue is covered by https://bugs.webkit.org/show_bug.cgi?id=116117
+        
+        Reviewed by Simon Fraser.
+
+        Added fast/flexbox/auto-height-with-flex.html
+
+        * rendering/RenderFlexibleBox.cpp:
+        (WebCore::RenderFlexibleBox::mainAxisContentExtent):
+        Make sure we return LayoutUnit::max when you have infinite free space and not
+        max - borderPadding.
+
+        (WebCore::RenderFlexibleBox::preferredMainAxisContentExtentForChild):
+        Only clear override size if it was set. Only mark for relayout if we did
+        an override size clear (i.e., if we were actually flexed). Add a new parameter,
+        hasInfiniteLineLength, that - if set - causes us to special case flex-basis:0
+        and treat it like flex-basis:auto.
+
+        (WebCore::RenderFlexibleBox::layoutFlexItems):
+        Define hasInfiniteLineLength and pass it to all the functions that need it.
+
+        (WebCore::RenderFlexibleBox::computeMainAxisPreferredSizes):
+        Remove the code that marks for layout and does a layout so early. This code
+        is moving (and changing) to preferredMainAxisContentExtentForChild.
+
+        (WebCore::RenderFlexibleBox::computeNextFlexLine):
+        Computes whether or not we have infinite line length now.
+
+        (WebCore::RenderFlexibleBox::freezeViolations):
+        (WebCore::RenderFlexibleBox::resolveFlexibleLengths):
+        Propagate hasInfiniteLineLength through to preferredMainAxisContentExtentForChild.
+
+        * rendering/RenderFlexibleBox.h:
+        (RenderFlexibleBox):
+        Add hasInfiniteLineLength parameter to a bunch of functions.
+
 2013-05-14  Andreas Kling  <akl...@apple.com>
 
         Assertion failure in GlyphPage::setGlyphDataForIndex: (!glyph || fontData == m_fontDataForAllGlyphs)

Modified: trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp (150086 => 150087)


--- trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp	2013-05-14 20:37:09 UTC (rev 150086)
+++ trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp	2013-05-14 20:37:13 UTC (rev 150087)
@@ -164,6 +164,9 @@
 
 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
 {
+    // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
+    // the flex shorthand stops setting it to 0.
+    // See https://bugs.webkit.org/show_bug.cgi?id=116117,
     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
         if (child->isOutOfFlowPositioned())
             continue;
@@ -525,6 +528,8 @@
         // FIXME: Remove this std:max once we enable saturated layout arithmetic. It's just here to handle overflow.
         LayoutUnit borderBoxLogicalHeight = std::max(contentLogicalHeight, contentLogicalHeight + borderPaddingAndScrollbar);
         computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
+        if (computedValues.m_extent == LayoutUnit::max())
+            return computedValues.m_extent;
         return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
     }
     return contentLogicalWidth();
@@ -734,10 +739,19 @@
     return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
 }
 
-LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child)
+LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength)
 {
+    bool hasOverrideSize = child->hasOverrideWidth() || child->hasOverrideHeight();
+    if (hasOverrideSize)
+        child->clearOverrideSize();
+
     Length flexBasis = flexBasisForChild(child);
-    if (flexBasis.isAuto()) {
+    if (flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength)) {
+        if (hasOrthogonalFlow(child)) {
+            if (hasOverrideSize)
+                child->setChildNeedsLayout(true, MarkOnlyThis);
+            child->layoutIfNeeded();
+        }
         LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
         ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
         return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
@@ -755,12 +769,13 @@
 
     m_orderIterator.first();
     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
-    while (computeNextFlexLine(orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent)) {
+    bool hasInfiniteLineLength = false;
+    while (computeNextFlexLine(orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent, hasInfiniteLineLength)) {
         LayoutUnit availableFreeSpace = mainAxisContentExtent(preferredMainAxisExtent) - preferredMainAxisExtent;
         FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility;
         InflexibleFlexItemSize inflexibleItems;
         Vector<LayoutUnit> childSizes;
-        while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes)) {
+        while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
             ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
             ASSERT(inflexibleItems.size() > 0);
         }
@@ -904,14 +919,6 @@
         if (child->isOutOfFlowPositioned())
             continue;
 
-        child->clearOverrideSize();
-
-        // Only need to layout here if we will need to get the logicalHeight of the child in computeNextFlexLine.
-        if (hasOrthogonalFlow(child) && flexBasisForChild(child).isAuto()) {
-            child->setChildNeedsLayout(true, MarkOnlyThis);
-            child->layout();
-        }
-
         // Before running the flex algorithm, 'auto' has a margin of 0.
         // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
         if (isHorizontalFlow()) {
@@ -940,7 +947,7 @@
     return std::max(childSize, minExtent);
 }
 
-bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent)
+bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent, bool& hasInfiniteLineLength)
 {
     orderedChildren.clear();
     preferredMainAxisExtent = 0;
@@ -951,6 +958,8 @@
         return false;
 
     LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
+    hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
+
     bool lineHasInFlowItem = false;
 
     for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
@@ -959,7 +968,7 @@
             continue;
         }
 
-        LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child);
+        LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
         LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(child) + childMainAxisExtent;
         childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
 
@@ -977,12 +986,12 @@
     return true;
 }
 
-void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems)
+void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
 {
     for (size_t i = 0; i < violations.size(); ++i) {
         RenderBox* child = violations[i].child;
         LayoutUnit childSize = violations[i].childSize;
-        LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
+        LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
         availableFreeSpace -= childSize - preferredChildSize;
         totalFlexGrow -= child->style()->flexGrow();
         totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
@@ -991,7 +1000,7 @@
 }
 
 // Returns true if we successfully ran the algorithm and sized the flex items.
-bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit>& childSizes)
+bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength)
 {
     childSizes.clear();
     LayoutUnit totalViolation = 0;
@@ -1008,7 +1017,7 @@
         if (inflexibleItems.contains(child))
             childSizes.append(inflexibleItems.get(child));
         else {
-            LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
+            LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
             LayoutUnit childSize = preferredChildSize;
             double extraSpace = 0;
             if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
@@ -1032,7 +1041,7 @@
     }
 
     if (totalViolation)
-        freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems);
+        freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
     else
         availableFreeSpace -= usedFreeSpace;
 

Modified: trunk/Source/WebCore/rendering/RenderFlexibleBox.h (150086 => 150087)


--- trunk/Source/WebCore/rendering/RenderFlexibleBox.h	2013-05-14 20:37:09 UTC (rev 150086)
+++ trunk/Source/WebCore/rendering/RenderFlexibleBox.h	2013-05-14 20:37:13 UTC (rev 150087)
@@ -138,7 +138,7 @@
     EAlignItems alignmentForChild(RenderBox* child) const;
     LayoutUnit mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const;
     LayoutUnit mainAxisScrollbarExtentForChild(RenderBox* child) const;
-    LayoutUnit preferredMainAxisContentExtentForChild(RenderBox* child);
+    LayoutUnit preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength);
 
     void layoutFlexItems(bool relayoutChildren, Vector<LineContext>&);
     LayoutUnit autoMarginOffsetInMainAxis(const OrderedFlexItemList&, LayoutUnit& availableFreeSpace);
@@ -156,10 +156,10 @@
     LayoutUnit computeChildMarginValue(Length margin, RenderView*);
     void computeMainAxisPreferredSizes(OrderHashSet&);
     LayoutUnit adjustChildSizeForMinAndMax(RenderBox*, LayoutUnit childSize);
-    bool computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent);
+    bool computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent, bool& hasInfiniteLineLength);
 
-    bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, Vector<LayoutUnit>& childSizes);
-    void freezeViolations(const Vector<Violation>&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&);
+    bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength);
+    void freezeViolations(const Vector<Violation>&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, bool hasInfiniteLineLength);
 
     void resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox*);
     bool needToStretchChild(RenderBox*);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to