Title: [93651] trunk
Revision
93651
Author
[email protected]
Date
2011-08-23 16:10:45 -0700 (Tue, 23 Aug 2011)

Log Message

Add handling of mix-width and max-width for flexitems
https://bugs.webkit.org/show_bug.cgi?id=66723

Reviewed by David Hyatt.

Source/WebCore:

If we flex past a min/max width value, we need to mark the flexitem as
a fixed width and re-start the flexing algorithm.  We use a HashMap to
keep track of fixed width items.

This patch also split out the size computation from the actual layout
to avoid unnecessary layouts caused by restarting the flexing algorithm.

Test: css3/flexbox/003.html

* rendering/RenderFlexibleBox.cpp:
(WebCore::RenderFlexibleBox::layoutHorizontalBlock):
(WebCore::RenderFlexibleBox::runFreeSpaceAllocationAlgorithm):
* rendering/RenderFlexibleBox.h:

LayoutTests:

* css3/flexbox/003-expected.txt: Added.
* css3/flexbox/003.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (93650 => 93651)


--- trunk/LayoutTests/ChangeLog	2011-08-23 23:08:31 UTC (rev 93650)
+++ trunk/LayoutTests/ChangeLog	2011-08-23 23:10:45 UTC (rev 93651)
@@ -1,3 +1,13 @@
+2011-08-23  Tony Chang  <[email protected]>
+
+        Add handling of mix-width and max-width for flexitems
+        https://bugs.webkit.org/show_bug.cgi?id=66723
+
+        Reviewed by David Hyatt.
+
+        * css3/flexbox/003-expected.txt: Added.
+        * css3/flexbox/003.html: Added.
+
 2011-08-23  Adam Barth  <[email protected]>
 
         Update expectations for pkasting.  The rebaseline script is having

Added: trunk/LayoutTests/css3/flexbox/003-expected.txt (0 => 93651)


--- trunk/LayoutTests/css3/flexbox/003-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/css3/flexbox/003-expected.txt	2011-08-23 23:10:45 UTC (rev 93651)
@@ -0,0 +1,8 @@
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/css3/flexbox/003.html (0 => 93651)


--- trunk/LayoutTests/css3/flexbox/003.html	                        (rev 0)
+++ trunk/LayoutTests/css3/flexbox/003.html	2011-08-23 23:10:45 UTC (rev 93651)
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<style>
+body {
+    margin: 0;
+}
+.horizontal-box {
+    width: 600px;
+    display: -webkit-flexbox;
+    background-color: #aaa;
+    position: relative;
+}
+.horizontal-box div {
+    height: 20px;
+    border: 0;
+}
+
+.horizontal-box :nth-child(1) {
+    background-color: blue;
+}
+.horizontal-box :nth-child(2) {
+    background-color: green;
+}
+.horizontal-box :nth-child(3) {
+    background-color: red;
+}
+</style>
+<script>
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
+</script>
+<script src=""
+<body _onload_="checkHorizontalBoxen()">
+<div class="horizontal-box">
+  <div data-expected-width="100" style="width: -webkit-flex(1 0 0); max-width: 100px;"></div>
+  <div data-expected-width="250" style="width: -webkit-flex(1 0 0);"></div>
+  <div data-expected-width="250" style="width: -webkit-flex(1 0 0);"></div>
+</div>
+
+<!-- The first two flexitems should hit their max width and the third item fills the remaining space. -->
+<div class="horizontal-box">
+  <div data-expected-width="50" style="width: -webkit-flex(1 0 0); max-width: 50px;"></div>
+  <div data-expected-width="300" style="width: -webkit-flex(4 0 0); max-width: 300px;"></div>
+  <div data-expected-width="250" style="width: -webkit-flex(1 0 0);"></div>
+</div>
+
+<div class="horizontal-box">
+  <div data-expected-width="100" style="width: -webkit-flex(1 0 0); max-width: 100px;"></div>
+  <div data-expected-width="300" style="width: -webkit-flex(1 0 200px); max-width: 300px;"></div>
+  <div data-expected-width="200" style="width: -webkit-flex(1 0 0);"></div>
+</div>
+
+<!-- Test min-width. -->
+<div class="horizontal-box">
+  <div data-expected-width="350" style="width: -webkit-flex(1 1 400px); min-width: 350px;"></div>
+  <div data-expected-width="250" style="width: -webkit-flex(1 1 400px);"></div>
+</div>
+
+<!-- The flex items can overflow the flexbox. -->
+<div class="horizontal-box">
+  <div data-expected-width="350" style="width: -webkit-flex(1 1 400px); min-width: 350px;"></div>
+  <div data-expected-width="300" style="width: -webkit-flex(2 0 300px); max-width: 300px;"></div>
+  <div data-expected-width="0" style="width: -webkit-flex(1 0 0);"></div>
+</div>
+
+<div class="horizontal-box">
+  <div data-expected-width="100" data-offset-x="100" style="width: -webkit-flex(1 0 0); margin: 0 auto; max-width: 100px;"></div>
+  <div data-expected-width="200" data-offset-x="300" style="width: -webkit-flex(2 0 0);"></div>
+  <div data-expected-width="100" data-offset-x="500" style="width: -webkit-flex(1 0 0);"></div>
+</div>
+
+<!-- min-width and max-width take priority over the preferred size. -->
+<div class="horizontal-box">
+  <div data-expected-width="500" style="width: -webkit-flex(1 0 0); min-width: 300px"></div>
+  <div data-expected-width="100" style="width: -webkit-flex(1 0 50%); max-width: 100px"></div>
+</div>
+
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (93650 => 93651)


