Bug 1397059 - Make sure we generate unique display item keys for nsDisplayTextOverflowMarker. r=mats
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 13 Sep 2017 15:28:24 -0400
changeset 430309 14d1ec48399778608f58e7e3bd29dfdb810f12f4
parent 430308 04077d71603ea4dc9dd47e2ccc8d49d92deaa8dc
child 430310 cfdf38e0d9befe93c007b5afdba802e924ba4774
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs1397059
milestone57.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 1397059 - Make sure we generate unique display item keys for nsDisplayTextOverflowMarker. r=mats
layout/generic/TextOverflow.cpp
layout/generic/TextOverflow.h
layout/generic/nsBlockFrame.cpp
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -161,19 +161,20 @@ IsFrameDescendantOfAny(nsIFrame* aChild,
 }
 
 class nsDisplayTextOverflowMarker : public nsDisplayItem
 {
 public:
   nsDisplayTextOverflowMarker(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                               const nsRect& aRect, nscoord aAscent,
                               const nsStyleTextOverflowSide* aStyle,
+                              uint32_t aLineNumber,
                               uint32_t aIndex)
     : nsDisplayItem(aBuilder, aFrame), mRect(aRect),
-      mStyle(aStyle), mAscent(aAscent), mIndex(aIndex) {
+      mStyle(aStyle), mAscent(aAscent), mIndex((aLineNumber << 1) + aIndex) {
     MOZ_COUNT_CTOR(nsDisplayTextOverflowMarker);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTextOverflowMarker() {
     MOZ_COUNT_DTOR(nsDisplayTextOverflowMarker);
   }
 #endif
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
@@ -651,17 +652,18 @@ TextOverflow::ExamineLineFrames(nsLineBo
   if (!iendOverflow || !mIEnd.mActive) {
     mIEnd.Reset();
   }
   return nonSnappedContentArea;
 }
 
 void
 TextOverflow::ProcessLine(const nsDisplayListSet& aLists,
-                          nsLineBox*              aLine)
+                          nsLineBox*              aLine,
+                          uint32_t                aLineNumber)
 {
   NS_ASSERTION(mIStart.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
                mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP,
                "TextOverflow with 'clip' for both sides");
   mIStart.Reset();
   mIStart.mActive = mIStart.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP;
   mIEnd.Reset();
   mIEnd.mActive = mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP;
@@ -700,17 +702,17 @@ TextOverflow::ProcessLine(const nsDispla
     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, needIStart, needIEnd, insideMarkersArea, contentArea);
+  CreateMarkers(aLine, needIStart, needIEnd, insideMarkersArea, contentArea, aLineNumber);
 }
 
 void
 TextOverflow::PruneDisplayListContents(nsDisplayList* aList,
                                        const FrameHashtable& aFramesToHide,
                                        const LogicalRect& aInsideMarkersArea)
 {
   nsDisplayList saved;
@@ -795,49 +797,50 @@ TextOverflow::CanHaveTextOverflow(nsIFra
   }
   return true;
 }
 
 void
 TextOverflow::CreateMarkers(const nsLineBox* aLine,
                             bool aCreateIStart, bool aCreateIEnd,
                             const LogicalRect& aInsideMarkersArea,
-                            const LogicalRect& aContentArea)
+                            const LogicalRect& aContentArea,
+                            uint32_t aLineNumber)
 {
   if (aCreateIStart) {
     DisplayListClipState::AutoSaveRestore clipState(mBuilder);
 
     LogicalRect markerLogicalRect(
       mBlockWM, aInsideMarkersArea.IStart(mBlockWM) - mIStart.mIntrinsicISize,
       aLine->BStart(), mIStart.mIntrinsicISize, aLine->BSize());
     nsPoint offset = mBuilder->ToReferenceFrame(mBlock);
     nsRect markerRect =
       markerLogicalRect.GetPhysicalRect(mBlockWM, mBlockSize) + offset;
     ClipMarker(aContentArea.GetPhysicalRect(mBlockWM, mBlockSize) + offset,
                markerRect, clipState);
     nsDisplayItem* marker = new (mBuilder)
       nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
-                                  aLine->GetLogicalAscent(), mIStart.mStyle, 0);
+                                  aLine->GetLogicalAscent(), mIStart.mStyle, aLineNumber, 0);
     mMarkerList.AppendNewToTop(marker);
   }
 
   if (aCreateIEnd) {
     DisplayListClipState::AutoSaveRestore clipState(mBuilder);
 
     LogicalRect markerLogicalRect(
       mBlockWM, aInsideMarkersArea.IEnd(mBlockWM), aLine->BStart(),
       mIEnd.mIntrinsicISize, aLine->BSize());
     nsPoint offset = mBuilder->ToReferenceFrame(mBlock);
     nsRect markerRect =
       markerLogicalRect.GetPhysicalRect(mBlockWM, mBlockSize) + offset;
     ClipMarker(aContentArea.GetPhysicalRect(mBlockWM, mBlockSize) + offset,
                markerRect, clipState);
     nsDisplayItem* marker = new (mBuilder)
       nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
-                                  aLine->GetLogicalAscent(), mIEnd.mStyle, 1);
+                                  aLine->GetLogicalAscent(), mIEnd.mStyle, aLineNumber, 1);
     mMarkerList.AppendNewToTop(marker);
   }
 }
 
 void
 TextOverflow::Marker::SetupString(nsIFrame* aFrame)
 {
   if (mInitialized) {
--- a/layout/generic/TextOverflow.h
+++ b/layout/generic/TextOverflow.h
@@ -45,17 +45,17 @@ class MOZ_HEAP_CLASS TextOverflow final 
   TextOverflow(nsDisplayListBuilder* aBuilder,
                nsIFrame* aBlockFrame);
 
   /**
    * Analyze the display lists for text overflow and what kind of item is at
    * the content edges.  Add display items for text-overflow markers as needed
    * and remove or clip items that would overlap a marker.
    */
-  void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine);
+  void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine, uint32_t aLineNumber);
 
   /**
    * Get the resulting text-overflow markers (the list may be empty).
    * @return a DisplayList containing any text-overflow markers.
    */
   nsDisplayList& GetMarkers() { return mMarkerList; }
 
   /**
@@ -210,17 +210,18 @@ class MOZ_HEAP_CLASS TextOverflow final 
    * @param aCreateIEnd if true, create a marker on the inline end side
    * @param aInsideMarkersArea is the area inside the markers
    * @param aContentArea is the area inside which we should add the markers;
    *   this is the block's content area narrowed by any floats on this line.
    */
   void CreateMarkers(const nsLineBox* aLine,
                      bool aCreateIStart, bool aCreateIEnd,
                      const LogicalRect& aInsideMarkersArea,
-                     const LogicalRect& aContentArea);
+                     const LogicalRect& aContentArea,
+                     uint32_t aLineNumber);
 
   LogicalRect            mContentArea;
   nsDisplayListBuilder*  mBuilder;
   nsIFrame*              mBlock;
   nsIScrollableFrame*    mScrollableFrame;
   nsDisplayList          mMarkerList;
   nsSize                 mBlockSize;
   WritingMode            mBlockWM;
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -6659,17 +6659,18 @@ static void DebugOutputDrawLine(int32_t 
   }
 }
 #endif
 
 static void
 DisplayLine(nsDisplayListBuilder* aBuilder, const nsRect& aLineArea,
             nsBlockFrame::LineIterator& aLine,
             int32_t aDepth, int32_t& aDrawnLines, const nsDisplayListSet& aLists,
-            nsBlockFrame* aFrame, TextOverflow* aTextOverflow) {
+            nsBlockFrame* aFrame, TextOverflow* aTextOverflow,
+            uint32_t aLineNumberForTextOverflow) {
   // If the line's combined area (which includes child frames that
   // stick outside of the line's bounding box or our bounding box)
   // intersects the dirty rect then paint the line.
   bool intersect = aLineArea.Intersects(aBuilder->GetDirtyRect());
 #ifdef DEBUG
   if (nsBlockFrame::gLamePaintMetrics) {
     aDrawnLines++;
   }
@@ -6703,17 +6704,17 @@ DisplayLine(nsDisplayListBuilder* aBuild
   nsIFrame* kid = aLine->mFirstChild;
   int32_t n = aLine->GetChildCount();
   while (--n >= 0) {
     aFrame->BuildDisplayListForChild(aBuilder, kid, childLists, flags);
     kid = kid->GetNextSibling();
   }
 
   if (lineMayHaveTextOverflow) {
-    aTextOverflow->ProcessLine(collection, aLine.get());
+    aTextOverflow->ProcessLine(collection, aLine.get(), aLineNumberForTextOverflow);
   }
 
   collection.MoveTo(aLists);
 }
 
 void
 nsBlockFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                const nsDisplayListSet& aLists)
