Bug 672944 - Setup overflow areas for the scrolled block frame in a XUL scroll frame for the benefit of text-overflow; Make the text-overflow code grok the extra wrapper frame in this case. r=roc
authorMats Palmgren <matspal@gmail.com>
Sat, 28 Jan 2012 04:35:59 +0100
changeset 85642 bdbd188e6f5fa3c6e959e15882d171dfed611e1d
parent 85641 2cae7e5c62ae63554993a8f32cea553846c6e4a4
child 85643 8f3fbc4a9c2a3971c1dcec4c7638e130ff6d027a
push id21940
push userjdrew@mozilla.com
push dateSun, 29 Jan 2012 02:43:03 +0000
treeherdermozilla-central@ec666b4c8d84 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs672944
milestone12.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 672944 - Setup overflow areas for the scrolled block frame in a XUL scroll frame for the benefit of text-overflow; Make the text-overflow code grok the extra wrapper frame in this case. r=roc
layout/generic/TextOverflow.cpp
layout/generic/TextOverflow.h
layout/generic/nsGfxScrollFrame.cpp
layout/style/ua.css
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -32,31 +32,30 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "mozilla/Util.h"
-
 #include "TextOverflow.h"
 
 // Please maintain alphabetical order below
 #include "nsBlockFrame.h"
 #include "nsCaret.h"
 #include "nsContentUtils.h"
+#include "nsGfxScrollFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsRect.h"
 #include "nsRenderingContext.h"
 #include "nsTextFrame.h"
-#include "nsGfxScrollFrame.h"
+#include "mozilla/Util.h"
 
 namespace mozilla {
 namespace css {
 
 static const PRUnichar kEllipsisChar[] = { 0x2026, 0x0 };
 static const PRUnichar kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 };
 
 // Return an ellipsis if the font supports it,
@@ -241,48 +240,73 @@ nsDisplayTextOverflowMarker::PaintTextTo
   aCtx->SetFont(fm);
   gfxFloat y = nsLayoutUtils::GetSnappedBaselineY(mFrame, aCtx->ThebesContext(),
                                                   mRect.y, mAscent);
   nsPoint baselinePt(mRect.x, NSToCoordFloor(y));
   nsLayoutUtils::DrawString(mFrame, aCtx, mString.get(),
                             mString.Length(), baselinePt + aOffsetFromRect);
 }
 
+void
+TextOverflow::Init(nsDisplayListBuilder*   aBuilder,
+                   const nsDisplayListSet& aLists,
+                   nsIFrame*               aBlockFrame)
+{
+  mBuilder = aBuilder;
+  mBlock = aBlockFrame;
+  mMarkerList = aLists.PositionedDescendants();
+  mContentArea = aBlockFrame->GetContentRectRelativeToSelf();
+  mScrollableFrame = nsLayoutUtils::GetScrollableFrameFor(aBlockFrame);
+  PRUint8 direction = aBlockFrame->GetStyleVisibility()->mDirection;
+  mBlockIsRTL = direction == NS_STYLE_DIRECTION_RTL;
+  mAdjustForPixelSnapping = false;
+#ifdef MOZ_XUL
+  if (!mScrollableFrame) {
+    nsIAtom* pseudoType = aBlockFrame->GetStyleContext()->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;
+    }
+  }
+#endif
+  mCanHaveHorizontalScrollbar = false;
+  if (mScrollableFrame) {
+    mCanHaveHorizontalScrollbar =
+      mScrollableFrame->GetScrollbarStyles().mHorizontal != 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;
+    }
+    mContentArea.MoveBy(mScrollableFrame->GetScrollPosition());
+    nsIFrame* scrollFrame = do_QueryFrame(mScrollableFrame);
+    scrollFrame->AddStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
+  }
+  const nsStyleTextReset* style = aBlockFrame->GetStyleTextReset();
+  mLeft.Init(style->mTextOverflow.GetLeft(direction));
+  mRight.Init(style->mTextOverflow.GetRight(direction));
+  // The left/right marker string is setup in ExamineLineFrames when a line
+  // has overflow on that side.
+}
+
 /* static */ TextOverflow*
 TextOverflow::WillProcessLines(nsDisplayListBuilder*   aBuilder,
                                const nsDisplayListSet& aLists,
                                nsIFrame*               aBlockFrame)
 {
   if (!CanHaveTextOverflow(aBuilder, aBlockFrame)) {
     return nsnull;
   }
-
   nsAutoPtr<TextOverflow> textOverflow(new TextOverflow);
-  textOverflow->mBuilder = aBuilder;
-  textOverflow->mBlock = aBlockFrame;
-  textOverflow->mMarkerList = aLists.PositionedDescendants();
-  textOverflow->mContentArea = aBlockFrame->GetContentRectRelativeToSelf();
-  nsIScrollableFrame* scroll =
-    nsLayoutUtils::GetScrollableFrameFor(aBlockFrame);
-  textOverflow->mCanHaveHorizontalScrollbar = false;
-  if (scroll) {
-    textOverflow->mCanHaveHorizontalScrollbar =
-      scroll->GetScrollbarStyles().mHorizontal != NS_STYLE_OVERFLOW_HIDDEN;
-    textOverflow->mContentArea.MoveBy(scroll->GetScrollPosition());
-    nsIFrame* scrollFrame = do_QueryFrame(scroll);
-    scrollFrame->AddStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL);
-  }
-  PRUint8 direction = aBlockFrame->GetStyleVisibility()->mDirection;
-  textOverflow->mBlockIsRTL = direction == NS_STYLE_DIRECTION_RTL;
-  const nsStyleTextReset* style = aBlockFrame->GetStyleTextReset();
-  textOverflow->mLeft.Init(style->mTextOverflow.GetLeft(direction));
-  textOverflow->mRight.Init(style->mTextOverflow.GetRight(direction));
-  // The left/right marker string is setup in ExamineLineFrames when a line
-  // has overflow on that side.
-
+  textOverflow->Init(aBuilder, aLists, aBlockFrame);
   return textOverflow.forget();
 }
 
 void
 TextOverflow::ExamineFrameSubtree(nsIFrame*       aFrame,
                                   const nsRect&   aContentArea,
                                   const nsRect&   aInsideMarkersArea,
                                   FrameHashtable* aFramesToHide,
@@ -402,34 +426,30 @@ 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) {
-    nsIScrollableFrame* scroll = nsLayoutUtils::GetScrollableFrameFor(mBlock);
-    nsPoint pos = scroll->GetScrollPosition();
-    nsRect scrollRange = scroll->GetScrollRange();
+    nsPoint pos = mScrollableFrame->GetScrollPosition();
+    nsRect scrollRange = mScrollableFrame->GetScrollRange();
     // 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.x >= scrollRange.XMost()) {
       suppressRight = true;
     }
   }
 
-  // Scrolling to the end position can leave some text still overflowing due to
-  // pixel snapping behaviour in our scrolling code so we move the edges 1px
-  // outward to avoid triggering a text-overflow marker for such overflow.
   nsRect contentArea = mContentArea;
-  const nscoord scrollAdjust = mCanHaveHorizontalScrollbar ?
+  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();
--- a/layout/generic/TextOverflow.h
+++ b/layout/generic/TextOverflow.h
@@ -38,16 +38,17 @@
 
 #ifndef TextOverflow_h_
 #define TextOverflow_h_
 
 #include "nsDisplayList.h"
 #include "nsLineBox.h"
 #include "nsStyleStruct.h"
 #include "nsTHashtable.h"
+class nsIScrollableFrame;
 
 namespace mozilla {
 namespace css {
 
 /**
  * A class for rendering CSS3 text-overflow.
  * Usage:
  *  1. allocate an object using WillProcessLines
@@ -74,16 +75,19 @@ class TextOverflow {
    */
   static bool CanHaveTextOverflow(nsDisplayListBuilder* aBuilder,
                                   nsIFrame*             aBlockFrame);
 
   typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable;
 
  protected:
   TextOverflow() {}
+  void Init(nsDisplayListBuilder*   aBuilder,
+            const nsDisplayListSet& aLists,
+            nsIFrame*               aBlockFrame);
 
   struct AlignmentEdges {
     AlignmentEdges() : mAssigned(false) {}
     void Accumulate(const nsRect& aRect) {
       if (NS_LIKELY(mAssigned)) {
         x = NS_MIN(x, aRect.X());
         xmost = NS_MAX(xmost, aRect.XMost());
       } else {
@@ -206,19 +210,21 @@ class TextOverflow {
   void CreateMarkers(const nsLineBox* aLine,
                      bool             aCreateLeft,
                      bool             aCreateRight,
                      const nsRect&    aInsideMarkersArea) const;
 
   nsRect                 mContentArea;
   nsDisplayListBuilder*  mBuilder;
   nsIFrame*              mBlock;
+  nsIScrollableFrame*    mScrollableFrame;
   nsDisplayList*         mMarkerList;
   bool                   mBlockIsRTL;
   bool                   mCanHaveHorizontalScrollbar;
+  bool                   mAdjustForPixelSnapping;
 
   class Marker {
   public:
     void Init(const nsStyleTextOverflowSide& aStyle) {
       mInitialized = false;
       mWidth = 0;
       mStyle = &aStyle;
     }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3142,16 +3142,30 @@ nsXULScrollFrame::Layout(nsBoxLayoutStat
     // Make sure we'll try scrolling to restored position
     PresContext()->PresShell()->PostReflowCallback(&mInner);
     mInner.mPostedReflowCallback = true;
   }
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     mInner.mHadNonInitialReflow = true;
   }
 
+  // Set up overflow areas for block frames for the benefit of
+  // text-overflow.
+  nsIFrame* f = mInner.mScrolledFrame->GetContentInsertionFrame();
+  if (nsLayoutUtils::GetAsBlock(f)) {
+    nsRect origRect = f->GetRect();
+    nsRect clippedRect = origRect;
+    clippedRect.MoveBy(mInner.mScrollPort.TopLeft());
+    clippedRect.IntersectRect(clippedRect, mInner.mScrollPort);
+    nsOverflowAreas overflow = f->GetOverflowAreas();
+    f->FinishAndStoreOverflow(overflow, clippedRect.Size());
+    clippedRect.MoveTo(origRect.TopLeft());
+    f->SetRect(clippedRect);
+  }
+
   mInner.PostOverflowEvent();
   return NS_OK;
 }
 
 void
 nsGfxScrollFrameInner::FinishReflowForScrollbar(nsIContent* aContent,
                                                 nscoord aMinXY, nscoord aMaxXY,
                                                 nscoord aCurPosXY,
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -139,16 +139,17 @@
   -moz-box-ordinal-group: inherit !important;
 }
 
 *|*::-moz-xul-anonymous-block {
   display: block ! important;
   position: static ! important;
   float: none ! important;
   -moz-box-ordinal-group: inherit !important;
+  text-overflow: inherit;
 }
 
 *|*::-moz-scrolled-content, *|*::-moz-scrolled-canvas,
 *|*::-moz-scrolled-page-sequence {
   /* e.g., text inputs, select boxes */
   padding: inherit;
   /* The display doesn't affect the kind of frame constructed here.  This just
      affects auto-width sizing of the block we create. */