--- trunk/Source/WebCore/ChangeLog	2011-08-23 23:08:31 UTC (rev 93650)
+++ trunk/Source/WebCore/ChangeLog	2011-08-23 23:10:45 UTC (rev 93651)
@@ -1,3 +1,24 @@
+2011-08-23  Tony Chang  <[email protected]>
+
+        Add handling of mix-width and max-width for flexitems
+        https://bugs.webkit.org/show_bug.cgi?id=66723
+
+        Reviewed by David Hyatt.
+
+        If we flex past a min/max width value, we need to mark the flexitem as
+        a fixed width and re-start the flexing algorithm.  We use a HashMap to
+        keep track of fixed width items.
+
+        This patch also split out the size computation from the actual layout
+        to avoid unnecessary layouts caused by restarting the flexing algorithm.
+
+        Test: css3/flexbox/003.html
+
+        * rendering/RenderFlexibleBox.cpp:
+        (WebCore::RenderFlexibleBox::layoutHorizontalBlock):
+        (WebCore::RenderFlexibleBox::runFreeSpaceAllocationAlgorithm):
+        * rendering/RenderFlexibleBox.h:
+
 2011-08-23  Pratik Solanki  <[email protected]>
 
         ResourceRequest::setStorageSession should update NSURLRequest as well

Modified: trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp (93650 => 93651)


--- trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp	2011-08-23 23:08:31 UTC (rev 93650)
+++ trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp	2011-08-23 23:10:45 UTC (rev 93651)
@@ -99,7 +99,7 @@
 
     m_overflow.clear();
 
-    // FIXME: Assume horizontal layout until flex-direction is added.
+    // FIXME: Assume horizontal layout until flex-flow is added.
     layoutHorizontalBlock(relayoutChildren);
 
     computeLogicalHeight();
