Bug 1131013: when setting the position of inline frames in vertical writing modes with right-to-left direction, subtract the inline start from the container height to get the correct vertical position. r=jfkthame
authorSimon Montagu <smontagu@smontagu.org>
Wed, 11 Feb 2015 01:43:03 -0800
changeset 228660 31f86276a98b2a1da9f0073f11f8ec541e1b6e3d
parent 228659 efec1f21b4a16bc2b3aa4939bba7bf2b63e25009
child 228661 70dda75a914f01300422fb5d65324089e4556b4f
push idunknown
push userunknown
push dateunknown
reviewersjfkthame
bugs1131013
milestone38.0a1
Bug 1131013: when setting the position of inline frames in vertical writing modes with right-to-left direction, subtract the inline start from the container height to get the correct vertical position. r=jfkthame
layout/base/nsBidiPresUtils.cpp
layout/base/nsBidiPresUtils.h
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockReflowContext.cpp
layout/generic/nsBlockReflowState.cpp
layout/generic/nsBlockReflowState.h
layout/generic/nsFirstLetterFrame.cpp
layout/generic/nsLineLayout.cpp
layout/generic/nsLineLayout.h
layout/generic/nsRubyBaseContainerFrame.cpp
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -1217,34 +1217,35 @@ nsBidiPresUtils::ResolveParagraphWithinB
                                              BidiParagraphData* aBpd)
 {
   aBpd->ClearBidiControls();
   ResolveParagraph(aBlockFrame, aBpd);
   aBpd->ResetData();
 }
 
 void
-nsBidiPresUtils::ReorderFrames(nsIFrame*   aFirstFrameOnLine,
-                               int32_t     aNumFramesOnLine,
-                               WritingMode aLineWM,
-                               nscoord     aLineWidth,
-                               nscoord     aStart)
+nsBidiPresUtils::ReorderFrames(nsIFrame*     aFirstFrameOnLine,
+                               int32_t       aNumFramesOnLine,
+                               WritingMode   aLineWM,
+                               const nsSize& aContainerSize,
+                               nscoord       aStart)
 {
   // If this line consists of a line frame, reorder the line frame's children.
   if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
     aFirstFrameOnLine = aFirstFrameOnLine->GetFirstPrincipalChild();
     if (!aFirstFrameOnLine)
       return;
     // All children of the line frame are on the first line. Setting aNumFramesOnLine
     // to -1 makes InitLogicalArrayFromLine look at all of them.
     aNumFramesOnLine = -1;
   }
 
   BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
-  RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth, aStart);
+  RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM,
+                         aContainerSize, aStart);
 }
 
 nsIFrame*
 nsBidiPresUtils::GetFirstLeaf(nsIFrame* aFrame)
 {
   nsIFrame* firstLeaf = aFrame;
   while (!IsBidiLeaf(firstLeaf)) {
     nsIFrame* firstChild = firstLeaf->GetFirstPrincipalChild();
@@ -1395,17 +1396,17 @@ nsBidiPresUtils::IsFirstOrLast(nsIFrame*
 }
 
 void
 nsBidiPresUtils::RepositionFrame(nsIFrame*             aFrame,
                                  bool                  aIsEvenLevel,
                                  nscoord&              aStart,
                                  nsContinuationStates* aContinuationStates,
                                  WritingMode           aContainerWM,
-                                 nscoord               aContainerWidth)
+                                 const nsSize&         aContainerSize)
 {
   if (!aFrame)
     return;
 
   bool isFirst, isLast;
   WritingMode frameWM = aFrame->GetWritingMode();
   IsFirstOrLast(aFrame,
                 aContinuationStates,
@@ -1460,33 +1461,44 @@ nsBidiPresUtils::RepositionFrame(nsIFram
     nscoord iCoord = borderPadding.IStart(frameWM);
 
     while (frame) {
       RepositionFrame(frame,
                       aIsEvenLevel,
                       iCoord,
                       aContinuationStates,
                       frameWM,
-                      aFrame->GetLogicalSize(aContainerWM).Width(aContainerWM));
+                      aFrame->GetSize());
       index++;
       frame = reverseOrder ?
                 childList[childList.Length() - index - 1] :
                 frame->GetNextSibling();
     }
 
     aStart += iCoord + borderPadding.IEnd(frameWM);
   } else {
     aStart += aFrame->ISize(aContainerWM);
   }
 
-  LogicalRect logicalRect = aFrame->GetLogicalRect(aContainerWM,
-                                                   aContainerWidth);
-  logicalRect.IStart(aContainerWM) = start;
-  logicalRect.ISize(aContainerWM) = aStart - start;
-  aFrame->SetRect(aContainerWM, logicalRect, aContainerWidth);
+  // LogicalRect doesn't correctly calculate the vertical position
+  // in vertical writing modes with right-to-left direction (Bug 1131451).
+  // This does the correct calculation ad hoc pending the fix for that.
+  nsRect rect = aFrame->GetRect();
+  nscoord lineSize = aContainerWM.IsVertical()
+    ? aContainerSize.height : aContainerSize.width;
+  NS_ASSERTION(aContainerWM.IsBidiLTR() || lineSize != NS_UNCONSTRAINEDSIZE,
+               "Unconstrained inline line size in bidi frame reordering");
+
+  nscoord frameIStart = aContainerWM.IsBidiLTR() ? start : lineSize - aStart;
+  nscoord frameISize = aStart - start;
+
+  (aContainerWM.IsVertical() ? rect.y : rect.x) = frameIStart;
+  (aContainerWM.IsVertical() ? rect.height : rect.width) = frameISize;
+
+  aFrame->SetRect(rect);
 
   aStart += margin.IEnd(aContainerWM);
 }
 
 void
 nsBidiPresUtils::InitContinuationStates(nsIFrame*              aFrame,
                                         nsContinuationStates*  aContinuationStates)
 {
@@ -1505,17 +1517,17 @@ nsBidiPresUtils::InitContinuationStates(
     }
   }
 }
 
 void
 nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
                                         nsIFrame* aFirstChild,
                                         WritingMode aLineWM,
