Bug 1304556 part 2 - Use AutoLineCursorSetup to optimize pre-render innerText query. r=dbaron
authorXidorn Quan <me@upsuper.org>
Fri, 21 Oct 2016 11:53:12 +1100
changeset 318829 df0022e05784068c0d9925bd69049af18f54522c
parent 318828 7e8d0d68f550e00f8c9ad628923a9e6b5fa6e011
child 318830 544da89e82defe4fdff2353974715d6da2e10e19
push id33401
push userxquan@mozilla.com
push dateFri, 21 Oct 2016 07:49:57 +0000
treeherderautoland@df0022e05784 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1304556
milestone52.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 1304556 part 2 - Use AutoLineCursorSetup to optimize pre-render innerText query. r=dbaron MozReview-Commit-ID: G0I4MPSeV38
layout/generic/nsTextFrame.cpp
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -9629,27 +9629,20 @@ static void TransformChars(nsTextFrame* 
     } else {
       // Should not happen (see assertion above), but as a fallback...
       aOut.Append(fragString);
     }
   }
 }
 
 static bool
-LineEndsInHardLineBreak(nsTextFrame* aFrame)
-{
-  nsIFrame* lineContainer = FindLineContainer(aFrame);
-  nsBlockFrame* block = do_QueryFrame(lineContainer);
-  if (!block) {
-    // Weird situation where we have a line layout without a block.
-    // No soft breaks occur in this situation.
-    return true;
-  }
+LineEndsInHardLineBreak(nsTextFrame* aFrame, nsBlockFrame* aLineContainer)
+{
   bool foundValidLine;
-  nsBlockInFlowLineIterator iter(block, aFrame, &foundValidLine);
+  nsBlockInFlowLineIterator iter(aLineContainer, aFrame, &foundValidLine);
   if (!foundValidLine) {
     NS_ERROR("Invalid line!");
     return true;
   }
   return !iter.GetLine()->IsLineWrapped();
 }
 
 nsIFrame::RenderedText
@@ -9657,40 +9650,62 @@ nsTextFrame::GetRenderedText(uint32_t aS
                              uint32_t aEndOffset,
                              TextOffsetType aOffsetType,
                              TrailingWhitespace aTrimTrailingWhitespace)
 {
   NS_ASSERTION(!GetPrevContinuation(), "Must be called on first-in-flow");
 
   // The handling of offsets could be more efficient...
   RenderedText result;
+  nsBlockFrame* lineContainer = nullptr;
   nsTextFrame* textFrame;
   const nsTextFragment* textFrag = mContent->GetText();
   uint32_t offsetInRenderedString = 0;
   bool haveOffsets = false;
 
+  Maybe<nsBlockFrame::AutoLineCursorSetup> autoLineCursor;
   for (textFrame = this; textFrame;
        textFrame = static_cast<nsTextFrame*>(textFrame->GetNextContinuation())) {
     if (textFrame->GetStateBits() & NS_FRAME_IS_DIRTY) {
       // We don't trust dirty frames, especially when computing rendered text.
       break;
     }
 
     // Ensure the text run and grab the gfxSkipCharsIterator for it
     gfxSkipCharsIterator iter =
       textFrame->EnsureTextRun(nsTextFrame::eInflated);
     if (!textFrame->mTextRun) {
       break;
     }
     gfxSkipCharsIterator tmpIter = iter;
 
+    // Whether we need to trim whitespaces after the text frame.
+    bool trimAfter;
+    if (!textFrame->IsAtEndOfLine() ||
+        aTrimTrailingWhitespace !=
+          TrailingWhitespace::TRIM_TRAILING_WHITESPACE) {
+      trimAfter = false;
+    } else if (nsBlockFrame* thisLc =
+               do_QueryFrame(FindLineContainer(textFrame))) {
+      if (thisLc != lineContainer) {
+        // Setup line cursor when needed.
+        lineContainer = thisLc;
+        autoLineCursor.reset();
+        autoLineCursor.emplace(lineContainer);
+      }
+      trimAfter = LineEndsInHardLineBreak(textFrame, lineContainer);
+    } else {
+      // Weird situation where we have a line layout without a block.
+      // No soft breaks occur in this situation.
+      trimAfter = true;
+    }
+
     // Skip to the start of the text run, past ignored chars at start of line
-    TrimmedOffsets trimmedOffsets = textFrame->GetTrimmedOffsets(textFrag,
-       textFrame->IsAtEndOfLine() && LineEndsInHardLineBreak(textFrame) &&
-       aTrimTrailingWhitespace == TrailingWhitespace::TRIM_TRAILING_WHITESPACE);
+    TrimmedOffsets trimmedOffsets =
+        textFrame->GetTrimmedOffsets(textFrag, trimAfter);
     bool trimmedSignificantNewline =
         trimmedOffsets.GetEnd() < GetContentEnd() &&
         HasSignificantTerminalNewline();
     uint32_t skippedToRenderedStringOffset = offsetInRenderedString -
         tmpIter.ConvertOriginalToSkipped(trimmedOffsets.mStart);
     uint32_t nextOffsetInRenderedString =
         tmpIter.ConvertOriginalToSkipped(trimmedOffsets.GetEnd()) +
         (trimmedSignificantNewline ? 1 : 0) + skippedToRenderedStringOffset;