@@ -116,6 +116,7 @@
 
 static LayoutUnit preferredFlexItemContentWidth(RenderBox* child)
 {
+    // FIXME: Handle vertical writing modes with horizontal flexing.
     if (child->style()->width().isAuto())
         return child->maxPreferredLogicalWidth() - child->borderLeft() - child->borderRight() - child->verticalScrollbarWidth() - child->paddingLeft() - child->paddingRight();
     return child->contentWidth();
@@ -128,34 +129,13 @@
     float totalNegativeFlexibility;
     FlexibleBoxIterator iterator(this);
 
-    computePreferredSize(relayoutChildren, iterator, preferredSize, totalPositiveFlexibility, totalNegativeFlexibility);
+    computePreferredSizeHorizontal(relayoutChildren, iterator, preferredSize, totalPositiveFlexibility, totalNegativeFlexibility);
     LayoutUnit availableFreeSpace = contentWidth() - preferredSize;
 
-    LayoutUnit xOffset = borderLeft() + paddingLeft();
-    LayoutUnit yOffset = borderTop() + paddingTop();
-    for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
-        LayoutUnit childPreferredSize = preferredFlexItemContentWidth(child);
-        // FIXME: Handle max-width and min-width (we should clamp to the max/min value and restart the algorithm).
-        if (availableFreeSpace > 0 && totalPositiveFlexibility > 0)
-            childPreferredSize += lroundf(availableFreeSpace * child->style()->flexboxWidthPositiveFlex() / totalPositiveFlexibility);
-        else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0)
-            childPreferredSize += lroundf(availableFreeSpace * child->style()->flexboxWidthNegativeFlex() / totalNegativeFlexibility);
-
-        childPreferredSize += child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight();
-        child->setOverrideSize(LayoutSize(childPreferredSize, 0));
-        child->setChildNeedsLayout(true);
-        child->layoutIfNeeded();
-
-        setHeight(std::max(height(), borderTop() + paddingTop() + child->marginTop() + child->height() + child->marginBottom() + paddingBottom() + borderBottom() + horizontalScrollbarHeight()));
-
-        if (child->style()->marginLeft().isAuto())
-            child->setMarginLeft(availableFreeSpace > 0 ? lroundf(availableFreeSpace / totalPositiveFlexibility) : 0);
-        if (child->style()->marginRight().isAuto())
-            child->setMarginRight(availableFreeSpace > 0 ? lroundf(availableFreeSpace / totalPositiveFlexibility) : 0);
-
-        xOffset += child->marginLeft();
-        child->setLocation(IntPoint(xOffset, yOffset));
-        xOffset += child->width() + child->marginRight();
+    InflexibleFlexItemSize inflexibleItems;
+    while (!runFreeSpaceAllocationAlgorithmHorizontal(availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems)) {
+        ASSERT(totalPositiveFlexibility >= 0 && totalNegativeFlexibility >= 0);
+        ASSERT(inflexibleItems.size() > 0);
     }
 
     // FIXME: Distribute leftover space to the packing space (second distribution round).
@@ -167,11 +147,12 @@
     return length.calcMinValue(containerLength);
 }
 
-void RenderFlexibleBox::computePreferredSize(bool relayoutChildren, FlexibleBoxIterator& iterator, LayoutUnit& preferredSize, float& totalPositiveFlexibility, float& totalNegativeFlexibility)
+void RenderFlexibleBox::computePreferredSizeHorizontal(bool relayoutChildren, FlexibleBoxIterator& iterator, LayoutUnit& preferredSize, float& totalPositiveFlexibility, float& totalNegativeFlexibility)
 {
     preferredSize = 0;
     totalPositiveFlexibility = totalNegativeFlexibility = 0;
 
+    // FIXME: Handle vertical writing modes with horizontal flexing.
     LayoutUnit flexboxAvailableLogicalWidth = availableLogicalWidth();
     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
         // We always have to lay out flexible objects again, since the flex distribution
@@ -200,6 +181,76 @@
     }
 }
 