-                                        nscoord aLineWidth,
+                                        const nsSize& aContainerSize,
                                         nscoord aStart)
 {
   nscoord start = aStart;
   nsIFrame* frame;
   int32_t count = aBld->mVisualFrames.Length();
   int32_t index;
   nsContinuationStates continuationStates;
 
@@ -1538,17 +1550,17 @@ nsBidiPresUtils::RepositionInlineFrames(
   }
   for (; index != limit; index += step) {
     frame = aBld->VisualFrameAt(index);
     RepositionFrame(frame,
                     !(IS_LEVEL_RTL(aBld->mLevels[aBld->mIndexMap[index]])),
                     start,
                     &continuationStates,
                     aLineWM,
-                    aLineWidth);
+                    aContainerSize);
   }
 }
 
 bool
 nsBidiPresUtils::CheckLineOrder(nsIFrame*  aFirstFrameOnLine,
                                 int32_t    aNumFramesOnLine,
                                 nsIFrame** aFirstVisual,
                                 nsIFrame** aLastVisual)
--- a/layout/base/nsBidiPresUtils.h
+++ b/layout/base/nsBidiPresUtils.h
@@ -20,16 +20,17 @@ struct BidiParagraphData;
 struct BidiLineData;
 class nsFontMetrics;
 class nsIFrame;
 class nsBlockFrame;
 class nsPresContext;
 class nsRenderingContext;
 class nsBlockInFlowLineIterator;
 class nsStyleContext;
+struct nsSize;
 template<class T> class nsTHashtable;
 namespace mozilla { class WritingMode; }
 
 /**
  * A structure representing some continuation state for each frame on the line,
  * used to determine the first and the last continuation frame for each
  * continuation chain on the line.
  */
