Bug 1449502: Cleanup a bit more the selector cache and CSSOM methods. r?xidorn
MozReview-Commit-ID: 32FgbGFUdCM
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3467,47 +3467,32 @@ Element::GetTokenList(nsAtom* aAtom,
SetProperty(aAtom, list, nsDOMTokenListPropertyDestructor);
}
return list;
}
Element*
Element::Closest(const nsAString& aSelector, ErrorResult& aResult)
{
- return WithSelectorList<Element*>(
- aSelector,
- aResult,
- [&](const RawServoSelectorList* aList) -> Element* {
- if (!aList) {
- return nullptr;
- }
- return const_cast<Element*>(Servo_SelectorList_Closest(this, aList));
- },
- [&](nsCSSSelectorList* aList) -> Element* {
- MOZ_CRASH("old style system disabled");
- }
- );
+ const RawServoSelectorList* list = ParseSelectorList(aSelector, aResult);
+ if (!list) {
+ return nullptr;
+ }
+
+ return const_cast<Element*>(Servo_SelectorList_Closest(this, list));
}
bool
-Element::Matches(const nsAString& aSelector, ErrorResult& aError)
+Element::Matches(const nsAString& aSelector, ErrorResult& aResult)
{
- return WithSelectorList<bool>(
- aSelector,
- aError,
- [&](const RawServoSelectorList* aList) {
- if (!aList) {
- return false;
- }
- return Servo_SelectorList_Matches(this, aList);
- },
- [&](nsCSSSelectorList* aList) {
- MOZ_CRASH("old style system disabled");
- }
- );
+ const RawServoSelectorList* list = ParseSelectorList(aSelector, aResult);
+ if (!list) {
+ return false;
+ }
+ return Servo_SelectorList_Matches(this, list);
}
static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
// Order matters here
// See ParseCORSValue
{ "anonymous", CORS_ANONYMOUS },
{ "use-credentials", CORS_USE_CREDENTIALS },
{ nullptr, 0 }
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1306,36 +1306,16 @@ nsIDocument::SelectorCache::SelectorCach
1000, "nsIDocument::SelectorCache", aEventTarget)
{ }
nsIDocument::SelectorCache::~SelectorCache()
{
AgeAllGenerations();
}
-void
-nsIDocument::SelectorCache::SelectorList::Reset()
-{
- if (mServo) {
- Servo_SelectorList_Drop(mServo);
- mServo = nullptr;
- }
-}
-
-
-void nsIDocument::SelectorCache::CacheList(
- const nsAString& aSelector,
- UniquePtr<RawServoSelectorList>&& aSelectorList)
-{
- MOZ_ASSERT(NS_IsMainThread());
- SelectorCacheKey* key = new SelectorCacheKey(aSelector);
- mTable.Put(key->mKey, SelectorList(Move(aSelectorList)));
- AddObject(key);
-}
-
void nsIDocument::SelectorCache::NotifyExpired(SelectorCacheKey* aSelector)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSelector);
// There is no guarantee that this method won't be re-entered when selector
// matching is ongoing because "memory-pressure" could be notified immediately
// when OOM happens according to the design of nsExpirationTracker.
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -1446,104 +1446,57 @@ private:
};
class SelectorCacheKeyDeleter;
public:
class SelectorCache final
: public nsExpirationTracker<SelectorCacheKey, 4>
{
- public:
- class SelectorList
- {
- public:
- SelectorList()
- : mGecko(nullptr)
- {}
-
- SelectorList(SelectorList&& aOther)
- {
- *this = mozilla::Move(aOther);
- }
-
- SelectorList& operator=(SelectorList&& aOther)
- {
- Reset();
- mServo = aOther.mServo;
- aOther.mServo = nullptr;
- return *this;
- }
-
- SelectorList(const SelectorList& aOther) = delete;
-
- explicit SelectorList(mozilla::UniquePtr<RawServoSelectorList>&& aList)
- : mServo(aList.release())
- {}
-
-
- ~SelectorList() {
- Reset();
- }
-
- explicit operator bool() const
- {
- return !!AsServo();
- }
-
- nsCSSSelectorList* AsGecko() const
- {
- return mGecko;
- }
-
- RawServoSelectorList* AsServo() const
- {
- return mServo;
- }
-
- private:
- void Reset();
-
- union {
- nsCSSSelectorList* mGecko;
- RawServoSelectorList* mServo;
- };
- };
-
- explicit SelectorCache(nsIEventTarget* aEventTarget);
-
- // CacheList takes ownership of aSelectorList.
- void CacheList(const nsAString& aSelector,
- mozilla::UniquePtr<nsCSSSelectorList>&& aSelectorList);
- void CacheList(const nsAString& aSelector,
- mozilla::UniquePtr<RawServoSelectorList>&& aSelectorList);
-
- virtual void NotifyExpired(SelectorCacheKey* aSelector) override;
-
- // We do not call MarkUsed because it would just slow down lookups and
- // because we're OK expiring things after a few seconds even if they're
- // being used. Returns whether we actually had an entry for aSelector.
- //
- // If we have an entry and the selector list returned has a null
- // nsCSSSelectorList*/RawServoSelectorList*, that indicates that aSelector
- // has already been parsed and is not a syntactically valid selector.
- SelectorList* GetList(const nsAString& aSelector)
- {
- return mTable.GetValue(aSelector);
- }
-
- ~SelectorCache();
-
- private:
- nsDataHashtable<nsStringHashKey, SelectorList> mTable;
+ public:
+ using SelectorList = mozilla::UniquePtr<RawServoSelectorList>;
+
+ explicit SelectorCache(nsIEventTarget* aEventTarget);
+
+ void CacheList(const nsAString& aSelector, SelectorList&& aSelectorList)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ SelectorCacheKey* key = new SelectorCacheKey(aSelector);
+ mTable.Put(key->mKey, Move(aSelectorList));
+ AddObject(key);
+ }
+
+ void NotifyExpired(SelectorCacheKey* aSelector) final;
+
+ // We do not call MarkUsed because it would just slow down lookups and
+ // because we're OK expiring things after a few seconds even if they're
+ // being used. Returns whether we actually had an entry for aSelector.
+ //
+ // If we have an entry and the selector list returned has a null
+ // nsCSSSelectorList*/RawServoSelectorList*, that indicates that aSelector
+ // has already been parsed and is not a syntactically valid selector.
+ SelectorList* GetList(const nsAString& aSelector)
+ {
+ return mTable.GetValue(aSelector);
+ }
+
+ ~SelectorCache();
+
+ private:
+ using SelectorTable =
+ nsDataHashtable<nsStringHashKey, SelectorList>;
+
+ SelectorTable mTable;
};
SelectorCache& GetSelectorCache() {
if (!mSelectorCache) {
- mSelectorCache.reset(new SelectorCache(
- EventTargetFor(mozilla::TaskCategory::Other)));
+ mSelectorCache =
+ mozilla::MakeUnique<SelectorCache>(
+ EventTargetFor(mozilla::TaskCategory::Other));
}
return *mSelectorCache;
}
// Get the root <html> element, or return null if there isn't one (e.g.
// if the root isn't <html>)
Element* GetHtmlElement() const;
// Returns the first child of GetHtmlContent which has the given tag,
// or nullptr if that doesn't exist.
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -2484,53 +2484,51 @@ nsINode::Length() const
return AsContent()->TextLength();
default:
return GetChildCount();
}
}
const RawServoSelectorList*
-nsINode::ParseServoSelectorList(
- const nsAString& aSelectorString,
- ErrorResult& aRv)
+nsINode::ParseSelectorList(const nsAString& aSelectorString,
+ ErrorResult& aRv)
{
nsIDocument* doc = OwnerDoc();
nsIDocument::SelectorCache& cache = doc->GetSelectorCache();
nsIDocument::SelectorCache::SelectorList* list =
cache.GetList(aSelectorString);
if (list) {
if (!*list) {
// Invalid selector.
aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
NS_LITERAL_CSTRING("'") + NS_ConvertUTF16toUTF8(aSelectorString) +
NS_LITERAL_CSTRING("' is not a valid selector")
);
return nullptr;
}
- return list->AsServo();
+ return list->get();
}
NS_ConvertUTF16toUTF8 selectorString(aSelectorString);
auto* selectorList = Servo_SelectorList_Parse(&selectorString);
if (!selectorList) {
aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
NS_LITERAL_CSTRING("'") + selectorString +
NS_LITERAL_CSTRING("' is not a valid selector")
);
}
cache.CacheList(aSelectorString, UniquePtr<RawServoSelectorList>(selectorList));
return selectorList;
}
-
namespace {
struct SelectorMatchInfo {
};
} // namespace
// Given an id, find elements with that id under aRoot that match aMatchInfo if
// any is provided. If no SelectorMatchInfo is provided, just find the ones
// with the given id. aRoot must be in the document.
@@ -2586,54 +2584,36 @@ struct ElementHolder {
Element* ElementAt(uint32_t aIndex) { return nullptr; }
Element* mElement;
};
Element*
nsINode::QuerySelector(const nsAString& aSelector, ErrorResult& aResult)
{
- return WithSelectorList<Element*>(
- aSelector,
- aResult,
- [&](const RawServoSelectorList* aList) -> Element* {
- if (!aList) {
- return nullptr;
- }
- const bool useInvalidation = false;
- return const_cast<Element*>(
- Servo_SelectorList_QueryFirst(this, aList, useInvalidation));
- },
- [&](nsCSSSelectorList* aList) -> Element* {
- MOZ_CRASH("old style system disabled");
- }
- );
+ const RawServoSelectorList* list = ParseSelectorList(aSelector, aResult);
+ if (!list) {
+ return nullptr;
+ }
+ const bool useInvalidation = false;
+ return const_cast<Element*>(
+ Servo_SelectorList_QueryFirst(this, list, useInvalidation));
}
already_AddRefed<nsINodeList>
nsINode::QuerySelectorAll(const nsAString& aSelector, ErrorResult& aResult)
{
RefPtr<nsSimpleContentList> contentList = new nsSimpleContentList(this);
-
- WithSelectorList<void>(
- aSelector,
- aResult,
- [&](const RawServoSelectorList* aList) {
- if (!aList) {
- return;
- }
- const bool useInvalidation = false;
- Servo_SelectorList_QueryAll(
- this, aList, contentList.get(), useInvalidation);
- },
- [&](nsCSSSelectorList* aList) {
- MOZ_CRASH("old style system disabled");
- }
- );
-
+ const RawServoSelectorList* list = ParseSelectorList(aSelector, aResult);
+ if (!list) {
+ return contentList.forget();
+ }
+
+ const bool useInvalidation = false;
+ Servo_SelectorList_QueryAll(this, list, contentList.get(), useInvalidation);
return contentList.forget();
}
Element*
nsINode::GetElementById(const nsAString& aId)
{
MOZ_ASSERT(IsElement() || IsNodeOfType(eDOCUMENT_FRAGMENT),
"Bogus this object for GetElementById call");
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -32,17 +32,16 @@
#ifdef XP_WIN
#ifdef GetClassInfo
#undef GetClassInfo
#endif
#endif
class nsAttrAndChildArray;
class nsAttrChildContentList;
-struct nsCSSSelectorList;
class nsDOMAttributeMap;
class nsIAnimationObserver;
class nsIContent;
class nsIDocument;
class nsIDOMElement;
class nsIDOMNodeList;
class nsIFrame;
class nsIMutationObserver;
@@ -1991,58 +1990,25 @@ protected:
* @param aIndex The index to insert at.
* @param aNotify Whether to notify.
* @param aChildArray The child array to work with
*/
nsresult doInsertChildAt(nsIContent* aKid, uint32_t aIndex,
bool aNotify, nsAttrAndChildArray& aChildArray);
/**
- * Parse the given selector string into an nsCSSSelectorList.
- *
- * A null return value with a non-failing aRv means the string only
- * contained pseudo-element selectors.
- *
- * A failing aRv means the string was not a valid selector.
- *
- * Note that the selector list returned here is owned by the owner doc's
- * selector cache.
- */
- nsCSSSelectorList* ParseSelectorList(const nsAString& aSelectorString,
- mozilla::ErrorResult& aRv);
-
- /**
* Parse the given selector string into a servo SelectorList.
*
* Never returns null if aRv is not failing.
*
* Note that the selector list returned here is owned by the owner doc's
* selector cache.
*/
- const RawServoSelectorList* ParseServoSelectorList(
- const nsAString& aSelectorString,
- mozilla::ErrorResult& aRv);
-
- /**
- * Parse the given selector string a SelectorList, depending on whether we're
- * in a Servo or Gecko-backed document, and execute either aServoFunctor or
- * aGeckoFunctor on it.
- *
- * Note that the selector list is owned by the owner doc's selector cache
- * which can get expired, so you shouldn't keep it around for long.
- */
- template<typename Ret, typename ServoFunctor, typename GeckoFunctor>
- Ret WithSelectorList(
- const nsAString& aSelectorString,
- mozilla::ErrorResult& aRv,
- const ServoFunctor& aServoFunctor,
- const GeckoFunctor& aGeckoFunctor)
- {
- return aServoFunctor(ParseServoSelectorList(aSelectorString, aRv));
- }
+ const RawServoSelectorList* ParseSelectorList(const nsAString& aSelectorString,
+ mozilla::ErrorResult&);
public:
/* Event stuff that documents and elements share. This needs to be
NS_IMETHOD because some subclasses implement DOM methods with
this exact name and signature and then the calling convention
needs to match.
Note that we include DOCUMENT_ONLY_EVENT events here so that we