Title: [279318] trunk
Revision
279318
Author
[email protected]
Date
2021-06-27 12:16:51 -0700 (Sun, 27 Jun 2021)

Log Message

[LFC][TFC] Add support for shrinking over-constrained columns based on the width type priority list
https://bugs.webkit.org/show_bug.cgi?id=227426

Reviewed by Antti Koivisto.

Source/WebCore:

Let's take the priority list into use when shrinking the columns in an over-constrained context.
e.g.
<div style="width: 100px">
  <table><tr><td style="width: 90%""></td><td style="width: 400px;"></td><td style="width: 100px;"></td></tr></table>
</div>

While the second and the third columns have the preferred width of 400px and 100px respectively, we can't accommodate
them as the containing block (<div>) sets a 100px horizontal constraint on the table content and the first column already takes up 90px space.

Now we start shrinking the columns using the following priority list: auto < relative < fixed < percent (ignoring the actual column order).

The preferred width of the table (assume 0px border spacing and padding) is 90px + 400px + 100px. It produces a -490px
available space. This negative space needs to be distributed among the columns staring with the fixed sized ones.
The fixed sized columns have a flex space of 500px which covers the -490px gap. Based on their 4:1 distribution ratio, they'll end
up with 8px and 2px and the percent column stays at 90px.

Tests: fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple.html
       fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2.html

* layout/formattingContexts/table/TableLayout.cpp:
(WebCore::Layout::distributeAvailableSpace):
(WebCore::Layout::TableFormattingContext::TableLayout::distributedHorizontalSpace):
(WebCore::Layout::TableFormattingContext::TableLayout::distributedVerticalSpace):

LayoutTests:

* fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple-expected.html: Added.
* fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple.html: Added.
* fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2-expected.html: Added.
* fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (279317 => 279318)


--- trunk/LayoutTests/ChangeLog	2021-06-27 17:39:38 UTC (rev 279317)
+++ trunk/LayoutTests/ChangeLog	2021-06-27 19:16:51 UTC (rev 279318)
@@ -1,3 +1,15 @@
+2021-06-27  Alan Bujtas  <[email protected]>
+
+        [LFC][TFC] Add support for shrinking over-constrained columns based on the width type priority list
+        https://bugs.webkit.org/show_bug.cgi?id=227426
+
+        Reviewed by Antti Koivisto.
+
+        * fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple-expected.html: Added.
+        * fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple.html: Added.
+        * fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2-expected.html: Added.
+        * fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2.html: Added.
+
 2021-06-27  Philippe Normand  <[email protected]>
 
         [GStreamer] SleepDisabler not destroyed when video playback stops

Added: trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple-expected.html (0 => 279318)


--- trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple-expected.html	2021-06-27 19:16:51 UTC (rev 279318)
@@ -0,0 +1,25 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ LayoutFormattingContextEnabled=true LayoutFormattingContextIntegrationEnabled=false ] -->
+<style>
+body {
+  font-size: 16px;
+  overflow: hidden;
+}
+
+div {
+  height: 20px;
+  background-color: blue;
+  width: 200px;
+}
+
+.inner {
+  background-color: green;
+}
+</style>
+
+<div><div class=inner style="width: 140px"></div></div>
+<div><div class=inner style="width: 120px"></div></div>
+<div><div class=inner style="width: 100px"></div></div>
+<div><div class=inner style="width: 80px"></div></div>
+<div><div class=inner style="width: 60px"></div></div>
+<div><div class=inner style="width: 40px"></div></div>
+<div><div class=inner style="width: 20px"></div></div>

Added: trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple.html (0 => 279318)


--- trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple.html	                        (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple.html	2021-06-27 19:16:51 UTC (rev 279318)
@@ -0,0 +1,35 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ LayoutFormattingContextEnabled=true LayoutFormattingContextIntegrationEnabled=false ] -->
+<style>
+body {
+  font-size: 16px;
+  overflow: hidden;
+}
+
+table {
+  border-spacing: 0px;
+}
+
+td {
+  height: 20px;
+  padding: 0px;
+  background-color: blue;
+  white-space: pre-wrap;
+}
+
+td:nth-child(odd) {
+  background-color: green;
+}
+
+div {
+  height: 20px;
+}
+</style>
+<div style="width: 200px; height: auto;">
+<table><tr><td style="width: 300px;"></td><td style="width: 30%;"></td></tr></table>
+<table><tr><td style="width: 400px;"></td><td style="width: 40%;"></td></tr></table>
+<table><tr><td style="width: 500px;"></td><td style="width: 50%;"></td></tr></table>
+<table><tr><td style="width: 600px;"></td><td style="width: 60%;"></td></tr></table>
+<table><tr><td style="width: 700px;"></td><td style="width: 70%;"></td></tr></table>
+<table><tr><td style="width: 800px;"></td><td style="width: 80%;"></td></tr></table>
+<table><tr><td style="width: 900px;"></td><td style="width: 90%;"></td></tr></table>
+</div>

Added: trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2-expected.html (0 => 279318)


--- trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2-expected.html	2021-06-27 19:16:51 UTC (rev 279318)
@@ -0,0 +1,26 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ LayoutFormattingContextEnabled=true LayoutFormattingContextIntegrationEnabled=false ] -->
+<style>
+body {
+  font-size: 16px;
+  overflow: hidden;
+}
+
+div {
+  height: 20px;
+  background-color: green;
+  width: 200px;
+}
+
+.inner {
+  background-color: blue;
+  position: relative;
+}
+</style>
+
+<div><div class=inner style="left: 60px; width: 80px"></div></div>
+<div><div class=inner style="left: 53px; width: 67px"></div></div>
+<div><div class=inner style="left: 45px; width: 55px"></div></div>
+<div><div class=inner style="left: 43.5px; width: 36.5px"></div></div>
+<div><div class=inner style="left: 38px; width: 22px"></div></div>
+<div><div class=inner style="left: 29px; width: 11px"></div></div>
+<div><div class=inner style="left: 16px; width: 4px"></div></div>

Added: trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2.html (0 => 279318)


--- trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2.html	                        (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2.html	2021-06-27 19:16:51 UTC (rev 279318)
@@ -0,0 +1,35 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ LayoutFormattingContextEnabled=true LayoutFormattingContextIntegrationEnabled=false ] -->
+<style>
+body {
+  font-size: 16px;
+  overflow: hidden;
+}
+
+table {
+  border-spacing: 0px;
+}
+
+td {
+  height: 20px;
+  padding: 0px;
+  background-color: blue;
+  white-space: pre-wrap;
+}
+
+td:nth-child(odd) {
+  background-color: green;
+}
+
+div {
+  height: 20px;
+}
+</style>
+<div style="width: 200px; height: auto;">
+<table><tr><td style="width: 300px;"></td><td style="width: 400px;"></td><td style="width: 30%;"></td></tr></table>
+<table><tr><td style="width: 400px;"></td><td style="width: 500px;"></td><td style="width: 40%;"></td></tr></table>
+<table><tr><td style="width: 500px;"></td><td style="width: 600px;"></td><td style="width: 50%;"></td></tr></table>
+<table><tr><td style="width: 600px;"></td><td style="width: 500px;"></td><td style="width: 60%;"></td></tr></table>
+<table><tr><td style="width: 700px;"></td><td style="width: 400px;"></td><td style="width: 70%;"></td></tr></table>
+<table><tr><td style="width: 800px;"></td><td style="width: 300px;"></td><td style="width: 80%;"></td></tr></table>
+<table><tr><td style="width: 900px;"></td><td style="width: 200px;"></td><td style="width: 90%;"></td></tr></table>
+</div>

Modified: trunk/Source/WebCore/ChangeLog (279317 => 279318)


