mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 17:23:59 +00:00
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:
parent
19b7e4b44b
commit
78a1fe605c
@ -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.
|
||||
|
@ -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 };
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user