Bug 1117227 part 2 - Convert TextOverflow to logical coordinate. r=roc
authorXidorn Quan <quanxunzhen@gmail.com>
Fri, 24 Apr 2015 10:15:32 +1200
changeset 240823 303979c9c80d53436b39ffdd1c6d332471e43292
parent 240822 b76fcf24a2f7ec833425f7a7171ca3333adfe366
child 240824 34d73ad5090a8fbaad4c80063156a193b9df8d8f
push id58940
push userxquan@mozilla.com
push dateThu, 23 Apr 2015 22:19:58 +0000
treeherdermozilla-inbound@58f1b4f600d4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1117227
milestone40.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 1117227 part 2 - Convert TextOverflow to logical coordinate. r=roc
layout/generic/TextOverflow.cpp
layout/generic/TextOverflow.h
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -82,27 +82,32 @@ IsFullyClipped(nsTextFrame* aFrame, nsco
   if (aLeft <= 0 && aRight <= 0) {
     return false;
   }
   return !aFrame->MeasureCharClippedText(aLeft, aRight,
                                          aSnappedLeft, aSnappedRight);
 }
 
 static bool
-IsHorizontalOverflowVisible(nsIFrame* aFrame)
+IsInlineAxisOverflowVisible(nsIFrame* aFrame)
 {
   NS_PRECONDITION(nsLayoutUtils::GetAsBlock(aFrame) != nullptr,
                   "expected a block frame");
 
   nsIFrame* f = aFrame;
   while (f && f->StyleContext()->GetPseudo() &&
          f->GetType() != nsGkAtoms::scrollFrame) {
     f = f->GetParent();
   }
-  return !f || f->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE;
+  if (!f) {
+    return true;
+  }
+  auto overflow = aFrame->GetWritingMode().IsVertical() ?
+    f->StyleDisplay()->mOverflowY : f->StyleDisplay()->mOverflowX;
+  return overflow == NS_STYLE_OVERFLOW_VISIBLE;
 }
 
 static void
 ClipMarker(const nsRect&                          aContentArea,
            const nsRect&                          aMarkerRect,
            DisplayListClipState::AutoSaveRestore& aClipState)
 {
   nscoord rightOverflow = aMarkerRect.XMost() - aContentArea.XMost();
@@ -118,27 +123,27 @@ ClipMarker(const nsRect&                
       markerRect.width -= leftOverflow;
       markerRect.x += leftOverflow;
       aClipState.ClipContentDescendants(markerRect);
     }
   }
 }
 
 static void
-InflateLeft(nsRect* aRect, nscoord aDelta)
+InflateIStart(WritingMode aWM, LogicalRect* aRect, nscoord aDelta)
 {
-  nscoord xmost = aRect->XMost();
-  aRect->x -= aDelta;
-  aRect->width = std::max(xmost - aRect->x, 0);
+  nscoord iend = aRect->IEnd(aWM);
+  aRect->IStart(aWM) -= aDelta;
+  aRect->ISize(aWM) = std::max(iend - aRect->IStart(aWM), 0);
 }
 
 static void
-InflateRight(nsRect* aRect, nscoord aDelta)
+InflateIEnd(WritingMode aWM, LogicalRect* aRect, nscoord aDelta)
 {
-  aRect->width = std::max(aRect->width + aDelta, 0);
+  aRect->ISize(aWM) = std::max(aRect->ISize(aWM) + aDelta, 0);
 }
 
 static bool
 IsFrameDescendantOfAny(nsIFrame* aChild,
                        const TextOverflow::FrameHashtable& aSetOfFrames,
                        nsIFrame* aCommonAncestor)
 {
   for (nsIFrame* f = aChild; f && f != aCommonAncestor;
@@ -236,106 +241,117 @@ nsDisplayTextOverflowMarker::PaintTextTo
     nsRefPtr<nsFontMetrics> fm;
     nsLayoutUtils::GetFontMetricsForFrame(mFrame, getter_AddRefs(fm),
       nsLayoutUtils::FontSizeInflationFor(mFrame));
     nsLayoutUtils::DrawString(mFrame, *fm, aCtx, mStyle->mString.get(),
                               mStyle->mString.Length(), pt);
   }
 }
 