--- trunk/Source/WebCore/ChangeLog	2021-06-27 17:39:38 UTC (rev 279317)
+++ trunk/Source/WebCore/ChangeLog	2021-06-27 19:16:51 UTC (rev 279318)
@@ -1,5 +1,36 @@
 2021-06-27  Alan Bujtas  <[email protected]>
 
+        [LFC][TFC] Add support for shrinking over-constrained columns based on the width type priority list
+        https://bugs.webkit.org/show_bug.cgi?id=227426
+
+        Reviewed by Antti Koivisto.
+
+        Let's take the priority list into use when shrinking the columns in an over-constrained context.
+        e.g.
+        <div style="width: 100px">
+          <table><tr><td style="width: 90%""></td><td style="width: 400px;"></td><td style="width: 100px;"></td></tr></table>
+        </div>
+
+        While the second and the third columns have the preferred width of 400px and 100px respectively, we can't accommodate 
+        them as the containing block (<div>) sets a 100px horizontal constraint on the table content and the first column already takes up 90px space.
+
+        Now we start shrinking the columns using the following priority list: auto < relative < fixed < percent (ignoring the actual column order).
+
+        The preferred width of the table (assume 0px border spacing and padding) is 90px + 400px + 100px. It produces a -490px 
+        available space. This negative space needs to be distributed among the columns staring with the fixed sized ones.
+        The fixed sized columns have a flex space of 500px which covers the -490px gap. Based on their 4:1 distribution ratio, they'll end
+        up with 8px and 2px and the percent column stays at 90px.
+
+        Tests: fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple.html
+               fast/layoutformattingcontext/table-space-shinking-mixed-width-type-simple2.html
+
+        * layout/formattingContexts/table/TableLayout.cpp:
+        (WebCore::Layout::distributeAvailableSpace):
+        (WebCore::Layout::TableFormattingContext::TableLayout::distributedHorizontalSpace):
+        (WebCore::Layout::TableFormattingContext::TableLayout::distributedVerticalSpace):
+
+2021-06-27  Alan Bujtas  <[email protected]>
+
         [LFC][TFC] Rename GridSpace::preferredSpace to preferredSize
         https://bugs.webkit.org/show_bug.cgi?id=227425
 

Modified: trunk/Source/WebCore/layout/formattingContexts/table/TableLayout.cpp (279317 => 279318)


--- trunk/Source/WebCore/layout/formattingContexts/table/TableLayout.cpp	2021-06-27 17:39:38 UTC (rev 279317)
+++ trunk/Source/WebCore/layout/formattingContexts/table/TableLayout.cpp	2021-06-27 19:16:51 UTC (rev 279318)
@@ -85,6 +85,7 @@
     // The base space value for the distribution computation e.g [ 9 ] [ 1 ] values for 2 columns in the table means that if
     // we've go 100px flexible space to distribute, 90px and 10px go to the columns respectively.
     float flexBase { 0 };
+    float minimumSize { 0 };
 };
 
 inline static GridSpace& operator-(GridSpace& a, const GridSpace& b)
@@ -210,60 +211,79 @@
             }
         }
     }