@@ -156,17 +157,17 @@ public:
    * Reorder this line using Bidi engine.
    * Update frame array, following the new visual sequence.
    * 
    * @lina 05/02/2000
    */
   static void ReorderFrames(nsIFrame*            aFirstFrameOnLine,
                             int32_t              aNumFramesOnLine,
                             mozilla::WritingMode aLineWM,
-                            nscoord              aLineWidth,
+                            const nsSize&        aContainerSize,
                             nscoord              aStart);
 
   /**
    * Format Unicode text, taking into account bidi capabilities
    * of the platform. The formatting includes: reordering, Arabic shaping,
    * symmetric and numeric swapping, removing control characters.
    *
    * @lina 06/18/2000 
@@ -425,17 +426,17 @@ private:
    *                             (after adding its inline-end margin)
    * @param aContinuationStates  A map from nsIFrame* to nsFrameContinuationState
    */
   static void RepositionFrame(nsIFrame*              aFrame,
                               bool                   aIsEvenLevel,
                               nscoord&               aStart,
                               nsContinuationStates*  aContinuationStates,
                               mozilla::WritingMode   aContainerWM,
-                              nscoord                aContainerWidth);
+                              const nsSize&          aContainerSize);
 
   /*
    * Initialize the continuation state(nsFrameContinuationState) to
    * (nullptr, 0) for aFrame and its descendants.
    *
    * @param aFrame               The frame which itself and its descendants will
    *                             be initialized
    * @param aContinuationStates  A map from nsIFrame* to nsFrameContinuationState
@@ -478,17 +479,17 @@ private:
    *
    *  @param aFirstChild the first kid
    *
    *  @lina 04/11/2000
    */
   static void RepositionInlineFrames(BidiLineData* aBld,
                                      nsIFrame* aFirstChild,
                                      mozilla::WritingMode aLineWM,
-                                     nscoord aLineWidth,
+                                     const nsSize& aContainerSize,
                                      nscoord aStart);
   
   /**
    * Helper method for Resolve()
    * Truncate a text frame to the end of a single-directional run and possibly
    * create a continuation frame for the remainder of its content.
    *
    * @param aFrame       the original frame
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1257,17 +1257,17 @@ nsBlockFrame::Reflow(nsPresContext*     
   //
   // Note that writing-mode:vertical-rl is the only case where the block
   // logical direction progresses in a negative physical direction, and
   // therefore block-dir coordinate conversion depends on knowing the width
   // of the coordinate space in order to translate between the logical and
   // physical origins.
   if (wm.IsVerticalRL()) {
     nscoord containerWidth = aMetrics.Width();
-    nscoord deltaX = containerWidth - state.mContainerWidth;
+    nscoord deltaX = containerWidth - state.ContainerWidth();
     if (deltaX) {
       for (line_iterator line = begin_lines(), end = end_lines();
            line != end; line++) {
         UpdateLineContainerWidth(line, containerWidth);
       }
       for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
         nsPoint physicalDelta(deltaX, 0);
         f->MovePositionBy(physicalDelta);
@@ -1918,17 +1918,17 @@ nsBlockFrame::PropagateFloatDamage(nsBlo
   if (floatManager->HasFloatDamage()) {
     // Need to check mBounds *and* mCombinedArea to find intersections 
     // with aLine's floats
     nscoord lineBCoordBefore = aLine->BStart() + aDeltaBCoord;
     nscoord lineBCoordAfter = lineBCoordBefore + aLine->BSize();
     // Scrollable overflow should be sufficient for things that affect
     // layout.
     WritingMode wm = aState.mReflowState.GetWritingMode();
-    nscoord containerWidth = aState.mContainerWidth;
+    nscoord containerWidth = aState.ContainerWidth();
     LogicalRect overflow = aLine->GetOverflowArea(eScrollableOverflow, wm,
                                                   containerWidth);
     nscoord lineBCoordCombinedBefore = overflow.BStart(wm) + aDeltaBCoord;
     nscoord lineBCoordCombinedAfter = lineBCoordCombinedBefore +
                                       overflow.BSize(wm);
 
     // "Translate" the float manager with an offset of (0, 0) in order to
     // set the origin to our writing mode
@@ -2169,18 +2169,18 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
       // See if there's any reflow damage that requires that we mark the
       // line dirty.
       PropagateFloatDamage(aState, line, deltaBCoord);
     }
 
     // If the container width has changed reset the container width. If the
     // line's writing mode is not ltr, or if the line is not left-aligned, also
     // mark the line dirty.
-    if (aState.mContainerWidth != line->mContainerWidth) {
-      line->mContainerWidth = aState.mContainerWidth;
+    if (aState.ContainerWidth() != line->mContainerWidth) {
+      line->mContainerWidth = aState.ContainerWidth();
 
       bool isLastLine = line == mLines.back() &&
                         !GetNextInFlow() &&
                         NS_STYLE_TEXT_ALIGN_AUTO == StyleText()->mTextAlignLast;
       uint8_t align = isLastLine ?
         StyleText()->mTextAlign : StyleText()->mTextAlignLast;
 
       if (line->mWritingMode.IsVertical() ||
@@ -2807,17 +2807,17 @@ nsBlockFrame::PullFrameFrom(nsLineBox*  
 
 void
 nsBlockFrame::SlideLine(nsBlockReflowState& aState,
                         nsLineBox* aLine, nscoord aDeltaBCoord)
 {
   NS_PRECONDITION(aDeltaBCoord != 0, "why slide a line nowhere?");
 
   // Adjust line state
-  aLine->SlideBy(aDeltaBCoord, aState.mContainerWidth);
+  aLine->SlideBy(aDeltaBCoord, aState.ContainerWidth());
 
   // Adjust the frames in the line
   MoveChildFramesOfLine(aLine, aDeltaBCoord);
 }
 
 void
 nsBlockFrame::UpdateLineContainerWidth(nsLineBox* aLine,
                                        nscoord aNewContainerWidth)
@@ -3694,17 +3694,17 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo
   printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n",
          this, aFloatAvailableSpace.mHasFloats);
 #endif
 
   WritingMode outerWM = aState.mReflowState.GetWritingMode();
   WritingMode lineWM = GetWritingMode(aLine->mFirstChild);
   LogicalRect lineRect =
     aFloatAvailableSpace.mRect.ConvertTo(lineWM, outerWM,
-                                         aState.mContainerWidth);
+                                         aState.ContainerWidth());
 
   nscoord iStart = lineRect.IStart(lineWM);
   nscoord availISize = lineRect.ISize(lineWM);
   nscoord availBSize;
   if (aState.GetFlag(BRS_UNCONSTRAINEDBSIZE)) {
     availBSize = NS_UNCONSTRAINEDSIZE;
   }
   else {
@@ -3715,17 +3715,17 @@ nsBlockFrame::DoReflowInlineFrames(nsBlo
   // Make sure to enable resize optimization before we call BeginLineReflow
   // because it might get disabled there
   aLine->EnableResizeReflowOptimization();
 
   aLineLayout.BeginLineReflow(iStart, aState.mBCoord,
                               availISize, availBSize,
                               aFloatAvailableSpace.mHasFloats,
                               false, /*XXX isTopOfPage*/
