Bug 776443 part 2. Support percent-less calc for internal table element widths. r=dbaron
authorBoris Zbarsky <bzbarsky@mit.edu>
Wed, 21 Nov 2012 11:19:37 -0500
changeset 123079 cf8196bc19b4015e8aeef1e2f6e286e1d136b80a
parent 123078 7f0893a44057f9976d57f85a7a6e38845492c56e
child 123080 bc303103fef9b8e0e80d2a0f2c10e00c6675fff0
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs776443
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 776443 part 2. Support percent-less calc for internal table element widths. r=dbaron
layout/base/nsLayoutUtils.cpp
layout/generic/nsHTMLReflowState.cpp
layout/reftests/bugs/776443-2-ref.html
layout/reftests/bugs/776443-2.html
layout/reftests/bugs/reftest.list
layout/reftests/css-calc/width-table-auto-1-ref.html
layout/reftests/css-calc/width-table-fixed-1-ref.html
layout/tables/BasicTableLayoutStrategy.cpp
layout/tables/FixedTableLayoutStrategy.cpp
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2537,26 +2537,28 @@ nsLayoutUtils::IntrinsicForContainer(nsR
     minw = 0;
     haveFixedMinWidth = true;
   } else {
     haveFixedMinWidth = GetAbsoluteCoord(styleMinWidth, minw);
   }
 
   // If we have a specified width (or a specified 'min-width' greater
   // than the specified 'max-width', which works out to the same thing),
