Bug 690187 - Use a bit on each marker to track if it's active (only text-overflow:clip means inactive for now); check the flag rather setting the clip edge at infinity to disable ellipsing on a side. r=roc
authorMats Palmgren <matspal@gmail.com>
Mon, 19 Dec 2011 15:48:30 +0100
changeset 83037 92bf605a98492e86790e793fd876711884cbb9fa
parent 82967 e6179f497b7468f5873cc532b596761f3e4ca003
child 83038 6489afe1cd34076c5f1535937367372712016dea
push id21724
push userbmo@edmorley.co.uk
push dateTue, 20 Dec 2011 11:16:15 +0000
treeherdermozilla-central@32d762c16927 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs690187
milestone11.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 690187 - Use a bit on each marker to track if it's active (only text-overflow:clip means inactive for now); check the flag rather setting the clip edge at infinity to disable ellipsing on a side. r=roc
layout/generic/TextOverflow.cpp
layout/generic/TextOverflow.h
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -143,35 +143,27 @@ ClipMarker(nsDisplayListBuilder* aBuilde
       item = new (aBuilder)
         nsDisplayClip(aBuilder, aFrame, aMarker, *aMarkerRect);
     }
   }
   return item;
 }
 
 static void
-InflateLeft(nsRect* aRect, bool aInfinity, nscoord aDelta)
+InflateLeft(nsRect* aRect, nscoord aDelta)
 {
   nscoord xmost = aRect->XMost();
-  if (aInfinity) {
-    aRect->x = nscoord_MIN;
-  } else {
-    aRect->x -= aDelta;
-  }
+  aRect->x -= aDelta;
   aRect->width = NS_MAX(xmost - aRect->x, 0);
 }
 
 static void
