Bug 508725 - Part 5: Record the <style scoped> elements in scope in preparation for selector matching. r=dbaron

This commit is contained in:
Cameron McCormack 2013-01-08 19:09:23 +11:00
parent ad3f65836e
commit e4e4c560a0
4 changed files with 86 additions and 57 deletions

View File

@ -2294,7 +2294,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
nullptr, aFrameState);
// Initialize the ancestor filter with null for now; we'll push
// aDocElement once we finish resolving style for it.
state.mTreeMatchContext.mAncestorFilter.Init(nullptr);
state.mTreeMatchContext.InitAncestors(nullptr);
// XXXbz why, exactly?
if (!mTempFrameTreeState)
@ -2361,8 +2361,8 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
return NS_OK;
}
AncestorFilter::AutoAncestorPusher
ancestorPusher(true, state.mTreeMatchContext.mAncestorFilter, aDocElement);
TreeMatchContext::AutoAncestorPusher
ancestorPusher(true, state.mTreeMatchContext, aDocElement);
// Make sure to start any background image loads for the root element now.
styleContext->StartBackgroundImageLoads();
@ -3571,9 +3571,9 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
// frames constructed), this is the best place to bottleneck the
// pushing of the content instead of having to do it in multiple
// places.
AncestorFilter::AutoAncestorPusher
TreeMatchContext::AutoAncestorPusher
ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
aState.mTreeMatchContext.mAncestorFilter,
aState.mTreeMatchContext,
content->IsElement() ? content->AsElement() : nullptr);
nsIFrame* newFrame;
@ -3807,9 +3807,9 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
aPendingBinding);
AncestorFilter::AutoAncestorPusher
TreeMatchContext::AutoAncestorPusher
ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
aState.mTreeMatchContext.mAncestorFilter,
aState.mTreeMatchContext,
aParent->AsElement());
nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
@ -6608,7 +6608,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
GetAbsoluteContainingBlock(parentFrame),
GetFloatContainingBlock(parentFrame));
state.mTreeMatchContext.mAncestorFilter.Init(aContainer->AsElement());
state.mTreeMatchContext.InitAncestors(aContainer->AsElement());
// See if the containing block has :first-letter style applied.
bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
@ -7044,9 +7044,9 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
GetAbsoluteContainingBlock(parentFrame),
GetFloatContainingBlock(parentFrame),
aFrameState);
state.mTreeMatchContext.mAncestorFilter.Init(aContainer ?
aContainer->AsElement() :
nullptr);
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
@ -11281,9 +11281,9 @@ nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
nsStyleContext* const parentStyleContext = aParentItem.mStyleContext;
nsIContent* const parentContent = aParentItem.mContent;
AncestorFilter::AutoAncestorPusher
TreeMatchContext::AutoAncestorPusher
ancestorPusher(aState.mTreeMatchContext.mAncestorFilter.HasFilter(),
aState.mTreeMatchContext.mAncestorFilter,
aState.mTreeMatchContext,
parentContent->AsElement());
CreateGeneratedContentItem(aState, nullptr, parentContent, parentStyleContext,

View File

@ -1379,8 +1379,8 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
if (checkUndisplayed && mUndisplayedMap) {
UndisplayedNode* undisplayed =
mUndisplayedMap->GetFirstNode(undisplayedParent);
for (AncestorFilter::AutoAncestorPusher
pushAncestor(undisplayed, aTreeMatchContext.mAncestorFilter,
for (TreeMatchContext::AutoAncestorPusher
pushAncestor(undisplayed, aTreeMatchContext,
undisplayedParent ? undisplayedParent->AsElement()
: nullptr);
undisplayed; undisplayed = undisplayed->mNext) {
@ -1536,9 +1536,9 @@ nsFrameManager::ReResolveStyleContext(nsPresContext *aPresContext,
// now do children
nsIFrame::ChildListIterator lists(aFrame);
for (AncestorFilter::AutoAncestorPusher
for (TreeMatchContext::AutoAncestorPusher
pushAncestor(!lists.IsDone(),
aTreeMatchContext.mAncestorFilter,
aTreeMatchContext,
content && content->IsElement() ? content->AsElement()
: nullptr);
!lists.IsDone(); lists.Next()) {
@ -1680,7 +1680,7 @@ nsFrameManager::ComputeStyleChangeFor(nsIFrame *aFrame,
nsIContent *parent = content ? content->GetParent() : nullptr;
Element *parentElement =
parent && parent->IsElement() ? parent->AsElement() : nullptr;
treeMatchContext.mAncestorFilter.Init(parentElement);
treeMatchContext.InitAncestors(parentElement);
nsTArray<nsIContent*> visibleKidsOfHiddenElement;
do {
// Outer loop over special siblings

View File

@ -3261,14 +3261,14 @@ nsCSSRuleProcessor::SelectorListMatches(Element* aElement,
return false;
}
// AncestorFilter out of line methods
// TreeMatchContext and AncestorFilter out of line methods
void
AncestorFilter::Init(Element *aElement)
TreeMatchContext::InitAncestors(Element *aElement)
{
MOZ_ASSERT(!mFilter);
MOZ_ASSERT(mHashes.IsEmpty());
MOZ_ASSERT(!mAncestorFilter.mFilter);
MOZ_ASSERT(mAncestorFilter.mHashes.IsEmpty());
mFilter = new Filter();
mAncestorFilter.mFilter = new AncestorFilter::Filter();
if (MOZ_LIKELY(aElement)) {
MOZ_ASSERT(aElement->IsInDoc(),
@ -3289,7 +3289,8 @@ AncestorFilter::Init(Element *aElement)
// Now push them in reverse order.
for (uint32_t i = ancestors.Length(); i-- != 0; ) {
PushAncestor(ancestors[i]);
mAncestorFilter.PushAncestor(ancestors[i]);
PushStyleScope(ancestors[i]);
}
}
}

View File

@ -26,6 +26,7 @@ class nsIStyleSheet;
class nsIAtom;
class nsICSSPseudoComparator;
class nsAttrValue;
struct TreeMatchContext;
/**
* An AncestorFilter is used to keep track of ancestors so that we can
@ -33,44 +34,12 @@ class nsAttrValue;
* element.
*/
class NS_STACK_CLASS AncestorFilter {
friend struct TreeMatchContext;
public:
/**
* Initialize the filter. If aElement is not null, it and all its
* ancestors will be passed to PushAncestor, starting from the root
* and going down the tree.
*/
void Init(mozilla::dom::Element *aElement);
/* Maintenance of our ancestor state */
void PushAncestor(mozilla::dom::Element *aElement);
void PopAncestor();
/* Helper class for maintaining the ancestor state */
class NS_STACK_CLASS AutoAncestorPusher {
public:
AutoAncestorPusher(bool aDoPush,
AncestorFilter &aFilter,
mozilla::dom::Element *aElement
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mPushed(aDoPush && aElement), mFilter(aFilter)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mPushed) {
mFilter.PushAncestor(aElement);
}
}
~AutoAncestorPusher() {
if (mPushed) {
mFilter.PopAncestor();
}
}
private:
bool mPushed;
AncestorFilter &mFilter;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/* Check whether we might have an ancestor matching one of the given
atom hashes. |hashes| must have length hashListLength */
template<size_t hashListLength>
@ -164,11 +133,66 @@ struct NS_STACK_CLASS TreeMatchContext {
return mHaveSpecifiedScope;
}
/**
* Initialize the ancestor filter and list of style scopes. If aElement is
* not null, it and all its ancestors will be passed to
* mAncestorFilter.PushAncestor and PushStyleScope, starting from the root and
* going down the tree.
*/
void InitAncestors(mozilla::dom::Element *aElement);
void PushStyleScope(mozilla::dom::Element* aElement)
{
NS_PRECONDITION(aElement, "aElement must not be null");
if (aElement->IsScopedStyleRoot()) {
mStyleScopes.AppendElement(aElement);
}
}
void PopStyleScope(mozilla::dom::Element* aElement)
{
NS_PRECONDITION(aElement, "aElement must not be null");
if (mStyleScopes.SafeLastElement(nullptr) == aElement) {
mStyleScopes.TruncateLength(mStyleScopes.Length() - 1);
}
}
// Is this matching operation for the creation of a style context?
// (If it is, we need to set slow selector bits on nodes indicating
// that certain restyling needs to happen.)
const bool mForStyling;
/* Helper class for maintaining the ancestor state */
class NS_STACK_CLASS AutoAncestorPusher {
public:
AutoAncestorPusher(bool aDoPush,
TreeMatchContext &aTreeMatchContext,
mozilla::dom::Element *aElement
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mPushed(aDoPush && aElement),
mTreeMatchContext(aTreeMatchContext),
mElement(aElement)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (mPushed) {
mTreeMatchContext.mAncestorFilter.PushAncestor(aElement);
mTreeMatchContext.PushStyleScope(aElement);
}
}
~AutoAncestorPusher() {
if (mPushed) {
mTreeMatchContext.mAncestorFilter.PopAncestor();
mTreeMatchContext.PopStyleScope(mElement);
}
}
private:
bool mPushed;
TreeMatchContext& mTreeMatchContext;
mozilla::dom::Element* mElement;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
private:
// When mVisitedHandling is eRelevantLinkUnvisited, this is set to true if a
// relevant link (see explanation in definition of VisitedHandling enum) was
@ -218,6 +242,10 @@ struct NS_STACK_CLASS TreeMatchContext {
eMatchVisitedDefault
};
// List of ancestor elements that define a style scope (due to having a
// <style scoped> child).
nsAutoTArray<mozilla::dom::Element*, 1> mStyleScopes;
// Constructor to use when creating a tree match context for styling
TreeMatchContext(bool aForStyling,
nsRuleWalker::VisitedHandlingType aVisitedHandling,