Bug 1329877: Optimize AncestorFilter usage in lazy frame construction. r=bz

MozReview-Commit-ID: ErzurfQldHf

--HG--
extra : rebase_source : 62ee2020c8fa14b9475a660ea995537d6521779f
This commit is contained in:
Emilio Cobos Álvarez 2017-02-27 23:35:06 +01:00
parent 19b7e4b44b
commit 78a1fe605c
3 changed files with 118 additions and 41 deletions

View File

@ -808,21 +808,23 @@ public:
nsCOMArray<nsIContent> mGeneratedTextNodesWithInitializer;
TreeMatchContext mTreeMatchContext;
TreeMatchContext& mTreeMatchContext;
// Constructor
// Use the passed-in history state.
nsFrameConstructorState(
nsIPresShell* aPresShell,
TreeMatchContext& aTreeMatchContext,
nsContainerFrame* aFixedContainingBlock,
nsContainerFrame* aAbsoluteContainingBlock,
nsContainerFrame* aFloatContainingBlock,
already_AddRefed<nsILayoutHistoryState> aHistoryState);
// Get the history state from the pres context's pres shell.
nsFrameConstructorState(nsIPresShell* aPresShell,
nsContainerFrame* aFixedContainingBlock,
nsContainerFrame* aAbsoluteContainingBlock,
nsContainerFrame* aFloatContainingBlock);
nsFrameConstructorState(nsIPresShell* aPresShell,
TreeMatchContext& aTreeMatchContext,
nsContainerFrame* aFixedContainingBlock,
nsContainerFrame* aAbsoluteContainingBlock,
nsContainerFrame* aFloatContainingBlock);
~nsFrameConstructorState();
@ -975,6 +977,7 @@ protected:
nsFrameConstructorState::nsFrameConstructorState(
nsIPresShell* aPresShell,
TreeMatchContext& aTreeMatchContext,
nsContainerFrame* aFixedContainingBlock,
nsContainerFrame* aAbsoluteContainingBlock,
nsContainerFrame* aFloatContainingBlock,
@ -1001,8 +1004,7 @@ nsFrameConstructorState::nsFrameConstructorState(
mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
mHavePendingPopupgroup(false),
mCreatingExtraFrames(false),
mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited,
aPresShell->GetDocument()),
mTreeMatchContext(aTreeMatchContext),
mCurrentPendingBindingInsertionPoint(nullptr)
{
#ifdef MOZ_XUL
@ -1015,10 +1017,13 @@ nsFrameConstructorState::nsFrameConstructorState(
}
nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
TreeMatchContext& aTreeMatchContext,
nsContainerFrame* aFixedContainingBlock,
nsContainerFrame* aAbsoluteContainingBlock,
nsContainerFrame* aFloatContainingBlock)
: nsFrameConstructorState(aPresShell, aFixedContainingBlock,
: nsFrameConstructorState(aPresShell,
aTreeMatchContext,
aFixedContainingBlock,
aAbsoluteContainingBlock,
aFloatContainingBlock,
aPresShell->GetDocument()->GetLayoutHistoryState())
@ -2420,13 +2425,15 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
// Initialize the ancestor filter with null for now; we'll push
// aDocElement once we finish resolving style for it.
matchContext.InitAncestors(nullptr);
nsFrameConstructorState state(mPresShell,
matchContext,
GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
nullptr,
nullptr, do_AddRef(aFrameState));
// Initialize the ancestor filter with null for now; we'll push
// aDocElement once we finish resolving style for it.
state.mTreeMatchContext.InitAncestors(nullptr);
// XXXbz why, exactly?
if (!mTempFrameTreeState)
@ -2867,7 +2874,8 @@ nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement)
RefPtr<nsStyleContext> rootPseudoStyle;
// we must create a state because if the scrollbars are GFX it needs the
// state to build the scrollbar frames.
nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr, nullptr);
// Start off with the viewport as parent; we'll adjust it as needed.
nsContainerFrame* parentFrame = viewportFrame;
@ -7137,12 +7145,17 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
}
void
nsCSSFrameConstructor::CreateNeededFrames(nsIContent* aContent)
nsCSSFrameConstructor::CreateNeededFrames(
nsIContent* aContent,
TreeMatchContext& aTreeMatchContext)
{
NS_ASSERTION(!aContent->HasFlag(NODE_NEEDS_FRAME),
"shouldn't get here with a content node that has needs frame bit set");
NS_ASSERTION(aContent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES),
"should only get here with a content node that has descendants needing frames");
MOZ_ASSERT(aTreeMatchContext.mAncestorFilter.HasFilter(),
"The whole point of having the tree match context is optimizing "
"the ancestor filter usage!");
aContent->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES);
@ -7178,19 +7191,32 @@ nsCSSFrameConstructor::CreateNeededFrames(nsIContent* aContent)
inRun = false;
// generate a ContentRangeInserted for [startOfRun,i)
ContentRangeInserted(aContent, firstChildInRun, child, nullptr,
false);
false, &aTreeMatchContext);
}
}
}
if (inRun) {
ContentAppended(aContent, firstChildInRun, false);
ContentAppended(aContent, firstChildInRun, false, &aTreeMatchContext);
}
// Now descend.
FlattenedChildIterator iter(aContent);
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
if (child->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
CreateNeededFrames(child);
TreeMatchContext::AutoAncestorPusher insertionPointPusher(
aTreeMatchContext);
// Handle stuff like xbl:children.
if (child->GetParent() != aContent && child->GetParent()->IsElement()) {
insertionPointPusher.PushAncestorAndStyleScope(
child->GetParent()->AsElement());
}
TreeMatchContext::AutoAncestorPusher pusher(aTreeMatchContext);
pusher.PushAncestorAndStyleScope(child);
CreateNeededFrames(child, aTreeMatchContext);
}
}
}
@ -7205,7 +7231,9 @@ void nsCSSFrameConstructor::CreateNeededFrames()
"root element should not have frame created lazily");
if (rootElement && rootElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
BeginUpdate();
CreateNeededFrames(rootElement);
TreeMatchContext treeMatchContext(mDocument, TreeMatchContext::ForFrameConstruction);
treeMatchContext.InitAncestors(rootElement);
CreateNeededFrames(rootElement, treeMatchContext);
EndUpdate();
}
}
@ -7321,10 +7349,13 @@ nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
}
nsresult
nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
nsIContent* aFirstNewContent,
bool aAllowLazyConstruction)
nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
nsIContent* aFirstNewContent,
bool aAllowLazyConstruction,
TreeMatchContext* aProvidedTreeMatchContext)
{
MOZ_ASSERT_IF(aProvidedTreeMatchContext, !aAllowLazyConstruction);
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
NS_PRECONDITION(mUpdateCount != 0,
"Should be in an update while creating frames");
@ -7484,11 +7515,20 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
aFirstNewContent, &parentAfterFrame);
// Create some new frames
//
// We use the provided tree match context, or create a new one on the fly
// otherwise.
Maybe<TreeMatchContext> matchContext;
if (!aProvidedTreeMatchContext) {
matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
matchContext->InitAncestors(aContainer->AsElement());
}
nsFrameConstructorState state(mPresShell,
aProvidedTreeMatchContext
? *aProvidedTreeMatchContext : *matchContext,
GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
GetAbsoluteContainingBlock(parentFrame, ABS_POS),
GetFloatContainingBlock(parentFrame));
state.mTreeMatchContext.InitAncestors(aContainer->AsElement());
// See if the containing block has :first-letter style applied.
bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
@ -7705,11 +7745,12 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
// (because when we treat the caption frames the other nodes have had their
// frames constructed but not yet inserted into the frame tree).
nsresult
nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
nsIContent* aStartChild,
nsIContent* aEndChild,
nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
nsIContent* aStartChild,
nsIContent* aEndChild,
nsILayoutHistoryState* aFrameState,
bool aAllowLazyConstruction)
bool aAllowLazyConstruction,
TreeMatchContext* aProvidedTreeMatchContext)
{
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
NS_PRECONDITION(mUpdateCount != 0,
@ -7978,14 +8019,18 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
return rv;
}
Maybe<TreeMatchContext> matchContext;
if (!aProvidedTreeMatchContext) {
matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
matchContext->InitAncestors(aContainer ? aContainer->AsElement() : nullptr);
}
nsFrameConstructorState state(mPresShell,
aProvidedTreeMatchContext
? *aProvidedTreeMatchContext : *matchContext,
GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
GetFloatContainingBlock(insertion.mParentFrame),
do_AddRef(aFrameState));
state.mTreeMatchContext.InitAncestors(aContainer ?
aContainer->AsElement() :
nullptr);
// Recover state for the containing block - we need to know if
// it has :first-letter or :first-line style applied to it. The
@ -8917,7 +8962,10 @@ nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell,
// Replicate the header/footer frame.
nsTableRowGroupFrame* headerFooterFrame;
nsFrameItems childItems;
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
nsFrameConstructorState state(mPresShell,
matchContext,
GetAbsoluteContainingBlock(newFrame, FIXED_POS),
GetAbsoluteContainingBlock(newFrame, ABS_POS),
nullptr);
@ -9191,7 +9239,10 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
// This should not normally be possible (because fixed-pos elements should
// be absolute containers) but fixed-pos tables currently aren't abs-pos
// containers.
nsFrameConstructorState state(mPresShell, aParentFrame,
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
nsFrameConstructorState state(mPresShell,
matchContext,
aParentFrame,
nullptr,
mRootElementFrame);
state.mCreatingExtraFrames = true;
@ -11491,7 +11542,10 @@ nsCSSFrameConstructor::CreateLetterFrame(nsContainerFrame* aBlockFrame,
NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
"Containing block is confused");
TreeMatchContext matchContext(mDocument,
TreeMatchContext::ForFrameConstruction);
nsFrameConstructorState state(mPresShell,
matchContext,
GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
aBlockContinuation);
@ -11877,7 +11931,10 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
// Construct a new frame
if (nullptr != aParentFrame) {
nsFrameItems frameItems;
nsFrameConstructorState state(mPresShell, GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
nsFrameConstructorState state(mPresShell,
matchContext,
GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
GetAbsoluteContainingBlock(aParentFrame, ABS_POS),
GetFloatContainingBlock(aParentFrame),
do_AddRef(mTempFrameTreeState.get()));
@ -12769,7 +12826,8 @@ nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
BeginUpdate();
nsFrameItems childItems;
nsFrameConstructorState state(mPresShell, nullptr, nullptr, nullptr);
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr, nullptr);
// We don't have a parent frame with a pending binding constructor here,
// so no need to worry about ordering of the kids' constructors with it.
// Pass null for the PendingBinding.

View File

@ -87,7 +87,8 @@ public:
void CreateNeededFrames();
private:
void CreateNeededFrames(nsIContent* aContent);
void CreateNeededFrames(nsIContent* aContent,
TreeMatchContext& aTreeMatchContext);
enum Operation {
CONTENTAPPEND,
@ -202,28 +203,40 @@ public:
// If aAllowLazyConstruction is true then frame construction of the new
// children can be done lazily.
//
// When constructing frames lazily, we can keep the tree match context in a
// much easier way than nsFrameConstructorState, and thus, we're allowed to
// provide a TreeMatchContext to avoid calling InitAncestors repeatedly deep
// in the DOM.
nsresult ContentAppended(nsIContent* aContainer,
nsIContent* aFirstNewContent,
bool aAllowLazyConstruction);
bool aAllowLazyConstruction,
TreeMatchContext* aProvidedTreeMatchContext = nullptr);
// If aAllowLazyConstruction is true then frame construction of the new child
// can be done lazily.
nsresult ContentInserted(nsIContent* aContainer,
nsIContent* aChild,
nsresult ContentInserted(nsIContent* aContainer,
nsIContent* aChild,
nsILayoutHistoryState* aFrameState,
bool aAllowLazyConstruction);
bool aAllowLazyConstruction);
// Like ContentInserted but handles inserting the children of aContainer in
// the range [aStartChild, aEndChild). aStartChild must be non-null.
// aEndChild may be null to indicate the range includes all kids after
// aStartChild. If aAllowLazyConstruction is true then frame construction of
// aStartChild.
//
// If aAllowLazyConstruction is true then frame construction of
// the new children can be done lazily. It is only allowed to be true when
// inserting a single node.
nsresult ContentRangeInserted(nsIContent* aContainer,
nsIContent* aStartChild,
nsIContent* aEndChild,
//
// See ContentAppended to see why we allow passing an already initialized
// TreeMatchContext.
nsresult ContentRangeInserted(nsIContent* aContainer,
nsIContent* aStartChild,
nsIContent* aEndChild,
nsILayoutHistoryState* aFrameState,
bool aAllowLazyConstruction);
bool aAllowLazyConstruction,
TreeMatchContext* aProvidedTreeMatchContext = nullptr);
enum RemoveFlags {
REMOVE_CONTENT, REMOVE_FOR_RECONSTRUCTION, REMOVE_DESTROY_FRAMES };

View File

@ -411,6 +411,12 @@ struct MOZ_STACK_CLASS TreeMatchContext {
}
}
}
enum ForFrameConstructionTag { ForFrameConstruction };
TreeMatchContext(nsIDocument* aDocument, ForFrameConstructionTag)
: TreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited, aDocument)
{}
};
struct MOZ_STACK_CLASS RuleProcessorData {