зеркало из https://github.com/mozilla/pjs.git
Bug 696205 part 2. Add a querySelector fast-path for selectors whose rightmost sequence of simple selectors contains an id. r=sicking
This commit is contained in:
Родитель
440978fc40
Коммит
5a98b45de1
|
@ -126,8 +126,8 @@ class Element;
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#define NS_IDOCUMENT_IID \
|
#define NS_IDOCUMENT_IID \
|
||||||
{ 0x3d24831e, 0x2a2b, 0x42f4, \
|
{ 0xb52356d4, 0xe191, 0x4cf8, \
|
||||||
{ 0x9d, 0x98, 0x17, 0x60, 0x18, 0xab, 0x6e, 0xfb } }
|
{ 0xb8, 0x58, 0xc0, 0xf1, 0xe1, 0x98, 0x09, 0xdf } }
|
||||||
|
|
||||||
// Flag for AddStyleSheet().
|
// Flag for AddStyleSheet().
|
||||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||||
|
@ -1510,6 +1510,13 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual Element* GetElementById(const nsAString& aElementId) = 0;
|
virtual Element* GetElementById(const nsAString& aElementId) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns _all_ the elements in this document which
|
||||||
|
* have id aElementId, if there are any. Otherwise it returns null.
|
||||||
|
* The entries of the nsSmallVoidArray are Element*
|
||||||
|
*/
|
||||||
|
virtual const nsSmallVoidArray* GetAllElementsForId(const nsAString& aElementId) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup an image element using its associated ID, which is usually provided
|
* Lookup an image element using its associated ID, which is usually provided
|
||||||
* by |-moz-element()|. Similar to GetElementById, with the difference that
|
* by |-moz-element()|. Similar to GetElementById, with the difference that
|
||||||
|
|
|
@ -4036,6 +4036,17 @@ nsDocument::GetElementById(const nsAString& aElementId)
|
||||||
return entry ? entry->GetIdElement() : nsnull;
|
return entry ? entry->GetIdElement() : nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nsSmallVoidArray*
|
||||||
|
nsDocument::GetAllElementsForId(const nsAString& aElementId) const
|
||||||
|
{
|
||||||
|
if (aElementId.IsEmpty()) {
|
||||||
|
return nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
|
||||||
|
return entry ? entry->GetIdElements() : nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn)
|
nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn)
|
||||||
{
|
{
|
||||||
|
|
|
@ -171,6 +171,12 @@ public:
|
||||||
* id. Otherwise returns null.
|
* id. Otherwise returns null.
|
||||||
*/
|
*/
|
||||||
Element* GetIdElement();
|
Element* GetIdElement();
|
||||||
|
/**
|
||||||
|
* Returns the list of all elements associated with this id.
|
||||||
|
*/
|
||||||
|
const nsSmallVoidArray* GetIdElements() const {
|
||||||
|
return &mIdContentList;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* If this entry has a non-null image element set (using SetImageElement),
|
* If this entry has a non-null image element set (using SetImageElement),
|
||||||
* the image element will be returned, otherwise the same as GetIdElement().
|
* the image element will be returned, otherwise the same as GetIdElement().
|
||||||
|
@ -244,7 +250,7 @@ private:
|
||||||
void FireChangeCallbacks(Element* aOldElement, Element* aNewElement,
|
void FireChangeCallbacks(Element* aOldElement, Element* aNewElement,
|
||||||
bool aImageOnly = false);
|
bool aImageOnly = false);
|
||||||
|
|
||||||
// empty if there are no elementswith this ID.
|
// empty if there are no elements with this ID.
|
||||||
// The elements are stored as weak pointers.
|
// The elements are stored as weak pointers.
|
||||||
nsSmallVoidArray mIdContentList;
|
nsSmallVoidArray mIdContentList;
|
||||||
nsRefPtr<nsBaseContentList> mNameContentList;
|
nsRefPtr<nsBaseContentList> mNameContentList;
|
||||||
|
@ -926,6 +932,7 @@ public:
|
||||||
const nsAString& aLocalName);
|
const nsAString& aLocalName);
|
||||||
|
|
||||||
virtual Element *GetElementById(const nsAString& aElementId);
|
virtual Element *GetElementById(const nsAString& aElementId);
|
||||||
|
virtual const nsSmallVoidArray* GetAllElementsForId(const nsAString& aElementId) const;
|
||||||
|
|
||||||
virtual Element *LookupImageElement(const nsAString& aElementId);
|
virtual Element *LookupImageElement(const nsAString& aElementId);
|
||||||
|
|
||||||
|
|
|
@ -5352,6 +5352,9 @@ ParseSelectorList(nsINode* aNode,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Actually find elements matching aSelectorList (which must not be
|
||||||
|
// null) and which are descendants of aRoot and put them in Alist. If
|
||||||
|
// onlyFirstMatch, then stop once the first one is found.
|
||||||
template<bool onlyFirstMatch, class T>
|
template<bool onlyFirstMatch, class T>
|
||||||
inline static nsresult FindMatchingElements(nsINode* aRoot,
|
inline static nsresult FindMatchingElements(nsINode* aRoot,
|
||||||
const nsAString& aSelector,
|
const nsAString& aSelector,
|
||||||
|
@ -5361,10 +5364,55 @@ inline static nsresult FindMatchingElements(nsINode* aRoot,
|
||||||
nsresult rv = ParseSelectorList(aRoot, aSelector,
|
nsresult rv = ParseSelectorList(aRoot, aSelector,
|
||||||
getter_Transfers(selectorList));
|
getter_Transfers(selectorList));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
NS_ENSURE_TRUE(selectorList, NS_OK);
|
||||||
|
|
||||||
|
NS_ASSERTION(selectorList->mSelectors,
|
||||||
|
"How can we not have any selectors?");
|
||||||
|
|
||||||
|
nsIDocument* doc = aRoot->OwnerDoc();
|
||||||
|
TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
|
||||||
|
doc);
|
||||||
|
|
||||||
|
// Fast-path selectors involving IDs. We can only do this if aRoot
|
||||||
|
// is in the document and the document is not in quirks mode, since
|
||||||
|
// ID selectors are case-insensitive in quirks mode. Also, only do
|
||||||
|
// this if selectorList only has one selector, because otherwise
|
||||||
|
// ordering the elements correctly is a pain.
|
||||||
|
NS_ASSERTION(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT),
|
||||||
|
"Unexpected root node");
|
||||||
|
if (aRoot->IsInDoc() &&
|
||||||
|
doc->GetCompatibilityMode() != eCompatibility_NavQuirks &&
|
||||||
|
!selectorList->mNext &&
|
||||||
|
selectorList->mSelectors->mIDList) {
|
||||||
|
nsIAtom* id = selectorList->mSelectors->mIDList->mAtom;
|
||||||
|
const nsSmallVoidArray* elements =
|
||||||
|
doc->GetAllElementsForId(nsDependentAtomString(id));
|
||||||
|
|
||||||
|
// XXXbz: Should we fall back to the tree walk if aRoot is not the
|
||||||
|
// document and |elements| is long, for some value of "long"?
|
||||||
|
if (elements) {
|
||||||
|
for (PRUint32 i = 0; i < elements->Count(); ++i) {
|
||||||
|
Element *element = static_cast<Element*>(elements->ElementAt(i));
|
||||||
|
if (!aRoot->IsElement() ||
|
||||||
|
nsContentUtils::ContentIsDescendantOf(element, aRoot)) {
|
||||||
|
// We have an element with the right id and it's a descendant
|
||||||
|
// of aRoot. Make sure it really matches the selector.
|
||||||
|
if (nsCSSRuleProcessor::SelectorListMatches(element, matchingContext,
|
||||||
|
selectorList)) {
|
||||||
|
aList.AppendElement(element);
|
||||||
|
if (onlyFirstMatch) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No elements with this id, or none of them are our descendants,
|
||||||
|
// or none of them match. We're done here.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
TreeMatchContext matchingContext(false,
|
|
||||||
nsRuleWalker::eRelevantLinkUnvisited,
|
|
||||||
aRoot->OwnerDoc());
|
|
||||||
for (nsIContent* cur = aRoot->GetFirstChild();
|
for (nsIContent* cur = aRoot->GetFirstChild();
|
||||||
cur;
|
cur;
|
||||||
cur = cur->GetNextNode(aRoot)) {
|
cur = cur->GetNextNode(aRoot)) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче