зеркало из https://github.com/mozilla/gecko-dev.git
Bug 598832 part 13. Stop using RuleProcessorData in the DOM-exposed selector-matching methods. r=dbaron
This commit is contained in:
Родитель
b65ed4354f
Коммит
7a803c365b
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче