Bug 1224230 - Explicitly store the lineContainer's writing mode in InlineIntrinsicISizeData. r=dbaron
authorJonathan Kew <jkew@mozilla.com>
Sat, 14 Nov 2015 08:46:11 +0000
changeset 308938 d69c292db762bcff2ee05c9f57ae08e59c2ece41
parent 308937 1c1535ec2bb03a473a245e51fc4117efb2cd0404
child 308939 51fa3e0d4f7bb2bf3457261091b1cb7a75e1255d
child 308943 49b930683c026adb4c3fd8b7ccf782db97abb7eb
push id7542
push usermaglione.k@gmail.com
push dateMon, 16 Nov 2015 00:59:26 +0000
reviewersdbaron
bugs1224230
milestone45.0a1
Bug 1224230 - Explicitly store the lineContainer's writing mode in InlineIntrinsicISizeData. r=dbaron
layout/generic/nsBlockFrame.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsRubyBaseContainerFrame.cpp
layout/generic/nsTextFrame.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -723,17 +723,17 @@ nsBlockFrame::GetMinISize(nsRenderingCon
           // behavior for calc(10%-3px).
           const nsStyleCoord &indent = StyleText()->mTextIndent;
           if (indent.ConvertsToLength())
             data.currentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
         }
         // XXX Bug NNNNNN Should probably handle percentage text-indent.
 
         data.line = &line;
