Bug 1260031 - Not force break before a block when calculating intrinsic width if the current line is empty and the block cannot intersect floats. r=dbaron draft
authorXidorn Quan <me@upsuper.org>
Tue, 23 Aug 2016 09:29:45 +1000
changeset 409822 2a852efe3f9801884e558f22ae7d9550fae87836
parent 409821 27b87d9c985561a5a06d9aa2138309e3ed6635b4
child 409823 7b0c0138cf1af76608db4fb997c313a590ef054e
push id28560
push userxquan@mozilla.com
push dateMon, 05 Sep 2016 08:24:31 +0000
reviewersdbaron
bugs1260031
milestone51.0a1
Bug 1260031 - Not force break before a block when calculating intrinsic width if the current line is empty and the block cannot intersect floats. r=dbaron MozReview-Commit-ID: 9rNUDK5t5jg
layout/generic/nsBlockFrame.cpp
layout/generic/nsFirstLetterFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsInlineFrame.cpp
layout/generic/nsRubyFrame.cpp
layout/generic/nsTextFrame.cpp
layout/reftests/floats/1260031-1-ref.html
layout/reftests/floats/1260031-1.html
layout/reftests/floats/reftest.list
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -778,29 +778,36 @@ nsBlockFrame::GetPrefISize(nsRenderingCo
         IndentBy(stdout, gNoiseIndent);
         printf("line (%s%s)\n",
                line->IsBlock() ? "block" : "inline",
                line->IsEmpty() ? ", empty" : "");
       }
       AutoNoisyIndenter lineindent(gNoisyIntrinsic);
 #endif
       if (line->IsBlock()) {
-        data.ForceBreak();
+        if (!data.mLineIsEmpty || BlockCanIntersectFloats(line->mFirstChild)) {
+          data.ForceBreak();
+        }
         data.mCurrentLine = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
                         line->mFirstChild, nsLayoutUtils::PREF_ISIZE);
         data.ForceBreak();
       } else {
         if (!curFrame->GetPrevContinuation() &&
             line == curFrame->begin_lines()) {
           // Only add text-indent if it has no percentages; using a
           // percentage basis of 0 unconditionally would give strange
           // behavior for calc(10%-3px).
           const nsStyleCoord &indent = StyleText()->mTextIndent;
-          if (indent.ConvertsToLength())
-            data.mCurrentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
+          if (indent.ConvertsToLength()) {
+            nscoord length = indent.ToLength();
+            if (length != 0) {
+              data.mCurrentLine += length;
+              data.mLineIsEmpty = false;
+            }
+          }
         }
         // XXX Bug NNNNNN Should probably handle percentage text-indent.
 
         data.mLine = &line;
         data.SetLineContainer(curFrame);
         nsIFrame *kid = line->mFirstChild;
         for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end;
              ++i, kid = kid->GetNextSibling()) {
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -120,16 +120,17 @@ nsFirstLetterFrame::AddInlineMinISize(ns
 
 // Needed for non-floating first-letter frames and for the continuations
 // following the first-letter that we also use nsFirstLetterFrame for.
 /* virtual */ void
 nsFirstLetterFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
                                        nsIFrame::InlinePrefISizeData *aData)
 {
   DoInlineIntrinsicISize(aRenderingContext, aData, nsLayoutUtils::PREF_ISIZE);
+  aData->mLineIsEmpty = false;
 }
 
 // Needed for floating first-letter frames.
 /* virtual */ nscoord
 nsFirstLetterFrame::GetMinISize(nsRenderingContext *aRenderingContext)
 {
   return nsLayoutUtils::MinISizeFromInline(this, aRenderingContext);
 }
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4438,16 +4438,17 @@ nsIFrame::InlineMinISizeData::DefaultAdd
 }
 
 void
 nsIFrame::InlinePrefISizeData::DefaultAddInlinePrefISize(nscoord aISize)
 {
   mCurrentLine = NSCoordSaturatingAdd(mCurrentLine, aISize);
   mTrailingWhitespace = 0;
   mSkipWhitespace = false;
+  mLineIsEmpty = false;
 }
 
 void
 nsIFrame::InlineMinISizeData::ForceBreak()
 {
   mCurrentLine -= mTrailingWhitespace;
   mPrevLines = std::max(mPrevLines, mCurrentLine);
   mCurrentLine = mTrailingWhitespace = 0;
@@ -4527,16 +4528,17 @@ nsIFrame::InlinePrefISizeData::ForceBrea
     mFloats.Clear();
   }
 
   mCurrentLine =
     NSCoordSaturatingSubtract(mCurrentLine, mTrailingWhitespace, nscoord_MAX);
   mPrevLines = std::max(mPrevLines, mCurrentLine);
   mCurrentLine = mTrailingWhitespace = 0;
   mSkipWhitespace = true;