-    // 4. Distribute the extra space using the final resolved widths.
-#if ASSERT_ENABLED
-    // We have to have all the spaces resolved at this point.
-    for (auto& resolvedItem : resolvedItems)
+    // 4. Distribute the extra space using the final resolved sizes.
+    Vector<LayoutUnit> distributedSpaces(resolvedItems.size());
+    float spaceToDistribute = availableSpace - (resolvedItems.size() + 1) * SpanType::spacing(grid);
+    auto adjustabledSpace = GridSpace { };
+    for (auto& resolvedItem : resolvedItems) {
         ASSERT(resolvedItem);
-#endif
-    Vector<size_t> percentColumnIndexes;
-    Vector<size_t> fixedColumnIndexes;
-    Vector<size_t> relativeColumnIndexes;
-    Vector<size_t> autoColumnIndexes;
-
-    // Fixed size cells don't participate in available space distribution.
-    auto adjustabledSpace = GridSpace { };
-    for (size_t columnIndex = 0; columnIndex < resolvedItems.size(); ++columnIndex) {
-        auto& resolvedItem = resolvedItems[columnIndex];
         adjustabledSpace += *resolvedItem;
-        switch (resolvedItem->type) {
-        case GridSpace::Type::Percent:
-            percentColumnIndexes.append(columnIndex);
-            break;
-        case GridSpace::Type::Fixed:
-            fixedColumnIndexes.append(columnIndex);
-            break;
-        case GridSpace::Type::Relative:
-            relativeColumnIndexes.append(columnIndex);
-            break;
-        case GridSpace::Type::Auto:
-            autoColumnIndexes.append(columnIndex);
-            break;
-        default:
-            ASSERT_NOT_REACHED();
-            break;
-        }
     }
+    spaceToDistribute -= adjustabledSpace.preferredSize;
+    // Let's start with the preferred size for each column.
+    for (size_t columnIndex = 0; columnIndex < resolvedItems.size(); ++columnIndex)
+        distributedSpaces[columnIndex] = LayoutUnit { resolvedItems[columnIndex]->preferredSize };
 
-    Vector<LayoutUnit> distributedSpaces(resolvedItems.size());
-    float spaceToDistribute = availableSpace;
-    // Top and bottom spacing are fixed.
-    spaceToDistribute -= 2 * SpanType::spacing(grid);
-    spaceToDistribute -= adjustabledSpace.preferredSize + ((resolvedItems.size() - 1) * SpanType::spacing(grid));
-    // Distribute the extra space based on the resolved spaces. Note that the extra space could be a negative value in which case
-    // we may assign less space to columns.
-    auto columnsFlexBase = adjustabledSpace.flexBase ? spaceToDistribute / adjustabledSpace.flexBase : 0.f;
-    auto distributeSpaceForType = [&](const auto& columnIndexes) {
-        for (auto& columnIndex : columnIndexes) {
+    if (spaceToDistribute > 0) {
+        // Each column can get some extra space.
+        auto columnsFlexBase = adjustabledSpace.flexBase ? spaceToDistribute / adjustabledSpace.flexBase : 0.f;
+        for (size_t columnIndex = 0; columnIndex < resolvedItems.size(); ++columnIndex) {
             auto columnExtraSpace = columnsFlexBase * resolvedItems[columnIndex]->flexBase;
-            distributedSpaces[columnIndex] = LayoutUnit { resolvedItems[columnIndex]->preferredSize + columnExtraSpace };
+            distributedSpaces[columnIndex] += LayoutUnit { columnExtraSpace };
         }
-    };
-    // Distribute the available space starting with percent columns and ending with autos.
-    distributeSpaceForType(percentColumnIndexes);
-    distributeSpaceForType(fixedColumnIndexes);
-    distributeSpaceForType(relativeColumnIndexes);
-    distributeSpaceForType(autoColumnIndexes);
+    } else if (spaceToDistribute < 0) {
+        // Can't accomodate the preferred width. Let's use the priority list to shrink columns.
+        Vector<size_t> autoColumnIndexes;
+        Vector<size_t> relativeColumnIndexes;
+        Vector<size_t> fixedColumnIndexes;
+        Vector<size_t> percentColumnIndexes;
+
+        for (size_t columnIndex = 0; columnIndex < resolvedItems.size(); ++columnIndex) {
+            switch (resolvedItems[columnIndex]->type) {
+            case GridSpace::Type::Percent:
+                percentColumnIndexes.append(columnIndex);
+                break;
+            case GridSpace::Type::Fixed:
+                fixedColumnIndexes.append(columnIndex);
+                break;
+            case GridSpace::Type::Relative:
+                relativeColumnIndexes.append(columnIndex);
+                break;
+            case GridSpace::Type::Auto:
+                autoColumnIndexes.append(columnIndex);
+                break;
+            default:
+                ASSERT_NOT_REACHED();
+                break;
+            }
+        }
+
+        auto spaceNeeded = -spaceToDistribute;
+        auto shrinkSpaceForType = [&](const auto& columnIndexes) {
+            auto adjustabledSpace = GridSpace { };
+            for (auto& columnIndex : columnIndexes)
+                adjustabledSpace += *resolvedItems[columnIndex];
+
+            auto columnsFlexBase = adjustabledSpace.flexBase ? spaceNeeded / adjustabledSpace.flexBase : 0.f;
+            for (auto& columnIndex : columnIndexes) {
+                auto& resolvedItem = *resolvedItems[columnIndex];
+                auto spaceToRemove = std::min(resolvedItem.preferredSize - resolvedItem.minimumSize, columnsFlexBase * resolvedItem.flexBase);
+                spaceToRemove = std::min(spaceToRemove, spaceNeeded);
+                distributedSpaces[columnIndex] -= spaceToRemove;
+                spaceNeeded -= spaceToRemove;
+                if (!spaceNeeded)
+                    return;
+            }
+            ASSERT(spaceNeeded > 0);
+        };
+        shrinkSpaceForType(autoColumnIndexes);
+        if (spaceNeeded)
+            shrinkSpaceForType(relativeColumnIndexes);
+        if (spaceNeeded)
+            shrinkSpaceForType(fixedColumnIndexes);
+        if (spaceNeeded)
+            shrinkSpaceForType(percentColumnIndexes);
+    }
     return distributedSpaces;
 }
 
@@ -304,7 +324,7 @@
             // total adjustable space: 120px - 80px - 50px = -10px <- Note the negative available space with over-constrained values.
             // columns extra widths: -10px / (30px + 0px) * 30px = -10px and -10px / (30px + 0px) * 0px = 0px
             // columns final widths: 70px and 50px (first column is narrower than its preferred width and the second is as wide as the minimum content width)
-            return GridSpace { type, preferredWidth, preferredWidth - minimumContentWidth };
+            return GridSpace { type, preferredWidth, preferredWidth - minimumContentWidth, minimumContentWidth };
         }
 
         // maximum width <= available horizontal space