-                              lineWM, aState.mContainerWidth);
+                              lineWM, aState.mContainerSize);
 
   aState.SetFlag(BRS_LINE_LAYOUT_EMPTY, false);
 
   // XXX Unfortunately we need to know this before reflowing the first
   // inline frame in the line. FIX ME.
   if ((0 == aLineLayout.GetLineNumber()) &&
       (NS_BLOCK_HAS_FIRST_LETTER_CHILD & mState) &&
       (NS_BLOCK_HAS_FIRST_LETTER_STYLE & mState)) {
@@ -7040,17 +7040,17 @@ nsBlockFrame::ReflowBullet(nsIFrame* aBu
 
   // Approximate the bullets position; vertical alignment will provide
   // the final vertical location. We pass our writing-mode here, because
   // it may be different from the bullet frame's mode.
   nscoord bStart = floatAvailSpace.BStart(wm);
   aBulletFrame->SetRect(wm, LogicalRect(wm, iStart, bStart,
                                         aMetrics.ISize(wm),
                                         aMetrics.BSize(wm)),
-                        aState.mContainerWidth);
+                        aState.ContainerWidth());
   aBulletFrame->DidReflow(aState.mPresContext, &aState.mReflowState,
                           nsDidReflowStatus::FINISHED);
 }
 
 // This is used to scan frames for any float placeholders, add their
 // floats to the list represented by aList, and remove the
 // floats from whatever list they might be in. We don't search descendants
 // that are float containing blocks.  Floats that or not children of 'this'
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -223,17 +223,17 @@ nsBlockReflowContext::ReflowBlock(const 
                                   bool                aIsAdjacentWithBStart,
                                   nsLineBox*          aLine,
                                   nsHTMLReflowState&  aFrameRS,
                                   nsReflowStatus&     aFrameReflowStatus,
                                   nsBlockReflowState& aState)
 {
   mFrame = aFrameRS.frame;
   mWritingMode = aState.mReflowState.GetWritingMode();
-  mContainerWidth = aState.mContainerWidth;
+  mContainerWidth = aState.ContainerWidth();
   mSpace = aSpace;
 
   if (!aIsAdjacentWithBStart) {
     aFrameRS.mFlags.mIsTopOfPage = false;  // make sure this is cleared
   }
 
   if (aApplyBStartMargin) {
     mBStartMargin = aPrevMargin;
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -60,29 +60,37 @@ nsBlockReflowState::nsBlockReflowState(c
   WritingMode wm = aReflowState.GetWritingMode();
   SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nullptr);
   SetFlag(BRS_ISOVERFLOWCONTAINER, IS_TRUE_OVERFLOW_CONTAINER(aFrame));
 
   nsIFrame::LogicalSides logicalSkipSides =
     aFrame->GetLogicalSkipSides(&aReflowState);
   mBorderPadding.ApplySkipSides(logicalSkipSides);
 
-  // Note that mContainerWidth is the physical width, needed to convert
-  // logical block-coordinates in vertical-rl writing mode (measured from a
-  // RHS origin) to physical coordinates within the containing block.
-  // If aReflowState doesn't have a constrained ComputedWidth(), we set it to
-  // zero, which means lines will be positioned (physically) incorrectly;
-  // we will fix them up at the end of nsBlockFrame::Reflow, after we know
-  // the total block-size of the frame.
-  mContainerWidth = aReflowState.ComputedWidth();
-  if (mContainerWidth == NS_UNCONSTRAINEDSIZE) {
-    mContainerWidth = 0;
+  // Note that mContainerSize is the physical size, needed to
+  // convert logical block-coordinates in vertical-rl writing mode
+  // (measured from a RHS origin) to physical coordinates within the
+  // containing block.
+  // If aReflowState doesn't have a constrained ComputedWidth(), we set
+  // mContainerSize.width to zero, which means lines will be positioned
+  // (physically) incorrectly; we will fix them up at the end of
+  // nsBlockFrame::Reflow, after we know the total block-size of the
+  // frame.
+  mContainerSize.width = aReflowState.ComputedWidth();
+  if (mContainerSize.width == NS_UNCONSTRAINEDSIZE) {
+    mContainerSize.width = 0;
   }
 
-  mContainerWidth += mBorderPadding.LeftRight(wm);
+  mContainerSize.width += mBorderPadding.LeftRight(wm);
+
+  // For now at least, we don't do that fix-up for mContainerHeight.
+  // It's only used in nsBidiUtils::ReorderFrames for vertical rtl
+  // writing modes, which aren't fully supported for the time being.
+  mContainerSize.height = aReflowState.ComputedHeight() +
+                          mBorderPadding.TopBottom(wm);
 
   if ((aBStartMarginRoot && !logicalSkipSides.BStart()) ||
       0 != mBorderPadding.BStart(wm)) {
     SetFlag(BRS_ISBSTARTMARGINROOT, true);
     SetFlag(BRS_APPLYBSTARTMARGIN, true);
   }
   if ((aBEndMarginRoot && !logicalSkipSides.BEnd()) ||
       0 != mBorderPadding.BEnd(wm)) {
@@ -315,17 +323,17 @@ nsBlockReflowState::GetFloatAvailableSpa
   }
 #endif
 
   nscoord blockSize = (mContentArea.BSize(wm) == nscoord_MAX)
     ? nscoord_MAX : std::max(mContentArea.BEnd(wm) - aBCoord, 0);
   nsFlowAreaRect result =
     mFloatManager->GetFlowArea(wm, aBCoord, nsFloatManager::BAND_FROM_POINT,
                                blockSize, mContentArea, aState,
-                               mContainerWidth);
+                               ContainerWidth());
   // Keep the inline size >= 0 for compatibility with nsSpaceManager.
   if (result.mRect.ISize(wm) < 0) {
     result.mRect.ISize(wm) = 0;
   }
 
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
@@ -352,17 +360,17 @@ nsBlockReflowState::GetFloatAvailableSpa
     NS_ASSERTION(wPt == mFloatManagerOrigin, "bad coord system");
   } else {
     //XXX if the writing modes are different we can't easily assert that
     //    the origin is the same.
   }
 #endif
   nsFlowAreaRect result =
     mFloatManager->GetFlowArea(wm, aBCoord, nsFloatManager::WIDTH_WITHIN_HEIGHT,
-                               aBSize, mContentArea, aState, mContainerWidth);
+                               aBSize, mContentArea, aState, ContainerWidth());
   // Keep the width >= 0 for compatibility with nsSpaceManager.
   if (result.mRect.ISize(wm) < 0) {
     result.mRect.ISize(wm) = 0;
   }
 
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
@@ -483,31 +491,31 @@ nsBlockReflowState::RecoverFloats(nsLine
         mFloatManager->GetTranslation(tWM, tPt);
         nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
         printf("RecoverFloats: txy=%d,%d (%d,%d) ",
                tPt.I(tWM), tPt.B(tWM),
                mFloatManagerOrigin.I(mFloatManagerWM),
                mFloatManagerOrigin.B(mFloatManagerWM));
         nsFrame::ListTag(stdout, floatFrame);
         LogicalRect region = nsFloatManager::GetRegionFor(wm, floatFrame,
-                                                          mContainerWidth);
+                                                          ContainerWidth());
         printf(" aDeltaBCoord=%d region={%d,%d,%d,%d}\n",
                aDeltaBCoord, region.IStart(wm), region.BStart(wm),
                region.ISize(wm), region.BSize(wm));
       }
 #endif
       mFloatManager->AddFloat(floatFrame,
                               nsFloatManager::GetRegionFor(wm, floatFrame,
-                                                           mContainerWidth),
-                              wm, mContainerWidth);
+                                                           ContainerWidth()),
+                              wm, ContainerWidth());
       fc = fc->Next();
     }
   } else if (aLine->IsBlock()) {
     nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager, wm,
-                                   mContainerWidth);
+                                   ContainerWidth());
   }
   mFloatManager->Untranslate(oldWM, oPt);
 }
 
 /**
  * Everything done in this function is done O(N) times for each pass of
  * reflow so it is O(N*M) where M is the number of incremental reflow
  * passes.  That's bad.  Don't do stuff here.
@@ -691,25 +699,25 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
   // FIXME: Should give AutoRestore a getter for the value to avoid this.
   const nscoord saveBCoord = mBCoord;
 
   // Grab the float's display information
   const nsStyleDisplay* floatDisplay = aFloat->StyleDisplay();
 
   // The float's old region, so we can propagate damage.
   LogicalRect oldRegion = nsFloatManager::GetRegionFor(wm, aFloat,
-                                                       mContainerWidth);
+                                                       ContainerWidth());
 
   // Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
   // ``above'' another float that preceded it in the flow.
   // "Translate" the float manager with an offset of (0, 0) in order to
   // set the origin to our writing mode
   LogicalPoint oPt(wm);
   WritingMode oldWM = mFloatManager->Translate(wm, oPt);
-  mBCoord = std::max(mFloatManager->GetLowestFloatTop(wm, mContainerWidth),
+  mBCoord = std::max(mFloatManager->GetLowestFloatTop(wm, ContainerWidth()),
                      mBCoord);
 
   // See if the float should clear any preceding floats...
   // XXX We need to mark this float somehow so that it gets reflowed
   // when floats are inserted before it.
   if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
     // XXXldb Does this handle vertical margins correctly?
     mBCoord = ClearFloats(mBCoord, floatDisplay->mBreakType);
@@ -913,49 +921,49 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
   // Calculate the actual origin of the float frame's border rect
   // relative to the parent block; the margin must be added in
   // to get the border rect
   LogicalPoint origin(wm, floatMargin.IStart(wm) + floatPos.I(wm),
                       floatMargin.BStart(wm) + floatPos.B(wm));
 
   // If float is relatively positioned, factor that in as well
   nsHTMLReflowState::ApplyRelativePositioning(aFloat, wm, floatOffsets,
-                                              &origin, mContainerWidth);
+                                              &origin, ContainerWidth());
 
   // Position the float and make sure and views are properly
   // positioned. We need to explicitly position its child views as
   // well, since we're moving the float after flowing it.
-  bool moved = aFloat->GetLogicalPosition(wm, mContainerWidth) != origin;
+  bool moved = aFloat->GetLogicalPosition(wm, ContainerWidth()) != origin;
   if (moved) {
-    aFloat->SetPosition(wm, origin, mContainerWidth);
+    aFloat->SetPosition(wm, origin, ContainerWidth());
     nsContainerFrame::PositionFrameView(aFloat);
     nsContainerFrame::PositionChildViews(aFloat);
   }
 
   // Update the float combined area state
   // XXX Floats should really just get invalidated here if necessary
   mFloatOverflowAreas.UnionWith(aFloat->GetOverflowAreas() +
                                 aFloat->GetPosition());
 
   // Place the float in the float manager
   // calculate region
   LogicalRect region =
     nsFloatManager::CalculateRegionFor(wm, aFloat, floatMargin,
-                                       mContainerWidth);
+                                       ContainerWidth());
   // if the float split, then take up all of the vertical height
   if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus) &&
       (NS_UNCONSTRAINEDSIZE != ContentBSize())) {
     region.BSize(wm) = std::max(region.BSize(wm),
                                 ContentBSize() - floatPos.B(wm));
   }
   DebugOnly<nsresult> rv = mFloatManager->AddFloat(aFloat, region, wm,
-                                                   mContainerWidth);
+                                                   ContainerWidth());
   MOZ_ASSERT(NS_SUCCEEDED(rv), "bad float placement");
   // store region
-  nsFloatManager::StoreRegionFor(wm, aFloat, region, mContainerWidth);
+  nsFloatManager::StoreRegionFor(wm, aFloat, region, ContainerWidth());
 
   // If the float's dimensions have changed, note the damage in the
   // float manager.
   if (!region.IsEqualEdges(oldRegion)) {
     // XXXwaterson conservative: we could probably get away with noting
     // less damage; e.g., if only height has changed, then only note the
     // area into which the float has grown or from which the float has
     // shrunk.
@@ -1073,17 +1081,17 @@ nsBlockReflowState::ClearFloats(nscoord 
     return aBCoord;
   }
 
   nscoord newBCoord = aBCoord;
   WritingMode wm = mReflowState.GetWritingMode();
 
   if (aBreakType != NS_STYLE_CLEAR_NONE) {
     newBCoord = mFloatManager->ClearFloats(wm, newBCoord, aBreakType,
-                                           mContainerWidth, aFlags);
+                                           ContainerWidth(), aFlags);
   }
 
   if (aReplacedBlock) {
     for (;;) {
       nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(newBCoord);
       if (!floatAvailableSpace.mHasFloats) {
         // If there aren't any floats here, then we always fit.
         // We check this before calling ISizeToClearPastFloats, which is
--- a/layout/generic/nsBlockReflowState.h
+++ b/layout/generic/nsBlockReflowState.h
@@ -201,18 +201,20 @@ public:
   nscoord ContentBEnd() const {
     return mContentArea.BEnd(mReflowState.GetWritingMode());
   }
   mozilla::LogicalSize ContentSize(mozilla::WritingMode aWM) const {
     mozilla::WritingMode wm = mReflowState.GetWritingMode();
     return mContentArea.Size(wm).ConvertTo(aWM, wm);
   }
 
-  // Physical width. Use only for physical <-> logical coordinate conversion.
-  nscoord mContainerWidth;
+  // Physical size. Use only for physical <-> logical coordinate conversion.
+  nsSize mContainerSize;
+  nscoord ContainerWidth() const { return mContainerSize.width; }
+  nscoord ContainerHeight() const { return mContainerSize.height; }
 
   // Continuation out-of-flow float frames that need to move to our
   // next in flow are placed here during reflow.  It's a pointer to
   // a frame list stored in the block's property table.
   nsFrameList *mPushedFloats;
   // This method makes sure pushed floats are accessible to
   // StealFrame. Call it before adding any frames to mPushedFloats.
   void SetupPushedFloatList();
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -194,17 +194,18 @@ nsFirstLetterFrame::Reflow(nsPresContext
     WritingMode kidWritingMode = GetWritingMode(kid);
     LogicalSize kidAvailSize = availSize.ConvertTo(kidWritingMode, wm);
     nsHTMLReflowState rs(aPresContext, aReflowState, kid, kidAvailSize);
     nsLineLayout ll(aPresContext, nullptr, &aReflowState, nullptr, nullptr);
 
     ll.BeginLineReflow(bp.IStart(wm), bp.BStart(wm),
                        availSize.ISize(wm), NS_UNCONSTRAINEDSIZE,
                        false, true, kidWritingMode,
-                       aReflowState.AvailableWidth());
+                       nsSize(aReflowState.AvailableWidth(),
+                              aReflowState.AvailableHeight()));
     rs.mLineLayout = &ll;
     ll.SetInFirstLetter(true);
     ll.SetFirstLetterStyleOK(true);
 
     kid->WillReflow(aPresContext);
     kid->Reflow(aPresContext, kidMetrics, rs, aReflowStatus);
 
     ll.EndLineReflow();
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -147,17 +147,17 @@ HasPrevInFlow(nsIFrame *aFrame)
 }
 
 void
 nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
                               nscoord aISize, nscoord aBSize,
                               bool aImpactedByFloats,
                               bool aIsTopOfPage,
                               WritingMode aWritingMode,
-                              nscoord aContainerWidth)
+                              const nsSize& aContainerSize)
 {
   NS_ASSERTION(nullptr == mRootSpan, "bad linelayout user");
   NS_WARN_IF_FALSE(aISize != NS_UNCONSTRAINEDSIZE,
                    "have unconstrained width; this should only result from "
                    "very large sizes, not attempts at intrinsic width "
                    "calculation");
 #ifdef DEBUG
   if ((aISize != NS_UNCONSTRAINEDSIZE) && CRAZY_SIZE(aISize)) {
@@ -202,17 +202,17 @@ nsLineLayout::BeginLineReflow(nscoord aI
   }
 
   PerSpanData* psd = NewPerSpanData();
   mCurrentSpan = mRootSpan = psd;
   psd->mReflowState = mBlockReflowState;
   psd->mIStart = aICoord;
   psd->mICoord = aICoord;
   psd->mIEnd = aICoord + aISize;
-  mContainerWidth = aContainerWidth;
+  mContainerSize = aContainerSize;
 
   // If we're in a constrained height frame, then we don't allow a
   // max line box width to take effect.
   if (!(LineContainerFrame()->GetStateBits() &
         NS_FRAME_IN_CONSTRAINED_HEIGHT)) {
 
     // If the available size is greater than the maximum line box width (if
     // specified), then we need to adjust the line box width to be at the max
@@ -316,17 +316,17 @@ void
 nsLineLayout::UpdateBand(WritingMode aWM,
                          const LogicalRect& aNewAvailSpace,
                          nsIFrame* aFloatFrame)
 {
   WritingMode lineWM = mRootSpan->mWritingMode;
   // need to convert to our writing mode, because we might have a different
   // mode from the caller due to dir: auto
   LogicalRect availSpace = aNewAvailSpace.ConvertTo(lineWM, aWM,
-                                                    mContainerWidth);
+                                                    ContainerWidth());
 #ifdef REALLY_NOISY_REFLOW
   printf("nsLL::UpdateBand %d, %d, %d, %d, (converted to %d, %d, %d, %d); frame=%p\n  will set mImpacted to true\n",
          aNewAvailSpace.x, aNewAvailSpace.y,
          aNewAvailSpace.width, aNewAvailSpace.height,
          availSpace.IStart(lineWM), availSpace.BStart(lineWM),
          availSpace.ISize(lineWM), availSpace.BSize(lineWM),
          aFloatFrame);
 #endif
@@ -1483,33 +1483,33 @@ nsLineLayout::AddBulletFrame(nsIFrame* a
   pfd->mIsBullet = true;
   if (aMetrics.BlockStartAscent() == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
     pfd->mAscent = aFrame->GetLogicalBaseline(lineWM);
   } else {
     pfd->mAscent = aMetrics.BlockStartAscent();
   }
 
   // Note: block-coord value will be updated during block-direction alignment
-  pfd->mBounds = LogicalRect(lineWM, aFrame->GetRect(), mContainerWidth);
+  pfd->mBounds = LogicalRect(lineWM, aFrame->GetRect(), ContainerWidth());
   pfd->mOverflowAreas = aMetrics.mOverflowAreas;
 }
 
 #ifdef DEBUG
 void
 nsLineLayout::DumpPerSpanData(PerSpanData* psd, int32_t aIndent)
 {
   nsFrame::IndentBy(stdout, aIndent);
   printf("%p: left=%d x=%d right=%d\n", static_cast<void*>(psd),
          psd->mIStart, psd->mICoord, psd->mIEnd);
   PerFrameData* pfd = psd->mFirstFrame;
   while (nullptr != pfd) {
     nsFrame::IndentBy(stdout, aIndent+1);
     nsFrame::ListTag(stdout, pfd->mFrame);
     nsRect rect = pfd->mBounds.GetPhysicalRect(psd->mWritingMode,
-                                               mContainerWidth);
+                                               ContainerWidth());
     printf(" %d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
     if (pfd->mSpan) {
       DumpPerSpanData(pfd->mSpan, aIndent + 1);
     }
     pfd = pfd->mNext;
   }
 }
 #endif
@@ -1588,28 +1588,28 @@ nsLineLayout::VerticalAlignLine()
   // recurse over the child spans and place any frames we find with
   // vertical-align: top or bottom.
   // XXX PERFORMANCE: set a bit per-span to avoid the extra work
   // (propagate it upward too)
   WritingMode lineWM = psd->mWritingMode;
   for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
     if (pfd->mBlockDirAlign == VALIGN_OTHER) {
       pfd->mBounds.BStart(lineWM) += baselineBCoord;
-      pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth);
+      pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerWidth());
     }
   }
   PlaceTopBottomFrames(psd, -mBStartEdge, lineBSize);
 
   mFinalLineBSize = lineBSize;
   if (mGotLineBox) {
     // Fill in returned line-box and max-element-width data
     mLineBox->SetBounds(lineWM,
                         psd->mIStart, mBStartEdge,
                         psd->mICoord - psd->mIStart, lineBSize,
-                        mContainerWidth);
+                        ContainerWidth());
 
     mLineBox->SetLogicalAscent(baselineBCoord - mBStartEdge);
 #ifdef NOISY_BLOCKDIR_ALIGN
     printf(
       "  [line]==> bounds{x,y,w,h}={%d,%d,%d,%d} lh=%d a=%d\n",
       mLineBox->GetBounds().IStart(lineWM), mLineBox->GetBounds().BStart(lineWM),
       mLineBox->GetBounds().ISize(lineWM), mLineBox->GetBounds().BSize(lineWM),
       mFinalLineBSize, mLineBox->GetLogicalAscent());
@@ -3032,47 +3032,47 @@ nsLineLayout::TextAlignLine(nsLineBox* a
   if (mHasRuby) {
     ExpandInlineRubyBoxes(mRootSpan);
   }
 
   if (mPresContext->BidiEnabled() &&
       (!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
     nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
                                    aLine->GetChildCount(),
-                                   lineWM, mContainerWidth,
+                                   lineWM, mContainerSize,
                                    psd->mIStart + mTextIndent + dx);
     if (dx) {
-      aLine->IndentBy(dx, mContainerWidth);
+      aLine->IndentBy(dx, ContainerWidth());
     }
   } else if (dx) {
     for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
       pfd->mBounds.IStart(lineWM) += dx;
       pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerWidthForSpan(psd));
     }
-    aLine->IndentBy(dx, mContainerWidth);
+    aLine->IndentBy(dx, ContainerWidth());
   }
 }
 
 // This method applies any relative positioning to the given frame.
 void
 nsLineLayout::ApplyRelativePositioning(PerFrameData* aPFD)
 {
   if (!aPFD->mRelativePos) {
     return;
   }
 
   nsIFrame* frame = aPFD->mFrame;
   WritingMode frameWM = frame->GetWritingMode();
-  LogicalPoint origin = frame->GetLogicalPosition(mContainerWidth);
+  LogicalPoint origin = frame->GetLogicalPosition(ContainerWidth());
   // right and bottom are handled by
   // nsHTMLReflowState::ComputeRelativeOffsets
   nsHTMLReflowState::ApplyRelativePositioning(frame, frameWM,
                                               aPFD->mOffsets, &origin,
-                                              mContainerWidth);
-  frame->SetPosition(frameWM, origin, mContainerWidth);
+                                              ContainerWidth());
+  frame->SetPosition(frameWM, origin, ContainerWidth());
 }
 
 // This method do relative positioning for ruby annotations.
 void
 nsLineLayout::RelativePositionAnnotations(PerSpanData* aRubyPSD,
                                           nsOverflowAreas& aOverflowAreas)
 {
   MOZ_ASSERT(aRubyPSD->mFrame->mFrame->GetType() == nsGkAtoms::rubyFrame);
@@ -3115,17 +3115,17 @@ nsLineLayout::RelativePositionFrames(Per
   }
   else {
     LogicalRect rect(wm, psd->mIStart, mBStartEdge,
                      psd->mICoord - psd->mIStart, mFinalLineBSize);
     // The minimum combined area for the frames that are direct
     // children of the block starts at the upper left corner of the
     // line and is sized to match the size of the line's bounding box
     // (the same size as the values returned from VerticalAlignFrames)
-    overflowAreas.VisualOverflow() = rect.GetPhysicalRect(wm, mContainerWidth);
+    overflowAreas.VisualOverflow() = rect.GetPhysicalRect(wm, ContainerWidth());
     overflowAreas.ScrollableOverflow() = overflowAreas.VisualOverflow();
   }
 
   for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
     nsIFrame* frame = pfd->mFrame;
 
     // Adjust the origin of the frame
     ApplyRelativePositioning(pfd);
--- a/layout/generic/nsLineLayout.h
+++ b/layout/generic/nsLineLayout.h
@@ -51,17 +51,17 @@ public:
     return mLineNumber;
   }
 
   void BeginLineReflow(nscoord aICoord, nscoord aBCoord,
                        nscoord aISize, nscoord aBSize,
                        bool aImpactedByFloats,
                        bool aIsTopOfPage,
                        mozilla::WritingMode aWritingMode,
-                       nscoord aContainerWidth);
+                       const nsSize& aContainerSize);
 
   void EndLineReflow();
 
   /**
    * Called when a float has been placed. This method updates the
    * inline frame and span data to account for any change in positions
    * due to available space for the line boxes changing.
    * @param aX/aY/aWidth/aHeight are the new available
@@ -544,21 +544,21 @@ protected:
     }
   };
   PerSpanData* mSpanFreeList;
   PerSpanData* mRootSpan;
   PerSpanData* mCurrentSpan;
 
   // The container width to use when converting between logical and
   // physical coordinates for frames in this span. For the root span
-  // this is the width of the block cached in mContainerWidth; for
+  // this is the width of the block cached in mContainerSize.width; for
   // child spans it's the width of the root span
   nscoord ContainerWidthForSpan(PerSpanData* aPSD) {
     return (aPSD == mRootSpan)
-      ? mContainerWidth
+      ? ContainerWidth()
       : aPSD->mFrame->mBounds.Width(mRootSpan->mWritingMode);
   }
 
   gfxBreakPriority mLastOptionalBreakPriority;
   int32_t     mLastOptionalBreakFrameOffset;
   int32_t     mForceBreakFrameOffset;
 
   nscoord mMinLineBSize;
@@ -583,18 +583,20 @@ protected:
   // Final computed line-bSize value after VerticalAlignFrames for
   // the block has been called.
   nscoord mFinalLineBSize;
   
   // Amount of trimmable whitespace inline size for the trailing text
   // frame, if any
   nscoord mTrimmableISize;
 
-  // Physical width. Use only for physical <-> logical coordinate conversion.
-  nscoord mContainerWidth;
+  // Physical size. Use only for physical <-> logical coordinate conversion.
+  nsSize mContainerSize;
+  nscoord ContainerWidth() const { return mContainerSize.width; }
+  nscoord ContainerHeight() const { return mContainerSize.height; }
 
   bool mFirstLetterStyleOK      : 1;
   bool mIsTopOfPage             : 1;
   bool mImpactedByFloats        : 1;
   bool mLastFloatWasLetterFrame : 1;
   bool mLineIsEmpty             : 1;
   bool mLineEndsInBR            : 1;
   bool mNeedBackup              : 1;
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -382,20 +382,20 @@ nsRubyBaseContainerFrame::Reflow(nsPresC
     // XXX nullptr here may cause problem, see comments for
     //     nsLineLayout::mBlockRS and nsLineLayout::AddFloat
     lineLayout->Init(nullptr, reflowState->CalcLineHeight(), -1);
     reflowState->mLineLayout = lineLayout;
 
     // Border and padding are suppressed on ruby text containers.
     // If the writing mode is vertical-rl, the horizontal position of
     // rt frames will be updated when reflowing this text container,
-    // hence leave container width 0 here for now.
+    // hence leave container size 0 here for now.
     lineLayout->BeginLineReflow(0, 0, reflowState->ComputedISize(),
                                 NS_UNCONSTRAINEDSIZE,
-                                false, false, lineWM, 0);
+                                false, false, lineWM, nsSize(0, 0));
     lineLayout->AttachRootFrameToBaseLineLayout();
   }
 
   aReflowState.mLineLayout->BeginSpan(this, &aReflowState,
                                       0, aReflowState.AvailableISize(),
                                       &mBaseline);
 
   nsIFrame* parent = GetParent();