This commit is contained in:
Cameron Kaiser 2017-10-02 20:35:38 -07:00
parent da843afa12
commit 539efce0cc
3 changed files with 59 additions and 12 deletions

View File

@ -397,6 +397,7 @@ nsFrame::nsFrame(nsStyleContext* aContext)
mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
mMayHaveRoundedCorners = false;
mReflowRequestedForCharDataChange = false;
mStyleContext = aContext;
mStyleContext->AddRef();
#ifdef DEBUG

View File

@ -3154,6 +3154,23 @@ protected:
bool mMayHaveRoundedCorners : 1;
/**
* This bit is used in nsTextFrame::CharacterDataChanged() as an optimization
* to skip redundant reflow-requests when the character data changes multiple
* times between reflows. If this flag is set, then it implies that the
* NS_FRAME_IS_DIRTY state bit is also set (and that intrinsic sizes have
* been marked as dirty on our ancestor chain).
*
* XXXdholbert This bit is *only* used on nsTextFrame, but it lives here on
* nsIFrame simply because this is where we've got unused state bits
* available in a gap. If bits become more scarce, we should perhaps consider
* expanding the range of frame-specific state bits in nsFrameStateBits.h and
* moving this to be one of those (e.g. by swapping one of the adjacent
* general-purpose bits to take the place of this bool:1 here, so we can grow
* that range of frame-specific bits by 1).
*/
bool mReflowRequestedForCharDataChange : 1;
// Helpers
/**
* Can we stop inside this frame when we're skipping non-rendered whitespace?

View File

@ -4589,7 +4589,12 @@ nsTextFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
}
int32_t endOfChangedText = aInfo->mChangeStart + aInfo->mReplaceLength;
nsTextFrame* lastDirtiedFrame = nullptr;
// Parent of the last frame that we passed to FrameNeedsReflow (or noticed
// had already received an earlier FrameNeedsReflow call).
// (For subsequent frames with this same parent, we can just set their
// dirty bit without bothering to call FrameNeedsReflow again.)
nsIFrame* lastDirtiedFrameParent = nullptr;
nsIPresShell* shell = PresContext()->GetPresShell();
do {
@ -4597,17 +4602,39 @@ nsTextFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
// if this was a pure insertion).
textFrame->mState &= ~TEXT_WHITESPACE_FLAGS;
textFrame->ClearTextRuns();
if (!lastDirtiedFrame ||
lastDirtiedFrame->GetParent() != textFrame->GetParent()) {
// Ask the parent frame to reflow me.
shell->FrameNeedsReflow(textFrame, nsIPresShell::eStyleChange,
NS_FRAME_IS_DIRTY);
lastDirtiedFrame = textFrame;
nsIFrame* parentOfTextFrame = textFrame->GetParent();
bool areAncestorsAwareOfReflowRequest = false;
if (lastDirtiedFrameParent == parentOfTextFrame) {
// An earlier iteration of this loop already called
// FrameNeedsReflow for a sibling of |textFrame|.
areAncestorsAwareOfReflowRequest = true;
} else {
// if the parent is a block, we're cheating here because we should
// be marking our line dirty, but we're not. nsTextFrame::SetLength
// will do that when it gets called during reflow.
textFrame->AddStateBits(NS_FRAME_IS_DIRTY);
lastDirtiedFrameParent = parentOfTextFrame;
}
if (textFrame->mReflowRequestedForCharDataChange) {
// We already requested a reflow for this frame; nothing to do.
MOZ_ASSERT(textFrame->HasAnyStateBits(NS_FRAME_IS_DIRTY),
"mReflowRequestedForCharDataChange should only be set "
"on dirty frames");
} else {
// Make sure textFrame is queued up for a reflow. Also set a flag so we
// don't waste time doing this again in repeated calls to this method.
textFrame->mReflowRequestedForCharDataChange = true;
if (!areAncestorsAwareOfReflowRequest) {
// Ask the parent frame to reflow me.
shell->FrameNeedsReflow(textFrame, nsIPresShell::eStyleChange,
NS_FRAME_IS_DIRTY);
} else {
// We already called FrameNeedsReflow on behalf of an earlier sibling,
// so we can just mark this frame as dirty and don't need to bother
// telling its ancestors.
// Note: if the parent is a block, we're cheating here because we should
// be marking our line dirty, but we're not. nsTextFrame::SetLength will
// do that when it gets called during reflow.
textFrame->AddStateBits(NS_FRAME_IS_DIRTY);
}
}
textFrame->InvalidateFrame();
@ -8514,8 +8541,10 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
// Clear out the reflow state flags in mState. We also clear the whitespace
// flags because this can change whether the frame maps whitespace-only text
// or not.
// or not. We also clear the flag that tracks whether we had a pending
// reflow request from CharacterDataChanged (since we're reflowing now).
RemoveStateBits(TEXT_REFLOW_FLAGS | TEXT_WHITESPACE_FLAGS);
mReflowRequestedForCharDataChange = false;
// Temporarily map all possible content while we construct our new textrun.
// so that when doing reflow our styles prevail over any part of the