-        data.lineContainer = curFrame;
+        data.SetLineContainer(curFrame);
         nsIFrame *kid = line->mFirstChild;
         for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end;
              ++i, kid = kid->GetNextSibling()) {
           kid->AddInlineMinISize(aRenderingContext, &data);
         }
       }
 #ifdef DEBUG
       if (gNoisyIntrinsic) {
@@ -808,17 +808,17 @@ nsBlockFrame::GetPrefISize(nsRenderingCo
           // behavior for calc(10%-3px).
           const nsStyleCoord &indent = StyleText()->mTextIndent;
           if (indent.ConvertsToLength())
             data.currentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
         }
         // XXX Bug NNNNNN Should probably handle percentage text-indent.
 
         data.line = &line;
-        data.lineContainer = curFrame;
+        data.SetLineContainer(curFrame);
         nsIFrame *kid = line->mFirstChild;
         for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end;
              ++i, kid = kid->GetNextSibling()) {
           kid->AddInlinePrefISize(aRenderingContext, &data);
         }
       }
 #ifdef DEBUG
       if (gNoisyIntrinsic) {
@@ -882,17 +882,17 @@ nsBlockFrame::GetPrefWidthTightBounds(ns
           const nsStyleCoord &indent = StyleText()->mTextIndent;
           if (indent.ConvertsToLength()) {
             data.currentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
           }
         }
         // XXX Bug NNNNNN Should probably handle percentage text-indent.
 
         data.line = &line;
-        data.lineContainer = curFrame;
+        data.SetLineContainer(curFrame);
         nsIFrame *kid = line->mFirstChild;
         for (int32_t i = 0, i_end = line->GetChildCount(); i != i_end;
              ++i, kid = kid->GetNextSibling()) {
           rv = kid->GetPrefWidthTightBounds(aRenderingContext, &childX,
                                             &childXMost);
           NS_ENSURE_SUCCESS(rv, rv);
           *aX = std::min(*aX, data.currentLine + childX);
           *aXMost = std::max(*aXMost, data.currentLine + childXMost);
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -845,17 +845,17 @@ nsContainerFrame::DoInlineIntrinsicISize
     std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
     styleBorder->GetComputedBorderWidth(endSide) +
     GetCoord(styleMargin->mMargin.Get(endSide), 0);
   if (MOZ_UNLIKELY(!sliceBreak)) {
     clonePBM += endPBM;
   }
 
   const nsLineList_iterator* savedLine = aData->line;
-  nsIFrame* const savedLineContainer = aData->lineContainer;
+  nsIFrame* const savedLineContainer = aData->LineContainer();
 
   nsContainerFrame *lastInFlow;
   for (nsContainerFrame *nif = this; nif;
        nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
     if (aData->currentLine == 0) {
       aData->currentLine = clonePBM;
     }
     for (nsIFrame* kid : nif->mFrames) {
@@ -865,23 +865,23 @@ nsContainerFrame::DoInlineIntrinsicISize
       else
         kid->AddInlinePrefISize(aRenderingContext,
                                 static_cast<InlinePrefISizeData*>(aData));
     }
 
     // After we advance to our next-in-flow, the stored line and line container
     // may no longer be correct. Just forget them.
     aData->line = nullptr;
-    aData->lineContainer = nullptr;
+    aData->SetLineContainer(nullptr);
 
     lastInFlow = nif;
   }
 
   aData->line = savedLine;
-  aData->lineContainer = savedLineContainer;
+  aData->SetLineContainer(savedLineContainer);
 
   // This goes at the end no matter how things are broken and how
   // messy the bidi situations are, since per CSS2.1 section 8.6
   // (implemented in bug 328168), the endSide border is always on the
   // last line.
   // We reached the last-in-flow, but it might have a next bidi
   // continuation, in which case that continuation should handle
   // the endSide border.
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4110,39 +4110,37 @@ nsIFrame::InlinePrefISizeData::ForceBrea
             // preferred widths accumulated for floats that have already
             // been cleared past
     nscoord floats_done = 0,
             // preferred widths accumulated for floats that have not yet
             // been cleared past
             floats_cur_left = 0,
             floats_cur_right = 0;
 
-    WritingMode wm = lineContainer->GetWritingMode();
-
     for (uint32_t i = 0, i_end = floats.Length(); i != i_end; ++i) {
       const FloatInfo& floatInfo = floats[i];
       const nsStyleDisplay *floatDisp = floatInfo.Frame()->StyleDisplay();
-      uint8_t breakType = floatDisp->PhysicalBreakType(wm);
+      uint8_t breakType = floatDisp->PhysicalBreakType(lineContainerWM);
       if (breakType == NS_STYLE_CLEAR_LEFT ||
           breakType == NS_STYLE_CLEAR_RIGHT ||
           breakType == NS_STYLE_CLEAR_BOTH) {
         nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
                                                   floats_cur_right);
         if (floats_cur > floats_done) {
           floats_done = floats_cur;
         }
         if (breakType != NS_STYLE_CLEAR_RIGHT) {
           floats_cur_left = 0;
         }
         if (breakType != NS_STYLE_CLEAR_LEFT) {
           floats_cur_right = 0;
         }
       }
 
-      uint8_t floatStyle = floatDisp->PhysicalFloats(wm);
+      uint8_t floatStyle = floatDisp->PhysicalFloats(lineContainerWM);
       nscoord& floats_cur = floatStyle == NS_STYLE_FLOAT_LEFT
                               ? floats_cur_left : floats_cur_right;
       nscoord floatWidth = floatInfo.Width();
       // Negative-width floats don't change the available space so they
       // shouldn't change our intrinsic line width either.
       floats_cur =
         NSCoordSaturatingAdd(floats_cur, std::max(0, floatWidth));
     }
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1558,43 +1558,64 @@ public:
    * information about whitespace (for both collapsing and trimming).
    */
   struct InlineIntrinsicISizeData {
     InlineIntrinsicISizeData()
       : line(nullptr)
       , lineContainer(nullptr)
       , prevLines(0)
       , currentLine(0)
+      , trailingWhitespace(0)
       , skipWhitespace(true)
-      , trailingWhitespace(0)
     {}
 
     // The line. This may be null if the inlines are not associated with
     // a block or if we just don't know the line.
     const nsLineList_iterator* line;
 
-    // The line container.
+    // The line container. Private, to ensure we always use SetLineContainer
+    // to update it (so that we have a chance to store the lineContainerWM).
+    //
+    // Note that nsContainerFrame::DoInlineIntrinsicISize will clear the
+    // |line| and |lineContainer| fields when following a next-in-flow link,
+    // so we must not assume these can always be dereferenced.
+  private:
     nsIFrame* lineContainer;
 
+    // Setter and getter for the lineContainer field:
+  public:
+    void SetLineContainer(nsIFrame* aLineContainer)
+    {
+      lineContainer = aLineContainer;
+      if (lineContainer) {
+        lineContainerWM = lineContainer->GetWritingMode();
+      }
+    }
+    nsIFrame* LineContainer() const { return lineContainer; }
+
     // The maximum intrinsic width for all previous lines.
     nscoord prevLines;
 
     // The maximum intrinsic width for the current line.  At a line
     // break (mandatory for preferred width; allowed for minimum width),
     // the caller should call |Break()|.
     nscoord currentLine;
 
+    // This contains the width of the trimmable whitespace at the end of
+    // |currentLine|; it is zero if there is no such whitespace.
+    nscoord trailingWhitespace;
+
     // True if initial collapsable whitespace should be skipped.  This
     // should be true at the beginning of a block, after hard breaks
     // and when the last text ended with whitespace.
     bool skipWhitespace;
 
-    // This contains the width of the trimmable whitespace at the end of
-    // |currentLine|; it is zero if there is no such whitespace.
-    nscoord trailingWhitespace;
+    // Writing mode of the line container (stored here so that we don't
+    // lose track of it if the lineContainer field is reset).
+    mozilla::WritingMode lineContainerWM;
 
     // Floats encountered in the lines.
     class FloatInfo {
     public:
       FloatInfo(const nsIFrame* aFrame, nscoord aWidth)
         : mFrame(aFrame), mWidth(aWidth)
       { }
       const nsIFrame* Frame() const { return mFrame; }
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -143,23 +143,23 @@ CalculateColumnPrefISize(nsRenderingCont
 {
   nscoord max = 0;
   uint32_t levelCount = aEnumerator.GetLevelCount();
   for (uint32_t i = 0; i < levelCount; i++) {
     nsIFrame* frame = aEnumerator.GetFrameAtLevel(i);
     if (frame) {
       nsIFrame::InlinePrefISizeData data;
       if (i == 0) {
-        data.lineContainer = aBaseISizeData->lineContainer;
+        data.SetLineContainer(aBaseISizeData->LineContainer());
         data.skipWhitespace = aBaseISizeData->skipWhitespace;
         data.trailingWhitespace = aBaseISizeData->trailingWhitespace;
       } else {
         // The line container of ruby text frames is their parent,
         // ruby text container frame.
-        data.lineContainer = frame->GetParent();
+        data.SetLineContainer(frame->GetParent());
       }
       frame->AddInlinePrefISize(aRenderingContext, &data);
       MOZ_ASSERT(data.prevLines == 0, "Shouldn't have prev lines");
       max = std::max(max, data.currentLine);
       if (i == 0) {
         aBaseISizeData->skipWhitespace = data.skipWhitespace;
         aBaseISizeData->trailingWhitespace = data.trailingWhitespace;
       }
@@ -177,17 +177,17 @@ nsRubyBaseContainerFrame::AddInlineMinIS
 {
   AutoRubyTextContainerArray textContainers(this);
 
   for (uint32_t i = 0, iend = textContainers.Length(); i < iend; i++) {
     if (textContainers[i]->IsSpanContainer()) {
       // Since spans are not breakable internally, use our pref isize
       // directly if there is any span.
       nsIFrame::InlinePrefISizeData data;
-      data.lineContainer = aData->lineContainer;
+      data.SetLineContainer(aData->LineContainer());
       data.skipWhitespace = aData->skipWhitespace;
       data.trailingWhitespace = aData->trailingWhitespace;
       AddInlinePrefISize(aRenderingContext, &data);
       aData->currentLine += data.currentLine;
       if (data.currentLine > 0) {
         aData->atStartOfLine = false;
       }
       aData->skipWhitespace = data.skipWhitespace;
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -7638,17 +7638,17 @@ void nsTextFrame::MarkIntrinsicISizesDir
 void
 nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext,
                                       nsIFrame::InlineMinISizeData *aData,
                                       TextRunType aTextRunType)
 {
   uint32_t flowEndInTextRun;
   gfxContext* ctx = aRenderingContext->ThebesContext();
   gfxSkipCharsIterator iter =
-    EnsureTextRun(aTextRunType, ctx, aData->lineContainer,
+    EnsureTextRun(aTextRunType, ctx, aData->LineContainer(),
                   aData->line, &flowEndInTextRun);
   gfxTextRun *textRun = GetTextRun(aTextRunType);
   if (!textRun)
     return;
 
   // Pass null for the line container. This will disable tab spacing, but that's
   // OK since we can't really handle tabs for intrinsic sizing anyway.
   const nsStyleText* textStyle = StyleText();
@@ -7787,22 +7787,22 @@ nsTextFrame::AddInlineMinISize(nsRenderi
   // nsContinuingTextFrame does nothing for AddInlineMinISize; all text frames
   // in the flow are handled right here.
   for (f = this; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
     // f->GetTextRun(nsTextFrame::eNotInflated) could be null if we
     // haven't set up textruns yet for f.  Except in OOM situations,
     // lastTextRun will only be null for the first text frame.
     if (f == this || f->GetTextRun(trtype) != lastTextRun) {
       nsIFrame* lc;
-      if (aData->lineContainer &&
-          aData->lineContainer != (lc = FindLineContainer(f))) {
+      if (aData->LineContainer() &&
+          aData->LineContainer() != (lc = FindLineContainer(f))) {
         NS_ASSERTION(f != this, "wrong InlineMinISizeData container"
                                 " for first continuation");
         aData->line = nullptr;
-        aData->lineContainer = lc;
+        aData->SetLineContainer(lc);
       }
 
       // This will process all the text frames that share the same textrun as f.
       f->AddInlineMinISizeForFlow(aRenderingContext, aData, trtype);
       lastTextRun = f->GetTextRun(trtype);
     }
   }
 }
@@ -7812,17 +7812,17 @@ nsTextFrame::AddInlineMinISize(nsRenderi
 void
 nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext,
                                        nsIFrame::InlinePrefISizeData *aData,
                                        TextRunType aTextRunType)
 {
   uint32_t flowEndInTextRun;
   gfxContext* ctx = aRenderingContext->ThebesContext();
   gfxSkipCharsIterator iter =
-    EnsureTextRun(aTextRunType, ctx, aData->lineContainer,
+    EnsureTextRun(aTextRunType, ctx, aData->LineContainer(),
                   aData->line, &flowEndInTextRun);
   gfxTextRun *textRun = GetTextRun(aTextRunType);
   if (!textRun)
     return;
 
   // Pass null for the line container. This will disable tab spacing, but that's
   // OK since we can't really handle tabs for intrinsic sizing anyway.
   
@@ -7925,22 +7925,22 @@ nsTextFrame::AddInlinePrefISize(nsRender
   // nsContinuingTextFrame does nothing for AddInlineMinISize; all text frames
   // in the flow are handled right here.
   for (f = this; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
     // f->GetTextRun(nsTextFrame::eNotInflated) could be null if we
     // haven't set up textruns yet for f.  Except in OOM situations,
     // lastTextRun will only be null for the first text frame.
     if (f == this || f->GetTextRun(trtype) != lastTextRun) {
       nsIFrame* lc;
-      if (aData->lineContainer &&
-          aData->lineContainer != (lc = FindLineContainer(f))) {
+      if (aData->LineContainer() &&
+          aData->LineContainer() != (lc = FindLineContainer(f))) {
         NS_ASSERTION(f != this, "wrong InlinePrefISizeData container"
                                 " for first continuation");
         aData->line = nullptr;
-        aData->lineContainer = lc;
+        aData->SetLineContainer(lc);
       }
 
       // This will process all the text frames that share the same textrun as f.
       f->AddInlinePrefISizeForFlow(aRenderingContext, aData, trtype);
       lastTextRun = f->GetTextRun(trtype);
     }
   }
 }