Bug 598832 part 13. Stop using RuleProcessorData in the DOM-exposed selector-matching methods. r=dbaron

This commit is contained in:
Boris Zbarsky 2011-03-29 13:29:21 -04:00
Родитель b65ed4354f
Коммит 7a803c365b
5 изменённых файлов: 32 добавлений и 89 удалений

Просмотреть файл

@ -5483,8 +5483,7 @@ nsGenericElement::GetLinkTarget(nsAString& aTarget)
static nsresult
ParseSelectorList(nsINode* aNode,
const nsAString& aSelectorString,
nsCSSSelectorList** aSelectorList,
nsPresContext** aPresContext)
nsCSSSelectorList** aSelectorList)
{
NS_ENSURE_ARG(aNode);
@ -5515,14 +5514,6 @@ ParseSelectorList(nsINode* aNode,
} while (*slot);
*aSelectorList = selectorList;
// It's not strictly necessary to have a prescontext here, but it's
// a bit of an optimization for various stuff.
*aPresContext = nsnull;
nsIPresShell* shell = doc->GetShell();
if (shell) {
*aPresContext = shell->GetPresContext();
}
return NS_OK;
}
@ -5536,85 +5527,34 @@ typedef PRBool
// returning false means stop iteration
static PRBool
TryMatchingElementsInSubtree(nsINode* aRoot,
RuleProcessorData* aParentData,
nsPresContext* aPresContext,
TreeMatchContext& aTreeMatchContext,
nsCSSSelectorList* aSelectorList,
ElementMatchedCallback aCallback,
void* aClosure)
{
/* To improve the performance of '+' and '~' combinators and the :nth-*
* selectors, we keep track of the immediately previous sibling data. That's
* cheaper than heap-allocating all the datas and keeping track of them all,
* and helps a good bit in the common cases. We also keep track of the whole
* parent data chain, since we have those Around anyway */
union { char c[2 * sizeof(RuleProcessorData)]; void *p; } databuf;
RuleProcessorData* prevSibling = nsnull;
RuleProcessorData* data = reinterpret_cast<RuleProcessorData*>(databuf.c);
PRBool continueIteration = PR_TRUE;
for (nsINode::ChildIterator iter(aRoot); !iter.IsDone(); iter.Next()) {
nsIContent* kid = iter;
if (!kid->IsElement()) {
continue;
}
/* See whether we match */
new (data) RuleProcessorData(aPresContext, kid->AsElement(), nsnull,
PR_FALSE);
NS_ASSERTION(!data->mParentData, "Shouldn't happen");
NS_ASSERTION(!data->mPreviousSiblingData, "Shouldn't happen");
data->mParentData = aParentData;
data->mPreviousSiblingData = prevSibling;
data->mVisitedHandling = nsRuleWalker::eRelevantLinkUnvisited;
if (nsCSSRuleProcessor::SelectorListMatches(kid->AsElement(), *data,
if (nsCSSRuleProcessor::SelectorListMatches(kid->AsElement(),
aTreeMatchContext,
aSelectorList)) {
continueIteration = (*aCallback)(kid, aClosure);
}
if (continueIteration) {
continueIteration =
TryMatchingElementsInSubtree(kid, data, aPresContext, aSelectorList,
TryMatchingElementsInSubtree(kid, aTreeMatchContext, aSelectorList,
aCallback, aClosure);
}
/* Clear out the parent and previous sibling data if we set them, so that
* ~RuleProcessorData won't try to delete a placement-new'd object. Make
* sure this happens before our possible early break. Note that we can
* have null aParentData but non-null data->mParentData if we're scoped to
* an element. However, prevSibling and data->mPreviousSiblingData must
* always match.
*/
NS_ASSERTION(!aParentData || data->mParentData == aParentData,
"Unexpected parent");
NS_ASSERTION(data->mPreviousSiblingData == prevSibling,
"Unexpected prev sibling");
data->mPreviousSiblingData = nsnull;
if (prevSibling) {
if (aParentData) {
prevSibling->mParentData = nsnull;
}
prevSibling->~RuleProcessorData();
} else {
/* This is the first time through, so point |prevSibling| to the location
we want to have |data| end up pointing to. */
prevSibling = data + 1;
}
/* Now swap |prevSibling| and |data|. Again, before the early break */
RuleProcessorData* temp = prevSibling;
prevSibling = data;
data = temp;
if (!continueIteration) {
break;
}
}
if (prevSibling) {
if (aParentData) {
prevSibling->mParentData = nsnull;
}
/* Make sure to clean this up */
prevSibling->~RuleProcessorData();
}
return continueIteration;
}
@ -5637,14 +5577,15 @@ nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
NS_PRECONDITION(aResult, "Null out param?");
nsAutoPtr<nsCSSSelectorList> selectorList;
nsPresContext* presContext;
*aResult = ParseSelectorList(aRoot, aSelector,
getter_Transfers(selectorList),
&presContext);
getter_Transfers(selectorList));
NS_ENSURE_SUCCESS(*aResult, nsnull);
nsIContent* foundElement = nsnull;
TryMatchingElementsInSubtree(aRoot, nsnull, presContext, selectorList,
TreeMatchContext matchingContext(PR_FALSE,
nsRuleWalker::eRelevantLinkUnvisited,
aRoot->GetOwnerDoc());
TryMatchingElementsInSubtree(aRoot, matchingContext, selectorList,
FindFirstMatchingElement, &foundElement);
return foundElement;
@ -5672,13 +5613,14 @@ nsGenericElement::doQuerySelectorAll(nsINode* aRoot,
NS_ADDREF(*aReturn = contentList);
nsAutoPtr<nsCSSSelectorList> selectorList;
nsPresContext* presContext;
nsresult rv = ParseSelectorList(aRoot, aSelector,
getter_Transfers(selectorList),
&presContext);
getter_Transfers(selectorList));
NS_ENSURE_SUCCESS(rv, rv);
TryMatchingElementsInSubtree(aRoot, nsnull, presContext, selectorList,
TreeMatchContext matchingContext(PR_FALSE,
nsRuleWalker::eRelevantLinkUnvisited,
aRoot->GetOwnerDoc());
TryMatchingElementsInSubtree(aRoot, matchingContext, selectorList,
AppendAllMatchingElements, contentList);
return NS_OK;
}
@ -5688,16 +5630,16 @@ PRBool
nsGenericElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResult)
{
nsAutoPtr<nsCSSSelectorList> selectorList;
nsPresContext* presContext;
PRBool matches = PR_FALSE;
*aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList),
&presContext);
*aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList));
if (NS_SUCCEEDED(*aResult)) {
RuleProcessorData data(presContext, this, nsnull, PR_FALSE);
data.mVisitedHandling = nsRuleWalker::eRelevantLinkUnvisited;
matches = nsCSSRuleProcessor::SelectorListMatches(this, data, selectorList);
TreeMatchContext matchingContext(PR_FALSE,
nsRuleWalker::eRelevantLinkUnvisited,
GetOwnerDoc());
matches = nsCSSRuleProcessor::SelectorListMatches(this, matchingContext,
selectorList);
}
return matches;

