--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -803,31 +803,33 @@ public:
// yet. The mCreatingExtraFrames == true mode is meant to be used for
// construction of random "extra" frames for elements via normal frame
// construction APIs (e.g. replication of things across pages in paginated
// mode).
bool mCreatingExtraFrames;
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();
// Function to push the existing absolute containing block state and
// create a new scope. Code that uses this function should get matching
// logic in GetAbsoluteContainingBlock.
// Also makes aNewAbsoluteContainingBlock the containing block for
// fixed-pos elements if necessary.
@@ -970,16 +972,17 @@ protected:
// AddToAttachedQueue on all of them, in order.
LinkedList<PendingBinding> mPendingBindings;
PendingBinding* mCurrentPendingBindingInsertionPoint;
};
nsFrameConstructorState::nsFrameConstructorState(
nsIPresShell* aPresShell,
+ TreeMatchContext& aTreeMatchContext,
nsContainerFrame* aFixedContainingBlock,
nsContainerFrame* aAbsoluteContainingBlock,
nsContainerFrame* aFloatContainingBlock,
already_AddRefed<nsILayoutHistoryState> aHistoryState)
: mPresContext(aPresShell->GetPresContext()),
mPresShell(aPresShell),
mFrameManager(aPresShell->FrameManager()),
#ifdef MOZ_XUL
@@ -996,34 +999,36 @@ nsFrameConstructorState::nsFrameConstruc
mFrameState(aHistoryState),
mAdditionalStateBits(nsFrameState(0)),
// If the fixed-pos containing block is equal to the abs-pos containing
// block, use the abs-pos containing block's abs-pos list for fixed-pos
// frames.
mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
mHavePendingPopupgroup(false),
mCreatingExtraFrames(false),
- mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited,
- aPresShell->GetDocument()),
+ mTreeMatchContext(aTreeMatchContext),
mCurrentPendingBindingInsertionPoint(nullptr)
{
#ifdef MOZ_XUL
nsIRootBox* rootBox = nsIRootBox::GetRootBox(aPresShell);
if (rootBox) {
mPopupItems.containingBlock = rootBox->GetPopupSetFrame();
}
#endif
MOZ_COUNT_CTOR(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())
{
}
nsFrameConstructorState::~nsFrameConstructorState()
{
@@ -2413,23 +2418,25 @@ nsCSSFrameConstructor::ConstructDocEleme
if (nsPresContext* presContext = mPresShell->GetPresContext()) {
propagatedScrollFrom = presContext->UpdateViewportScrollbarStylesOverride();
}
SetUpDocElementContainingBlock(aDocElement);
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)
state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
// Make sure that we'll handle restyles for this document element in
// the future. We need this, because the document element might
// have stale restyle bits from a previous frame constructor for
@@ -2860,17 +2867,18 @@ nsCSSFrameConstructor::SetUpDocElementCo
// propagated
NS_ASSERTION(!isScrollable || !isXUL,
"XUL documents should never be scrollable - see above");
nsContainerFrame* newFrame = rootFrame;
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;
StyleSetHandle styleSet = mPresShell->StyleSet();
// If paginated, make sure we don't put scrollbars in
if (!isScrollable) {
rootPseudoStyle = styleSet->ResolveAnonymousBoxStyle(rootPseudo,
@@ -7129,22 +7137,27 @@ nsCSSFrameConstructor::MaybeConstructLaz
}
}
RestyleManager()->PostRestyleEventForLazyConstruction();
return true;
}
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);
// We could either descend first (on nodes that don't have NODE_NEEDS_FRAME
// set) or issue content notifications for our kids first. In absence of
// anything definitive either way we'll go with the latter.
// It might be better to use GetChildArray and scan it completely first and
@@ -7170,44 +7183,59 @@ nsCSSFrameConstructor::CreateNeededFrame
inRun = true;
firstChildInRun = child;
}
} else {
if (inRun) {
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);
}
}
}
void nsCSSFrameConstructor::CreateNeededFrames()
{
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
"Someone forgot a script blocker");
Element* rootElement = mDocument->GetRootElement();
NS_ASSERTION(!rootElement || !rootElement->HasFlag(NODE_NEEDS_FRAME),
"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();
}
}
void
nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aContainer,
nsIContent* aStartChild,
nsIContent* aEndChild,
@@ -7313,20 +7341,23 @@ nsCSSFrameConstructor::MaybeRecreateForF
return true;
}
}
}
return false;
}
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");
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::ContentAppended container=%p "
"first-child=%p lazy=%d\n",
@@ -7476,21 +7507,30 @@ nsCSSFrameConstructor::ContentAppended(n
// Deal with possible :after generated content on the parent
nsIFrame* parentAfterFrame;
parentFrame =
::AdjustAppendParentForAfterContent(this, insertion.mContainer, parentFrame,
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;
nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
if (containingBlock) {
haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
haveFirstLineStyle =
ShouldHaveFirstLineStyle(containingBlock->GetContent(),
@@ -7697,21 +7737,22 @@ nsCSSFrameConstructor::ContentInserted(n
// IsValidSibling (the only place GetInsertionPrevSibling might look at the
// passed in node itself) needs to resolve style on the node we record this and
// return that this range needs to be split up and inserted separately. Table
// captions need extra attention as we need to determine where to insert them
// in the caption list, while skipping any nodes in the range being inserted
// (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,
"Should be in an update while creating frames");
NS_PRECONDITION(aStartChild, "must always pass a child");
// XXXldb Do we need to re-resolve style to handle the CSS2 + combinator and
@@ -7970,24 +8011,28 @@ nsCSSFrameConstructor::ContentRangeInser
if (insertion.mParentFrame->IsFrameOfType(nsIFrame::eMathML)) {
LAYOUT_PHASE_TEMP_EXIT();
nsresult rv = RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
REMOVE_FOR_RECONSTRUCTION, nullptr);
LAYOUT_PHASE_TEMP_REENTER();
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
// reason we care is that the internal structure in these cases
// is not the normal structure and requires custom updating
// logic.
nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
bool haveFirstLetterStyle = false;
@@ -8909,17 +8954,20 @@ nsCSSFrameConstructor::CreateContinuingT
nsIFrame* rgNextInFlow = rowGroupFrame->GetNextInFlow();
if (rgNextInFlow) {
rowGroupFrame->SetRepeatable(false);
}
else if (rowGroupFrame->IsRepeatable()) {
// 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);
state.mCreatingExtraFrames = true;
nsStyleContext* const headerFooterStyleContext = rowGroupFrame->StyleContext();
headerFooterFrame = static_cast<nsTableRowGroupFrame*>
(NS_NewTableRowGroupFrame(aPresShell, headerFooterStyleContext));
@@ -9183,17 +9231,20 @@ nsCSSFrameConstructor::ReplicateFixedFra
if (!firstFixed) {
return NS_OK;
}
// Don't allow abs-pos descendants of the fixed content to escape the content.
// 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;
// We can't use an ancestor filter here, because we're not going to
// be usefully recurring down the tree. This means that other
// places in frame construction can't assume a filter is
// initialized!
@@ -11483,17 +11534,20 @@ nsCSSFrameConstructor::CreateLetterFrame
// frame.
// XXXbz it would be really nice to destroy the old frame _first_,
// then create the new one, so we could avoid this hack.
aTextContent->SetPrimaryFrame(nullptr);
nsIFrame* textFrame = NS_NewTextFrame(mPresShell, textSC);
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);
// Create the right type of first-letter frame
const nsStyleDisplay* display = sc->StyleDisplay();
if (display->IsFloatingStyle() && !aParentFrame->IsSVGText()) {
// Make a floating first-letter frame
@@ -11869,17 +11923,20 @@ nsCSSFrameConstructor::CreateListBoxCont
bool aIsAppend)
{
#ifdef MOZ_XUL
nsresult rv = NS_OK;
// 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()));
// If we ever initialize the ancestor filter on |state|, make sure
// to push the right parent!
RefPtr<nsStyleContext> styleContext;
@@ -12760,17 +12817,18 @@ nsCSSFrameConstructor::ReframeContaining
nsresult
nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
{
{
nsAutoScriptBlocker scriptBlocker;
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.
ProcessChildren(state, aFrame->GetContent(), aFrame->StyleContext(),
aFrame, false, childItems, false,
nullptr);
aFrame->SetInitialChildList(kPrincipalList, childItems);