@@ -324,7 +344,7 @@
         // total adjustable space: 2600px - 500px = 2100px
         // columns extra widths: 2100px / 500px * 200px = 840px and 2100px / 500px * 300px = 1260px
         // columns final widths: 1040px and 1560px
-        return GridSpace { type, preferredWidth, preferredWidth };
+        return GridSpace { type, preferredWidth, preferredWidth, minimumContentWidth };
     });
 }
 
@@ -367,12 +387,14 @@
     auto availableSpace = std::max(availableVerticalSpace.value_or(0_lu), tableUsedHeight);
     // Distribute extra space if the table is supposed to be taller than the sum of the row heights.
     return distributeAvailableSpace<RowSpan>(m_grid, availableSpace, [&] (const TableGrid::Slot& slot, size_t rowIndex) {
-        if (slot.hasRowSpan())
-            return GridSpace { { }, formattingContext().geometryForBox(slot.cell().box()).borderBoxHeight(), formattingContext().geometryForBox(slot.cell().box()).borderBoxHeight() };
+        if (slot.hasRowSpan()) {
+            auto borderBoxHeight = formattingContext().geometryForBox(slot.cell().box()).borderBoxHeight();
+            return GridSpace { { }, borderBoxHeight, borderBoxHeight, borderBoxHeight };
+        }
         auto& rows = m_grid.rows();
         auto computedRowHeight = formattingContext().formattingGeometry().computedHeight(rows.list()[rowIndex].box(), { });
         auto height = std::max<float>(rowHeight[rowIndex], computedRowHeight.value_or(0_lu));
-        return GridSpace { { }, height, height };
+        return GridSpace { { }, height, height, height };
     });
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to