-void
-TextOverflow::Init(nsDisplayListBuilder*   aBuilder,
-                   nsIFrame*               aBlockFrame)
+TextOverflow::TextOverflow(nsDisplayListBuilder* aBuilder,
+                           nsIFrame* aBlockFrame)
+  : mContentArea(aBlockFrame->GetWritingMode(),
+                 aBlockFrame->GetContentRectRelativeToSelf(),
+                 aBlockFrame->GetRect().width)
+  , mBuilder(aBuilder)
+  , mBlock(aBlockFrame)
+  , mScrollableFrame(nsLayoutUtils::GetScrollableFrameFor(aBlockFrame))
+  , mBlockWidth(aBlockFrame->GetRect().width)
+  , mBlockWM(aBlockFrame->GetWritingMode())
+  , mAdjustForPixelSnapping(false)
 {
-  mBuilder = aBuilder;
-  mBlock = aBlockFrame;
-  mContentArea = aBlockFrame->GetContentRectRelativeToSelf();
-  mScrollableFrame = nsLayoutUtils::GetScrollableFrameFor(aBlockFrame);
-  uint8_t direction = aBlockFrame->StyleVisibility()->mDirection;
-  mBlockIsRTL = direction == NS_STYLE_DIRECTION_RTL;
-  mAdjustForPixelSnapping = false;
 #ifdef MOZ_XUL
   if (!mScrollableFrame) {
     nsIAtom* pseudoType = aBlockFrame->StyleContext()->GetPseudo();
     if (pseudoType == nsCSSAnonBoxes::mozXULAnonymousBlock) {
       mScrollableFrame =
         nsLayoutUtils::GetScrollableFrameFor(aBlockFrame->GetParent());
       // nsXULScrollFrame::ClampAndSetBounds rounds to nearest pixels
       // for RTL blocks (also for overflow:hidden), so we need to move
       // the edges 1px outward in ExamineLineFrames to avoid triggering
       // a text-overflow marker in this case.
-      mAdjustForPixelSnapping = mBlockIsRTL;
+      mAdjustForPixelSnapping = !mBlockWM.IsBidiLTR();
     }
   }
 #endif
-  mCanHaveHorizontalScrollbar = false;
+  mCanHaveInlineAxisScrollbar = false;
   if (mScrollableFrame) {
-    mCanHaveHorizontalScrollbar =
-      mScrollableFrame->GetScrollbarStyles().mHorizontal != NS_STYLE_OVERFLOW_HIDDEN;
+    auto scrollbarStyle = mBlockWM.IsVertical() ?
+      mScrollableFrame->GetScrollbarStyles().mVertical :
+      mScrollableFrame->GetScrollbarStyles().mHorizontal;
+    mCanHaveInlineAxisScrollbar = scrollbarStyle != NS_STYLE_OVERFLOW_HIDDEN;
     if (!mAdjustForPixelSnapping) {
       // Scrolling to the end position can leave some text still overflowing due
       // to pixel snapping behaviour in our scrolling code.
-      mAdjustForPixelSnapping = mCanHaveHorizontalScrollbar;
+      mAdjustForPixelSnapping = mCanHaveInlineAxisScrollbar;
     }
-    mContentArea.MoveBy(mScrollableFrame->GetScrollPosition());
+    mContentArea.MoveBy(mBlockWM,
+                        LogicalPoint(mBlockWM,
+                                     mScrollableFrame->GetScrollPosition(), 0));
     nsIFrame* scrollFrame = do_QueryFrame(mScrollableFrame);
     scrollFrame->AddStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
   }
+  uint8_t direction = aBlockFrame->StyleVisibility()->mDirection;
   const nsStyleTextReset* style = aBlockFrame->StyleTextReset();
-  mLeft.Init(style->mTextOverflow.GetLeft(direction));
-  mRight.Init(style->mTextOverflow.GetRight(direction));
+  if (mBlockWM.IsBidiLTR()) {
+    mIStart.Init(style->mTextOverflow.GetLeft(direction));
+    mIEnd.Init(style->mTextOverflow.GetRight(direction));
+  } else {
+    mIStart.Init(style->mTextOverflow.GetRight(direction));
+    mIEnd.Init(style->mTextOverflow.GetLeft(direction));
+  }
   // The left/right marker string is setup in ExamineLineFrames when a line
   // has overflow on that side.
 }
 
 /* static */ TextOverflow*
 TextOverflow::WillProcessLines(nsDisplayListBuilder*   aBuilder,
                                nsIFrame*               aBlockFrame)
 {
   if (!CanHaveTextOverflow(aBuilder, aBlockFrame)) {
     return nullptr;
   }
   nsIScrollableFrame* scrollableFrame = nsLayoutUtils::GetScrollableFrameFor(aBlockFrame);
   if (scrollableFrame && scrollableFrame->IsTransformingByAPZ()) {
     // If the APZ is actively scrolling this, don't bother with markers.
     return nullptr;
   }
-  nsAutoPtr<TextOverflow> textOverflow(new TextOverflow);
-  textOverflow->Init(aBuilder, aBlockFrame);
-  return textOverflow.forget();
+  return new TextOverflow(aBuilder, aBlockFrame);
 }
 
 void
 TextOverflow::ExamineFrameSubtree(nsIFrame*       aFrame,
-                                  const nsRect&   aContentArea,
-                                  const nsRect&   aInsideMarkersArea,
+                                  const LogicalRect& aContentArea,
+                                  const LogicalRect& aInsideMarkersArea,
                                   FrameHashtable* aFramesToHide,
                                   AlignmentEdges* aAlignmentEdges,
                                   bool*           aFoundVisibleTextOrAtomic,
                                   InnerClipEdges* aClippedMarkerEdges)
 {
   const nsIAtom* frameType = aFrame->GetType();
   if (frameType == nsGkAtoms::brFrame ||
       frameType == nsGkAtoms::placeholderFrame) {
     return;
   }
   const bool isAtomic = IsAtomicElement(aFrame, frameType);
   if (aFrame->StyleVisibility()->IsVisible()) {
-    nsRect childRect = aFrame->GetScrollableOverflowRect() +
-                       aFrame->GetOffsetTo(mBlock);
-    bool overflowLeft = childRect.x < aContentArea.x;
-    bool overflowRight = childRect.XMost() > aContentArea.XMost();
-    if (overflowLeft) {
-      mLeft.mHasOverflow = true;
+    LogicalRect childRect =
+      GetLogicalScrollableOverflowRectRelativeToBlock(aFrame);
+    bool overflowIStart =
+      childRect.IStart(mBlockWM) < aContentArea.IStart(mBlockWM);
+    bool overflowIEnd =
+      childRect.IEnd(mBlockWM) > aContentArea.IEnd(mBlockWM);
+    if (overflowIStart) {
+      mIStart.mHasOverflow = true;
     }
-    if (overflowRight) {
-      mRight.mHasOverflow = true;
+    if (overflowIEnd) {
+      mIEnd.mHasOverflow = true;
     }
-    if (isAtomic && ((mLeft.mActive && overflowLeft) ||
-                     (mRight.mActive && overflowRight))) {
+    if (isAtomic && ((mIStart.mActive && overflowIStart) ||
+                     (mIEnd.mActive && overflowIEnd))) {
       aFramesToHide->PutEntry(aFrame);
     } else if (isAtomic || frameType == nsGkAtoms::textFrame) {
       AnalyzeMarkerEdges(aFrame, frameType, aInsideMarkersArea,
                          aFramesToHide, aAlignmentEdges,
                          aFoundVisibleTextOrAtomic,
                          aClippedMarkerEdges);
     }
   }
@@ -351,154 +367,162 @@ TextOverflow::ExamineFrameSubtree(nsIFra
                         aClippedMarkerEdges);
     child = child->GetNextSibling();
   }
 }
 
 void
 TextOverflow::AnalyzeMarkerEdges(nsIFrame*       aFrame,
                                  const nsIAtom*  aFrameType,
-                                 const nsRect&   aInsideMarkersArea,
+                                 const LogicalRect& aInsideMarkersArea,
                                  FrameHashtable* aFramesToHide,
                                  AlignmentEdges* aAlignmentEdges,
                                  bool*           aFoundVisibleTextOrAtomic,
                                  InnerClipEdges* aClippedMarkerEdges)
 {
-  nsRect borderRect(aFrame->GetOffsetTo(mBlock), aFrame->GetSize());
-  nscoord leftOverlap =
-    std::max(aInsideMarkersArea.x - borderRect.x, 0);
-  nscoord rightOverlap =
-    std::max(borderRect.XMost() - aInsideMarkersArea.XMost(), 0);
-  bool insideLeftEdge = aInsideMarkersArea.x <= borderRect.XMost();
-  bool insideRightEdge = borderRect.x <= aInsideMarkersArea.XMost();
+  LogicalRect borderRect(mBlockWM,
+                         nsRect(aFrame->GetOffsetTo(mBlock),
+                                aFrame->GetSize()),
+                         mBlockWidth);
+  nscoord istartOverlap = std::max(
+    aInsideMarkersArea.IStart(mBlockWM) - borderRect.IStart(mBlockWM), 0);
+  nscoord iendOverlap = std::max(
+    borderRect.IEnd(mBlockWM) - aInsideMarkersArea.IEnd(mBlockWM), 0);
+  bool insideIStartEdge =
+    aInsideMarkersArea.IStart(mBlockWM) <= borderRect.IEnd(mBlockWM);
+  bool insideIEndEdge =
+    borderRect.IStart(mBlockWM) <= aInsideMarkersArea.IEnd(mBlockWM);
 
-  if (leftOverlap > 0) {
-    aClippedMarkerEdges->AccumulateLeft(borderRect);
-    if (!mLeft.mActive) {
-      leftOverlap = 0;
+  if (istartOverlap > 0) {
+    aClippedMarkerEdges->AccumulateIStart(mBlockWM, borderRect);
+    if (!mIStart.mActive) {
+      istartOverlap = 0;
     }
   }
-  if (rightOverlap > 0) {
-    aClippedMarkerEdges->AccumulateRight(borderRect);
-    if (!mRight.mActive) {
-      rightOverlap = 0;
+  if (iendOverlap > 0) {
+    aClippedMarkerEdges->AccumulateIEnd(mBlockWM, borderRect);
+    if (!mIEnd.mActive) {
+      iendOverlap = 0;
     }
   }
 
-  if ((leftOverlap > 0 && insideLeftEdge) ||
-      (rightOverlap > 0 && insideRightEdge)) {
+  if ((istartOverlap > 0 && insideIStartEdge) ||
+      (iendOverlap > 0 && insideIEndEdge)) {
     if (aFrameType == nsGkAtoms::textFrame) {
-      if (aInsideMarkersArea.x < aInsideMarkersArea.XMost()) {
+      if (aInsideMarkersArea.IStart(mBlockWM) <
+          aInsideMarkersArea.IEnd(mBlockWM)) {
         // a clipped text frame and there is some room between the markers
-        nscoord snappedLeft, snappedRight;
-        bool isFullyClipped =
-          IsFullyClipped(static_cast<nsTextFrame*>(aFrame),
-                         leftOverlap, rightOverlap, &snappedLeft, &snappedRight);
+        nscoord snappedIStart, snappedIEnd;
+        auto textFrame = static_cast<nsTextFrame*>(aFrame);
+        bool isFullyClipped = mBlockWM.IsBidiLTR() ?
+          IsFullyClipped(textFrame, istartOverlap, iendOverlap,
+                         &snappedIStart, &snappedIEnd) :
+          IsFullyClipped(textFrame, iendOverlap, istartOverlap,
+                         &snappedIEnd, &snappedIStart);
         if (!isFullyClipped) {
-          nsRect snappedRect = borderRect;
-          if (leftOverlap > 0) {
-            snappedRect.x += snappedLeft;
-            snappedRect.width -= snappedLeft;
+          LogicalRect snappedRect = borderRect;
+          if (istartOverlap > 0) {
+            snappedRect.IStart(mBlockWM) += snappedIStart;
+            snappedRect.ISize(mBlockWM) -= snappedIStart;
           }
-          if (rightOverlap > 0) {
-            snappedRect.width -= snappedRight;
+          if (iendOverlap > 0) {
+            snappedRect.ISize(mBlockWM) -= snappedIEnd;
           }
-          aAlignmentEdges->Accumulate(snappedRect);
+          aAlignmentEdges->Accumulate(mBlockWM, snappedRect);
           *aFoundVisibleTextOrAtomic = true;
         }
       }
     } else {
       aFramesToHide->PutEntry(aFrame);
     }
-  } else if (!insideLeftEdge || !insideRightEdge) {
+  } else if (!insideIStartEdge || !insideIEndEdge) {
     // frame is outside
     if (IsAtomicElement(aFrame, aFrameType)) {
       aFramesToHide->PutEntry(aFrame);
     }
   } else {
     // frame is inside
-    aAlignmentEdges->Accumulate(borderRect);
+    aAlignmentEdges->Accumulate(mBlockWM, borderRect);
     *aFoundVisibleTextOrAtomic = true;
   }
 }
 
 void
 TextOverflow::ExamineLineFrames(nsLineBox*      aLine,
                                 FrameHashtable* aFramesToHide,
                                 AlignmentEdges* aAlignmentEdges)
 {
   // No ellipsing for 'clip' style.
-  bool suppressLeft = mLeft.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
-  bool suppressRight = mRight.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
-  if (mCanHaveHorizontalScrollbar) {
-    nsPoint pos = mScrollableFrame->GetScrollPosition();
-    nsRect scrollRange = mScrollableFrame->GetScrollRange();
+  bool suppressIStart = mIStart.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
+  bool suppressIEnd = mIEnd.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
+  if (mCanHaveInlineAxisScrollbar) {
+    LogicalPoint pos(mBlockWM, mScrollableFrame->GetScrollPosition(),
+                     mBlockWidth);
+    LogicalRect scrollRange(mBlockWM, mScrollableFrame->GetScrollRange(),
+                            mBlockWidth);
     // No ellipsing when nothing to scroll to on that side (this includes
     // overflow:auto that doesn't trigger a horizontal scrollbar).
-    if (pos.x <= scrollRange.x) {
-      suppressLeft = true;
+    if (pos.I(mBlockWM) <= scrollRange.IStart(mBlockWM)) {
+      suppressIStart = true;
     }
-    if (pos.x >= scrollRange.XMost()) {
-      suppressRight = true;
+    if (pos.I(mBlockWM) >= scrollRange.IEnd(mBlockWM)) {
+      suppressIEnd = true;
     }
   }
 
-  nsRect contentArea = mContentArea;
+  LogicalRect contentArea = mContentArea;
   const nscoord scrollAdjust = mAdjustForPixelSnapping ?
     mBlock->PresContext()->AppUnitsPerDevPixel() : 0;
-  InflateLeft(&contentArea, scrollAdjust);
-  InflateRight(&contentArea, scrollAdjust);
-  nsRect lineRect = aLine->GetScrollableOverflowArea();
-  const bool leftOverflow =
-    !suppressLeft && lineRect.x < contentArea.x;
-  const bool rightOverflow =
-    !suppressRight && lineRect.XMost() > contentArea.XMost();
-  if (!leftOverflow && !rightOverflow) {
+  InflateIStart(mBlockWM, &contentArea, scrollAdjust);
+  InflateIEnd(mBlockWM, &contentArea, scrollAdjust);
+  LogicalRect lineRect(mBlockWM, aLine->GetScrollableOverflowArea(),
+                       mBlockWidth);
+  const bool istartOverflow =
+    !suppressIStart && lineRect.IStart(mBlockWM) < contentArea.IStart(mBlockWM);
+  const bool iendOverflow =
+    !suppressIEnd && lineRect.IEnd(mBlockWM) > contentArea.IEnd(mBlockWM);
+  if (!istartOverflow && !iendOverflow) {
     // The line does not overflow on a side we should ellipsize.
     return;
   }
 
   int pass = 0;
   bool retryEmptyLine = true;
-  bool guessLeft = leftOverflow;
-  bool guessRight = rightOverflow;
-  mLeft.mActive = leftOverflow;
-  mRight.mActive = rightOverflow;
-  bool clippedLeftMarker = false;
-  bool clippedRightMarker = false;
+  bool guessIStart = istartOverflow;
+  bool guessIEnd = iendOverflow;
+  mIStart.mActive = istartOverflow;
+  mIEnd.mActive = iendOverflow;
+  bool clippedIStartMarker = false;
+  bool clippedIEndMarker = false;
   do {
     // Setup marker strings as needed.
-    if (guessLeft) {
-      mLeft.SetupString(mBlock);
+    if (guessIStart) {
+      mIStart.SetupString(mBlock);
     }
-    if (guessRight) {
-      mRight.SetupString(mBlock);
+    if (guessIEnd) {
+      mIEnd.SetupString(mBlock);
     }
     
     // If there is insufficient space for both markers then keep the one on the
     // end side per the block's 'direction'.
-    nscoord rightMarkerWidth = mRight.mActive ? mRight.mWidth : 0;
-    nscoord leftMarkerWidth = mLeft.mActive ? mLeft.mWidth : 0;
-    if (leftMarkerWidth && rightMarkerWidth &&
-        leftMarkerWidth + rightMarkerWidth > contentArea.width) {
-      if (mBlockIsRTL) {
-        rightMarkerWidth = 0;
-      } else {
-        leftMarkerWidth = 0;
-      }
+    nscoord istartMarkerISize = mIStart.mActive ? mIStart.mISize : 0;
+    nscoord iendMarkerISize = mIEnd.mActive ? mIEnd.mISize : 0;
+    if (istartMarkerISize && iendMarkerISize &&
+        istartMarkerISize + iendMarkerISize > contentArea.ISize(mBlockWM)) {
+      istartMarkerISize = 0;
     }
 
     // Calculate the area between the potential markers aligned at the
     // block's edge.
-    nsRect insideMarkersArea = mContentArea;
-    if (guessLeft) {
-      InflateLeft(&insideMarkersArea, -leftMarkerWidth);
+    LogicalRect insideMarkersArea = mContentArea;
+    if (guessIStart) {
+      InflateIStart(mBlockWM, &insideMarkersArea, -istartMarkerISize);
     }
-    if (guessRight) {
-      InflateRight(&insideMarkersArea, -rightMarkerWidth);
+    if (guessIEnd) {
+      InflateIEnd(mBlockWM, &insideMarkersArea, -iendMarkerISize);
     }
 
     // Analyze the frames on aLine for the overflow situation at the content
     // edges and at the edges of the area between the markers.
     bool foundVisibleTextOrAtomic = false;
     int32_t n = aLine->GetChildCount();
     nsIFrame* child = aLine->mFirstChild;
     InnerClipEdges clippedMarkerEdges;
@@ -507,129 +531,127 @@ TextOverflow::ExamineLineFrames(nsLineBo
                           aFramesToHide, aAlignmentEdges,
                           &foundVisibleTextOrAtomic,
                           &clippedMarkerEdges);
     }
     if (!foundVisibleTextOrAtomic && retryEmptyLine) {
       aAlignmentEdges->mAssigned = false;
       aFramesToHide->Clear();
       pass = -1;
-      if (mLeft.IsNeeded() && mLeft.mActive && !clippedLeftMarker) {
-        if (clippedMarkerEdges.mAssignedLeft &&
-            clippedMarkerEdges.mLeft - mContentArea.X() > 0) {
-          mLeft.mWidth = clippedMarkerEdges.mLeft - mContentArea.X();
-          NS_ASSERTION(mLeft.mWidth < mLeft.mIntrinsicISize,
-                       "clipping a marker should make it strictly smaller");
-          clippedLeftMarker = true;
+      if (mIStart.IsNeeded() && mIStart.mActive && !clippedIStartMarker) {
+        if (clippedMarkerEdges.mAssignedIStart &&
+            clippedMarkerEdges.mIStart > mContentArea.IStart(mBlockWM)) {
+          mIStart.mISize =
+            clippedMarkerEdges.mIStart - mContentArea.IStart(mBlockWM);
+          NS_ASSERTION(mIStart.mISize < mIStart.mIntrinsicISize,
+                      "clipping a marker should make it strictly smaller");
+          clippedIStartMarker = true;
         } else {
-          mLeft.mActive = guessLeft = false;
+          mIStart.mActive = guessIStart = false;
         }
         continue;
       }
-      if (mRight.IsNeeded() && mRight.mActive && !clippedRightMarker) {
-        if (clippedMarkerEdges.mAssignedRight &&
-            mContentArea.XMost() - clippedMarkerEdges.mRight > 0) {
-          mRight.mWidth = mContentArea.XMost() - clippedMarkerEdges.mRight;
-          NS_ASSERTION(mRight.mWidth < mRight.mIntrinsicISize,
-                       "clipping a marker should make it strictly smaller");
-          clippedRightMarker = true;
+      if (mIEnd.IsNeeded() && mIEnd.mActive && !clippedIEndMarker) {
+        if (clippedMarkerEdges.mAssignedIEnd &&
+            mContentArea.IEnd(mBlockWM) > clippedMarkerEdges.mIEnd) {
+          mIEnd.mISize = mContentArea.IEnd(mBlockWM) - clippedMarkerEdges.mIEnd;
+          NS_ASSERTION(mIEnd.mISize < mIEnd.mIntrinsicISize,
+                      "clipping a marker should make it strictly smaller");
+          clippedIEndMarker = true;
         } else {
-          mRight.mActive = guessRight = false;
+          mIEnd.mActive = guessIEnd = false;
         }
         continue;
       }
       // The line simply has no visible content even without markers,
       // so examine the line again without suppressing markers.
       retryEmptyLine = false;
-      mLeft.mWidth = mLeft.mIntrinsicISize;
-      mLeft.mActive = guessLeft = leftOverflow;
-      mRight.mWidth = mRight.mIntrinsicISize;
-      mRight.mActive = guessRight = rightOverflow;
+      mIStart.mISize = mIStart.mIntrinsicISize;
+      mIStart.mActive = guessIStart = istartOverflow;
+      mIEnd.mISize = mIEnd.mIntrinsicISize;
+      mIEnd.mActive = guessIEnd = iendOverflow;
       continue;
     }
-    if (guessLeft == (mLeft.mActive && mLeft.IsNeeded()) &&
-        guessRight == (mRight.mActive && mRight.IsNeeded())) {
+    if (guessIStart == (mIStart.mActive && mIStart.IsNeeded()) &&
+        guessIEnd == (mIEnd.mActive && mIEnd.IsNeeded())) {
       break;
     } else {
-      guessLeft = mLeft.mActive && mLeft.IsNeeded();
-      guessRight = mRight.mActive && mRight.IsNeeded();
-      mLeft.Reset();
-      mRight.Reset();
+      guessIStart = mIStart.mActive && mIStart.IsNeeded();
+      guessIEnd = mIEnd.mActive && mIEnd.IsNeeded();
+      mIStart.Reset();
+      mIEnd.Reset();
       aFramesToHide->Clear();
     }
     NS_ASSERTION(pass == 0, "2nd pass should never guess wrong");
   } while (++pass != 2);
-  if (!leftOverflow || !mLeft.mActive) {
-    mLeft.Reset();
+  if (!istartOverflow || !mIStart.mActive) {
+    mIStart.Reset();
   }
-  if (!rightOverflow || !mRight.mActive) {
-    mRight.Reset();
+  if (!iendOverflow || !mIEnd.mActive) {
+    mIEnd.Reset();
   }
 }
 
 void
 TextOverflow::ProcessLine(const nsDisplayListSet& aLists,
                           nsLineBox*              aLine)
 {
-  NS_ASSERTION(mLeft.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
-               mRight.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP,
+  NS_ASSERTION(mIStart.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
+               mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP,
                "TextOverflow with 'clip' for both sides");
-  mLeft.Reset();
-  mLeft.mActive = mLeft.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP;
-  mRight.Reset();
-  mRight.mActive = mRight.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP;
+  mIStart.Reset();
+  mIStart.mActive = mIStart.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP;
+  mIEnd.Reset();
+  mIEnd.mActive = mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP;
 
   FrameHashtable framesToHide(64);
   AlignmentEdges alignmentEdges;
   ExamineLineFrames(aLine, &framesToHide, &alignmentEdges);
-  bool needLeft = mLeft.IsNeeded();
-  bool needRight = mRight.IsNeeded();
-  if (!needLeft && !needRight) {
+  bool needIStart = mIStart.IsNeeded();
+  bool needIEnd = mIEnd.IsNeeded();
+  if (!needIStart && !needIEnd) {
     return;
   }
-  NS_ASSERTION(mLeft.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
-               !needLeft, "left marker for 'clip'");
-  NS_ASSERTION(mRight.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
-               !needRight, "right marker for 'clip'");
+  NS_ASSERTION(mIStart.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
+               !needIStart, "left marker for 'clip'");
+  NS_ASSERTION(mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
+               !needIEnd, "right marker for 'clip'");
 
   // If there is insufficient space for both markers then keep the one on the
   // end side per the block's 'direction'.
-  if (needLeft && needRight &&
-      mLeft.mWidth + mRight.mWidth > mContentArea.width) {
-    if (mBlockIsRTL) {
-      needRight = false;
-    } else {
-      needLeft = false;
-    }
+  if (needIStart && needIEnd &&
+      mIStart.mISize + mIEnd.mISize > mContentArea.ISize(mBlockWM)) {
+    needIStart = false;
+  }
+  LogicalRect insideMarkersArea = mContentArea;
+  if (needIStart) {
+    InflateIStart(mBlockWM, &insideMarkersArea, -mIStart.mISize);
   }
-  nsRect insideMarkersArea = mContentArea;
-  if (needLeft) {
-    InflateLeft(&insideMarkersArea, -mLeft.mWidth);
+  if (needIEnd) {
+    InflateIEnd(mBlockWM, &insideMarkersArea, -mIEnd.mISize);
   }
-  if (needRight) {
-    InflateRight(&insideMarkersArea, -mRight.mWidth);
-  }
-  if (!mCanHaveHorizontalScrollbar && alignmentEdges.mAssigned) {
-    nsRect alignmentRect = nsRect(alignmentEdges.x, insideMarkersArea.y,
-                                  alignmentEdges.Width(), 1);
+  if (!mCanHaveInlineAxisScrollbar && alignmentEdges.mAssigned) {
+    LogicalRect alignmentRect(mBlockWM, alignmentEdges.mIStart,
+                              insideMarkersArea.BStart(mBlockWM),
+                              alignmentEdges.ISize(), 1);
     insideMarkersArea.IntersectRect(insideMarkersArea, alignmentRect);
   }
 
   // Clip and remove display items as needed at the final marker edges.
   nsDisplayList* lists[] = { aLists.Content(), aLists.PositionedDescendants() };
   for (uint32_t i = 0; i < ArrayLength(lists); ++i) {
     PruneDisplayListContents(lists[i], framesToHide, insideMarkersArea);
   }
-  CreateMarkers(aLine, needLeft, needRight, insideMarkersArea);
+  CreateMarkers(aLine, needIStart, needIEnd, insideMarkersArea);
 }
 
 void
-TextOverflow::PruneDisplayListContents(nsDisplayList*        aList,
+TextOverflow::PruneDisplayListContents(nsDisplayList* aList,
                                        const FrameHashtable& aFramesToHide,
-                                       const nsRect&         aInsideMarkersArea)
+                                       const LogicalRect& aInsideMarkersArea)
 {
   nsDisplayList saved;
   nsDisplayItem* item;
   while ((item = aList->RemoveBottom())) {
     nsIFrame* itemFrame = item->Frame();
     if (IsFrameDescendantOfAny(itemFrame, aFramesToHide, mBlock)) {
       item->~nsDisplayItem();
       continue;
@@ -640,33 +662,32 @@ TextOverflow::PruneDisplayListContents(n
       if (!itemFrame || GetSelfOrNearestBlock(itemFrame) == mBlock) {
         PruneDisplayListContents(wrapper, aFramesToHide, aInsideMarkersArea);
       }
     }
 
     nsCharClipDisplayItem* charClip = itemFrame ? 
       nsCharClipDisplayItem::CheckCast(item) : nullptr;
     if (charClip && GetSelfOrNearestBlock(itemFrame) == mBlock) {
-      nsRect rect = itemFrame->GetScrollableOverflowRect() +
-                    itemFrame->GetOffsetTo(mBlock);
-      if (mLeft.IsNeeded() && rect.x < aInsideMarkersArea.x) {
-        nscoord left = aInsideMarkersArea.x - rect.x;
-        if (MOZ_UNLIKELY(left < 0)) {
-          item->~nsDisplayItem();
-          continue;
+      LogicalRect rect =
+        GetLogicalScrollableOverflowRectRelativeToBlock(itemFrame);
+      if (mIStart.IsNeeded()) {
+        nscoord istart =
+          aInsideMarkersArea.IStart(mBlockWM) - rect.IStart(mBlockWM);
+        if (istart > 0) {
+          (mBlockWM.IsBidiLTR() ?
+           charClip->mLeftEdge : charClip->mRightEdge) = istart;
         }
-        charClip->mLeftEdge = left;
       }
-      if (mRight.IsNeeded() && rect.XMost() > aInsideMarkersArea.XMost()) {
-        nscoord right = rect.XMost() - aInsideMarkersArea.XMost();
-        if (MOZ_UNLIKELY(right < 0)) {
-          item->~nsDisplayItem();
-          continue;
+      if (mIEnd.IsNeeded()) {
+        nscoord iend = rect.IEnd(mBlockWM) - aInsideMarkersArea.IEnd(mBlockWM);
+        if (iend > 0) {
+          (mBlockWM.IsBidiLTR() ?
+           charClip->mRightEdge : charClip->mLeftEdge) = iend;
         }
-        charClip->mRightEdge = right;
       }
     }
 
     saved.AppendToTop(item);
   }
   aList->AppendToTop(&saved);
 }
 
@@ -677,20 +698,20 @@ TextOverflow::HasClippedOverflow(nsIFram
   return style->mTextOverflow.mLeft.mType == NS_STYLE_TEXT_OVERFLOW_CLIP &&
          style->mTextOverflow.mRight.mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
 }
 
 /* static */ bool
 TextOverflow::CanHaveTextOverflow(nsDisplayListBuilder* aBuilder,
                                   nsIFrame*             aBlockFrame)
 {
-  // Nothing to do for text-overflow:clip or if 'overflow-x:visible' or if
+  // Nothing to do for text-overflow:clip or if 'overflow-x/y:visible' or if
   // we're just building items for event processing or image visibility.
   if (HasClippedOverflow(aBlockFrame) ||
-      IsHorizontalOverflowVisible(aBlockFrame) ||
+      IsInlineAxisOverflowVisible(aBlockFrame) ||
       aBuilder->IsForEventDelivery() || aBuilder->IsForImageVisibility()) {
     return false;
   }
 
   // Skip ComboboxControlFrame because it would clip the drop-down arrow.
   // Its anon block inherits 'text-overflow' and does what is expected.
   if (aBlockFrame->GetType() == nsGkAtoms::comboboxControlFrame) {
     return false;
@@ -710,73 +731,75 @@ TextOverflow::CanHaveTextOverflow(nsDisp
       }
     }
   }
   return true;
 }
 
 void
 TextOverflow::CreateMarkers(const nsLineBox* aLine,
-                            bool             aCreateLeft,
-                            bool             aCreateRight,
-                            const nsRect&    aInsideMarkersArea)
+                            bool aCreateIStart, bool aCreateIEnd,
+                            const mozilla::LogicalRect& aInsideMarkersArea)
 {
-  if (aCreateLeft) {
+  if (aCreateIStart) {
     DisplayListClipState::AutoSaveRestore clipState(mBuilder);
 
-    //XXX Needs vertical text love
-    nsRect markerRect = nsRect(aInsideMarkersArea.x - mLeft.mIntrinsicISize,
-                               aLine->BStart(),
-                               mLeft.mIntrinsicISize, aLine->BSize());
-    markerRect += mBuilder->ToReferenceFrame(mBlock);
-    ClipMarker(mContentArea + mBuilder->ToReferenceFrame(mBlock),
+    LogicalRect markerLogicalRect(
+      mBlockWM, aInsideMarkersArea.IStart(mBlockWM) - mIStart.mIntrinsicISize,
+      aLine->BStart(), mIStart.mIntrinsicISize, aLine->BSize());
+    nsPoint offset = mBuilder->ToReferenceFrame(mBlock);
+    nsRect markerRect =
+      markerLogicalRect.GetPhysicalRect(mBlockWM, mBlockWidth) + offset;
+    ClipMarker(mContentArea.GetPhysicalRect(mBlockWM, mBlockWidth) + offset,
                markerRect, clipState);
     nsDisplayItem* marker = new (mBuilder)
       nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
-                                  aLine->GetLogicalAscent(), mLeft.mStyle, 0);
+                                  aLine->GetLogicalAscent(), mIStart.mStyle, 0);
     mMarkerList.AppendNewToTop(marker);
   }
 
-  if (aCreateRight) {
+  if (aCreateIEnd) {
     DisplayListClipState::AutoSaveRestore clipState(mBuilder);
 
-    nsRect markerRect = nsRect(aInsideMarkersArea.XMost(),
-                               aLine->BStart(),
-                               mRight.mIntrinsicISize, aLine->BSize());
-    markerRect += mBuilder->ToReferenceFrame(mBlock);
-    ClipMarker(mContentArea + mBuilder->ToReferenceFrame(mBlock),
+    LogicalRect markerLogicalRect(
+      mBlockWM, aInsideMarkersArea.IEnd(mBlockWM), aLine->BStart(),
+      mIEnd.mIntrinsicISize, aLine->BSize());
+    nsPoint offset = mBuilder->ToReferenceFrame(mBlock);
+    nsRect markerRect =
+      markerLogicalRect.GetPhysicalRect(mBlockWM, mBlockWidth) + offset;
+    ClipMarker(mContentArea.GetPhysicalRect(mBlockWM, mBlockWidth) + offset,
                markerRect, clipState);
     nsDisplayItem* marker = new (mBuilder)
       nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
-                                  aLine->GetLogicalAscent(), mRight.mStyle, 1);
+                                  aLine->GetLogicalAscent(), mIEnd.mStyle, 1);
     mMarkerList.AppendNewToTop(marker);
   }
 }
 
 void
 TextOverflow::Marker::SetupString(nsIFrame* aFrame)
 {
   if (mInitialized) {
     return;
   }
 
   if (mStyle->mType == NS_STYLE_TEXT_OVERFLOW_ELLIPSIS) {
     gfxTextRun* textRun = GetEllipsisTextRun(aFrame);
     if (textRun) {
-      mWidth = textRun->GetAdvanceWidth(0, textRun->GetLength(), nullptr);
+      mISize = textRun->GetAdvanceWidth(0, textRun->GetLength(), nullptr);
     } else {
-      mWidth = 0;
+      mISize = 0;
     }
   } else {
     nsRenderingContext rc(
       aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext());
     nsRefPtr<nsFontMetrics> fm;
     nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm),
       nsLayoutUtils::FontSizeInflationFor(aFrame));
-    mWidth = nsLayoutUtils::AppUnitWidthOfStringBidi(mStyle->mString, aFrame,
+    mISize = nsLayoutUtils::AppUnitWidthOfStringBidi(mStyle->mString, aFrame,
                                                      *fm, rc);
   }
-  mIntrinsicISize = mWidth;
+  mIntrinsicISize = mISize;
   mInitialized = true;
 }
 
 }  // namespace css
 }  // namespace mozilla
--- a/layout/generic/TextOverflow.h
+++ b/layout/generic/TextOverflow.h
@@ -4,17 +4,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef TextOverflow_h_
 #define TextOverflow_h_
 
 #include "nsDisplayList.h"
 #include "nsTHashtable.h"
+#include "nsAutoPtr.h"
 #include "mozilla/Likely.h"
+#include "mozilla/WritingModes.h"
 #include <algorithm>
 
 class nsIScrollableFrame;
 class nsLineBox;
 
 namespace mozilla {
 namespace css {
 
@@ -53,62 +55,76 @@ class TextOverflow {
    * @return true if aBlockFrame needs analysis for text overflow.
    */
   static bool CanHaveTextOverflow(nsDisplayListBuilder* aBuilder,
                                   nsIFrame*             aBlockFrame);
 
   typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable;
 
  protected:
-  TextOverflow() {}
-  void Init(nsDisplayListBuilder*   aBuilder,
-            nsIFrame*               aBlockFrame);
+  TextOverflow(nsDisplayListBuilder* aBuilder,
+               nsIFrame* aBlockFrame);
+
+  typedef mozilla::WritingMode WritingMode;
+  typedef mozilla::LogicalRect LogicalRect;
 
   struct AlignmentEdges {
     AlignmentEdges() : mAssigned(false) {}
-    void Accumulate(const nsRect& aRect) {
+    void Accumulate(WritingMode aWM, const LogicalRect& aRect)
+    {
       if (MOZ_LIKELY(mAssigned)) {
-        x = std::min(x, aRect.X());
-        xmost = std::max(xmost, aRect.XMost());
+        mIStart = std::min(mIStart, aRect.IStart(aWM));
+        mIEnd = std::max(mIEnd, aRect.IEnd(aWM));
       } else {
-        x = aRect.X();
-        xmost = aRect.XMost();
+        mIStart = aRect.IStart(aWM);
+        mIEnd = aRect.IEnd(aWM);
         mAssigned = true;
       }
     }
-    nscoord Width() { return xmost - x; }
-    nscoord x;
-    nscoord xmost;
+    nscoord ISize() { return mIEnd - mIStart; }
+    nscoord mIStart;
+    nscoord mIEnd;
     bool mAssigned;
   };
 
   struct InnerClipEdges {
-    InnerClipEdges() : mAssignedLeft(false), mAssignedRight(false) {}
-    void AccumulateLeft(const nsRect& aRect) {
-      if (MOZ_LIKELY(mAssignedLeft)) {
-        mLeft = std::max(mLeft, aRect.X());
+    InnerClipEdges() : mAssignedIStart(false), mAssignedIEnd(false) {}
+    void AccumulateIStart(WritingMode aWM, const LogicalRect& aRect)
+    {
+      if (MOZ_LIKELY(mAssignedIStart)) {
+        mIStart = std::max(mIStart, aRect.IStart(aWM));
       } else {
-        mLeft = aRect.X();
-        mAssignedLeft = true;
+        mIStart = aRect.IStart(aWM);
+        mAssignedIStart = true;
       }
     }
-    void AccumulateRight(const nsRect& aRect) {
-      if (MOZ_LIKELY(mAssignedRight)) {
-        mRight = std::min(mRight, aRect.XMost());
+    void AccumulateIEnd(WritingMode aWM, const LogicalRect& aRect)
+    {
+      if (MOZ_LIKELY(mAssignedIEnd)) {
+        mIEnd = std::min(mIEnd, aRect.IEnd(aWM));
       } else {
-        mRight = aRect.XMost();
-        mAssignedRight = true;
+        mIEnd = aRect.IEnd(aWM);
+        mAssignedIEnd = true;
       }
     }
-    nscoord mLeft;
-    nscoord mRight;
-    bool mAssignedLeft;
-    bool mAssignedRight;
+    nscoord mIStart;
+    nscoord mIEnd;
+    bool mAssignedIStart;
+    bool mAssignedIEnd;
   };
 
+  LogicalRect
+    GetLogicalScrollableOverflowRectRelativeToBlock(nsIFrame* aFrame) const
+  {
+    return LogicalRect(mBlockWM,
+                       aFrame->GetScrollableOverflowRect() +
+                         aFrame->GetOffsetTo(mBlock),
+                       mBlockWidth);
+  }
+
   /**
    * Examines frames on the line to determine whether we should draw a left
    * and/or right marker, and if so, which frames should be completely hidden
    * and the bounds of what will be displayed between the markers.
    * @param aLine the line we're processing
    * @param aFramesToHide frames that should have their display items removed
    * @param aAlignmentEdges the outermost edges of all text and atomic
    *   inline-level frames that are inside the area between the markers
@@ -127,18 +143,18 @@ class TextOverflow {
    * @param aAlignmentEdges the outermost edges of all text and atomic
    *   inline-level frames that are inside the area between the markers
    * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
    *   inline-level frame is visible between the marker edges
    * @param aClippedMarkerEdges the innermost edges of all text and atomic
    *   inline-level frames that are clipped by the current marker width
    */
   void ExamineFrameSubtree(nsIFrame*       aFrame,
-                           const nsRect&   aContentArea,
-                           const nsRect&   aInsideMarkersArea,
+                           const LogicalRect& aContentArea,
+                           const LogicalRect& aInsideMarkersArea,
                            FrameHashtable* aFramesToHide,
                            AlignmentEdges* aAlignmentEdges,
                            bool*           aFoundVisibleTextOrAtomic,
                            InnerClipEdges* aClippedMarkerEdges);
 
   /**
    * ExamineFrameSubtree calls this to analyze a frame against the hypothetical
    * marker edges (aInsideMarkersArea) for text frames and atomic inline-level
@@ -155,90 +171,90 @@ class TextOverflow {
    *                       inside aInsideMarkersArea
    * @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
    *   inline-level frame is visible between the marker edges
    * @param aClippedMarkerEdges the innermost edges of all text and atomic
    *   inline-level frames that are clipped by the current marker width
    */
   void AnalyzeMarkerEdges(nsIFrame*       aFrame,
                           const nsIAtom*  aFrameType,
-                          const nsRect&   aInsideMarkersArea,
+                          const LogicalRect& aInsideMarkersArea,
                           FrameHashtable* aFramesToHide,
                           AlignmentEdges* aAlignmentEdges,
                           bool*           aFoundVisibleTextOrAtomic,
                           InnerClipEdges* aClippedMarkerEdges);
 
   /**
    * Clip or remove items given the final marker edges. ("clip" here just means
    * assigning mLeftEdge/mRightEdge for any nsCharClipDisplayItem that needs it,
    * see nsDisplayList.h for a description of that item).
    * @param aFramesToHide remove display items for these frames
    * @param aInsideMarkersArea is the area inside the markers
    */
-  void PruneDisplayListContents(nsDisplayList*        aList,
+  void PruneDisplayListContents(nsDisplayList* aList,
                                 const FrameHashtable& aFramesToHide,
-                                const nsRect&         aInsideMarkersArea);
+                                const LogicalRect& aInsideMarkersArea);
 
   /**
    * ProcessLine calls this to create display items for the markers and insert
    * them into mMarkerList.
    * @param aLine the line we're processing
-   * @param aCreateLeft if true, create a marker on the left side
-   * @param aCreateRight if true, create a marker on the right side
+   * @param aCreateIStart if true, create a marker on the inline start side
+   * @param aCreateIEnd if true, create a marker on the inline end side
    * @param aInsideMarkersArea is the area inside the markers
    */
   void CreateMarkers(const nsLineBox* aLine,
-                     bool             aCreateLeft,
-                     bool             aCreateRight,
-                     const nsRect&    aInsideMarkersArea);
+                     bool aCreateIStart, bool aCreateIEnd,
+                     const LogicalRect& aInsideMarkersArea);
 
-  nsRect                 mContentArea;
+  LogicalRect            mContentArea;
   nsDisplayListBuilder*  mBuilder;
   nsIFrame*              mBlock;
   nsIScrollableFrame*    mScrollableFrame;
   nsDisplayList          mMarkerList;
-  bool                   mBlockIsRTL;
-  bool                   mCanHaveHorizontalScrollbar;
+  nscoord                mBlockWidth;
+  WritingMode            mBlockWM;
+  bool                   mCanHaveInlineAxisScrollbar;
   bool                   mAdjustForPixelSnapping;
 
   class Marker {
   public:
     void Init(const nsStyleTextOverflowSide& aStyle) {
       mInitialized = false;
-      mWidth = 0;
+      mISize = 0;
       mStyle = &aStyle;
     }
 
     /**
      * Setup the marker string and calculate its size, if not done already.
      */
     void SetupString(nsIFrame* aFrame);
 
     bool IsNeeded() const {
       return mHasOverflow;
     }
     void Reset() {
       mHasOverflow = false;
     }
 
     // The current width of the marker, the range is [0 .. mIntrinsicISize].
-    nscoord                        mWidth;
+    nscoord                        mISize;
     // The intrinsic width of the marker.
     nscoord                        mIntrinsicISize;
     // The style for this side.
     const nsStyleTextOverflowSide* mStyle;
     // True if there is visible overflowing inline content on this side.
     bool                           mHasOverflow;
     // True if mMarkerString and mWidth have been setup from style.
     bool                           mInitialized;
     // True if the style is text-overflow:clip on this side and the marker
     // won't cause the line to become empty.
     bool                           mActive;
   };
 
-  Marker mLeft;  // the horizontal left marker
-  Marker mRight; // the horizontal right marker
+  Marker mIStart; // the inline start marker
+  Marker mIEnd; // the inline end marker
 };
 
 } // namespace css
 } // namespace mozilla
 
 #endif /* !defined(TextOverflow_h_) */