-InflateRight(nsRect* aRect, bool aInfinity, nscoord aDelta)
+InflateRight(nsRect* aRect, nscoord aDelta)
 {
-  if (aInfinity) {
-    aRect->width = nscoord_MAX;
-  } else {
-    aRect->width = NS_MAX(aRect->width + aDelta, 0);
-  }
+  aRect->width = NS_MAX(aRect->width + aDelta, 0);
 }
 
 static bool
 IsFrameDescendantOfAny(nsIFrame* aChild,
                        const TextOverflow::FrameHashtable& aSetOfFrames,
                        nsIFrame* aCommonAncestor)
 {
   for (nsIFrame* f = aChild; f && f != aCommonAncestor;
@@ -308,17 +300,18 @@ TextOverflow::ExamineFrameSubtree(nsIFra
     bool overflowLeft = childRect.x < aContentArea.x;
     bool overflowRight = childRect.XMost() > aContentArea.XMost();
     if (overflowLeft) {
       mLeft.mHasOverflow = true;
     }
     if (overflowRight) {
       mRight.mHasOverflow = true;
     }
-    if (isAtomic && (overflowLeft || overflowRight)) {
+    if (isAtomic && ((mLeft.mActive && overflowLeft) ||
+                     (mRight.mActive && overflowRight))) {
       aFramesToHide->PutEntry(aFrame);
     } else if (isAtomic || frameType == nsGkAtoms::textFrame) {
       AnalyzeMarkerEdges(aFrame, frameType, aInsideMarkersArea,
                          aFramesToHide, aAlignmentEdges);
     }
   }
   if (isAtomic) {
     return;
@@ -346,16 +339,25 @@ TextOverflow::AnalyzeMarkerEdges(nsIFram
     NS_MAX(borderRect.XMost() - aInsideMarkersArea.XMost(), 0);
   bool insideLeftEdge = aInsideMarkersArea.x <= borderRect.XMost();
   bool insideRightEdge = borderRect.x <= aInsideMarkersArea.XMost();
 
   if ((leftOverlap > 0 && insideLeftEdge) ||
       (rightOverlap > 0 && insideRightEdge)) {
     if (aFrameType == nsGkAtoms::textFrame &&
         aInsideMarkersArea.x < aInsideMarkersArea.XMost()) {
+      if (!mLeft.mActive) {
+        leftOverlap = 0;
+      }
+      if (!mRight.mActive) {
+        rightOverlap = 0;
+      }
+      if (leftOverlap == 0 && rightOverlap == 0) {
+        return;
+      }
       // 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);
       if (!isFullyClipped) {
         nsRect snappedRect = borderRect;
         if (leftOverlap > 0) {
@@ -363,17 +365,20 @@ TextOverflow::AnalyzeMarkerEdges(nsIFram
           snappedRect.width -= snappedLeft;
         }
         if (rightOverlap > 0) {
           snappedRect.width -= snappedRight;
         }
         aAlignmentEdges->Accumulate(snappedRect);
       }
     } else if (IsAtomicElement(aFrame, aFrameType)) {
-      aFramesToHide->PutEntry(aFrame);
+      if ((insideLeftEdge && mLeft.mActive) ||
+          (insideRightEdge && mRight.mActive)) {
+        aFramesToHide->PutEntry(aFrame);
+      }
     }
   } else if (!insideLeftEdge || !insideRightEdge) {
     // frame is outside
     if (IsAtomicElement(aFrame, aFrameType)) {
       aFramesToHide->PutEntry(aFrame);
     }
   } else {
     // frame is inside
@@ -404,31 +409,33 @@ TextOverflow::ExamineLineFrames(nsLineBo
   }
 
   // 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 ?
     mBlock->PresContext()->AppUnitsPerDevPixel() : 0;
-  InflateLeft(&contentArea, suppressLeft, scrollAdjust);
-  InflateRight(&contentArea, suppressRight, scrollAdjust);
+  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) {
     // The line does not overflow on a side we should ellipsize.
     return;
   }
 
   PRUint32 pass = 0;
   bool guessLeft = leftOverflow;
   bool guessRight = rightOverflow;
+  mLeft.mActive = leftOverflow;
+  mRight.mActive = rightOverflow;
   do {
     // Setup marker strings as needed.
     if (guessLeft) {
       mLeft.SetupString(mBlock);
     }
     if (guessRight) {
       mRight.SetupString(mBlock);
     }
@@ -444,18 +451,22 @@ TextOverflow::ExamineLineFrames(nsLineBo
       } else {
         leftMarkerWidth = 0;
       }
     }
 
     // Calculate the area between the potential markers aligned at the
     // block's edge.
     nsRect insideMarkersArea = mContentArea;
-    InflateLeft(&insideMarkersArea, !guessLeft, -leftMarkerWidth);
-    InflateRight(&insideMarkersArea, !guessRight, -rightMarkerWidth);
+    if (guessLeft) {
+      InflateLeft(&insideMarkersArea, -leftMarkerWidth);
+    }
+    if (guessRight) {
+      InflateRight(&insideMarkersArea, -rightMarkerWidth);
+    }
 
     // Analyze the frames on aLine for the overflow situation at the content
     // edges and at the edges of the area between the markers.
     PRInt32 n = aLine->GetChildCount();
     nsIFrame* child = aLine->mFirstChild;
     for (; n-- > 0; child = child->GetNextSibling()) {
       ExamineFrameSubtree(child, contentArea, insideMarkersArea,
                           aFramesToHide, aAlignmentEdges);
@@ -466,27 +477,36 @@ TextOverflow::ExamineLineFrames(nsLineBo
       guessLeft = mLeft.IsNeeded();
       guessRight = mRight.IsNeeded();
       mLeft.Reset();
       mRight.Reset();
       aFramesToHide->Clear();
     }
     NS_ASSERTION(pass == 0, "2nd pass should never guess wrong");
   } while (++pass != 2);
+  if (!leftOverflow) {
+    mLeft.Reset();
+  }
+  if (!rightOverflow) {
+    mRight.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,
                "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;
+  
   FrameHashtable framesToHide;
   if (!framesToHide.Init(100)) {
     return;
   }
   AlignmentEdges alignmentEdges;
   ExamineLineFrames(aLine, &framesToHide, &alignmentEdges);
   bool needLeft = mLeft.IsNeeded();
   bool needRight = mRight.IsNeeded();
@@ -505,20 +525,20 @@ TextOverflow::ProcessLine(const nsDispla
     if (mBlockIsRTL) {
       needRight = false;
     } else {
       needLeft = false;
     }
   }
   nsRect insideMarkersArea = mContentArea;
   if (needLeft) {
-    InflateLeft(&insideMarkersArea, false, -mLeft.mWidth);
+    InflateLeft(&insideMarkersArea, -mLeft.mWidth);
   }
   if (needRight) {
-    InflateRight(&insideMarkersArea, false, -mRight.mWidth);
+    InflateRight(&insideMarkersArea, -mRight.mWidth);
   }
   if (!mCanHaveHorizontalScrollbar && alignmentEdges.mAssigned) {
     nsRect alignmentRect = nsRect(alignmentEdges.x, insideMarkersArea.y,
                                   alignmentEdges.Width(), 1);
     insideMarkersArea.IntersectRect(insideMarkersArea, alignmentRect);
   }
 
   // Clip and remove display items as needed at the final marker edges.
--- a/layout/generic/TextOverflow.h
+++ b/layout/generic/TextOverflow.h
@@ -204,16 +204,18 @@ class TextOverflow {
     // The marker text.
     nsString                       mMarkerString;
     // 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.
+    bool                           mActive;
   };
 
   Marker mLeft;  // the horizontal left marker
   Marker mRight; // the horizontal right marker
 };
 
 } // namespace css
 } // namespace mozilla