+  mLineIsEmpty = true;
 }
 
 static void
 AddCoord(const nsStyleCoord& aStyle,
          nsIFrame* aFrame,
          nscoord* aCoord, float* aPercent,
          bool aClampNegativeToZero)
 {
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1823,20 +1823,27 @@ public:
 
     // Whether we're currently at the start of the line.  If we are, we
     // can't break (for example, between the text-indent and the first
     // word).
     bool mAtStartOfLine;
   };
 
   struct InlinePrefISizeData : public InlineIntrinsicISizeData {
+    InlinePrefISizeData()
+      : mLineIsEmpty(true)
+    {}
+
     void ForceBreak();
 
     // The default implementation for nsIFrame::AddInlinePrefISize.
     void DefaultAddInlinePrefISize(nscoord aISize);
+
+    // True if the current line contains nothing other than placeholders.
+    bool mLineIsEmpty;
   };
 
   /**
    * Add the intrinsic minimum width of a frame in a way suitable for
    * use in inline layout to an |InlineIntrinsicISizeData| object that
    * represents the intrinsic width information of all the previous
    * frames in the inline layout region.
    *
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -268,16 +268,17 @@ nsInlineFrame::AddInlineMinISize(nsRende
   DoInlineIntrinsicISize(aRenderingContext, aData, nsLayoutUtils::MIN_ISIZE);
 }
 
 /* virtual */ void
 nsInlineFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
                                   nsIFrame::InlinePrefISizeData *aData)
 {
   DoInlineIntrinsicISize(aRenderingContext, aData, nsLayoutUtils::PREF_ISIZE);
+  aData->mLineIsEmpty = false;
 }
 
 /* virtual */
 LogicalSize
 nsInlineFrame::ComputeSize(nsRenderingContext *aRenderingContext,
                            WritingMode aWM,
                            const LogicalSize& aCBSize,
                            nscoord aAvailableISize,
--- a/layout/generic/nsRubyFrame.cpp
+++ b/layout/generic/nsRubyFrame.cpp
@@ -82,16 +82,17 @@ nsRubyFrame::AddInlinePrefISize(nsRender
                                 nsIFrame::InlinePrefISizeData *aData)
 {
   for (nsIFrame* frame = this; frame; frame = frame->GetNextInFlow()) {
     for (RubySegmentEnumerator e(static_cast<nsRubyFrame*>(frame));
          !e.AtEnd(); e.Next()) {
       e.GetBaseContainer()->AddInlinePrefISize(aRenderingContext, aData);
     }
   }
+  aData->mLineIsEmpty = false;
 }
 
 /* virtual */ void
 nsRubyFrame::Reflow(nsPresContext* aPresContext,
                     ReflowOutput& aDesiredSize,
                     const ReflowInput& aReflowInput,
                     nsReflowStatus& aStatus)
 {
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -8342,16 +8342,17 @@ nsTextFrame::AddInlinePrefISizeForFlow(n
   const nsTextFragment* frag = mContent->GetText();
   PropertyProvider provider(textRun, textStyle, frag, this,
                             iter, INT32_MAX, nullptr, 0, aTextRunType);
 
   // text-combine-upright frame is constantly 1em on inline-axis.
   if (StyleContext()->IsTextCombined()) {
     aData->mCurrentLine += provider.GetFontMetrics()->EmHeight();
     aData->mTrailingWhitespace = 0;
+    aData->mLineIsEmpty = false;
     return;
   }
 
   bool collapseWhitespace = !textStyle->WhiteSpaceIsSignificant();
   bool preformatNewlines = textStyle->NewlineIsSignificant(this);
   bool preformatTabs = textStyle->TabIsSignificant();
   gfxFloat tabWidth = -1;
   uint32_t start =
@@ -8379,16 +8380,17 @@ nsTextFrame::AddInlinePrefISizeForFlow(n
       }
     }
 
     if (i > lineStart) {
       nscoord width = NSToCoordCeilClamped(
         textRun->GetAdvanceWidth(Range(lineStart, i), &provider));
       width = std::max(0, width);
       aData->mCurrentLine = NSCoordSaturatingAdd(aData->mCurrentLine, width);
+      aData->mLineIsEmpty = false;
 
       if (collapseWhitespace) {
         uint32_t trimStart = GetEndOfTrimmedText(frag, textStyle, lineStart, i, &iter);
         if (trimStart == start) {
           // This is *all* trimmable whitespace, so whatever trailingWhitespace
           // we saw previously is still trailing...
           aData->mTrailingWhitespace += width;
         } else {
@@ -8405,16 +8407,17 @@ nsTextFrame::AddInlinePrefISizeForFlow(n
     if (preformattedTab) {
       PropertyProvider::Spacing spacing;
       provider.GetSpacing(Range(i, i + 1), &spacing);
       aData->mCurrentLine += nscoord(spacing.mBefore);
       gfxFloat afterTab =
         AdvanceToNextTab(aData->mCurrentLine, this,
                          textRun, &tabWidth);
       aData->mCurrentLine = nscoord(afterTab + spacing.mAfter);
+      aData->mLineIsEmpty = false;
       lineStart = i + 1;
     } else if (preformattedNewline) {
       aData->ForceBreak();
       lineStart = i;
     }
   }
 
   // Check if we have collapsible whitespace at the end
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/1260031-1-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1260031 - Intrinsic width with float</title>
+  <style>
+    #left {
+      display: inline-block;
+      width: 50px;
+      height: 50px;
+      background: green;
+    }
+    #right {
+      display: inline-block;
+      width: 50px;
+      height: 50px;
+      background: blue;
+    }
+  </style>
+</head>
+<body>
+  <div id="test">
+    <div id="wrapper">
+      <div id="left"></div><div id="right"></div>
+    </div>
+  </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/floats/1260031-1.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1260031 - Intrinsic width with float</title>
+  <style>
+    #wrapper {
+      background: red;
+      width: -moz-fit-content;
+      width: fit-content;
+    }
+    #left {
+      float: left;
+      width: 50px;
+      height: 50px;
+      background: green;
+    }
+    #right {
+      width: 50px;
+      height: 50px;
+      background: blue;
+    }
+  </style>
+</head>
+<body>
+  <div id="test">
+    <div id="wrapper">
+      <div id="left"></div>
+      <div id="right"></div>
+    </div>
+  </div>
+  <script>
+    document.getElementById("right").style = location.search.slice(1);
+  </script>
+</body>
+</html>
--- a/layout/reftests/floats/reftest.list
+++ b/layout/reftests/floats/reftest.list
@@ -16,16 +16,19 @@ fails == 345369-2.html 345369-2-ref.html
 == 345369-4.html 345369-4-ref.html
 == 345369-5.html 345369-5-ref.html
 == 429974-1.html 429974-1-ref.html
 == 478834-1.html 478834-1-ref.html
 == 546048-1.html 546048-1-ref.html
 == 775350-1.html 775350-1-ref.html
 == 1114329.html 1114329-ref.html
 == 1236745-1.html 1236745-1-ref.html
+== 1260031-1.html?display:table 1260031-1-ref.html
+== 1260031-1.html?display:table-cell 1260031-1-ref.html
+== 1260031-1.html?overflow:hidden 1260031-1-ref.html
 == float-in-rtl-1a.html float-in-rtl-1-ref.html
 fuzzy-if(skiaContent,1,27000) == float-in-rtl-1b.html float-in-rtl-1-ref.html
 fuzzy-if(skiaContent,1,27000) == float-in-rtl-1c.html float-in-rtl-1-ref.html
 fuzzy-if(skiaContent,1,27000) == float-in-rtl-1d.html float-in-rtl-1-ref.html
 == float-in-rtl-2a.html float-in-rtl-2-ref.html
 fuzzy-if(skiaContent,1,12000) == float-in-rtl-2b.html float-in-rtl-2-ref.html
 fuzzy-if(skiaContent,1,12000) == float-in-rtl-2c.html float-in-rtl-2-ref.html
 fuzzy-if(skiaContent,1,12000) == float-in-rtl-2d.html float-in-rtl-2-ref.html