@@ -6761,46 +6762,50 @@ nsBlockFrame::BuildDisplayList(nsDisplay
 
   // Don't use the line cursor if we might have a descendant placeholder ...
   // it might skip lines that contain placeholders but don't themselves
   // intersect with the dirty area.
   // In particular, we really want to check ShouldDescendIntoFrame()
   // on all our child frames, but that might be expensive.  So we
   // approximate it by checking it on |this|; if it's true for any
   // frame in our child list, it's also true for |this|.
-  nsLineBox* cursor = aBuilder->ShouldDescendIntoFrame(this) ?
+  // Also skip the cursor if we're creating text overflow markers,
+  // since we need to know what line number we're up to in order
+  // to generate unique display item keys.
+  nsLineBox* cursor = (aBuilder->ShouldDescendIntoFrame(this) || textOverflow) ?
     nullptr : GetFirstLineContaining(aBuilder->GetDirtyRect().y);
   LineIterator line_end = LinesEnd();
 
   if (cursor) {
     for (LineIterator line = mLines.begin(cursor);
          line != line_end;
          ++line) {
       nsRect lineArea = line->GetVisualOverflowArea();
       if (!lineArea.IsEmpty()) {
         // Because we have a cursor, the combinedArea.ys are non-decreasing.
         // Once we've passed aDirtyRect.YMost(), we can never see it again.
         if (lineArea.y >= aBuilder->GetDirtyRect().YMost()) {
           break;
         }
+        MOZ_ASSERT(!textOverflow);
         DisplayLine(aBuilder, lineArea, line, depth, drawnLines,
-                    linesDisplayListCollection, this, textOverflow.get());
+                    linesDisplayListCollection, this, nullptr, 0);
       }
     }
   } else {
     bool nonDecreasingYs = true;
-    int32_t lineCount = 0;
+    uint32_t lineCount = 0;
     nscoord lastY = INT32_MIN;
     nscoord lastYMost = INT32_MIN;
     for (LineIterator line = LinesBegin();
          line != line_end;
          ++line) {
       nsRect lineArea = line->GetVisualOverflowArea();
       DisplayLine(aBuilder, lineArea, line, depth, drawnLines,
-                  linesDisplayListCollection, this, textOverflow.get());
+                  linesDisplayListCollection, this, textOverflow.get(), lineCount);
       if (!lineArea.IsEmpty()) {
         if (lineArea.y < lastY
             || lineArea.YMost() < lastYMost) {
           nonDecreasingYs = false;
         }
         lastY = lineArea.y;
         lastYMost = lineArea.YMost();
       }