+// Returns true if we successfully ran the algorithm and sized the flex items.
+bool RenderFlexibleBox::runFreeSpaceAllocationAlgorithmHorizontal(LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems)
+{
+    FlexibleBoxIterator iterator(this);
+
+    // FIXME: Handle vertical writing modes with horizontal flexing.
+    LayoutUnit flexboxAvailableLogicalWidth = availableLogicalWidth();
+    WTF::Vector<LayoutUnit> childSizes;
+    for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
+        LayoutUnit childPreferredSize;
+        if (inflexibleItems.contains(child))
+            childPreferredSize = inflexibleItems.get(child);
+        else {
+            childPreferredSize = preferredFlexItemContentWidth(child);
+            if (availableFreeSpace > 0 && totalPositiveFlexibility > 0) {
+                childPreferredSize += lroundf(availableFreeSpace * child->style()->flexboxWidthPositiveFlex() / totalPositiveFlexibility);
+
+                Length childMaxWidth = child->style()->maxWidth();
+                if (!childMaxWidth.isUndefined() && childMaxWidth.isSpecified() && childPreferredSize > childMaxWidth.calcValue(flexboxAvailableLogicalWidth)) {
+                    childPreferredSize = childMaxWidth.calcValue(flexboxAvailableLogicalWidth);
+                    availableFreeSpace -= childPreferredSize - preferredFlexItemContentWidth(child);
+                    totalPositiveFlexibility -= child->style()->flexboxWidthPositiveFlex();
+
+                    inflexibleItems.set(child, childPreferredSize);
+                    return false;
+                }
+            } else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0) {
+                childPreferredSize += lroundf(availableFreeSpace * child->style()->flexboxWidthNegativeFlex() / totalNegativeFlexibility);
+
+                Length childMinWidth = child->style()->minWidth();
+                if (!childMinWidth.isUndefined() && childMinWidth.isSpecified() && childPreferredSize < childMinWidth.calcValue(flexboxAvailableLogicalWidth)) {
+                    childPreferredSize = childMinWidth.calcValue(flexboxAvailableLogicalWidth);
+                    availableFreeSpace += preferredFlexItemContentWidth(child) - childPreferredSize;
+                    totalNegativeFlexibility -= child->style()->flexboxWidthNegativeFlex();
+
+                    inflexibleItems.set(child, childPreferredSize);
+                    return false;
+                }
+            }
+        }
+        childSizes.append(childPreferredSize);
+    }
+
+    // Now that we know the sizes, layout and position the flex items.
+    LayoutUnit xOffset = borderLeft() + paddingLeft();
+    LayoutUnit yOffset = borderTop() + paddingTop();
+    setHeight(0);
+    size_t i = 0;
+    for (RenderBox* child = iterator.first(); child; child = iterator.next(), ++i) {
+        LayoutUnit childPreferredSize = childSizes[i];
+        childPreferredSize += child->borderLeft() + child->borderRight() + child->paddingLeft() + child->paddingRight();
+        // FIXME: Handle vertical writing modes with horizontal flexing.
+        child->setOverrideSize(LayoutSize(childPreferredSize, 0));
+        child->setChildNeedsLayout(true);
+        child->layoutIfNeeded();
+
+        setHeight(std::max(height(), borderTop() + paddingTop() + child->marginTop() + child->height() + child->marginBottom() + paddingBottom() + borderBottom() + horizontalScrollbarHeight()));
+
+        if (child->style()->marginLeft().isAuto())
+            child->setMarginLeft(availableFreeSpace > 0 ? lroundf(availableFreeSpace / totalPositiveFlexibility) : 0);
+        if (child->style()->marginRight().isAuto())
+            child->setMarginRight(availableFreeSpace > 0 ? lroundf(availableFreeSpace / totalPositiveFlexibility) : 0);
+
+        xOffset += child->marginLeft();
+        child->setLocation(IntPoint(xOffset, yOffset));
+        xOffset += child->width() + child->marginRight();
+    }
+    return true;
 }
 
+}
+
 #endif // ENABLE(CSS3_FLEXBOX)

Modified: trunk/Source/WebCore/rendering/RenderFlexibleBox.h (93650 => 93651)


--- trunk/Source/WebCore/rendering/RenderFlexibleBox.h	2011-08-23 23:08:31 UTC (rev 93650)
+++ trunk/Source/WebCore/rendering/RenderFlexibleBox.h	2011-08-23 23:10:45 UTC (rev 93651)
@@ -50,10 +50,12 @@
 
 private:
     class FlexibleBoxIterator;
+    typedef WTF::HashMap<const RenderBox*, LayoutUnit> InflexibleFlexItemSize;
 
     void layoutHorizontalBlock(bool relayoutChildren);
 
-    void computePreferredSize(bool relayoutChildren, FlexibleBoxIterator&, LayoutUnit&, float& totalPositiveFlexibility, float& totalNegativeFlexibility);
+    void computePreferredSizeHorizontal(bool relayoutChildren, FlexibleBoxIterator&, LayoutUnit&, float& totalPositiveFlexibility, float& totalNegativeFlexibility);
+    bool runFreeSpaceAllocationAlgorithmHorizontal(LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize&);
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to