Просмотреть файл

@ -2987,8 +2987,8 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
}
/* static */ PRBool
nsCSSRuleProcessor::SelectorListMatches(mozilla::dom::Element* aElement,
RuleProcessorData& aData,
nsCSSRuleProcessor::SelectorListMatches(Element* aElement,
TreeMatchContext& aTreeMatchContext,
nsCSSSelectorList* aSelectorList)
{
while (aSelectorList) {
@ -2996,9 +2996,10 @@ nsCSSRuleProcessor::SelectorListMatches(mozilla::dom::Element* aElement,
NS_ASSERTION(sel, "Should have *some* selectors");
NS_ASSERTION(!sel->IsPseudoElement(), "Shouldn't have been called");
NodeMatchContext nodeContext(nsEventStates(), PR_FALSE);
if (SelectorMatches(aElement, sel, nodeContext, aData)) {
if (SelectorMatches(aElement, sel, nodeContext, aTreeMatchContext)) {
nsCSSSelector* next = sel->mNext;
if (!next || SelectorMatchesTree(aElement, next, aData, PR_FALSE)) {
if (!next ||
SelectorMatchesTree(aElement, next, aTreeMatchContext, PR_FALSE)) {
return PR_TRUE;
}
}

Просмотреть файл

@ -55,6 +55,7 @@
struct RuleCascadeData;
struct nsCSSSelectorList;
struct CascadeEnumData;
struct TreeMatchContext;
/**
* The CSS style rule processor provides a mechanism for sibling style
@ -87,12 +88,12 @@ public:
/*
* Returns true if the given aElement matches one of the
* selectors in aSelectorList. Note that this method will assume
* the matching is not for styling purposes. aSelectorList must not
* the given aElement is not a relevant link. aSelectorList must not
* include any pseudo-element selectors. aSelectorList is allowed
* to be null; in this case PR_FALSE will be returned.
*/
static PRBool SelectorListMatches(mozilla::dom::Element* aElement,
RuleProcessorData& aData,
TreeMatchContext& aTreeMatchContext,
nsCSSSelectorList* aSelectorList);
/*

Просмотреть файл

@ -186,9 +186,8 @@ public:
struct ElementRuleProcessorData : public RuleProcessorData {
ElementRuleProcessorData(nsPresContext* aPresContext,
mozilla::dom::Element* aElement,
nsRuleWalker* aRuleWalker,
PRBool aForStyling)
: RuleProcessorData(aPresContext, aElement, aRuleWalker, aForStyling)
nsRuleWalker* aRuleWalker)
: RuleProcessorData(aPresContext, aElement, aRuleWalker, PR_TRUE)
{
NS_PRECONDITION(aPresContext, "null pointer");
NS_PRECONDITION(aRuleWalker, "null pointer");

Просмотреть файл

@ -766,7 +766,7 @@ nsStyleSet::ResolveStyleFor(Element* aElement,
NS_ASSERTION(aElement, "aElement must not be null");
nsRuleWalker ruleWalker(mRuleTree);
ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker, PR_TRUE);
ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker);
FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
&ruleWalker);