Bug 1304556 part 2 - Use AutoLineCursorSetup to optimize pre-render innerText query. r=dbaron
MozReview-Commit-ID: G0I4MPSeV38
--- 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;