Bug 1172774: for a box with a writing mode orthogonal to its containing block, calculate positioning values (margin, padding and offsets) in the writing mode of the containing block, r=jfkthame
authorSimon Montagu <smontagu@smontagu.org>
Wed, 10 Jun 2015 23:42:56 -0700
changeset 248261 bcaca4f837e80a7e28d0fa44cc0a1c5d335fd6a7
parent 248260 4636a1c2b824a1d0f6e0b4d405778572df460678
child 248262 6fd48f8bf7b4e2006bb66062ac3986030023b216
push id28893
push userkwierso@gmail.com
push dateFri, 12 Jun 2015 00:02:58 +0000
treeherderautoland@8cf9d3e497f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1172774
milestone41.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 1172774: for a box with a writing mode orthogonal to its containing block, calculate positioning values (margin, padding and offsets) in the writing mode of the containing block, r=jfkthame
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockReflowState.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsHTMLReflowState.h
layout/mathml/nsMathMLSelectedFrame.cpp
layout/tables/nsTableOuterFrame.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -7210,17 +7210,17 @@ nsBlockFrame::BlockCanIntersectFloats(ns
 nsBlockFrame::ReplacedElementISizeToClear
 nsBlockFrame::ISizeToClearPastFloats(nsBlockReflowState& aState,
                                      const LogicalRect& aFloatAvailableSpace,
                                      nsIFrame* aFrame)
 {
   nscoord inlineStartOffset, inlineEndOffset;
   WritingMode wm = aState.mReflowState.GetWritingMode();
   nsCSSOffsetState offsetState(aFrame, aState.mReflowState.rendContext,
-                               aState.mContentArea.Width(wm));
+                               wm, aState.mContentArea.ISize(wm));
 
   ReplacedElementISizeToClear result;
   aState.ComputeReplacedBlockOffsetsForFloats(aFrame, aFloatAvailableSpace,
                                               inlineStartOffset,
                                               inlineEndOffset);
   nscoord availISize = aState.mContentArea.ISize(wm) -
                        inlineStartOffset - inlineEndOffset;
 
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -177,17 +177,17 @@ nsBlockReflowState::ComputeReplacedBlock
   nscoord iStartOffset, iEndOffset;
   if (aFloatAvailableSpace.ISize(wm) == mContentArea.ISize(wm)) {
     // We don't need to compute margins when there are no floats around.
     iStartOffset = 0;
     iEndOffset = 0;
   } else {
     LogicalMargin frameMargin(wm);
     nsCSSOffsetState os(aFrame, mReflowState.rendContext,
-                        mContentArea.ISize(wm));
+                        wm, mContentArea.ISize(wm));
     frameMargin =
       os.ComputedLogicalMargin().ConvertTo(wm, aFrame->GetWritingMode());
 
     nscoord iStartFloatIOffset =
       aFloatAvailableSpace.IStart(wm) - mContentArea.IStart(wm);
     iStartOffset = std::max(iStartFloatIOffset, frameMargin.IStart(wm)) -
                    frameMargin.IStart(wm);
     iStartOffset = std::max(iStartOffset, 0); // in case of negative margin
@@ -204,17 +204,18 @@ nsBlockReflowState::ComputeReplacedBlock
 static nscoord
 GetBEndMarginClone(nsIFrame* aFrame,
                    nsRenderingContext* aRenderingContext,
                    const LogicalRect& aContentArea,
                    WritingMode aWritingMode)
 {
   if (aFrame->StyleBorder()->mBoxDecorationBreak ==
         NS_STYLE_BOX_DECORATION_BREAK_CLONE) {
-    nsCSSOffsetState os(aFrame, aRenderingContext, aContentArea.ISize(aWritingMode));
+    nsCSSOffsetState os(aFrame, aRenderingContext, aWritingMode,
+                        aContentArea.ISize(aWritingMode));
     return os.ComputedLogicalMargin().
                 ConvertTo(aWritingMode,
                           aFrame->GetWritingMode()).BEnd(aWritingMode);
   }
   return 0;
 }
 
 // Compute the amount of available space for reflowing a block frame
@@ -716,17 +717,17 @@ nsBlockReflowState::FlowAndPlaceFloat(ns
   nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mBCoord);
   LogicalRect adjustedAvailableSpace =
     mBlock->AdjustFloatAvailableSpace(*this, floatAvailableSpace.mRect, aFloat);
 
   NS_ASSERTION(aFloat->GetParent() == mBlock,
                "Float frame has wrong parent");
 
   nsCSSOffsetState offsets(aFloat, mReflowState.rendContext,
-                           mReflowState.ComputedISize());
+                           wm, mReflowState.ComputedISize());
 
   nscoord floatMarginISize = FloatMarginISize(mReflowState,
                                               adjustedAvailableSpace.ISize(wm),
                                               aFloat, offsets);
 
   LogicalMargin floatMargin(wm); // computed margin
   LogicalMargin floatOffsets(wm);
   nsReflowStatus reflowStatus;
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -139,28 +139,29 @@ FontSizeInflationListMarginAdjustment(co
 
 // NOTE: If we ever want to use nsCSSOffsetState for a flex item or a
 // grid item, we need to make it take the containing-block block-size as
 // well as the inline-size, since flex items and grid items resolve
 // block-direction percent margins and padding against the
 // containing-block block-size, rather than its inline-size.
 nsCSSOffsetState::nsCSSOffsetState(nsIFrame *aFrame,
                                    nsRenderingContext *aRenderingContext,
+                                   WritingMode aContainingBlockWritingMode,
                                    nscoord aContainingBlockISize)
   : frame(aFrame)
   , rendContext(aRenderingContext)
   , mWritingMode(aFrame->GetWritingMode())
 {
   MOZ_ASSERT(!aFrame->IsFlexOrGridItem(),
              "We're about to resolve percent margin & padding "
              "values against CB inline size, which is incorrect for "
              "flex/grid items");
-  LogicalSize cbSize(mWritingMode, aContainingBlockISize,
+  LogicalSize cbSize(aContainingBlockWritingMode, aContainingBlockISize,
                      aContainingBlockISize);
-  InitOffsets(cbSize, frame->GetType());
+  InitOffsets(aContainingBlockWritingMode, cbSize, frame->GetType());
 }
 
 // Initialize a reflow state for a child frame's reflow. Some state
 // is copied from the parent reflow state; the remaining state is
 // computed.
 nsHTMLReflowState::nsHTMLReflowState(
                      nsPresContext*           aPresContext,
                      const nsHTMLReflowState& aParentReflowState,
@@ -2026,17 +2027,17 @@ nsHTMLReflowState::InitConstraints(nsPre
                            aContainingBlockSize.ISize(wm),
                            aContainingBlockSize.BSize(wm),
                            aBorder, aPadding);
 
   // If this is a reflow root, then set the computed width and
   // height equal to the available space
   if (nullptr == parentReflowState || mFlags.mDummyParentReflowState) {
     // XXXldb This doesn't mean what it used to!
-    InitOffsets(OffsetPercentBasis(frame, wm, aContainingBlockSize),
+    InitOffsets(wm, OffsetPercentBasis(frame, wm, aContainingBlockSize),
                 aFrameType, aBorder, aPadding);
     // Override mComputedMargin since reflow roots start from the
     // frame's boundary, which is inside the margin.
     ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
     ComputedPhysicalOffsets().SizeTo(0, 0, 0, 0);
 
     ComputedISize() =
       AvailableISize() - ComputedLogicalBorderPadding().IStartEnd(wm);
@@ -2079,19 +2080,25 @@ nsHTMLReflowState::InitConstraints(nsPre
           // use the cell's computed block size
           cbSize.BSize(wm) = cbrs->ComputedSize(wm).BSize(wm);
         }
       }
     }
 
     // XXX Might need to also pass the CB height (not width) for page boxes,
     // too, if we implement them.
-    InitOffsets(OffsetPercentBasis(frame, wm, cbSize),
+
+    // For calculating positioning offsets, margins, borders and
+    // padding, we use the writing mode of the containing block
+    WritingMode cbwm = cbrs->GetWritingMode();
+    InitOffsets(cbwm, OffsetPercentBasis(frame, cbwm,
+                                         cbSize.ConvertTo(cbwm, wm)),
                 aFrameType, aBorder, aPadding);
 
+    // For calculating the size of this box, we use its own writing mode
     const nsStyleCoord &blockSize = mStylePosition->BSize(wm);
     nsStyleUnit blockSizeUnit = blockSize.GetUnit();
 
     // Check for a percentage based block size and a containing block
     // block size that depends on the content block size
     // XXX twiddling blockSizeUnit doesn't help anymore
     // FIXME Shouldn't we fix that?
     if (blockSize.HasPercent()) {
@@ -2133,24 +2140,26 @@ nsHTMLReflowState::InitConstraints(nsPre
         }
         else {
           // default to interpreting the blockSize like 'auto'
           blockSizeUnit = eStyleUnit_Auto;
         }
       }
     }
 
-    // Compute our offsets if the element is relatively positioned.  We need
-    // the correct containing block width and blockSize here, which is why we need
-    // to do it after all the quirks-n-such above. (If the element is sticky
-    // positioned, we need to wait until the scroll container knows its size,
-    // so we compute offsets from StickyScrollContainer::UpdatePositions.)
+    // Compute our offsets if the element is relatively positioned.  We
+    // need the correct containing block inline-size and block-size
+    // here, which is why we need to do it after all the quirks-n-such
+    // above. (If the element is sticky positioned, we need to wait
+    // until the scroll container knows its size, so we compute offsets
+    // from StickyScrollContainer::UpdatePositions.)
     if (mStyleDisplay->IsRelativelyPositioned(frame) &&
         NS_STYLE_POSITION_RELATIVE == mStyleDisplay->mPosition) {
-      ComputeRelativeOffsets(wm, frame, cbSize, ComputedPhysicalOffsets());
+      ComputeRelativeOffsets(cbwm, frame, cbSize.ConvertTo(cbwm, wm),
+                             ComputedPhysicalOffsets());
     } else {
       // Initialize offsets to 0
       ComputedPhysicalOffsets().SizeTo(0, 0, 0, 0);
     }
 
     // Calculate the computed values for min and max properties.  Note that
     // this MUST come after we've computed our border and padding.
     ComputeMinMaxValues(cbSize);
@@ -2301,34 +2310,35 @@ UpdateProp(FrameProperties& aProps,
       aProps.Set(aProperty, new nsMargin(aNewValue));
     }
   } else {
     aProps.Delete(aProperty);
   }
 }
 
 void
-nsCSSOffsetState::InitOffsets(const LogicalSize& aPercentBasis,
+nsCSSOffsetState::InitOffsets(WritingMode aWM,
+                              const LogicalSize& aPercentBasis,
                               nsIAtom* aFrameType,
                               const nsMargin *aBorder,
                               const nsMargin *aPadding)
 {
   DISPLAY_INIT_OFFSETS(frame, this, aPercentBasis, aBorder, aPadding);
 
   // Since we are in reflow, we don't need to store these properties anymore
   // unless they are dependent on width, in which case we store the new value.
   nsPresContext *presContext = frame->PresContext();
   FrameProperties props(presContext->PropertyTable(), frame);
   props.Delete(nsIFrame::UsedBorderProperty());
 
   // Compute margins from the specified margin style information. These
   // become the default computed values, and may be adjusted below
   // XXX fix to provide 0,0 for the top&bottom margins for
   // inline-non-replaced elements
-  bool needMarginProp = ComputeMargin(aPercentBasis);
+  bool needMarginProp = ComputeMargin(aWM, aPercentBasis);
   // XXX We need to include 'auto' horizontal margins in this too!
   // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
   // to use it even when the margins are all zero (since sometimes
   // they get treated as auto)
   ::UpdateProp(props, nsIFrame::UsedMarginProperty(), needMarginProp,
                ComputedPhysicalMargin());
 
 
@@ -2351,17 +2361,17 @@ nsCSSOffsetState::InitOffsets(const Logi
     needPaddingProp = false;
   }
   else if (aPadding) { // padding is an input arg
     ComputedPhysicalPadding() = *aPadding;
     needPaddingProp = frame->StylePadding()->IsWidthDependent() ||
 	  (frame->GetStateBits() & NS_FRAME_REFLOW_ROOT);
   }
   else {
-    needPaddingProp = ComputePadding(aPercentBasis, aFrameType);
+    needPaddingProp = ComputePadding(aWM, aPercentBasis, aFrameType);
   }
 
   if (isThemed) {
     nsIntMargin widget;
     presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
                                              frame, disp->mAppearance,
                                              &widget);
     ComputedPhysicalBorderPadding().top =
@@ -2645,94 +2655,100 @@ nsHTMLReflowState::CalcLineHeight(nsICon
       lineHeight = lineHeightOne;
     }
   }
 
   return lineHeight;
 }
 
 bool
-nsCSSOffsetState::ComputeMargin(const LogicalSize& aPercentBasis)
+nsCSSOffsetState::ComputeMargin(WritingMode aWM,
+                                const LogicalSize& aPercentBasis)
 {
   // SVG text frames have no margin.
   if (frame->IsSVGText()) {
     return false;
   }
 
   // If style style can provide us the margin directly, then use it.
   const nsStyleMargin *styleMargin = frame->StyleMargin();
 
   bool isCBDependent = !styleMargin->GetMargin(ComputedPhysicalMargin());
   if (isCBDependent) {
-    // We have to compute the value
-    WritingMode wm = GetWritingMode();
-    LogicalMargin m(wm);
-    m.IStart(wm) = nsLayoutUtils::
-      ComputeCBDependentValue(aPercentBasis.ISize(wm),
-                              styleMargin->mMargin.GetIStart(wm));
-    m.IEnd(wm) = nsLayoutUtils::
-      ComputeCBDependentValue(aPercentBasis.ISize(wm),
-                              styleMargin->mMargin.GetIEnd(wm));
+    // We have to compute the value. Note that this calculation is
+    // performed according to the writing mode of the containing block
+    // (http://dev.w3.org/csswg/css-writing-modes-3/#orthogonal-flows)
+    LogicalMargin m(aWM);
+    m.IStart(aWM) = nsLayoutUtils::
+      ComputeCBDependentValue(aPercentBasis.ISize(aWM),
+                              styleMargin->mMargin.GetIStart(aWM));
+    m.IEnd(aWM) = nsLayoutUtils::
+      ComputeCBDependentValue(aPercentBasis.ISize(aWM),
+                              styleMargin->mMargin.GetIEnd(aWM));
 
-    m.BStart(wm) = nsLayoutUtils::
-      ComputeCBDependentValue(aPercentBasis.BSize(wm),
-                              styleMargin->mMargin.GetBStart(wm));
-    m.BEnd(wm) = nsLayoutUtils::
-      ComputeCBDependentValue(aPercentBasis.BSize(wm),
-                              styleMargin->mMargin.GetBEnd(wm));
+    m.BStart(aWM) = nsLayoutUtils::
+      ComputeCBDependentValue(aPercentBasis.BSize(aWM),
+                              styleMargin->mMargin.GetBStart(aWM));
+    m.BEnd(aWM) = nsLayoutUtils::
+      ComputeCBDependentValue(aPercentBasis.BSize(aWM),
+                              styleMargin->mMargin.GetBEnd(aWM));
 
-    SetComputedLogicalMargin(m);
+    SetComputedLogicalMargin(aWM, m);
   }
 
+  // ... but font-size-inflation-based margin adjustment uses the
+  // frame's writing mode
   nscoord marginAdjustment = FontSizeInflationListMarginAdjustment(frame);
 
   if (marginAdjustment > 0) {
     LogicalMargin m = ComputedLogicalMargin();
     m.IStart(mWritingMode) += marginAdjustment;
     SetComputedLogicalMargin(m);
   }
 
   return isCBDependent;
 }
 
 bool
-nsCSSOffsetState::ComputePadding(const LogicalSize& aPercentBasis,
+nsCSSOffsetState::ComputePadding(WritingMode aWM,
+                                 const LogicalSize& aPercentBasis,
                                  nsIAtom* aFrameType)
 {
   // If style can provide us the padding directly, then use it.
   const nsStylePadding *stylePadding = frame->StylePadding();
   bool isCBDependent = !stylePadding->GetPadding(ComputedPhysicalPadding());
   // a table row/col group, row/col doesn't have padding
   // XXXldb Neither do border-collapse tables.
   if (nsGkAtoms::tableRowGroupFrame == aFrameType ||
       nsGkAtoms::tableColGroupFrame == aFrameType ||
       nsGkAtoms::tableRowFrame      == aFrameType ||
       nsGkAtoms::tableColFrame      == aFrameType) {
     ComputedPhysicalPadding().SizeTo(0,0,0,0);
   }
   else if (isCBDependent) {
-    // We have to compute the value
+    // We have to compute the value. This calculation is performed
+    // according to the writing mode of the containing block
+    // (http://dev.w3.org/csswg/css-writing-modes-3/#orthogonal-flows)
     // clamp negative calc() results to 0
-    WritingMode wm = GetWritingMode();
-    LogicalMargin p(wm);
-    p.IStart(wm) = std::max(0, nsLayoutUtils::
-      ComputeCBDependentValue(aPercentBasis.ISize(wm),
-                              stylePadding->mPadding.GetIStart(wm)));
-    p.IEnd(wm) = std::max(0, nsLayoutUtils::
-      ComputeCBDependentValue(aPercentBasis.ISize(wm),
-                              stylePadding->mPadding.GetIEnd(wm)));
+    LogicalMargin p(aWM);
+    p.IStart(aWM) = std::max(0, nsLayoutUtils::
+      ComputeCBDependentValue(aPercentBasis.ISize(aWM),
+                              stylePadding->mPadding.GetIStart(aWM)));
+    p.IEnd(aWM) = std::max(0, nsLayoutUtils::
+      ComputeCBDependentValue(aPercentBasis.ISize(aWM),
+                              stylePadding->mPadding.GetIEnd(aWM)));
 
-    p.BStart(wm) = std::max(0, nsLayoutUtils::
-      ComputeCBDependentValue(aPercentBasis.BSize(wm),
-                              stylePadding->mPadding.GetBStart(wm)));
-    p.BEnd(wm) = std::max(0, nsLayoutUtils::
-      ComputeCBDependentValue(aPercentBasis.BSize(wm),
-                              stylePadding->mPadding.GetBEnd(wm)));
+    p.BStart(aWM) = std::max(0, nsLayoutUtils::
+      ComputeCBDependentValue(aPercentBasis.BSize(aWM),
+                              stylePadding->mPadding.GetBStart(aWM)));
+    p.BEnd(aWM) = std::max(0, nsLayoutUtils::
+      ComputeCBDependentValue(aPercentBasis.BSize(aWM),
+                              stylePadding->mPadding.GetBEnd(aWM)));
 
-    SetComputedLogicalPadding(p);
+    SetComputedLogicalPadding(aWM, p);
   }
   return isCBDependent;
 }
 
 void
 nsHTMLReflowState::ComputeMinMaxValues(const LogicalSize&aCBSize)
 {
   WritingMode wm = GetWritingMode();
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -119,22 +119,33 @@ public:
 
   const LogicalMargin ComputedLogicalMargin() const
     { return LogicalMargin(mWritingMode, mComputedMargin); }
   const LogicalMargin ComputedLogicalBorderPadding() const
     { return LogicalMargin(mWritingMode, mComputedBorderPadding); }
   const LogicalMargin ComputedLogicalPadding() const
     { return LogicalMargin(mWritingMode, mComputedPadding); }
 
+  void SetComputedLogicalMargin(mozilla::WritingMode aWM,
+                                const LogicalMargin& aMargin)
+    { mComputedMargin = aMargin.GetPhysicalMargin(aWM); }
   void SetComputedLogicalMargin(const LogicalMargin& aMargin)
-    { mComputedMargin = aMargin.GetPhysicalMargin(mWritingMode); }
+    { SetComputedLogicalMargin(mWritingMode, aMargin); }
+
+  void SetComputedLogicalBorderPadding(mozilla::WritingMode aWM,
+                                       const LogicalMargin& aMargin)
+    { mComputedBorderPadding = aMargin.GetPhysicalMargin(aWM); }
   void SetComputedLogicalBorderPadding(const LogicalMargin& aMargin)
-    { mComputedBorderPadding = aMargin.GetPhysicalMargin(mWritingMode); }
+    { SetComputedLogicalBorderPadding(mWritingMode, aMargin); }
+
+  void SetComputedLogicalPadding(mozilla::WritingMode aWM,
+                                 const LogicalMargin& aMargin)
+    { mComputedPadding = aMargin.GetPhysicalMargin(aWM); }
   void SetComputedLogicalPadding(const LogicalMargin& aMargin)
-    { mComputedPadding = aMargin.GetPhysicalMargin(mWritingMode); }
+    { SetComputedLogicalPadding(mWritingMode, aMargin); }
 
   WritingMode GetWritingMode() const { return mWritingMode; }
 
 protected:
   // cached copy of the frame's writing-mode, for logical coordinates
   WritingMode      mWritingMode;
 
   // These are PHYSICAL coordinates (for now).
@@ -154,16 +165,17 @@ public:
   nsCSSOffsetState(nsIFrame *aFrame, nsRenderingContext *aRenderingContext)
     : frame(aFrame)
     , rendContext(aRenderingContext)
     , mWritingMode(aFrame->GetWritingMode())
   {
   }
 
   nsCSSOffsetState(nsIFrame *aFrame, nsRenderingContext *aRenderingContext,
+                   mozilla::WritingMode aContainingBlockWritingMode,
                    nscoord aContainingBlockISize);
 
 #ifdef DEBUG
   // Reflow trace methods.  Defined in nsFrame.cpp so they have access
   // to the display-reflow infrastructure.
   static void* DisplayInitOffsetsEnter(
                                      nsIFrame* aFrame,
                                      nsCSSOffsetState* aState,
@@ -175,50 +187,57 @@ public:
                                      void* aValue);
 #endif
 
 private:
   /**
    * Computes margin values from the specified margin style information, and
    * fills in the mComputedMargin member.
    *
+   * @param aWM Writing mode of the containing block
    * @param aPercentBasis
-   *    Logical size to use for resolving percentage margin values in
-   *    the inline and block axes.
+   *    Logical size in the writing mode of the containing block to use
+   *    for resolving percentage margin values in the inline and block
+   *    axes.
    *    The inline size is usually the containing block inline-size
    *    (width if writing mode is horizontal, and height if vertical).
    *    The block size is usually the containing block inline-size, per
    *    CSS21 sec 8.3 (read in conjunction with CSS Writing Modes sec
    *    7.2), but may be the containing block block-size, e.g. in CSS3
    *    Flexbox and Grid.
    * @return true if the margin is dependent on the containing block size.
    */
-  bool ComputeMargin(const mozilla::LogicalSize& aPercentBasis);
+  bool ComputeMargin(mozilla::WritingMode aWM,
+                     const mozilla::LogicalSize& aPercentBasis);
   
   /**
    * Computes padding values from the specified padding style information, and
    * fills in the mComputedPadding member.
    *
+   * @param aWM Writing mode of the containing block
    * @param aPercentBasis
-   *    Length to use for resolving percentage padding values in
-   *    the inline and block axes.
+   *    Logical size in the writing mode of the containing block to use
+   *    for resolving percentage padding values in the inline and block
+   *    axes.
    *    The inline size is usually the containing block inline-size
    *    (width if writing mode is horizontal, and height if vertical).
    *    The block size is usually the containing block inline-size, per
    *    CSS21 sec 8.3 (read in conjunction with CSS Writing Modes sec
    *    7.2), but may be the containing block block-size, e.g. in CSS3
    *    Flexbox and Grid.
    * @return true if the padding is dependent on the containing block size.
    */
-  bool ComputePadding(const mozilla::LogicalSize& aPercentBasis,
+  bool ComputePadding(mozilla::WritingMode aWM,
+                      const mozilla::LogicalSize& aPercentBasis,
                       nsIAtom* aFrameType);
 
 protected:
 
-  void InitOffsets(const mozilla::LogicalSize& aPercentBasis,
+  void InitOffsets(mozilla::WritingMode aWM,
+                   const mozilla::LogicalSize& aPercentBasis,
                    nsIAtom* aFrameType,
                    const nsMargin *aBorder = nullptr,
                    const nsMargin *aPadding = nullptr);
 
   /*
    * Convert nsStyleCoord to nscoord when percentages depend on the
    * inline size of the containing block, and enumerated values are for
    * inline size, min-inline-size, or max-inline-size.  Does not handle
--- a/layout/mathml/nsMathMLSelectedFrame.cpp
+++ b/layout/mathml/nsMathMLSelectedFrame.cpp
@@ -112,17 +112,18 @@ nsMathMLSelectedFrame::ComputeSize(nsRen
   nsIFrame* childFrame = GetSelectedFrame();
   if (childFrame) {
     // Delegate size computation to the child frame.
     // Try to account for border/padding/margin on this frame and the child,
     // though we don't really support them during reflow anyway...
     nscoord availableISize = aAvailableISize - aBorder.ISize(aWM) -
         aPadding.ISize(aWM) - aMargin.ISize(aWM);
     LogicalSize cbSize = aCBSize - aBorder - aPadding - aMargin;
-    nsCSSOffsetState offsetState(childFrame, aRenderingContext, availableISize);
+    nsCSSOffsetState offsetState(childFrame, aRenderingContext, aWM,
+                                 availableISize);
     LogicalSize size =
         childFrame->ComputeSize(aRenderingContext, aWM, cbSize,
             availableISize, offsetState.ComputedLogicalMargin().Size(aWM),
             offsetState.ComputedLogicalBorderPadding().Size(aWM) -
             offsetState.ComputedLogicalPadding().Size(aWM),
             offsetState.ComputedLogicalPadding().Size(aWM),
             aFlags);
     return size + offsetState.ComputedLogicalBorderPadding().Size(aWM);
--- a/layout/tables/nsTableOuterFrame.cpp
+++ b/layout/tables/nsTableOuterFrame.cpp
@@ -378,17 +378,18 @@ ChildShrinkWrapISize(nsRenderingContext 
   // have orthogonal writing modes, but unless we enforce that
   // somewhere, better to make sure that the size we pass to ComputeSize
   // is in the child's writing mode.
   WritingMode wm = aChildFrame->GetWritingMode();
   LogicalSize cbSize = aCBSize.ConvertTo(wm, aWM);
 
   // On the other hand, the inline size that we pass to nsCSSOffsetState
   // needs to be in the containing block's writing mode.
-  nsCSSOffsetState offsets(aChildFrame, aRenderingContext, aCBSize.ISize(aWM));
+  nsCSSOffsetState offsets(aChildFrame, aRenderingContext, aWM,
+                           aCBSize.ISize(aWM));
   LogicalSize size =
     aChildFrame->ComputeSize(aRenderingContext,
                   wm, cbSize, aAvailableWidth,
                   offsets.ComputedLogicalMargin().Size(wm),
                   offsets.ComputedLogicalBorderPadding().Size(wm) -
                     offsets.ComputedLogicalPadding().Size(wm),
                   offsets.ComputedLogicalPadding().Size(wm),
                   nsIFrame::ComputeSizeFlags::eShrinkWrap);