-  // don't even bother getting the frame's intrinsic width.
+  // don't even bother getting the frame's intrinsic width, because in
+  // this case GetAbsoluteCoord(styleWidth, w) will always succeed, so
+  // we'll never need the intrinsic dimensions.
   if (styleWidth.GetUnit() == eStyleUnit_Enumerated &&
       (styleWidth.GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT ||
        styleWidth.GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT)) {
     // -moz-fit-content and -moz-available enumerated widths compute intrinsic
     // widths just like auto.
     // For -moz-max-content and -moz-min-content, we handle them like
     // specified widths, but ignore -moz-box-sizing.
     boxSizing = NS_STYLE_BOX_SIZING_CONTENT;
-  } else if (styleWidth.GetUnit() != eStyleUnit_Coord &&
+  } else if (!styleWidth.ConvertsToLength() &&
              !(haveFixedMinWidth && haveFixedMaxWidth && maxw <= minw)) {
 #ifdef DEBUG_INTRINSIC_WIDTH
     ++gNoiseIndent;
 #endif
     if (aType == MIN_WIDTH)
       result = aFrame->GetMinWidth(aRenderingContext);
     else
       result = aFrame->GetPrefWidth(aRenderingContext);
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -1963,18 +1963,19 @@ nsHTMLReflowState::InitConstraints(nsPre
       nsStyleUnit widthUnit = width.GetUnit();
       if ((NS_STYLE_DISPLAY_TABLE_ROW == mStyleDisplay->mDisplay) ||
           (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == mStyleDisplay->mDisplay)) {
         // 'width' property doesn't apply to table rows and row groups
         widthUnit = eStyleUnit_Auto;
         rowOrRowGroup = true;
       }
 
-      // calc() acts like auto on internal table elements
-      if (eStyleUnit_Auto == widthUnit || width.IsCalcUnit()) {
+      // calc() with percentages acts like auto on internal table elements
+      if (eStyleUnit_Auto == widthUnit ||
+          (width.IsCalcUnit() && width.CalcHasPercent())) {
         mComputedWidth = availableWidth;
 
         if ((mComputedWidth != NS_UNCONSTRAINEDSIZE) && !rowOrRowGroup){
           // Internal table elements don't have margins. Only tables and
           // cells have border and padding
           mComputedWidth -= mComputedBorderPadding.left +
             mComputedBorderPadding.right;
           if (mComputedWidth < 0)
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/776443-2-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<style>
+  table { background: yellow; }
+  td { width: 500px; }
+</style>
+<table><tr><td>Should be 500px wide</td></tr></table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/776443-2.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<style>
+  table { background: yellow; }
+  td { width: calc(250px + 250px); }
+</style>
+<table><tr><td>Should be 500px wide</td></tr></table>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1710,16 +1710,17 @@ needs-focus == 731726-1.html 731726-1-re
 == 690643-1.html 690643-1-ref.html
 == 748692-1a.html 748692-1-ref.html
 == 748692-1b.html 748692-1-ref.html
 == 753329-1.html about:blank
 == 758561-1.html 758561-1-ref.html
 fuzzy-if(true,1,19) == 759036-1.html 759036-1-ref.html
 fuzzy-if(true,17,5859) == 759036-2.html 759036-2-ref.html
 == 776443-1.html 776443-1-ref.html
+== 776443-2.html 776443-2-ref.html
 == 776265-1a.html 776265-1-ref.html
 == 776265-1b.html 776265-1-ref.html
 == 776265-1c.html 776265-1-ref.html
 == 776265-1d.html 776265-1-ref.html
 == 776265-2a.html 776265-2-ref.html
 == 776265-2b.html 776265-2-ref.html
 == 776265-2c.html 776265-2-ref.html
 == 776265-2d.html 776265-2-ref.html
--- a/layout/reftests/css-calc/width-table-auto-1-ref.html
+++ b/layout/reftests/css-calc/width-table-auto-1-ref.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML>
 <title>width: calc() on table-layout: auto tables</title>
 <table border>
   <tr>
-    <td>x</td>
+    <td style="width: 500px">x</td>
     <td style="width: 100px">y</td>
 </table>
 <table border>
   <tr>
     <td>x</td>
     <td style="width: 100px">y</td>
 </table>
 <table border>
--- a/layout/reftests/css-calc/width-table-fixed-1-ref.html
+++ b/layout/reftests/css-calc/width-table-fixed-1-ref.html
@@ -1,16 +1,16 @@
 <!DOCTYPE HTML>
 <title>width: calc() on table-layout: auto tables</title>
 <style>
 table { table-layout: fixed; width: 500px; border-spacing: 0 }
 </style>
 <table border>
   <tr>
-    <td>x</td>
+    <td style="width: 500px">x</td>
     <td style="width: 100px">y</td>
 </table>
 <table border>
   <tr>
     <td>x</td>
     <td style="width: 100px">y</td>
 </table>
 <table border>
--- a/layout/tables/BasicTableLayoutStrategy.cpp
+++ b/layout/tables/BasicTableLayoutStrategy.cpp
@@ -132,20 +132,21 @@ GetWidthInfo(nsRenderingContext *aRender
         minCoord = 0;
         prefCoord = 0;
     }
     float prefPercent = 0.0f;
     bool hasSpecifiedWidth = false;
 
     const nsStyleCoord &width = stylePos->mWidth;
     nsStyleUnit unit = width.GetUnit();
-    // NOTE: We're ignoring calc() units here, for lack of a sensible
-    // idea for what to do with them.  This means calc() is basically
-    // handled like 'auto' for table cells and columns.
-    if (unit == eStyleUnit_Coord) {
+    // NOTE: We're ignoring calc() units with percentages here, for lack of a
+    // sensible idea for what to do with them.  This means calc() with
+    // percentages is basically handled like 'auto' for table cells and
+    // columns.
+    if (width.ConvertsToLength()) {
         hasSpecifiedWidth = true;
         // Note: since ComputeWidthValue was designed to return content-box
         // width, it will (in some cases) subtract the box-sizing edges.
         // We prevent this unwanted behavior by calling it with
         // aContentEdgeToBoxSizing and aBoxSizingToMarginEdge set to 0.
         nscoord w = nsLayoutUtils::ComputeWidthValue(aRenderingContext,
                                                      aFrame, 0, 0, 0, width);
         // Quirk: A cell with "nowrap" set and a coord value for the
@@ -187,56 +188,56 @@ GetWidthInfo(nsRenderingContext *aRender
             // for 'max-width', '-moz-fit-content' is like
             // '-moz-max-content'
             maxWidth.SetIntValue(NS_STYLE_WIDTH_MAX_CONTENT,
                                  eStyleUnit_Enumerated);
     }
     unit = maxWidth.GetUnit();
     // XXX To really implement 'max-width' well, we'd need to store
     // it separately on the columns.
-    if (unit == eStyleUnit_Coord || unit == eStyleUnit_Enumerated) {
+    if (maxWidth.ConvertsToLength() || unit == eStyleUnit_Enumerated) {
         nscoord w =
             nsLayoutUtils::ComputeWidthValue(aRenderingContext, aFrame,
                                              0, 0, 0, maxWidth);
         if (w < minCoord)
             minCoord = w;
         if (w < prefCoord)
             prefCoord = w;
     } else if (unit == eStyleUnit_Percent) {
         float p = stylePos->mMaxWidth.GetPercentValue();
         if (p < prefPercent)
             prefPercent = p;
     }
-    // treat calc() on max-width just like 'none'.
+    // treat calc() with percentages on max-width just like 'none'.
 
     nsStyleCoord minWidth(stylePos->mMinWidth);
     if (minWidth.GetUnit() == eStyleUnit_Enumerated) {
         if (!aIsCell || minWidth.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE)
             minWidth.SetCoordValue(0);
         else if (minWidth.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT)
             // for 'min-width', '-moz-fit-content' is like
             // '-moz-min-content'
             minWidth.SetIntValue(NS_STYLE_WIDTH_MIN_CONTENT,
                                  eStyleUnit_Enumerated);
     }
     unit = minWidth.GetUnit();
-    if (unit == eStyleUnit_Coord || unit == eStyleUnit_Enumerated) {
+    if (minWidth.ConvertsToLength() || unit == eStyleUnit_Enumerated) {
         nscoord w =
             nsLayoutUtils::ComputeWidthValue(aRenderingContext, aFrame,
                                              0, 0, 0, minWidth);
         if (w > minCoord)
             minCoord = w;
         if (w > prefCoord)
             prefCoord = w;
     } else if (unit == eStyleUnit_Percent) {
         float p = stylePos->mMinWidth.GetPercentValue();
         if (p > prefPercent)
             prefPercent = p;
     }
-    // treat calc() on min-width just like '0'.
+    // treat calc() with percentages on min-width just like '0'.
 
     // XXX Should col frame have border/padding considered?
     if (aIsCell) {
         minCoord += boxSizingToBorderEdge;
         prefCoord = NSCoordSaturatingAdd(prefCoord, boxSizingToBorderEdge);
     }
 
     return CellWidthInfo(minCoord, prefCoord, prefPercent, hasSpecifiedWidth);
--- a/layout/tables/FixedTableLayoutStrategy.cpp
+++ b/layout/tables/FixedTableLayoutStrategy.cpp
@@ -61,36 +61,36 @@ FixedTableLayoutStrategy::GetMinWidth(ns
     for (int32_t col = 0; col < colCount; ++col) {
         nsTableColFrame *colFrame = mTableFrame->GetColFrame(col);
         if (!colFrame) {
             NS_ERROR("column frames out of sync with cell map");
             continue;
         }
         const nsStyleCoord *styleWidth =
             &colFrame->GetStylePosition()->mWidth;
-        if (styleWidth->GetUnit() == eStyleUnit_Coord) {
+        if (styleWidth->ConvertsToLength()) {
             result += nsLayoutUtils::ComputeWidthValue(aRenderingContext,
                         colFrame, 0, 0, 0, *styleWidth);
         } else if (styleWidth->GetUnit() == eStyleUnit_Percent) {
             // do nothing
         } else {
             NS_ASSERTION(styleWidth->GetUnit() == eStyleUnit_Auto ||
                          styleWidth->GetUnit() == eStyleUnit_Enumerated ||
-                         styleWidth->IsCalcUnit(),
+                         (styleWidth->IsCalcUnit() && styleWidth->CalcHasPercent()),
                          "bad width");
 
             // The 'table-layout: fixed' algorithm considers only cells
             // in the first row.
             bool originates;
             int32_t colSpan;
             nsTableCellFrame *cellFrame =
                 cellMap->GetCellInfoAt(0, col, &originates, &colSpan);
             if (cellFrame) {
                 styleWidth = &cellFrame->GetStylePosition()->mWidth;
-                if (styleWidth->GetUnit() == eStyleUnit_Coord ||
+                if (styleWidth->ConvertsToLength() ||
                     (styleWidth->GetUnit() == eStyleUnit_Enumerated &&
                      (styleWidth->GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT ||
                       styleWidth->GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT))) {
                     nscoord cellWidth = nsLayoutUtils::IntrinsicForContainer(
                         aRenderingContext, cellFrame, nsLayoutUtils::MIN_WIDTH);
                     if (colSpan > 1) {
                         // If a column-spanning cell is in the first
                         // row, split up the space evenly.  (XXX This
@@ -102,17 +102,17 @@ FixedTableLayoutStrategy::GetMinWidth(ns
                 } else if (styleWidth->GetUnit() == eStyleUnit_Percent) {
                     if (colSpan > 1) {
                         // XXX Can this force columns to negative
                         // widths?
                         result -= spacing * (colSpan - 1);
                     }
                 }
                 // else, for 'auto', '-moz-available', '-moz-fit-content',
-                // and 'calc()', do nothing
+                // and 'calc()' with percentages, do nothing
             }
         }
     }
 
     return (mMinWidth = result);
 }
 
 /* virtual */ nscoord
@@ -203,41 +203,41 @@ FixedTableLayoutStrategy::ComputeColumnW
             NS_ERROR("column frames out of sync with cell map");
             continue;
         }
         oldColWidths.AppendElement(colFrame->GetFinalWidth());
         colFrame->ResetPrefPercent();
         const nsStyleCoord *styleWidth =
             &colFrame->GetStylePosition()->mWidth;
         nscoord colWidth;
-        if (styleWidth->GetUnit() == eStyleUnit_Coord) {
+        if (styleWidth->ConvertsToLength()) {
             colWidth = nsLayoutUtils::ComputeWidthValue(
                          aReflowState.rendContext,
                          colFrame, 0, 0, 0, *styleWidth);
             specTotal += colWidth;
         } else if (styleWidth->GetUnit() == eStyleUnit_Percent) {
             float pct = styleWidth->GetPercentValue();
             colWidth = NSToCoordFloor(pct * float(tableWidth));
             colFrame->AddPrefPercent(pct);
             pctTotal += pct;
         } else {
             NS_ASSERTION(styleWidth->GetUnit() == eStyleUnit_Auto ||
                          styleWidth->GetUnit() == eStyleUnit_Enumerated ||
-                         styleWidth->IsCalcUnit(),
+                         (styleWidth->IsCalcUnit() && styleWidth->CalcHasPercent()),
                          "bad width");
 
             // The 'table-layout: fixed' algorithm considers only cells
             // in the first row.
             bool originates;
             int32_t colSpan;
             nsTableCellFrame *cellFrame =
                 cellMap->GetCellInfoAt(0, col, &originates, &colSpan);
             if (cellFrame) {
                 styleWidth = &cellFrame->GetStylePosition()->mWidth;
-                if (styleWidth->GetUnit() == eStyleUnit_Coord ||
+                if (styleWidth->ConvertsToLength() ||
                     (styleWidth->GetUnit() == eStyleUnit_Enumerated &&
                      (styleWidth->GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT ||
                       styleWidth->GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT))) {
                     // XXX This should use real percentage padding
                     // Note that the difference between MIN_WIDTH and
                     // PREF_WIDTH shouldn't matter for any of these
                     // values of styleWidth; use MIN_WIDTH for symmetry
                     // with GetMinWidth above, just in case there is a
@@ -252,17 +252,17 @@ FixedTableLayoutStrategy::ComputeColumnW
                     float pct = styleWidth->GetPercentValue();
                     colWidth = NSToCoordFloor(pct * float(tableWidth)) +
                                offsets.hPadding + offsets.hBorder;
                     pct /= float(colSpan);
                     colFrame->AddPrefPercent(pct);
                     pctTotal += pct;
                 } else {
                     // 'auto', '-moz-available', '-moz-fit-content', and
-                    // 'calc()'
+                    // 'calc()' with percentages
                     colWidth = unassignedMarker;
                 }
                 if (colWidth != unassignedMarker) {
                     if (colSpan > 1) {
                         // If a column-spanning cell is in the first
                         // row, split up the space evenly.  (XXX This
                         // isn't quite right if some of the columns it's
                         // in have specified widths.  Should we care?)