LCOV - code coverage report
Current view: top level - layout/style - nsCSSRuleProcessor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1188 1618 73.4 %
Date: 2017-07-14 16:53:18 Functions: 123 142 86.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * style rule processor for CSS style sheets, responsible for selector
       9             :  * matching and cascading
      10             :  */
      11             : 
      12             : #include "nsCSSRuleProcessor.h"
      13             : 
      14             : #include "nsAutoPtr.h"
      15             : #include "nsRuleProcessorData.h"
      16             : #include <algorithm>
      17             : #include "nsIAtom.h"
      18             : #include "PLDHashTable.h"
      19             : #include "nsICSSPseudoComparator.h"
      20             : #include "mozilla/MemoryReporting.h"
      21             : #include "mozilla/css/ImportRule.h"
      22             : #include "mozilla/css/StyleRule.h"
      23             : #include "mozilla/css/GroupRule.h"
      24             : #include "nsIDocument.h"
      25             : #include "nsPresContext.h"
      26             : #include "nsGkAtoms.h"
      27             : #include "nsUnicharUtils.h"
      28             : #include "nsError.h"
      29             : #include "nsRuleWalker.h"
      30             : #include "nsCSSPseudoClasses.h"
      31             : #include "nsCSSPseudoElements.h"
      32             : #include "nsIContent.h"
      33             : #include "nsCOMPtr.h"
      34             : #include "nsHashKeys.h"
      35             : #include "nsStyleUtil.h"
      36             : #include "nsQuickSort.h"
      37             : #include "nsAttrValue.h"
      38             : #include "nsAttrValueInlines.h"
      39             : #include "nsAttrName.h"
      40             : #include "nsTArray.h"
      41             : #include "nsContentUtils.h"
      42             : #include "nsMediaList.h"
      43             : #include "nsCSSRules.h"
      44             : #include "nsCSSCounterStyleRule.h"
      45             : #include "nsCSSFontFaceRule.h"
      46             : #include "nsStyleSet.h"
      47             : #include "mozilla/dom/Element.h"
      48             : #include "nsNthIndexCache.h"
      49             : #include "mozilla/ArrayUtils.h"
      50             : #include "mozilla/EventStates.h"
      51             : #include "mozilla/Preferences.h"
      52             : #include "mozilla/ServoStyleSet.h"
      53             : #include "mozilla/LookAndFeel.h"
      54             : #include "mozilla/Likely.h"
      55             : #include "mozilla/OperatorNewExtensions.h"
      56             : #include "mozilla/TypedEnumBits.h"
      57             : #include "RuleProcessorCache.h"
      58             : #include "nsIDOMMutationEvent.h"
      59             : 
      60             : using namespace mozilla;
      61             : using namespace mozilla::dom;
      62             : 
      63             : typedef ArenaAllocator<4096, 8> CascadeAllocator;
      64             : 
      65             : #define VISITED_PSEUDO_PREF "layout.css.visited_links_enabled"
      66             : 
      67             : static bool gSupportVisitedPseudo = true;
      68             : 
      69             : static nsTArray< nsCOMPtr<nsIAtom> >* sSystemMetrics = 0;
      70             : 
      71             : #ifdef XP_WIN
      72             : uint8_t nsCSSRuleProcessor::sWinThemeId = LookAndFeel::eWindowsTheme_Generic;
      73             : #endif
      74             : 
      75             : /**
      76             :  * A struct representing a given CSS rule and a particular selector
      77             :  * from that rule's selector list.
      78             :  */
      79             : struct RuleSelectorPair {
      80       14586 :   RuleSelectorPair(css::StyleRule* aRule, nsCSSSelector* aSelector)
      81       14586 :     : mRule(aRule), mSelector(aSelector) {}
      82             :   // If this class ever grows a destructor, deal with
      83             :   // PerWeightDataListItem appropriately.
      84             : 
      85             :   css::StyleRule*   mRule;
      86             :   nsCSSSelector*    mSelector; // which of |mRule|'s selectors
      87             : };
      88             : 
      89             : #define NS_IS_ANCESTOR_OPERATOR(ch) \
      90             :   ((ch) == char16_t(' ') || (ch) == char16_t('>'))
      91             : 
      92             : /**
      93             :  * A struct representing a particular rule in an ordered list of rules
      94             :  * (the ordering depending on the weight of mSelector and the order of
      95             :  * our rules to start with).
      96             :  */
      97             : struct RuleValue : RuleSelectorPair {
      98             :   enum {
      99             :     eMaxAncestorHashes = 4
     100             :   };
     101             : 
     102       14586 :   RuleValue(const RuleSelectorPair& aRuleSelectorPair, int32_t aIndex,
     103       14586 :             bool aQuirksMode) :
     104             :     RuleSelectorPair(aRuleSelectorPair),
     105       14586 :     mIndex(aIndex)
     106             :   {
     107       14586 :     CollectAncestorHashes(aQuirksMode);
     108       14586 :   }
     109             : 
     110             :   int32_t mIndex; // High index means high weight/order.
     111             :   uint32_t mAncestorSelectorHashes[eMaxAncestorHashes];
     112             : 
     113             : private:
     114       14586 :   void CollectAncestorHashes(bool aQuirksMode) {
     115             :     // Collect up our mAncestorSelectorHashes.  It's not clear whether it's
     116             :     // better to stop once we've found eMaxAncestorHashes of them or to keep
     117             :     // going and preferentially collect information from selectors higher up the
     118             :     // chain...  Let's do the former for now.
     119       14586 :     size_t hashIndex = 0;
     120       23478 :     for (nsCSSSelector* sel = mSelector->mNext; sel; sel = sel->mNext) {
     121        8998 :       if (!NS_IS_ANCESTOR_OPERATOR(sel->mOperator)) {
     122             :         // |sel| is going to select something that's not actually one of our
     123             :         // ancestors, so don't add it to mAncestorSelectorHashes.  But keep
     124             :         // going, because it'll select a sibling of one of our ancestors, so its
     125             :         // ancestors would be our ancestors too.
     126         905 :         continue;
     127             :       }
     128             : 
     129             :       // Now sel is supposed to select one of our ancestors.  Grab
     130             :       // whatever info we can from it into mAncestorSelectorHashes.
     131             :       // But in qurks mode, don't grab IDs and classes because those
     132             :       // need to be matched case-insensitively.
     133        8093 :       if (!aQuirksMode) {
     134        6537 :         nsAtomList* ids = sel->mIDList;
     135       11109 :         while (ids) {
     136        2367 :           mAncestorSelectorHashes[hashIndex++] = ids->mAtom->hash();
     137        2367 :           if (hashIndex == eMaxAncestorHashes) {
     138          81 :             return;
     139             :           }
     140        2286 :           ids = ids->mNext;
     141             :         }
     142             : 
     143        6456 :         nsAtomList* classes = sel->mClassList;
     144       10726 :         while (classes) {
     145        2135 :           mAncestorSelectorHashes[hashIndex++] = classes->mAtom->hash();
     146        2135 :           if (hashIndex == eMaxAncestorHashes) {
     147           0 :             return;
     148             :           }
     149        2135 :           classes = classes->mNext;
     150             :         }
     151             :       }
     152             : 
     153             :       // Only put in the tag name if it's all-lowercase.  Otherwise we run into
     154             :       // trouble because we may test the wrong one of mLowercaseTag and
     155             :       // mCasedTag against the filter.
     156        8012 :       if (sel->mLowercaseTag && sel->mCasedTag == sel->mLowercaseTag) {
     157        3089 :         mAncestorSelectorHashes[hashIndex++] = sel->mLowercaseTag->hash();
     158        3089 :         if (hashIndex == eMaxAncestorHashes) {
     159          25 :           return;
     160             :         }
     161             :       }
     162             :     }
     163             : 
     164      115986 :     while (hashIndex != eMaxAncestorHashes) {
     165       50753 :       mAncestorSelectorHashes[hashIndex++] = 0;
     166             :     }
     167             :   }
     168             : };
     169             : 
     170             : // ------------------------------
     171             : // Rule hash table
     172             : //
     173             : 
     174             : // Uses any of the sets of ops below.
     175       16471 : struct RuleHashTableEntry : public PLDHashEntryHdr {
     176             :   // If you add members that have heap allocated memory be sure to change the
     177             :   // logic in SizeOfRuleHashTable().
     178             :   // Auto length 1, because we always have at least one entry in mRules.
     179             :   AutoTArray<RuleValue, 1> mRules;
     180             : };
     181             : 
     182        7644 : struct RuleHashTagTableEntry : public RuleHashTableEntry {
     183             :   // If you add members that have heap allocated memory be sure to change the
     184             :   // logic in RuleHash::SizeOf{In,Ex}cludingThis.
     185             :   nsCOMPtr<nsIAtom> mTag;
     186             : };
     187             : 
     188             : static PLDHashNumber
     189         713 : RuleHash_CIHashKey(const void *key)
     190             : {
     191         713 :   nsIAtom *atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     192             : 
     193        1426 :   nsAutoString str;
     194         713 :   atom->ToString(str);
     195         713 :   nsContentUtils::ASCIIToLower(str);
     196        1426 :   return HashString(str);
     197             : }
     198             : 
     199             : static inline nsCSSSelector*
     200        7397 : SubjectSelectorForRuleHash(const PLDHashEntryHdr *hdr)
     201             : {
     202        7397 :   auto entry = static_cast<const RuleHashTableEntry*>(hdr);
     203        7397 :   nsCSSSelector* selector = entry->mRules[0].mSelector;
     204        7397 :   if (selector->IsPseudoElement()) {
     205         204 :     selector = selector->mNext;
     206             :   }
     207        7397 :   return selector;
     208             : }
     209             : 
     210             : static inline bool
     211         455 : CIMatchAtoms(const void* key, nsIAtom *entry_atom)
     212             : {
     213         455 :   auto match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     214             : 
     215             :   // Check for case-sensitive match first.
     216         455 :   if (match_atom == entry_atom) {
     217         455 :     return true;
     218             :   }
     219             : 
     220             :   // Use EqualsIgnoreASCIICase instead of full on unicode case conversion
     221             :   // in order to save on performance. This is only used in quirks mode
     222             :   // anyway.
     223             :   return
     224           0 :     nsContentUtils::EqualsIgnoreASCIICase(nsDependentAtomString(entry_atom),
     225           0 :                                           nsDependentAtomString(match_atom));
     226             : }
     227             : 
     228             : static inline bool
     229        7241 : CSMatchAtoms(const void* key, nsIAtom *entry_atom)
     230             : {
     231        7241 :   auto match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     232        7241 :   return match_atom == entry_atom;
     233             : }
     234             : 
     235             : static bool
     236          81 : RuleHash_ClassCIMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
     237             : {
     238          81 :   return CIMatchAtoms(key, SubjectSelectorForRuleHash(hdr)->mClassList->mAtom);
     239             : }
     240             : 
     241             : static bool
     242          75 : RuleHash_IdCIMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
     243             : {
     244          75 :   return CIMatchAtoms(key, SubjectSelectorForRuleHash(hdr)->mIDList->mAtom);
     245             : }
     246             : 
     247             : static bool
     248        5063 : RuleHash_ClassCSMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
     249             : {
     250        5063 :   return CSMatchAtoms(key, SubjectSelectorForRuleHash(hdr)->mClassList->mAtom);
     251             : }
     252             : 
     253             : static bool
     254        2178 : RuleHash_IdCSMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
     255             : {
     256        2178 :   return CSMatchAtoms(key, SubjectSelectorForRuleHash(hdr)->mIDList->mAtom);
     257             : }
     258             : 
     259             : static void
     260        2357 : RuleHash_InitEntry(PLDHashEntryHdr *hdr, const void *key)
     261             : {
     262        2357 :   RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(hdr);
     263        2357 :   new (KnownNotNull, entry) RuleHashTableEntry();
     264        2357 : }
     265             : 
     266             : static void
     267         590 : RuleHash_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
     268             : {
     269         590 :   RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(hdr);
     270         590 :   entry->~RuleHashTableEntry();
     271         590 : }
     272             : 
     273             : static void
     274        2940 : RuleHash_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
     275             :                    PLDHashEntryHdr *to)
     276             : {
     277        2940 :   NS_PRECONDITION(from != to, "This is not going to work!");
     278             :   RuleHashTableEntry *oldEntry =
     279             :     const_cast<RuleHashTableEntry*>(
     280        2940 :       static_cast<const RuleHashTableEntry*>(from));
     281        2940 :   auto* newEntry = new (KnownNotNull, to) RuleHashTableEntry();
     282        2940 :   newEntry->mRules.SwapElements(oldEntry->mRules);
     283        2940 :   oldEntry->~RuleHashTableEntry();
     284        2940 : }
     285             : 
     286             : static bool
     287        8700 : RuleHash_TagTable_MatchEntry(const PLDHashEntryHdr *hdr, const void *key)
     288             : {
     289        8700 :   nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     290        8700 :   nsIAtom *entry_atom = static_cast<const RuleHashTagTableEntry*>(hdr)->mTag;
     291             : 
     292        8700 :   return match_atom == entry_atom;
     293             : }
     294             : 
     295             : static void
     296        2133 : RuleHash_TagTable_InitEntry(PLDHashEntryHdr *hdr, const void *key)
     297             : {
     298        2133 :   RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>(hdr);
     299        2133 :   new (KnownNotNull, entry) RuleHashTagTableEntry();
     300        2133 :   entry->mTag = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     301        2133 : }
     302             : 
     303             : static void
     304          51 : RuleHash_TagTable_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
     305             : {
     306          51 :   RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>(hdr);
     307          51 :   entry->~RuleHashTagTableEntry();
     308          51 : }
     309             : 
     310             : static void
     311        2730 : RuleHash_TagTable_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
     312             :                             PLDHashEntryHdr *to)
     313             : {
     314        2730 :   NS_PRECONDITION(from != to, "This is not going to work!");
     315             :   RuleHashTagTableEntry *oldEntry =
     316             :     const_cast<RuleHashTagTableEntry*>(
     317        2730 :       static_cast<const RuleHashTagTableEntry*>(from));
     318        2730 :   auto* newEntry = new (KnownNotNull, to) RuleHashTagTableEntry();
     319        2730 :   newEntry->mTag.swap(oldEntry->mTag);
     320        2730 :   newEntry->mRules.SwapElements(oldEntry->mRules);
     321        2730 :   oldEntry->~RuleHashTagTableEntry();
     322        2730 : }
     323             : 
     324             : static PLDHashNumber
     325        4820 : RuleHash_NameSpaceTable_HashKey(const void *key)
     326             : {
     327        4820 :   return HashGeneric(key);
     328             : }
     329             : 
     330             : static bool
     331        4715 : RuleHash_NameSpaceTable_MatchEntry(const PLDHashEntryHdr *hdr, const void *key)
     332             : {
     333             :   const RuleHashTableEntry *entry =
     334        4715 :     static_cast<const RuleHashTableEntry*>(hdr);
     335             : 
     336        4715 :   nsCSSSelector* selector = entry->mRules[0].mSelector;
     337        4715 :   if (selector->IsPseudoElement()) {
     338          24 :     selector = selector->mNext;
     339             :   }
     340        4715 :   return NS_PTR_TO_INT32(key) == selector->mNameSpace;
     341             : }
     342             : 
     343             : static const PLDHashTableOps RuleHash_TagTable_Ops = {
     344             :   PLDHashTable::HashVoidPtrKeyStub,
     345             :   RuleHash_TagTable_MatchEntry,
     346             :   RuleHash_TagTable_MoveEntry,
     347             :   RuleHash_TagTable_ClearEntry,
     348             :   RuleHash_TagTable_InitEntry
     349             : };
     350             : 
     351             : // Case-sensitive ops.
     352             : static const PLDHashTableOps RuleHash_ClassTable_CSOps = {
     353             :   PLDHashTable::HashVoidPtrKeyStub,
     354             :   RuleHash_ClassCSMatchEntry,
     355             :   RuleHash_MoveEntry,
     356             :   RuleHash_ClearEntry,
     357             :   RuleHash_InitEntry
     358             : };
     359             : 
     360             : // Case-insensitive ops.
     361             : static const PLDHashTableOps RuleHash_ClassTable_CIOps = {
     362             :   RuleHash_CIHashKey,
     363             :   RuleHash_ClassCIMatchEntry,
     364             :   RuleHash_MoveEntry,
     365             :   RuleHash_ClearEntry,
     366             :   RuleHash_InitEntry
     367             : };
     368             : 
     369             : // Case-sensitive ops.
     370             : static const PLDHashTableOps RuleHash_IdTable_CSOps = {
     371             :   PLDHashTable::HashVoidPtrKeyStub,
     372             :   RuleHash_IdCSMatchEntry,
     373             :   RuleHash_MoveEntry,
     374             :   RuleHash_ClearEntry,
     375             :   RuleHash_InitEntry
     376             : };
     377             : 
     378             : // Case-insensitive ops.
     379             : static const PLDHashTableOps RuleHash_IdTable_CIOps = {
     380             :   RuleHash_CIHashKey,
     381             :   RuleHash_IdCIMatchEntry,
     382             :   RuleHash_MoveEntry,
     383             :   RuleHash_ClearEntry,
     384             :   RuleHash_InitEntry
     385             : };
     386             : 
     387             : static const PLDHashTableOps RuleHash_NameSpaceTable_Ops = {
     388             :   RuleHash_NameSpaceTable_HashKey,
     389             :   RuleHash_NameSpaceTable_MatchEntry,
     390             :   RuleHash_MoveEntry,
     391             :   RuleHash_ClearEntry,
     392             :   RuleHash_InitEntry
     393             : };
     394             : 
     395             : #undef RULE_HASH_STATS
     396             : #undef PRINT_UNIVERSAL_RULES
     397             : 
     398             : #ifdef RULE_HASH_STATS
     399             : #define RULE_HASH_STAT_INCREMENT(var_) PR_BEGIN_MACRO ++(var_); PR_END_MACRO
     400             : #else
     401             : #define RULE_HASH_STAT_INCREMENT(var_) PR_BEGIN_MACRO PR_END_MACRO
     402             : #endif
     403             : 
     404             : struct NodeMatchContext;
     405             : 
     406             : class RuleHash {
     407             : public:
     408             :   explicit RuleHash(bool aQuirksMode);
     409             :   ~RuleHash();
     410             :   void AppendRule(const RuleSelectorPair &aRuleInfo);
     411             :   void EnumerateAllRules(Element* aElement, ElementDependentRuleProcessorData* aData,
     412             :                          NodeMatchContext& aNodeMatchContext);
     413             : 
     414             :   size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
     415             :   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
     416             : 
     417             : protected:
     418             :   typedef nsTArray<RuleValue> RuleValueList;
     419             :   void AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
     420             :                          const RuleSelectorPair& aRuleInfo);
     421             :   void AppendUniversalRule(const RuleSelectorPair& aRuleInfo);
     422             : 
     423             :   int32_t     mRuleCount;
     424             : 
     425             :   PLDHashTable mIdTable;
     426             :   PLDHashTable mClassTable;
     427             :   PLDHashTable mTagTable;
     428             :   PLDHashTable mNameSpaceTable;
     429             :   RuleValueList mUniversalRules;
     430             : 
     431             :   struct EnumData {
     432             :     const RuleValue* mCurValue;
     433             :     const RuleValue* mEnd;
     434             :   };
     435             :   EnumData* mEnumList;
     436             :   int32_t   mEnumListSize;
     437             : 
     438             :   bool mQuirksMode;
     439             : 
     440       15317 :   inline EnumData ToEnumData(const RuleValueList& arr) {
     441       15317 :     EnumData data = { arr.Elements(), arr.Elements() + arr.Length() };
     442       15317 :     return data;
     443             :   }
     444             : 
     445             : #ifdef RULE_HASH_STATS
     446             :   uint32_t    mUniversalSelectors;
     447             :   uint32_t    mNameSpaceSelectors;
     448             :   uint32_t    mTagSelectors;
     449             :   uint32_t    mClassSelectors;
     450             :   uint32_t    mIdSelectors;
     451             : 
     452             :   uint32_t    mElementsMatched;
     453             : 
     454             :   uint32_t    mElementUniversalCalls;
     455             :   uint32_t    mElementNameSpaceCalls;
     456             :   uint32_t    mElementTagCalls;
     457             :   uint32_t    mElementClassCalls;
     458             :   uint32_t    mElementIdCalls;
     459             : #endif // RULE_HASH_STATS
     460             : };
     461             : 
     462         211 : RuleHash::RuleHash(bool aQuirksMode)
     463             :   : mRuleCount(0),
     464             :     mIdTable(aQuirksMode ? &RuleHash_IdTable_CIOps
     465             :                          : &RuleHash_IdTable_CSOps,
     466             :              sizeof(RuleHashTableEntry)),
     467             :     mClassTable(aQuirksMode ? &RuleHash_ClassTable_CIOps
     468             :                             : &RuleHash_ClassTable_CSOps,
     469             :                 sizeof(RuleHashTableEntry)),
     470             :     mTagTable(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
     471             :     mNameSpaceTable(&RuleHash_NameSpaceTable_Ops, sizeof(RuleHashTableEntry)),
     472             :     mUniversalRules(0),
     473             :     mEnumList(nullptr), mEnumListSize(0),
     474         211 :     mQuirksMode(aQuirksMode)
     475             : #ifdef RULE_HASH_STATS
     476             :     ,
     477             :     mUniversalSelectors(0),
     478             :     mNameSpaceSelectors(0),
     479             :     mTagSelectors(0),
     480             :     mClassSelectors(0),
     481             :     mIdSelectors(0),
     482             :     mElementsMatched(0),
     483             :     mElementUniversalCalls(0),
     484             :     mElementNameSpaceCalls(0),
     485             :     mElementTagCalls(0),
     486             :     mElementClassCalls(0),
     487             :     mElementIdCalls(0)
     488             : #endif
     489             : {
     490         211 :   MOZ_COUNT_CTOR(RuleHash);
     491         211 : }
     492             : 
     493           8 : RuleHash::~RuleHash()
     494             : {
     495           4 :   MOZ_COUNT_DTOR(RuleHash);
     496             : #ifdef RULE_HASH_STATS
     497             :   printf(
     498             : "RuleHash(%p):\n"
     499             : "  Selectors: Universal (%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
     500             : "  Content Nodes: Elements(%u)\n"
     501             : "  Element Calls: Universal(%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
     502             :          static_cast<void*>(this),
     503             :          mUniversalSelectors, mNameSpaceSelectors, mTagSelectors,
     504             :            mClassSelectors, mIdSelectors,
     505             :          mElementsMatched,
     506             :          mElementUniversalCalls, mElementNameSpaceCalls, mElementTagCalls,
     507             :            mElementClassCalls, mElementIdCalls);
     508             : #ifdef PRINT_UNIVERSAL_RULES
     509             :   {
     510             :     if (mUniversalRules.Length() > 0) {
     511             :       printf("  Universal rules:\n");
     512             :       for (uint32_t i = 0; i < mUniversalRules.Length(); ++i) {
     513             :         RuleValue* value = &(mUniversalRules[i]);
     514             :         nsAutoString selectorText;
     515             :         uint32_t lineNumber = value->mRule->GetLineNumber();
     516             :         RefPtr<CSSStyleSheet> cssSheet = value->mRule->GetStyleSheet();
     517             :         value->mSelector->ToString(selectorText, cssSheet);
     518             : 
     519             :         printf("    line %d, %s\n",
     520             :                lineNumber, NS_ConvertUTF16toUTF8(selectorText).get());
     521             :       }
     522             :     }
     523             :   }
     524             : #endif // PRINT_UNIVERSAL_RULES
     525             : #endif // RULE_HASH_STATS
     526             :   // Rule Values are arena allocated no need to delete them. Their destructor
     527             :   // isn't doing any cleanup. So we dont even bother to enumerate through
     528             :   // the hash tables and call their destructors.
     529           4 :   if (nullptr != mEnumList) {
     530           3 :     delete [] mEnumList;
     531             :   }
     532           4 : }
     533             : 
     534        7484 : void RuleHash::AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
     535             :                                  const RuleSelectorPair& aRuleInfo)
     536             : {
     537             :   // Get a new or existing entry.
     538        7484 :   auto entry = static_cast<RuleHashTableEntry*>(aTable->Add(aKey, fallible));
     539        7484 :   if (!entry)
     540           0 :     return;
     541        7484 :   entry->mRules.AppendElement(RuleValue(aRuleInfo, mRuleCount++, mQuirksMode));
     542             : }
     543             : 
     544             : static void
     545        6915 : AppendRuleToTagTable(PLDHashTable* aTable, nsIAtom* aKey,
     546             :                      const RuleValue& aRuleInfo)
     547             : {
     548             :   // Get a new or exisiting entry
     549        6915 :   auto entry = static_cast<RuleHashTagTableEntry*>(aTable->Add(aKey, fallible));
     550        6915 :   if (!entry)
     551           0 :     return;
     552             : 
     553        6915 :   entry->mRules.AppendElement(aRuleInfo);
     554             : }
     555             : 
     556         195 : void RuleHash::AppendUniversalRule(const RuleSelectorPair& aRuleInfo)
     557             : {
     558         195 :   mUniversalRules.AppendElement(RuleValue(aRuleInfo, mRuleCount++, mQuirksMode));
     559         195 : }
     560             : 
     561       14140 : void RuleHash::AppendRule(const RuleSelectorPair& aRuleInfo)
     562             : {
     563       14140 :   nsCSSSelector *selector = aRuleInfo.mSelector;
     564       14140 :   if (selector->IsPseudoElement()) {
     565         696 :     selector = selector->mNext;
     566             :   }
     567       14140 :   if (nullptr != selector->mIDList) {
     568        2755 :     AppendRuleToTable(&mIdTable, selector->mIDList->mAtom, aRuleInfo);
     569             :     RULE_HASH_STAT_INCREMENT(mIdSelectors);
     570             :   }
     571       11385 :   else if (nullptr != selector->mClassList) {
     572        4494 :     AppendRuleToTable(&mClassTable, selector->mClassList->mAtom, aRuleInfo);
     573             :     RULE_HASH_STAT_INCREMENT(mClassSelectors);
     574             :   }
     575        6891 :   else if (selector->mLowercaseTag) {
     576        6461 :     RuleValue ruleValue(aRuleInfo, mRuleCount++, mQuirksMode);
     577        6461 :     AppendRuleToTagTable(&mTagTable, selector->mLowercaseTag, ruleValue);
     578             :     RULE_HASH_STAT_INCREMENT(mTagSelectors);
     579       12922 :     if (selector->mCasedTag &&
     580       12922 :         selector->mCasedTag != selector->mLowercaseTag) {
     581           8 :       AppendRuleToTagTable(&mTagTable, selector->mCasedTag, ruleValue);
     582             :       RULE_HASH_STAT_INCREMENT(mTagSelectors);
     583             :     }
     584             :   }
     585         430 :   else if (kNameSpaceID_Unknown != selector->mNameSpace) {
     586         235 :     AppendRuleToTable(&mNameSpaceTable,
     587         470 :                       NS_INT32_TO_PTR(selector->mNameSpace), aRuleInfo);
     588             :     RULE_HASH_STAT_INCREMENT(mNameSpaceSelectors);
     589             :   }
     590             :   else {  // universal tag selector
     591         195 :     AppendUniversalRule(aRuleInfo);
     592             :     RULE_HASH_STAT_INCREMENT(mUniversalSelectors);
     593             :   }
     594       14140 : }
     595             : 
     596             : // this should cover practically all cases so we don't need to reallocate
     597             : #define MIN_ENUM_LIST_SIZE 8
     598             : 
     599             : #ifdef RULE_HASH_STATS
     600             : #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
     601             :   (var_) += (list_).Length()
     602             : #else
     603             : #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
     604             :   PR_BEGIN_MACRO PR_END_MACRO
     605             : #endif
     606             : 
     607             : static inline
     608             : void ContentEnumFunc(const RuleValue &value, nsCSSSelector* selector,
     609             :                      ElementDependentRuleProcessorData* data, NodeMatchContext& nodeContext,
     610             :                      AncestorFilter *ancestorFilter);
     611             : 
     612        8768 : void RuleHash::EnumerateAllRules(Element* aElement, ElementDependentRuleProcessorData* aData,
     613             :                                  NodeMatchContext& aNodeContext)
     614             : {
     615        8768 :   int32_t nameSpace = aElement->GetNameSpaceID();
     616        8768 :   nsIAtom* tag = aElement->NodeInfo()->NameAtom();
     617        8768 :   nsIAtom* id = aElement->GetID();
     618        8768 :   const nsAttrValue* classList = aElement->GetClasses();
     619             : 
     620        8768 :   MOZ_ASSERT(tag, "How could we not have a tag?");
     621             : 
     622        8768 :   int32_t classCount = classList ? classList->GetAtomCount() : 0;
     623             : 
     624             :   // assume 1 universal, tag, id, and namespace, rather than wasting
     625             :   // time counting
     626        8768 :   int32_t testCount = classCount + 4;
     627             : 
     628        8768 :   if (mEnumListSize < testCount) {
     629          55 :     delete [] mEnumList;
     630          55 :     mEnumListSize = std::max(testCount, MIN_ENUM_LIST_SIZE);
     631         110 :     mEnumList = new EnumData[mEnumListSize];
     632             :   }
     633             : 
     634        8768 :   int32_t valueCount = 0;
     635             :   RULE_HASH_STAT_INCREMENT(mElementsMatched);
     636             : 
     637        8768 :   if (mUniversalRules.Length() != 0) { // universal rules
     638        4594 :     mEnumList[valueCount++] = ToEnumData(mUniversalRules);
     639             :     RULE_HASH_STAT_INCREMENT_LIST_COUNT(mUniversalRules, mElementUniversalCalls);
     640             :   }
     641             :   // universal rules within the namespace
     642        8768 :   if (kNameSpaceID_Unknown != nameSpace && mNameSpaceTable.EntryCount() > 0) {
     643             :     auto entry = static_cast<RuleHashTableEntry*>
     644        4585 :       (mNameSpaceTable.Search(NS_INT32_TO_PTR(nameSpace)));
     645        4585 :     if (entry) {
     646        4525 :       mEnumList[valueCount++] = ToEnumData(entry->mRules);
     647             :       RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementNameSpaceCalls);
     648             :     }
     649             :   }
     650        8768 :   if (mTagTable.EntryCount() > 0) {
     651        7626 :     auto entry = static_cast<RuleHashTableEntry*>(mTagTable.Search(tag));
     652        7626 :     if (entry) {
     653        3738 :       mEnumList[valueCount++] = ToEnumData(entry->mRules);
     654             :       RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementTagCalls);
     655             :     }
     656             :   }
     657        8768 :   if (id && mIdTable.EntryCount() > 0) {
     658        2832 :     auto entry = static_cast<RuleHashTableEntry*>(mIdTable.Search(id));
     659        2832 :     if (entry) {
     660         471 :       mEnumList[valueCount++] = ToEnumData(entry->mRules);
     661             :       RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementIdCalls);
     662             :     }
     663             :   }
     664        8768 :   if (mClassTable.EntryCount() > 0) {
     665       12317 :     for (int32_t index = 0; index < classCount; ++index) {
     666             :       auto entry = static_cast<RuleHashTableEntry*>
     667        5164 :         (mClassTable.Search(classList->AtomAt(index)));
     668        5164 :       if (entry) {
     669        1989 :         mEnumList[valueCount++] = ToEnumData(entry->mRules);
     670             :         RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementClassCalls);
     671             :       }
     672             :     }
     673             :   }
     674        8768 :   NS_ASSERTION(valueCount <= testCount, "values exceeded list size");
     675             : 
     676        8768 :   if (valueCount > 0) {
     677             :     AncestorFilter *filter =
     678       10689 :       aData->mTreeMatchContext.mAncestorFilter.HasFilter() ?
     679       10689 :         &aData->mTreeMatchContext.mAncestorFilter : nullptr;
     680             : #ifdef DEBUG
     681        5687 :     if (filter) {
     682        5002 :       filter->AssertHasAllAncestors(aElement);
     683             :     }
     684             : #endif
     685             :     // Merge the lists while there are still multiple lists to merge.
     686      314581 :     while (valueCount > 1) {
     687      154447 :       int32_t valueIndex = 0;
     688      154447 :       int32_t lowestRuleIndex = mEnumList[valueIndex].mCurValue->mIndex;
     689      453201 :       for (int32_t index = 1; index < valueCount; ++index) {
     690      298754 :         int32_t ruleIndex = mEnumList[index].mCurValue->mIndex;
     691      298754 :         if (ruleIndex < lowestRuleIndex) {
     692      103408 :           valueIndex = index;
     693      103408 :           lowestRuleIndex = ruleIndex;
     694             :         }
     695             :       }
     696      154447 :       const RuleValue *cur = mEnumList[valueIndex].mCurValue;
     697      154447 :       ContentEnumFunc(*cur, cur->mSelector, aData, aNodeContext, filter);
     698      154447 :       cur++;
     699      154447 :       if (cur == mEnumList[valueIndex].mEnd) {
     700        9630 :         mEnumList[valueIndex] = mEnumList[--valueCount];
     701             :       } else {
     702      144817 :         mEnumList[valueIndex].mCurValue = cur;
     703             :       }
     704             :     }
     705             : 
     706             :     // Fast loop over single value.
     707       38438 :     for (const RuleValue *value = mEnumList[0].mCurValue,
     708        5687 :                          *end = mEnumList[0].mEnd;
     709       38438 :          value != end; ++value) {
     710       32751 :       ContentEnumFunc(*value, value->mSelector, aData, aNodeContext, filter);
     711             :     }
     712             :   }
     713        8768 : }
     714             : 
     715             : static size_t
     716          12 : SizeOfRuleHashTable(const PLDHashTable& aTable, MallocSizeOf aMallocSizeOf)
     717             : {
     718          12 :   size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
     719          15 :   for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
     720           3 :     auto entry = static_cast<RuleHashTableEntry*>(iter.Get());
     721           3 :     n += entry->mRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
     722             :   }
     723          12 :   return n;
     724             : }
     725             : 
     726             : size_t
     727           2 : RuleHash::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
     728             : {
     729           2 :   size_t n = 0;
     730             : 
     731           2 :   n += SizeOfRuleHashTable(mIdTable, aMallocSizeOf);
     732             : 
     733           2 :   n += SizeOfRuleHashTable(mClassTable, aMallocSizeOf);
     734             : 
     735           2 :   n += SizeOfRuleHashTable(mTagTable, aMallocSizeOf);
     736             : 
     737           2 :   n += SizeOfRuleHashTable(mNameSpaceTable, aMallocSizeOf);
     738             : 
     739           2 :   n += mUniversalRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
     740             : 
     741           2 :   return n;
     742             : }
     743             : 
     744             : size_t
     745           0 : RuleHash::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     746             : {
     747           0 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     748             : }
     749             : 
     750             : //--------------------------------
     751             : 
     752             : /**
     753             :  * A struct that stores an nsCSSSelector pointer along side a pointer to
     754             :  * the rightmost nsCSSSelector in the selector.  For example, for
     755             :  *
     756             :  *   .main p > span
     757             :  *
     758             :  * if mSelector points to the |p| nsCSSSelector, mRightmostSelector would
     759             :  * point to the |span| nsCSSSelector.
     760             :  *
     761             :  * Both mSelector and mRightmostSelector are always top-level selectors,
     762             :  * i.e. they aren't selectors within a :not() or :-moz-any().
     763             :  */
     764             : struct SelectorPair
     765             : {
     766       19679 :   SelectorPair(nsCSSSelector* aSelector, nsCSSSelector* aRightmostSelector)
     767       19679 :     : mSelector(aSelector), mRightmostSelector(aRightmostSelector)
     768             :   {
     769       19679 :     MOZ_ASSERT(aSelector);
     770       19679 :     MOZ_ASSERT(mRightmostSelector);
     771       19679 :   }
     772             :   SelectorPair(const SelectorPair& aOther) = default;
     773             :   nsCSSSelector* const mSelector;
     774             :   nsCSSSelector* const mRightmostSelector;
     775             : };
     776             : 
     777             : // A hash table mapping atoms to lists of selectors
     778       12502 : struct AtomSelectorEntry : public PLDHashEntryHdr {
     779             :   nsIAtom *mAtom;
     780             :   // Auto length 2, because a decent fraction of these arrays ends up
     781             :   // with 2 elements, and each entry is cheap.
     782             :   AutoTArray<SelectorPair, 2> mSelectors;
     783             : };
     784             : 
     785             : static void
     786         850 : AtomSelector_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
     787             : {
     788         850 :   (static_cast<AtomSelectorEntry*>(hdr))->~AtomSelectorEntry();
     789         850 : }
     790             : 
     791             : static void
     792        3588 : AtomSelector_InitEntry(PLDHashEntryHdr *hdr, const void *key)
     793             : {
     794        3588 :   AtomSelectorEntry *entry = static_cast<AtomSelectorEntry*>(hdr);
     795        3588 :   new (KnownNotNull, entry) AtomSelectorEntry();
     796        3588 :   entry->mAtom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     797        3588 : }
     798             : 
     799             : static void
     800        4032 : AtomSelector_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
     801             :                        PLDHashEntryHdr *to)
     802             : {
     803        4032 :   NS_PRECONDITION(from != to, "This is not going to work!");
     804             :   AtomSelectorEntry *oldEntry =
     805        4032 :     const_cast<AtomSelectorEntry*>(static_cast<const AtomSelectorEntry*>(from));
     806        4032 :   auto* newEntry = new (KnownNotNull, to) AtomSelectorEntry();
     807        4032 :   newEntry->mAtom = oldEntry->mAtom;
     808        4032 :   newEntry->mSelectors.SwapElements(oldEntry->mSelectors);
     809        4032 :   oldEntry->~AtomSelectorEntry();
     810        4032 : }
     811             : 
     812             : static bool
     813         299 : AtomSelector_CIMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
     814             : {
     815         299 :   const AtomSelectorEntry *entry = static_cast<const AtomSelectorEntry*>(hdr);
     816         299 :   return CIMatchAtoms(key, entry->mAtom);
     817             : }
     818             : 
     819             : // Case-sensitive ops.
     820             : static const PLDHashTableOps AtomSelector_CSOps = {
     821             :   PLDHashTable::HashVoidPtrKeyStub,
     822             :   PLDHashTable::MatchEntryStub,
     823             :   AtomSelector_MoveEntry,
     824             :   AtomSelector_ClearEntry,
     825             :   AtomSelector_InitEntry
     826             : };
     827             : 
     828             : // Case-insensitive ops.
     829             : static const PLDHashTableOps AtomSelector_CIOps = {
     830             :   RuleHash_CIHashKey,
     831             :   AtomSelector_CIMatchEntry,
     832             :   AtomSelector_MoveEntry,
     833             :   AtomSelector_ClearEntry,
     834             :   AtomSelector_InitEntry
     835             : };
     836             : 
     837             : //--------------------------------
     838             : 
     839             : struct RuleCascadeData {
     840          42 :   RuleCascadeData(nsIAtom *aMedium, bool aQuirksMode)
     841          42 :     : mRuleHash(aQuirksMode),
     842             :       mStateSelectors(),
     843             :       mSelectorDocumentStates(0),
     844             :       mClassSelectors(aQuirksMode ? &AtomSelector_CIOps
     845             :                                   : &AtomSelector_CSOps,
     846             :                       sizeof(AtomSelectorEntry)),
     847             :       mIdSelectors(aQuirksMode ? &AtomSelector_CIOps
     848             :                                : &AtomSelector_CSOps,
     849             :                    sizeof(AtomSelectorEntry)),
     850             :       // mAttributeSelectors is matching on the attribute _name_, not the
     851             :       // value, and we case-fold names at parse-time, so this is a
     852             :       // case-sensitive match.
     853             :       mAttributeSelectors(&AtomSelector_CSOps, sizeof(AtomSelectorEntry)),
     854             :       mAnonBoxRules(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
     855             : #ifdef MOZ_XUL
     856             :       mXULTreeRules(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
     857             : #endif
     858             :       mKeyframesRuleTable(),
     859             :       mCounterStyleRuleTable(),
     860             :       mCacheKey(aMedium),
     861             :       mNext(nullptr),
     862          42 :       mQuirksMode(aQuirksMode)
     863             :   {
     864          42 :     memset(mPseudoElementRuleHashes, 0, sizeof(mPseudoElementRuleHashes));
     865          42 :   }
     866             : 
     867           1 :   ~RuleCascadeData()
     868           1 :   {
     869          26 :     for (uint32_t i = 0; i < ArrayLength(mPseudoElementRuleHashes); ++i) {
     870          25 :       delete mPseudoElementRuleHashes[i];
     871             :     }
     872           1 :   }
     873             : 
     874             :   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
     875             : 
     876             :   RuleHash                 mRuleHash;
     877             :   RuleHash*                mPseudoElementRuleHashes[
     878             :     static_cast<CSSPseudoElementTypeBase>(CSSPseudoElementType::Count)];
     879             :   nsTArray<nsCSSRuleProcessor::StateSelector>  mStateSelectors;
     880             :   EventStates              mSelectorDocumentStates;
     881             :   PLDHashTable             mClassSelectors;
     882             :   PLDHashTable             mIdSelectors;
     883             :   nsTArray<nsCSSSelector*> mPossiblyNegatedClassSelectors;
     884             :   nsTArray<nsCSSSelector*> mPossiblyNegatedIDSelectors;
     885             :   PLDHashTable             mAttributeSelectors;
     886             :   PLDHashTable             mAnonBoxRules;
     887             : #ifdef MOZ_XUL
     888             :   PLDHashTable             mXULTreeRules;
     889             : #endif
     890             : 
     891             :   nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
     892             :   nsTArray<nsCSSKeyframesRule*> mKeyframesRules;
     893             :   nsTArray<nsCSSFontFeatureValuesRule*> mFontFeatureValuesRules;
     894             :   nsTArray<nsCSSPageRule*> mPageRules;
     895             :   nsTArray<nsCSSCounterStyleRule*> mCounterStyleRules;
     896             : 
     897             :   nsDataHashtable<nsStringHashKey, nsCSSKeyframesRule*> mKeyframesRuleTable;
     898             :   // The hashtable doesn't need to hold a strong reference to the name
     899             :   // atom, because nsCSSCounterStyleRule always does. If the name changes
     900             :   // we need to discard this table and rebuild it anyway.
     901             :   nsDataHashtable<nsPtrHashKey<nsIAtom>,
     902             :                   nsCSSCounterStyleRule*> mCounterStyleRuleTable;
     903             : 
     904             :   // Looks up or creates the appropriate list in |mAttributeSelectors|.
     905             :   // Returns null only on allocation failure.
     906             :   nsTArray<SelectorPair>* AttributeListFor(nsIAtom* aAttribute);
     907             : 
     908             :   nsMediaQueryResultCacheKey mCacheKey;
     909             :   RuleCascadeData*  mNext; // for a different medium
     910             : 
     911             :   const bool mQuirksMode;
     912             : };
     913             : 
     914             : static size_t
     915           6 : SizeOfSelectorsHashTable(const PLDHashTable& aTable, MallocSizeOf aMallocSizeOf)
     916             : {
     917           6 :   size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
     918           6 :   for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
     919           0 :     auto entry = static_cast<AtomSelectorEntry*>(iter.Get());
     920           0 :     n += entry->mSelectors.ShallowSizeOfExcludingThis(aMallocSizeOf);
     921             :   }
     922           6 :   return n;
     923             : }
     924             : 
     925             : size_t
     926           2 : RuleCascadeData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     927             : {
     928           2 :   size_t n = aMallocSizeOf(this);
     929             : 
     930           2 :   n += mRuleHash.SizeOfExcludingThis(aMallocSizeOf);
     931          52 :   for (uint32_t i = 0; i < ArrayLength(mPseudoElementRuleHashes); ++i) {
     932          50 :     if (mPseudoElementRuleHashes[i])
     933           0 :       n += mPseudoElementRuleHashes[i]->SizeOfIncludingThis(aMallocSizeOf);
     934             :   }
     935             : 
     936           2 :   n += mStateSelectors.ShallowSizeOfExcludingThis(aMallocSizeOf);
     937             : 
     938           2 :   n += SizeOfSelectorsHashTable(mIdSelectors, aMallocSizeOf);
     939           2 :   n += SizeOfSelectorsHashTable(mClassSelectors, aMallocSizeOf);
     940             : 
     941           2 :   n += mPossiblyNegatedClassSelectors.ShallowSizeOfExcludingThis(aMallocSizeOf);
     942           2 :   n += mPossiblyNegatedIDSelectors.ShallowSizeOfExcludingThis(aMallocSizeOf);
     943             : 
     944           2 :   n += SizeOfSelectorsHashTable(mAttributeSelectors, aMallocSizeOf);
     945           2 :   n += SizeOfRuleHashTable(mAnonBoxRules, aMallocSizeOf);
     946             : #ifdef MOZ_XUL
     947           2 :   n += SizeOfRuleHashTable(mXULTreeRules, aMallocSizeOf);
     948             : #endif
     949             : 
     950           2 :   n += mFontFaceRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
     951           2 :   n += mKeyframesRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
     952           2 :   n += mFontFeatureValuesRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
     953           2 :   n += mPageRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
     954           2 :   n += mCounterStyleRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
     955             : 
     956           2 :   n += mKeyframesRuleTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
     957           2 :   for (auto iter = mKeyframesRuleTable.ConstIter(); !iter.Done(); iter.Next()) {
     958             :     // We don't own the nsCSSKeyframesRule objects so we don't count them. We
     959             :     // do care about the size of the keys' nsAString members' buffers though.
     960             :     //
     961             :     // Note that we depend on nsStringHashKey::GetKey() returning a reference,
     962             :     // since otherwise aKey would be a copy of the string key and we would not
     963             :     // be measuring the right object here.
     964           0 :     n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     965             :   }
     966             : 
     967           2 :   return n;
     968             : }
     969             : 
     970             : nsTArray<SelectorPair>*
     971        7460 : RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
     972             : {
     973             :   auto entry = static_cast<AtomSelectorEntry*>
     974        7460 :                           (mAttributeSelectors.Add(aAttribute, fallible));
     975        7460 :   if (!entry)
     976           0 :     return nullptr;
     977        7460 :   return &entry->mSelectors;
     978             : }
     979             : 
     980             : // -------------------------------
     981             : // CSS Style rule processor implementation
     982             : //
     983             : 
     984          22 : nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets,
     985             :                                        SheetType aSheetType,
     986             :                                        Element* aScopeElement,
     987             :                                        nsCSSRuleProcessor*
     988             :                                          aPreviousCSSRuleProcessor,
     989          22 :                                        bool aIsShared)
     990          44 :   : nsCSSRuleProcessor(sheet_array_type(aSheets), aSheetType, aScopeElement,
     991          44 :                        aPreviousCSSRuleProcessor, aIsShared)
     992             : {
     993          22 : }
     994             : 
     995          54 : nsCSSRuleProcessor::nsCSSRuleProcessor(sheet_array_type&& aSheets,
     996             :                                        SheetType aSheetType,
     997             :                                        Element* aScopeElement,
     998             :                                        nsCSSRuleProcessor*
     999             :                                          aPreviousCSSRuleProcessor,
    1000          54 :                                        bool aIsShared)
    1001             :   : mSheets(aSheets)
    1002             :   , mRuleCascades(nullptr)
    1003             :   , mPreviousCacheKey(aPreviousCSSRuleProcessor
    1004             :                        ? aPreviousCSSRuleProcessor->CloneMQCacheKey()
    1005             :                        : UniquePtr<nsMediaQueryResultCacheKey>())
    1006             :   , mLastPresContext(nullptr)
    1007             :   , mScopeElement(aScopeElement)
    1008             :   , mStyleSetRefCnt(0)
    1009             :   , mSheetType(aSheetType)
    1010             :   , mIsShared(aIsShared)
    1011             :   , mMustGatherDocumentRules(aIsShared)
    1012             :   , mInRuleProcessorCache(false)
    1013             : #ifdef DEBUG
    1014          54 :   , mDocumentRulesAndCacheKeyValid(false)
    1015             : #endif
    1016             : {
    1017          54 :   NS_ASSERTION(!!mScopeElement == (aSheetType == SheetType::ScopedDoc),
    1018             :                "aScopeElement must be specified iff aSheetType is "
    1019             :                "eScopedDocSheet");
    1020         198 :   for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) {
    1021         144 :     mSheets[i]->AddRuleProcessor(this);
    1022             :   }
    1023          54 : }
    1024             : 
    1025          45 : nsCSSRuleProcessor::~nsCSSRuleProcessor()
    1026             : {
    1027          15 :   if (mInRuleProcessorCache) {
    1028           0 :     RuleProcessorCache::RemoveRuleProcessor(this);
    1029             :   }
    1030          15 :   MOZ_ASSERT(!mExpirationState.IsTracked());
    1031          15 :   MOZ_ASSERT(mStyleSetRefCnt == 0);
    1032          15 :   ClearSheets();
    1033          15 :   ClearRuleCascades();
    1034          45 : }
    1035             : 
    1036         160 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSRuleProcessor)
    1037          46 :   NS_INTERFACE_MAP_ENTRY(nsIStyleRuleProcessor)
    1038           0 : NS_INTERFACE_MAP_END
    1039             : 
    1040         145 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSRuleProcessor)
    1041          96 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSRuleProcessor)
    1042             : 
    1043             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSRuleProcessor)
    1044             : 
    1045           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSRuleProcessor)
    1046           0 :   tmp->ClearSheets();
    1047           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScopeElement)
    1048           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1049             : 
    1050           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSRuleProcessor)
    1051           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSheets)
    1052           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScopeElement)
    1053           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1054             : 
    1055             : void
    1056          15 : nsCSSRuleProcessor::ClearSheets()
    1057             : {
    1058          46 :   for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) {
    1059          31 :     mSheets[i]->DropRuleProcessor(this);
    1060             :   }
    1061          15 :   mSheets.Clear();
    1062          15 : }
    1063             : 
    1064             : /* static */ void
    1065           3 : nsCSSRuleProcessor::Startup()
    1066             : {
    1067             :   Preferences::AddBoolVarCache(&gSupportVisitedPseudo, VISITED_PSEUDO_PREF,
    1068           3 :                                true);
    1069           3 : }
    1070             : 
    1071             : /* static */ void
    1072         125 : nsCSSRuleProcessor::InitSystemMetrics()
    1073             : {
    1074         125 :   if (sSystemMetrics)
    1075         123 :     return;
    1076             : 
    1077           2 :   MOZ_ASSERT(NS_IsMainThread());
    1078             : 
    1079           2 :   sSystemMetrics = new nsTArray< nsCOMPtr<nsIAtom> >;
    1080             : 
    1081             :   /***************************************************************************
    1082             :    * ANY METRICS ADDED HERE SHOULD ALSO BE ADDED AS MEDIA QUERIES IN         *
    1083             :    * nsMediaFeatures.cpp                                                     *
    1084             :    ***************************************************************************/
    1085             : 
    1086             :   int32_t metricResult =
    1087           2 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollArrowStyle);
    1088           2 :   if (metricResult & LookAndFeel::eScrollArrow_StartBackward) {
    1089           0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_start_backward);
    1090             :   }
    1091           2 :   if (metricResult & LookAndFeel::eScrollArrow_StartForward) {
    1092           0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_start_forward);
    1093             :   }
    1094           2 :   if (metricResult & LookAndFeel::eScrollArrow_EndBackward) {
    1095           0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_end_backward);
    1096             :   }
    1097           2 :   if (metricResult & LookAndFeel::eScrollArrow_EndForward) {
    1098           0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_end_forward);
    1099             :   }
    1100             : 
    1101           2 :   metricResult =
    1102           2 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollSliderStyle);
    1103           2 :   if (metricResult != LookAndFeel::eScrollThumbStyle_Normal) {
    1104           2 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_thumb_proportional);
    1105             :   }
    1106             : 
    1107           2 :   metricResult =
    1108           2 :     LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars);
    1109           2 :   if (metricResult) {
    1110           0 :     sSystemMetrics->AppendElement(nsGkAtoms::overlay_scrollbars);
    1111             :   }
    1112             : 
    1113           2 :   metricResult =
    1114           2 :     LookAndFeel::GetInt(LookAndFeel::eIntID_MenuBarDrag);
    1115           2 :   if (metricResult) {
    1116           2 :     sSystemMetrics->AppendElement(nsGkAtoms::menubar_drag);
    1117             :   }
    1118             : 
    1119             :   nsresult rv =
    1120           2 :     LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsDefaultTheme, &metricResult);
    1121           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1122           0 :     sSystemMetrics->AppendElement(nsGkAtoms::windows_default_theme);
    1123             :   }
    1124             : 
    1125           2 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacGraphiteTheme, &metricResult);
    1126           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1127           0 :     sSystemMetrics->AppendElement(nsGkAtoms::mac_graphite_theme);
    1128             :   }
    1129             : 
    1130           2 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacYosemiteTheme, &metricResult);
    1131           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1132           0 :     sSystemMetrics->AppendElement(nsGkAtoms::mac_yosemite_theme);
    1133             :   }
    1134             : 
    1135           2 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsAccentColorApplies, &metricResult);
    1136           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1137           0 :     sSystemMetrics->AppendElement(nsGkAtoms::windows_accent_color_applies);
    1138             :   }
    1139             : 
    1140           2 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_DWMCompositor, &metricResult);
    1141           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1142           0 :     sSystemMetrics->AppendElement(nsGkAtoms::windows_compositor);
    1143             :   }
    1144             : 
    1145           2 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsGlass, &metricResult);
    1146           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1147           0 :     sSystemMetrics->AppendElement(nsGkAtoms::windows_glass);
    1148             :   }
    1149             : 
    1150           2 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_ColorPickerAvailable, &metricResult);
    1151           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1152           2 :     sSystemMetrics->AppendElement(nsGkAtoms::color_picker_available);
    1153             :   }
    1154             : 
    1155           2 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsClassic, &metricResult);
    1156           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1157           0 :     sSystemMetrics->AppendElement(nsGkAtoms::windows_classic);
    1158             :   }
    1159             : 
    1160           2 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_TouchEnabled, &metricResult);
    1161           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1162           0 :     sSystemMetrics->AppendElement(nsGkAtoms::touch_enabled);
    1163             :   }
    1164             : 
    1165             :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_SwipeAnimationEnabled,
    1166           2 :                            &metricResult);
    1167           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1168           0 :     sSystemMetrics->AppendElement(nsGkAtoms::swipe_animation_enabled);
    1169             :   }
    1170             : 
    1171             :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_PhysicalHomeButton,
    1172           2 :                            &metricResult);
    1173           2 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1174           0 :     sSystemMetrics->AppendElement(nsGkAtoms::physical_home_button);
    1175             :   }
    1176             : 
    1177             : #ifdef XP_WIN
    1178             :   if (NS_SUCCEEDED(
    1179             :         LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsThemeIdentifier,
    1180             :                             &metricResult))) {
    1181             :     nsCSSRuleProcessor::SetWindowsThemeIdentifier(static_cast<uint8_t>(metricResult));
    1182             :     switch(metricResult) {
    1183             :       case LookAndFeel::eWindowsTheme_Aero:
    1184             :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_aero);
    1185             :         break;
    1186             :       case LookAndFeel::eWindowsTheme_AeroLite:
    1187             :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_aero_lite);
    1188             :         break;
    1189             :       case LookAndFeel::eWindowsTheme_LunaBlue:
    1190             :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_blue);
    1191             :         break;
    1192             :       case LookAndFeel::eWindowsTheme_LunaOlive:
    1193             :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_olive);
    1194             :         break;
    1195             :       case LookAndFeel::eWindowsTheme_LunaSilver:
    1196             :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_silver);
    1197             :         break;
    1198             :       case LookAndFeel::eWindowsTheme_Royale:
    1199             :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_royale);
    1200             :         break;
    1201             :       case LookAndFeel::eWindowsTheme_Zune:
    1202             :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_zune);
    1203             :         break;
    1204             :       case LookAndFeel::eWindowsTheme_Generic:
    1205             :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_generic);
    1206             :         break;
    1207             :     }
    1208             :   }
    1209             : #endif
    1210             : }
    1211             : 
    1212             : /* static */ void
    1213           0 : nsCSSRuleProcessor::FreeSystemMetrics()
    1214             : {
    1215           0 :   delete sSystemMetrics;
    1216           0 :   sSystemMetrics = nullptr;
    1217           0 : }
    1218             : 
    1219             : /* static */ void
    1220           0 : nsCSSRuleProcessor::Shutdown()
    1221             : {
    1222           0 :   FreeSystemMetrics();
    1223           0 : }
    1224             : 
    1225             : /* static */ bool
    1226         125 : nsCSSRuleProcessor::HasSystemMetric(nsIAtom* aMetric)
    1227             : {
    1228         125 :   nsCSSRuleProcessor::InitSystemMetrics();
    1229         125 :   return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
    1230             : }
    1231             : 
    1232             : #ifdef XP_WIN
    1233             : /* static */ uint8_t
    1234             : nsCSSRuleProcessor::GetWindowsThemeIdentifier()
    1235             : {
    1236             :   nsCSSRuleProcessor::InitSystemMetrics();
    1237             :   return sWinThemeId;
    1238             : }
    1239             : #endif
    1240             : 
    1241             : /* static */
    1242             : EventStates
    1243        2501 : nsCSSRuleProcessor::GetContentState(Element* aElement, bool aUsingPrivateBrowsing)
    1244             : {
    1245        2501 :   EventStates state = aElement->StyleState();
    1246             : 
    1247             :   // If we are not supposed to mark visited links as such, be sure to
    1248             :   // flip the bits appropriately.  We want to do this here, rather
    1249             :   // than in GetContentStateForVisitedHandling, so that we don't
    1250             :   // expose that :visited support is disabled to the Web page.
    1251        2501 :   if (state.HasState(NS_EVENT_STATE_VISITED) &&
    1252           0 :       (!gSupportVisitedPseudo ||
    1253           0 :        aElement->OwnerDoc()->IsBeingUsedAsImage() ||
    1254             :        aUsingPrivateBrowsing)) {
    1255           0 :     state &= ~NS_EVENT_STATE_VISITED;
    1256           0 :     state |= NS_EVENT_STATE_UNVISITED;
    1257             :   }
    1258        2501 :   return state;
    1259             : }
    1260             : 
    1261             : /* static */
    1262             : EventStates
    1263        2501 : nsCSSRuleProcessor::GetContentState(Element* aElement, const TreeMatchContext& aTreeMatchContext)
    1264             : {
    1265             :   return nsCSSRuleProcessor::GetContentState(
    1266             :     aElement,
    1267        2501 :     aTreeMatchContext.mUsingPrivateBrowsing
    1268        2501 :   );
    1269             : }
    1270             : 
    1271             : /* static */
    1272             : EventStates
    1273           0 : nsCSSRuleProcessor::GetContentState(Element* aElement)
    1274             : {
    1275           0 :   nsILoadContext* loadContext = aElement->OwnerDoc()->GetLoadContext();
    1276           0 :   bool usingPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
    1277           0 :   return nsCSSRuleProcessor::GetContentState(aElement, usingPrivateBrowsing);
    1278             : }
    1279             : 
    1280             : /* static */
    1281             : bool
    1282       35881 : nsCSSRuleProcessor::IsLink(const Element* aElement)
    1283             : {
    1284       35881 :   EventStates state = aElement->StyleState();
    1285       35881 :   return state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
    1286             : }
    1287             : 
    1288             : /* static */
    1289             : EventStates
    1290       16978 : nsCSSRuleProcessor::GetContentStateForVisitedHandling(
    1291             :                      Element* aElement,
    1292             :                      nsRuleWalker::VisitedHandlingType aVisitedHandling,
    1293             :                      bool aIsRelevantLink)
    1294             : {
    1295             :   // It's unnecessary to call GetContentState() here (which may flip visited to
    1296             :   // unvisited) since this function will remove both unvisited and visited if
    1297             :   // either is set and produce a new value.
    1298       16978 :   EventStates state = aElement->StyleState();
    1299       16978 :   if (state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) {
    1300           0 :     MOZ_ASSERT(IsLink(aElement), "IsLink() should match state");
    1301           0 :     state &= ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
    1302           0 :     if (aIsRelevantLink) {
    1303           0 :       switch (aVisitedHandling) {
    1304             :         case nsRuleWalker::eRelevantLinkUnvisited:
    1305           0 :           state |= NS_EVENT_STATE_UNVISITED;
    1306           0 :           break;
    1307             :         case nsRuleWalker::eRelevantLinkVisited:
    1308           0 :           state |= NS_EVENT_STATE_VISITED;
    1309           0 :           break;
    1310             :         case nsRuleWalker::eLinksVisitedOrUnvisited:
    1311           0 :           state |= NS_EVENT_STATE_UNVISITED | NS_EVENT_STATE_VISITED;
    1312           0 :           break;
    1313             :       }
    1314             :     } else {
    1315           0 :       state |= NS_EVENT_STATE_UNVISITED;
    1316             :     }
    1317             :   }
    1318       16978 :   return state;
    1319             : }
    1320             : 
    1321             : /**
    1322             :  * A |NodeMatchContext| has data about matching a selector (without
    1323             :  * combinators) against a single node.  It contains only input to the
    1324             :  * matching.
    1325             :  *
    1326             :  * Unlike |RuleProcessorData|, which is similar, a |NodeMatchContext|
    1327             :  * can vary depending on the selector matching process.  In other words,
    1328             :  * there might be multiple NodeMatchContexts corresponding to a single
    1329             :  * node, but only one possible RuleProcessorData.
    1330             :  */
    1331             : struct NodeMatchContext {
    1332             :   // In order to implement nsCSSRuleProcessor::HasStateDependentStyle,
    1333             :   // we need to be able to see if a node might match an
    1334             :   // event-state-dependent selector for any value of that event state.
    1335             :   // So mStateMask contains the states that should NOT be tested.
    1336             :   //
    1337             :   // NOTE: For |mStateMask| to work correctly, it's important that any
    1338             :   // change that changes multiple state bits include all those state
    1339             :   // bits in the notification.  Otherwise, if multiple states change but
    1340             :   // we do separate notifications then we might determine the style is
    1341             :   // not state-dependent when it really is (e.g., determining that a
    1342             :   // :hover:active rule no longer matches when both states are unset).
    1343             :   const EventStates mStateMask;
    1344             : 
    1345             :   // Is this link the unique link whose visitedness can affect the style
    1346             :   // of the node being matched?  (That link is the nearest link to the
    1347             :   // node being matched that is itself or an ancestor.)
    1348             :   //
    1349             :   // Always false when TreeMatchContext::mForStyling is false.  (We
    1350             :   // could figure it out for SelectorListMatches, but we're starting
    1351             :   // from the middle of the selector list when doing
    1352             :   // Has{Attribute,State}DependentStyle, so we can't tell.  So when
    1353             :   // mForStyling is false, we have to assume we don't know.)
    1354             :   const bool mIsRelevantLink;
    1355             : 
    1356       49534 :   NodeMatchContext(EventStates aStateMask, bool aIsRelevantLink)
    1357       49534 :     : mStateMask(aStateMask)
    1358       49534 :     , mIsRelevantLink(aIsRelevantLink)
    1359             :   {
    1360       49534 :   }
    1361             : };
    1362             : 
    1363             : /**
    1364             :  * Additional information about a selector (without combinators) that is
    1365             :  * being matched.
    1366             :  */
    1367             : enum class SelectorMatchesFlags : uint8_t {
    1368             :   NONE = 0,
    1369             : 
    1370             :   // The selector's flags are unknown.  This happens when you don't know
    1371             :   // if you're starting from the top of a selector.  Only used in cases
    1372             :   // where it's acceptable for matching to return a false positive.
    1373             :   // (It's not OK to return a false negative.)
    1374             :   UNKNOWN = 1 << 0,
    1375             : 
    1376             :   // The selector is part of a compound selector which has been split in
    1377             :   // half, where the other half is a pseudo-element.  The current
    1378             :   // selector is not a pseudo-element itself.
    1379             :   HAS_PSEUDO_ELEMENT = 1 << 1,
    1380             : 
    1381             :   // The selector is part of an argument to a functional pseudo-class or
    1382             :   // pseudo-element.
    1383             :   IS_PSEUDO_CLASS_ARGUMENT = 1 << 2
    1384             : };
    1385         768 : MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SelectorMatchesFlags)
    1386             : 
    1387             : // Return whether the selector matches conditions for the :active and
    1388             : // :hover quirk.
    1389           0 : static inline bool ActiveHoverQuirkMatches(nsCSSSelector* aSelector,
    1390             :                                            SelectorMatchesFlags aSelectorFlags)
    1391             : {
    1392           0 :   if (aSelector->HasTagSelector() || aSelector->mAttrList ||
    1393           0 :       aSelector->mIDList || aSelector->mClassList ||
    1394           0 :       aSelector->IsPseudoElement() ||
    1395             :       // Having this quirk means that some selectors will no longer match,
    1396             :       // so it's better to return false when we aren't sure (i.e., the
    1397             :       // flags are unknown).
    1398           0 :       aSelectorFlags & (SelectorMatchesFlags::UNKNOWN |
    1399           0 :                         SelectorMatchesFlags::HAS_PSEUDO_ELEMENT |
    1400         256 :                         SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
    1401           0 :     return false;
    1402             :   }
    1403             : 
    1404             :   // No pseudo-class other than :active and :hover.
    1405           0 :   for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
    1406           0 :        pseudoClass; pseudoClass = pseudoClass->mNext) {
    1407           0 :     if (pseudoClass->mType != CSSPseudoClassType::hover &&
    1408           0 :         pseudoClass->mType != CSSPseudoClassType::active) {
    1409           0 :       return false;
    1410             :     }
    1411             :   }
    1412             : 
    1413           0 :   return true;
    1414             : }
    1415             : 
    1416             : 
    1417             : static inline bool
    1418          38 : IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
    1419             :                    bool aWhitespaceIsSignificant)
    1420             : {
    1421          38 :   return nsStyleUtil::IsSignificantChild(aChild, aTextIsSignificant,
    1422          38 :                                          aWhitespaceIsSignificant);
    1423             : }
    1424             : 
    1425             : // This function is to be called once we have fetched a value for an attribute
    1426             : // whose namespace and name match those of aAttrSelector.  This function
    1427             : // performs comparisons on the value only, based on aAttrSelector->mFunction.
    1428         206 : static bool AttrMatchesValue(const nsAttrSelector* aAttrSelector,
    1429             :                                const nsString& aValue, bool isHTML)
    1430             : {
    1431         206 :   NS_PRECONDITION(aAttrSelector, "Must have an attribute selector");
    1432             : 
    1433             :   // http://lists.w3.org/Archives/Public/www-style/2008Apr/0038.html
    1434             :   // *= (CONTAINSMATCH) ~= (INCLUDES) ^= (BEGINSMATCH) $= (ENDSMATCH)
    1435             :   // all accept the empty string, but match nothing.
    1436         206 :   if (aAttrSelector->mValue.IsEmpty() &&
    1437           0 :       (aAttrSelector->mFunction == NS_ATTR_FUNC_INCLUDES ||
    1438           0 :        aAttrSelector->mFunction == NS_ATTR_FUNC_ENDSMATCH ||
    1439           0 :        aAttrSelector->mFunction == NS_ATTR_FUNC_BEGINSMATCH ||
    1440           0 :        aAttrSelector->mFunction == NS_ATTR_FUNC_CONTAINSMATCH))
    1441           0 :     return false;
    1442             : 
    1443         206 :   const nsDefaultStringComparator defaultComparator;
    1444         206 :   const nsASCIICaseInsensitiveStringComparator ciComparator;
    1445             :   const nsStringComparator& comparator =
    1446         206 :     aAttrSelector->IsValueCaseSensitive(isHTML)
    1447             :                 ? static_cast<const nsStringComparator&>(defaultComparator)
    1448         206 :                 : static_cast<const nsStringComparator&>(ciComparator);
    1449             : 
    1450         206 :   switch (aAttrSelector->mFunction) {
    1451             :     case NS_ATTR_FUNC_EQUALS:
    1452           0 :       return aValue.Equals(aAttrSelector->mValue, comparator);
    1453             :     case NS_ATTR_FUNC_INCLUDES:
    1454         182 :       return nsStyleUtil::ValueIncludes(aValue, aAttrSelector->mValue, comparator);
    1455             :     case NS_ATTR_FUNC_DASHMATCH:
    1456           0 :       return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
    1457             :     case NS_ATTR_FUNC_ENDSMATCH:
    1458           0 :       return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
    1459             :     case NS_ATTR_FUNC_BEGINSMATCH:
    1460          17 :       return StringBeginsWith(aValue, aAttrSelector->mValue, comparator);
    1461             :     case NS_ATTR_FUNC_CONTAINSMATCH:
    1462           7 :       return FindInReadable(aAttrSelector->mValue, aValue, comparator);
    1463             :     default:
    1464           0 :       NS_NOTREACHED("Shouldn't be ending up here");
    1465           0 :       return false;
    1466             :   }
    1467             : }
    1468             : 
    1469             : static inline bool
    1470           6 : edgeChildMatches(Element* aElement, TreeMatchContext& aTreeMatchContext,
    1471             :                  bool checkFirst, bool checkLast)
    1472             : {
    1473           6 :   nsIContent* parent = aElement->GetParent();
    1474           6 :   if (parent && aTreeMatchContext.mForStyling)
    1475           6 :     parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
    1476             : 
    1477          12 :   return (!checkFirst ||
    1478             :           aTreeMatchContext.mNthIndexCache.
    1479           6 :             GetNthIndex(aElement, false, false, true) == 1) &&
    1480           0 :          (!checkLast ||
    1481             :           aTreeMatchContext.mNthIndexCache.
    1482           6 :             GetNthIndex(aElement, false, true, true) == 1);
    1483             : }
    1484             : 
    1485             : static inline bool
    1486           0 : nthChildGenericMatches(Element* aElement,
    1487             :                        TreeMatchContext& aTreeMatchContext,
    1488             :                        nsPseudoClassList* pseudoClass,
    1489             :                        bool isOfType, bool isFromEnd)
    1490             : {
    1491           0 :   nsIContent* parent = aElement->GetParent();
    1492           0 :   if (parent && aTreeMatchContext.mForStyling) {
    1493           0 :     if (isFromEnd)
    1494           0 :       parent->SetFlags(NODE_HAS_SLOW_SELECTOR);
    1495             :     else
    1496           0 :       parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
    1497             :   }
    1498             : 
    1499             :   const int32_t index = aTreeMatchContext.mNthIndexCache.
    1500           0 :     GetNthIndex(aElement, isOfType, isFromEnd, false);
    1501           0 :   if (index <= 0) {
    1502             :     // Node is anonymous content (not really a child of its parent).
    1503           0 :     return false;
    1504             :   }
    1505             : 
    1506           0 :   const int32_t a = pseudoClass->u.mNumbers[0];
    1507           0 :   const int32_t b = pseudoClass->u.mNumbers[1];
    1508             :   // result should be true if there exists n >= 0 such that
    1509             :   // a * n + b == index.
    1510           0 :   if (a == 0) {
    1511           0 :     return b == index;
    1512             :   }
    1513             : 
    1514             :   // Integer division in C does truncation (towards 0).  So
    1515             :   // check that the result is nonnegative, and that there was no
    1516             :   // truncation.
    1517           0 :   const CheckedInt<int32_t> indexMinusB = CheckedInt<int32_t>(index) - b;
    1518           0 :   const CheckedInt<int32_t> n = indexMinusB / a;
    1519           0 :   return n.isValid() &&
    1520           0 :          n.value() >= 0 &&
    1521           0 :          a * n == indexMinusB;
    1522             : }
    1523             : 
    1524             : static inline bool
    1525           0 : edgeOfTypeMatches(Element* aElement, TreeMatchContext& aTreeMatchContext,
    1526             :                   bool checkFirst, bool checkLast)
    1527             : {
    1528           0 :   nsIContent *parent = aElement->GetParent();
    1529           0 :   if (parent && aTreeMatchContext.mForStyling) {
    1530           0 :     if (checkLast)
    1531           0 :       parent->SetFlags(NODE_HAS_SLOW_SELECTOR);
    1532             :     else
    1533           0 :       parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
    1534             :   }
    1535             : 
    1536           0 :   return (!checkFirst ||
    1537             :           aTreeMatchContext.mNthIndexCache.
    1538           0 :             GetNthIndex(aElement, true, false, true) == 1) &&
    1539           0 :          (!checkLast ||
    1540             :           aTreeMatchContext.mNthIndexCache.
    1541           0 :             GetNthIndex(aElement, true, true, true) == 1);
    1542             : }
    1543             : 
    1544             : static inline bool
    1545          43 : checkGenericEmptyMatches(Element* aElement,
    1546             :                          TreeMatchContext& aTreeMatchContext,
    1547             :                          bool isWhitespaceSignificant)
    1548             : {
    1549          43 :   nsIContent *child = nullptr;
    1550          43 :   int32_t index = -1;
    1551             : 
    1552          43 :   if (aTreeMatchContext.mForStyling)
    1553          43 :     aElement->SetFlags(NODE_HAS_EMPTY_SELECTOR);
    1554             : 
    1555          43 :   do {
    1556          43 :     child = aElement->GetChildAt(++index);
    1557             :     // stop at first non-comment (and non-whitespace for
    1558             :     // :-moz-only-whitespace) node
    1559          43 :   } while (child && !IsSignificantChild(child, true, isWhitespaceSignificant));
    1560          43 :   return (child == nullptr);
    1561             : }
    1562             : 
    1563             : // Arrays of the states that are relevant for various pseudoclasses.
    1564             : static const EventStates sPseudoClassStateDependences[] = {
    1565             : #define CSS_PSEUDO_CLASS(_name, _value, _flags, _pref) \
    1566             :   EventStates(),
    1567             : #define CSS_STATE_DEPENDENT_PSEUDO_CLASS(_name, _value, _flags, _pref, _states) \
    1568             :   _states,
    1569             : #include "nsCSSPseudoClassList.h"
    1570             : #undef CSS_STATE_DEPENDENT_PSEUDO_CLASS
    1571             : #undef CSS_PSEUDO_CLASS
    1572             :   // Add more entries for our fake values to make sure we can't
    1573             :   // index out of bounds into this array no matter what.
    1574             :   EventStates(),
    1575             :   EventStates()
    1576             : };
    1577             : 
    1578             : static const EventStates sPseudoClassStates[] = {
    1579             : #define CSS_PSEUDO_CLASS(_name, _value, _flags, _pref) \
    1580             :   EventStates(),
    1581             : #define CSS_STATE_PSEUDO_CLASS(_name, _value, _flags, _pref, _states) \
    1582             :   _states,
    1583             : #include "nsCSSPseudoClassList.h"
    1584             : #undef CSS_STATE_PSEUDO_CLASS
    1585             : #undef CSS_PSEUDO_CLASS
    1586             :   // Add more entries for our fake values to make sure we can't
    1587             :   // index out of bounds into this array no matter what.
    1588             :   EventStates(),
    1589             :   EventStates()
    1590             : };
    1591             : static_assert(MOZ_ARRAY_LENGTH(sPseudoClassStates) ==
    1592             :               static_cast<size_t>(CSSPseudoClassType::MAX),
    1593             :               "CSSPseudoClassType::MAX is no longer equal to the length of "
    1594             :               "sPseudoClassStates");
    1595             : 
    1596             : static bool
    1597       16984 : StateSelectorMatches(Element* aElement,
    1598             :                      nsCSSSelector* aSelector,
    1599             :                      NodeMatchContext& aNodeMatchContext,
    1600             :                      TreeMatchContext& aTreeMatchContext,
    1601             :                      SelectorMatchesFlags aSelectorFlags,
    1602             :                      bool* const aDependence,
    1603             :                      EventStates aStatesToCheck)
    1604             : {
    1605       16984 :   NS_PRECONDITION(!aStatesToCheck.IsEmpty(),
    1606             :                   "should only need to call StateSelectorMatches if "
    1607             :                   "aStatesToCheck is not empty");
    1608             : 
    1609             :   // Bit-based pseudo-classes
    1610       50952 :   if (aStatesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_ACTIVE |
    1611       69873 :                                            NS_EVENT_STATE_HOVER) &&
    1612        1937 :       aTreeMatchContext.mCompatMode == eCompatibility_NavQuirks &&
    1613           0 :       ActiveHoverQuirkMatches(aSelector, aSelectorFlags) &&
    1614       67936 :       aElement->IsHTMLElement() && !nsCSSRuleProcessor::IsLink(aElement)) {
    1615             :     // In quirks mode, only make links sensitive to selectors ":active"
    1616             :     // and ":hover".
    1617           0 :     return false;
    1618             :   }
    1619             : 
    1620       67682 :   if (aTreeMatchContext.mForStyling &&
    1621       67174 :       aStatesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER)) {
    1622             :     // Mark the element as having :hover-dependent style
    1623        1669 :     aElement->SetHasRelevantHoverRules();
    1624             :   }
    1625             : 
    1626       16984 :   if (aNodeMatchContext.mStateMask.HasAtLeastOneOfStates(aStatesToCheck)) {
    1627           6 :     if (aDependence) {
    1628           2 :       *aDependence = true;
    1629             :     }
    1630             :   } else {
    1631             :     EventStates contentState =
    1632             :       nsCSSRuleProcessor::GetContentStateForVisitedHandling(
    1633             :                                    aElement,
    1634             :                                    aTreeMatchContext.VisitedHandling(),
    1635       16978 :                                    aNodeMatchContext.mIsRelevantLink);
    1636       16978 :     if (!contentState.HasAtLeastOneOfStates(aStatesToCheck)) {
    1637       16966 :       return false;
    1638             :     }
    1639             :   }
    1640             : 
    1641          18 :   return true;
    1642             : }
    1643             : 
    1644             : static bool
    1645         256 : StateSelectorMatches(Element* aElement,
    1646             :                      nsCSSSelector* aSelector,
    1647             :                      NodeMatchContext& aNodeMatchContext,
    1648             :                      TreeMatchContext& aTreeMatchContext,
    1649             :                      SelectorMatchesFlags aSelectorFlags)
    1650             : {
    1651         256 :   for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
    1652         256 :        pseudoClass; pseudoClass = pseudoClass->mNext) {
    1653           0 :     auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
    1654           0 :     EventStates statesToCheck = sPseudoClassStates[idx];
    1655           0 :     if (!statesToCheck.IsEmpty() &&
    1656           0 :         !StateSelectorMatches(aElement, aSelector, aNodeMatchContext,
    1657             :                               aTreeMatchContext, aSelectorFlags, nullptr,
    1658             :                               statesToCheck)) {
    1659           0 :       return false;
    1660             :     }
    1661             :   }
    1662         256 :   return true;
    1663             : }
    1664             : 
    1665             : // Chooses the thread safe version in Servo mode, and
    1666             : // the non-thread safe one in Gecko mode. The non thread safe one does
    1667             : // some extra caching, and is preferred when possible.
    1668             : static inline bool
    1669           0 : IsSignificantChildMaybeThreadSafe(const nsIContent* aContent,
    1670             :                                   bool aTextIsSignificant,
    1671             :                                   bool aWhitespaceIsSignificant)
    1672             : {
    1673           0 :   if (ServoStyleSet::IsInServoTraversal()) {
    1674             :     // See bug 1349100 for optimizing this
    1675           0 :     return nsStyleUtil::ThreadSafeIsSignificantChild(aContent,
    1676             :                                                      aTextIsSignificant,
    1677           0 :                                                      aWhitespaceIsSignificant);
    1678             :   } else {
    1679           0 :     auto content = const_cast<nsIContent*>(aContent);
    1680           0 :     return IsSignificantChild(content, aTextIsSignificant, aWhitespaceIsSignificant);
    1681             :   }
    1682             : }
    1683             : 
    1684             : /* static */ bool
    1685           0 : nsCSSRuleProcessor::LangPseudoMatches(const mozilla::dom::Element* aElement,
    1686             :                                       const nsIAtom* aOverrideLang,
    1687             :                                       bool aHasOverrideLang,
    1688             :                                       const char16_t* aString,
    1689             :                                       const nsIDocument* aDocument)
    1690             : {
    1691           0 :   NS_ASSERTION(aString, "null lang parameter");
    1692           0 :   if (!aString || !*aString) {
    1693           0 :     return false;
    1694             :   }
    1695             : 
    1696             :   // We have to determine the language of the current element.  Since
    1697             :   // this is currently no property and since the language is inherited
    1698             :   // from the parent we have to be prepared to look at all parent
    1699             :   // nodes.  The language itself is encoded in the LANG attribute.
    1700           0 :   if (auto* language = aHasOverrideLang ? aOverrideLang : aElement->GetLang()) {
    1701           0 :     return nsStyleUtil::DashMatchCompare(nsDependentAtomString(language),
    1702           0 :                                          nsDependentString(aString),
    1703           0 :                                          nsASCIICaseInsensitiveStringComparator());
    1704             :   }
    1705             : 
    1706           0 :   if (!aDocument) {
    1707           0 :     return false;
    1708             :   }
    1709             : 
    1710             :   // Try to get the language from the HTTP header or if this
    1711             :   // is missing as well from the preferences.
    1712             :   // The content language can be a comma-separated list of
    1713             :   // language codes.
    1714           0 :   nsAutoString language;
    1715           0 :   aDocument->GetContentLanguage(language);
    1716             : 
    1717           0 :   nsDependentString langString(aString);
    1718           0 :   language.StripWhitespace();
    1719           0 :   int32_t begin = 0;
    1720           0 :   int32_t len = language.Length();
    1721           0 :   while (begin < len) {
    1722           0 :     int32_t end = language.FindChar(char16_t(','), begin);
    1723           0 :     if (end == kNotFound) {
    1724           0 :       end = len;
    1725             :     }
    1726           0 :     if (nsStyleUtil::DashMatchCompare(Substring(language, begin, end - begin),
    1727             :                                       langString,
    1728           0 :                                       nsASCIICaseInsensitiveStringComparator())) {
    1729           0 :       return true;
    1730             :     }
    1731           0 :     begin = end + 1;
    1732             :   }
    1733           0 :   if (begin < len) {
    1734           0 :     return true;
    1735             :   }
    1736           0 :   return false;
    1737             : }
    1738             : 
    1739             : /* static */ bool
    1740         780 : nsCSSRuleProcessor::StringPseudoMatches(const mozilla::dom::Element* aElement,
    1741             :                                         CSSPseudoClassType aPseudo,
    1742             :                                         const char16_t* aString,
    1743             :                                         const nsIDocument* aDocument,
    1744             :                                         bool aForStyling,
    1745             :                                         EventStates aStateMask,
    1746             :                                         bool* aSetSlowSelectorFlag,
    1747             :                                         bool* const aDependence)
    1748             : {
    1749         780 :   MOZ_ASSERT(aSetSlowSelectorFlag);
    1750             : 
    1751         780 :   switch (aPseudo) {
    1752             :     case CSSPseudoClassType::mozLocaleDir:
    1753             :       {
    1754             :         bool docIsRTL;
    1755         667 :         if (ServoStyleSet::IsInServoTraversal()) {
    1756           0 :           docIsRTL = aDocument->ThreadSafeGetDocumentState()
    1757           0 :                               .HasState(NS_DOCUMENT_STATE_RTL_LOCALE);
    1758             :         } else {
    1759         667 :           auto doc = const_cast<nsIDocument*>(aDocument);
    1760        1334 :           docIsRTL = doc->GetDocumentState()
    1761        2001 :                         .HasState(NS_DOCUMENT_STATE_RTL_LOCALE);
    1762             :         }
    1763             : 
    1764         760 :         nsDependentString dirString(aString);
    1765             : 
    1766         667 :         if (dirString.EqualsLiteral("rtl")) {
    1767         574 :           if (!docIsRTL) {
    1768         574 :             return false;
    1769             :           }
    1770          93 :         } else if (dirString.EqualsLiteral("ltr")) {
    1771          93 :           if (docIsRTL) {
    1772           0 :             return false;
    1773             :           }
    1774             :         } else {
    1775             :           // Selectors specifying other directions never match.
    1776           0 :           return false;
    1777             :         }
    1778             :       }
    1779          93 :       break;
    1780             : 
    1781             :     case CSSPseudoClassType::mozSystemMetric:
    1782             :       {
    1783         210 :         nsCOMPtr<nsIAtom> metric = NS_Atomize(aString);
    1784         113 :         if (!nsCSSRuleProcessor::HasSystemMetric(metric)) {
    1785          16 :           return false;
    1786             :         }
    1787             :       }
    1788          97 :       break;
    1789             : 
    1790             :     case CSSPseudoClassType::mozEmptyExceptChildrenWithLocalname:
    1791             :       {
    1792           0 :         NS_ASSERTION(aString, "Must have string!");
    1793           0 :         const nsIContent *child = nullptr;
    1794           0 :         int32_t index = -1;
    1795             : 
    1796           0 :         if (aForStyling) {
    1797             :           // FIXME:  This isn't sufficient to handle:
    1798             :           //   :-moz-empty-except-children-with-localname() + E
    1799             :           //   :-moz-empty-except-children-with-localname() ~ E
    1800             :           // because we don't know to restyle the grandparent of the
    1801             :           // inserted/removed element (as in bug 534804 for :empty).
    1802           0 :           *aSetSlowSelectorFlag = true;
    1803             :         }
    1804           0 :         do {
    1805           0 :           child = aElement->GetChildAt(++index);
    1806           0 :         } while (child &&
    1807           0 :                   (!IsSignificantChildMaybeThreadSafe(child, true, false) ||
    1808           0 :                   (child->GetNameSpaceID() == aElement->GetNameSpaceID() &&
    1809           0 :                     child->NodeInfo()->NameAtom()->Equals(nsDependentString(aString)))));
    1810           0 :         if (child) {
    1811           0 :           return false;
    1812             :         }
    1813             :       }
    1814           0 :       break;
    1815             : 
    1816             :     case CSSPseudoClassType::dir:
    1817             :       {
    1818           0 :         if (aDependence) {
    1819             :           EventStates states = sPseudoClassStateDependences[
    1820           0 :             static_cast<CSSPseudoClassTypeBase>(aPseudo)];
    1821           0 :           if (aStateMask.HasAtLeastOneOfStates(states)) {
    1822           0 :             *aDependence = true;
    1823           0 :             return false;
    1824             :           }
    1825             :         }
    1826             : 
    1827             :         // If we only had to consider HTML, directionality would be
    1828             :         // exclusively LTR or RTL.
    1829             :         //
    1830             :         // However, in markup languages where there is no direction attribute
    1831             :         // we have to consider the possibility that neither dir(rtl) nor
    1832             :         // dir(ltr) matches.
    1833           0 :         EventStates state = aElement->StyleState();
    1834           0 :         nsDependentString dirString(aString);
    1835             : 
    1836           0 :         if (dirString.EqualsLiteral("rtl")) {
    1837           0 :           if (!state.HasState(NS_EVENT_STATE_RTL)) {
    1838           0 :             return false;
    1839             :           }
    1840           0 :         } else if (dirString.EqualsLiteral("ltr")) {
    1841           0 :           if (!state.HasState(NS_EVENT_STATE_LTR)) {
    1842           0 :             return false;
    1843             :           }
    1844             :         } else {
    1845             :           // Selectors specifying other directions never match.
    1846           0 :           return false;
    1847             :         }
    1848             :       }
    1849           0 :       break;
    1850             : 
    1851             :     case CSSPseudoClassType::lang:
    1852           0 :       if (LangPseudoMatches(aElement, nullptr, false, aString, aDocument)) {
    1853           0 :         break;
    1854             :       }
    1855           0 :       return false;
    1856             : 
    1857           0 :     default: MOZ_ASSERT_UNREACHABLE("Called StringPseudoMatches() with unknown string-like pseudo");
    1858             :   }
    1859         190 :   return true;
    1860             : }
    1861             : 
    1862             : // |aDependence| has two functions:
    1863             : //  * when non-null, it indicates that we're processing a negation,
    1864             : //    which is done only when SelectorMatches calls itself recursively
    1865             : //  * what it points to should be set to true whenever a test is skipped
    1866             : //    because of aNodeMatchContent.mStateMask
    1867      281699 : static bool SelectorMatches(Element* aElement,
    1868             :                             nsCSSSelector* aSelector,
    1869             :                             NodeMatchContext& aNodeMatchContext,
    1870             :                             TreeMatchContext& aTreeMatchContext,
    1871             :                             SelectorMatchesFlags aSelectorFlags,
    1872             :                             bool* const aDependence = nullptr)
    1873             : {
    1874      281699 :   NS_PRECONDITION(!aSelector->IsPseudoElement(),
    1875             :                   "Pseudo-element snuck into SelectorMatches?");
    1876      281699 :   MOZ_ASSERT(aTreeMatchContext.mForStyling ||
    1877             :              !aNodeMatchContext.mIsRelevantLink,
    1878             :              "mIsRelevantLink should be set to false when mForStyling "
    1879             :              "is false since we don't know how to set it correctly in "
    1880             :              "Has(Attribute|State)DependentStyle");
    1881             : 
    1882             :   // namespace/tag match
    1883             :   // optimization : bail out early if we can
    1884      481426 :   if ((kNameSpaceID_Unknown != aSelector->mNameSpace &&
    1885      199727 :        aElement->GetNameSpaceID() != aSelector->mNameSpace))
    1886        5465 :     return false;
    1887             : 
    1888      276234 :   if (aSelector->mLowercaseTag) {
    1889             :     nsIAtom* selectorTag =
    1890       28217 :       (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTMLElement()) ?
    1891       27961 :         aSelector->mLowercaseTag : aSelector->mCasedTag;
    1892       27850 :     if (selectorTag != aElement->NodeInfo()->NameAtom()) {
    1893       13872 :       return false;
    1894             :     }
    1895             :   }
    1896             : 
    1897      262362 :   nsAtomList* IDList = aSelector->mIDList;
    1898      262362 :   if (IDList) {
    1899      115838 :     nsIAtom* id = aElement->GetID();
    1900      115838 :     if (id) {
    1901             :       // case sensitivity: bug 93371
    1902             :       const bool isCaseSensitive =
    1903       67276 :         aTreeMatchContext.mCompatMode != eCompatibility_NavQuirks;
    1904             : 
    1905       67276 :       if (isCaseSensitive) {
    1906           0 :         do {
    1907       67276 :           if (IDList->mAtom != id) {
    1908       63981 :             return false;
    1909             :           }
    1910        3295 :           IDList = IDList->mNext;
    1911        3295 :         } while (IDList);
    1912             :       } else {
    1913             :         // Use EqualsIgnoreASCIICase instead of full on unicode case conversion
    1914             :         // in order to save on performance. This is only used in quirks mode
    1915             :         // anyway.
    1916           0 :         nsDependentAtomString id1Str(id);
    1917           0 :         do {
    1918           0 :           if (!nsContentUtils::EqualsIgnoreASCIICase(id1Str,
    1919           0 :                  nsDependentAtomString(IDList->mAtom))) {
    1920           0 :             return false;
    1921             :           }
    1922           0 :           IDList = IDList->mNext;
    1923           0 :         } while (IDList);
    1924             :       }
    1925             :     } else {
    1926             :       // Element has no id but we have an id selector
    1927       48562 :       return false;
    1928             :     }
    1929             :   }
    1930             : 
    1931      149819 :   nsAtomList* classList = aSelector->mClassList;
    1932      149819 :   if (classList) {
    1933             :     // test for class match
    1934       20163 :     const nsAttrValue *elementClasses = aElement->GetClasses();
    1935       20163 :     if (!elementClasses) {
    1936             :       // Element has no classes but we have a class selector
    1937        7371 :       return false;
    1938             :     }
    1939             : 
    1940             :     // case sensitivity: bug 93371
    1941             :     const bool isCaseSensitive =
    1942       12792 :       aTreeMatchContext.mCompatMode != eCompatibility_NavQuirks;
    1943             : 
    1944       28832 :     while (classList) {
    1945       12963 :       if (!elementClasses->Contains(classList->mAtom,
    1946             :                                     isCaseSensitive ?
    1947             :                                       eCaseMatters : eIgnoreCase)) {
    1948        4943 :         return false;
    1949             :       }
    1950        8020 :       classList = classList->mNext;
    1951             :     }
    1952             :   }
    1953             : 
    1954      137505 :   const bool isNegated = (aDependence != nullptr);
    1955             :   // The selectors for which we set node bits are, unfortunately, early
    1956             :   // in this function (because they're pseudo-classes, which are
    1957             :   // generally quick to test, and thus earlier).  If they were later,
    1958             :   // we'd probably avoid setting those bits in more cases where setting
    1959             :   // them is unnecessary.
    1960      137505 :   NS_ASSERTION(aNodeMatchContext.mStateMask.IsEmpty() ||
    1961             :                !aTreeMatchContext.mForStyling,
    1962             :                "mForStyling must be false if we're just testing for "
    1963             :                "state-dependence");
    1964             : 
    1965             :   // test for pseudo class match
    1966      138368 :   for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
    1967      139231 :        pseudoClass; pseudoClass = pseudoClass->mNext) {
    1968       63993 :     auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
    1969       63993 :     EventStates statesToCheck = sPseudoClassStates[idx];
    1970       63993 :     if (!statesToCheck.IsEmpty()) {
    1971       16984 :       if (!StateSelectorMatches(aElement, aSelector, aNodeMatchContext,
    1972             :                                 aTreeMatchContext, aSelectorFlags, aDependence,
    1973             :                                 statesToCheck)) {
    1974       80096 :         return false;
    1975             :       }
    1976          40 :       continue;
    1977             :     }
    1978             :     Maybe<bool> matchesElement =
    1979       47850 :       nsCSSPseudoClasses::MatchesElement(pseudoClass->mType, aElement);
    1980       47009 :     if (matchesElement.isSome()) {
    1981           4 :       if (!matchesElement.value()) {
    1982           0 :         return false;
    1983             :       }
    1984           4 :       continue;
    1985             :     }
    1986             :     // keep the cases here in the same order as the list in
    1987             :     // nsCSSPseudoClassList.h
    1988       47005 :     switch (pseudoClass->mType) {
    1989             :     case CSSPseudoClassType::empty:
    1990          43 :       if (!checkGenericEmptyMatches(aElement, aTreeMatchContext, true)) {
    1991          38 :         return false;
    1992             :       }
    1993           5 :       break;
    1994             : 
    1995             :     case CSSPseudoClassType::mozOnlyWhitespace:
    1996           0 :       if (!checkGenericEmptyMatches(aElement, aTreeMatchContext, false)) {
    1997           0 :         return false;
    1998             :       }
    1999           0 :       break;
    2000             : 
    2001             :     case CSSPseudoClassType::root:
    2002       39637 :       if (aElement != aElement->OwnerDoc()->GetRootElement()) {
    2003       39273 :         return false;
    2004             :       }
    2005         364 :       break;
    2006             : 
    2007             :     case CSSPseudoClassType::any:
    2008             :       {
    2009             :         nsCSSSelectorList *l;
    2010      118293 :         for (l = pseudoClass->u.mSelectors; l; l = l->mNext) {
    2011      112974 :           nsCSSSelector *s = l->mSelectors;
    2012      112974 :           MOZ_ASSERT(!s->mNext && !s->IsPseudoElement(),
    2013             :                       "parser failed");
    2014      112974 :           if (SelectorMatches(
    2015             :                 aElement, s, aNodeMatchContext, aTreeMatchContext,
    2016             :                 SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
    2017         266 :             break;
    2018             :           }
    2019             :         }
    2020        5585 :         if (!l) {
    2021        5319 :           return false;
    2022             :         }
    2023             :       }
    2024         266 :       break;
    2025             : 
    2026             :     case CSSPseudoClassType::firstChild:
    2027           6 :       if (!edgeChildMatches(aElement, aTreeMatchContext, true, false)) {
    2028           6 :         return false;
    2029             :       }
    2030           0 :       break;
    2031             : 
    2032             :     case CSSPseudoClassType::firstNode:
    2033             :       {
    2034           0 :         nsIContent *firstNode = nullptr;
    2035           0 :         nsIContent *parent = aElement->GetParent();
    2036           0 :         if (parent) {
    2037           0 :           if (aTreeMatchContext.mForStyling)
    2038           0 :             parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
    2039             : 
    2040           0 :           int32_t index = -1;
    2041           0 :           do {
    2042           0 :             firstNode = parent->GetChildAt(++index);
    2043             :             // stop at first non-comment and non-whitespace node
    2044           0 :           } while (firstNode &&
    2045           0 :                     !IsSignificantChild(firstNode, true, false));
    2046             :         }
    2047           0 :         if (aElement != firstNode) {
    2048           0 :           return false;
    2049             :         }
    2050             :       }
    2051           0 :       break;
    2052             : 
    2053             :     case CSSPseudoClassType::lastChild:
    2054           0 :       if (!edgeChildMatches(aElement, aTreeMatchContext, false, true)) {
    2055           0 :         return false;
    2056             :       }
    2057           0 :       break;
    2058             : 
    2059             :     case CSSPseudoClassType::lastNode:
    2060             :       {
    2061           0 :         nsIContent *lastNode = nullptr;
    2062           0 :         nsIContent *parent = aElement->GetParent();
    2063           0 :         if (parent) {
    2064           0 :           if (aTreeMatchContext.mForStyling)
    2065           0 :             parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
    2066             : 
    2067           0 :           uint32_t index = parent->GetChildCount();
    2068           0 :           do {
    2069           0 :             lastNode = parent->GetChildAt(--index);
    2070             :             // stop at first non-comment and non-whitespace node
    2071           0 :           } while (lastNode &&
    2072           0 :                     !IsSignificantChild(lastNode, true, false));
    2073             :         }
    2074           0 :         if (aElement != lastNode) {
    2075           0 :           return false;
    2076             :         }
    2077             :       }
    2078           0 :       break;
    2079             : 
    2080             :     case CSSPseudoClassType::onlyChild:
    2081           0 :       if (!edgeChildMatches(aElement, aTreeMatchContext, true, true)) {
    2082           0 :         return false;
    2083             :       }
    2084           0 :       break;
    2085             : 
    2086             :     case CSSPseudoClassType::firstOfType:
    2087           0 :       if (!edgeOfTypeMatches(aElement, aTreeMatchContext, true, false)) {
    2088           0 :         return false;
    2089             :       }
    2090           0 :       break;
    2091             : 
    2092             :     case CSSPseudoClassType::lastOfType:
    2093           0 :       if (!edgeOfTypeMatches(aElement, aTreeMatchContext, false, true)) {
    2094           0 :         return false;
    2095             :       }
    2096           0 :       break;
    2097             : 
    2098             :     case CSSPseudoClassType::onlyOfType:
    2099           0 :       if (!edgeOfTypeMatches(aElement, aTreeMatchContext, true, true)) {
    2100           0 :         return false;
    2101             :       }
    2102           0 :       break;
    2103             : 
    2104             :     case CSSPseudoClassType::nthChild:
    2105           0 :       if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
    2106             :                                   false, false)) {
    2107           0 :         return false;
    2108             :       }
    2109           0 :       break;
    2110             : 
    2111             :     case CSSPseudoClassType::nthLastChild:
    2112           0 :       if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
    2113             :                                   false, true)) {
    2114           0 :         return false;
    2115             :       }
    2116           0 :     break;
    2117             : 
    2118             :     case CSSPseudoClassType::nthOfType:
    2119           0 :       if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
    2120             :                                   true, false)) {
    2121           0 :         return false;
    2122             :       }
    2123           0 :       break;
    2124             : 
    2125             :     case CSSPseudoClassType::nthLastOfType:
    2126           0 :       if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
    2127             :                                   true, true)) {
    2128           0 :         return false;
    2129             :       }
    2130           0 :       break;
    2131             : 
    2132             :     case CSSPseudoClassType::mozIsHTML:
    2133           0 :       if (!aTreeMatchContext.mIsHTMLDocument || !aElement->IsHTMLElement()) {
    2134           0 :         return false;
    2135             :       }
    2136           0 :       break;
    2137             : 
    2138             :     case CSSPseudoClassType::mozLWTheme:
    2139             :       {
    2140         855 :         if (aTreeMatchContext.mDocument->GetDocumentLWTheme() <=
    2141             :               nsIDocument::Doc_Theme_None) {
    2142         855 :           return false;
    2143             :         }
    2144             :       }
    2145           0 :       break;
    2146             : 
    2147             :     case CSSPseudoClassType::mozLWThemeBrightText:
    2148             :       {
    2149          46 :         if (aTreeMatchContext.mDocument->GetDocumentLWTheme() !=
    2150             :               nsIDocument::Doc_Theme_Bright) {
    2151          46 :           return false;
    2152             :         }
    2153             :       }
    2154           0 :       break;
    2155             : 
    2156             :     case CSSPseudoClassType::mozLWThemeDarkText:
    2157             :       {
    2158          31 :         if (aTreeMatchContext.mDocument->GetDocumentLWTheme() !=
    2159             :               nsIDocument::Doc_Theme_Dark) {
    2160          31 :           return false;
    2161             :         }
    2162             :       }
    2163           0 :       break;
    2164             : 
    2165             :     case CSSPseudoClassType::mozWindowInactive:
    2166          66 :       if (!aTreeMatchContext.mDocument->GetDocumentState().
    2167          66 :               HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
    2168           6 :         return false;
    2169             :       }
    2170          16 :       break;
    2171             : 
    2172             :     case CSSPseudoClassType::scope:
    2173           0 :       if (aTreeMatchContext.mForScopedStyle) {
    2174           0 :         if (aTreeMatchContext.mCurrentStyleScope) {
    2175             :           // If mCurrentStyleScope is null, aElement must be the style
    2176             :           // scope root.  This is because the PopStyleScopeForSelectorMatching
    2177             :           // call in SelectorMatchesTree sets mCurrentStyleScope to null
    2178             :           // as soon as we visit the style scope element, and we won't
    2179             :           // progress further up the tree after this call to
    2180             :           // SelectorMatches.  Thus if mCurrentStyleScope is still set,
    2181             :           // we know the selector does not match.
    2182           0 :           return false;
    2183             :         }
    2184           0 :       } else if (aTreeMatchContext.HasSpecifiedScope()) {
    2185           0 :         if (!aTreeMatchContext.IsScopeElement(aElement)) {
    2186           0 :           return false;
    2187             :         }
    2188             :       } else {
    2189           0 :         if (aElement != aElement->OwnerDoc()->GetRootElement()) {
    2190           0 :           return false;
    2191             :         }
    2192             :       }
    2193           0 :       break;
    2194             : 
    2195             :     default:
    2196             :       {
    2197         780 :         MOZ_ASSERT(nsCSSPseudoClasses::HasStringArg(pseudoClass->mType));
    2198         780 :         bool setSlowSelectorFlag = false;
    2199        1560 :         bool matched = nsCSSRuleProcessor::StringPseudoMatches(aElement,
    2200             :                                                                pseudoClass->mType,
    2201         780 :                                                                pseudoClass->u.mString,
    2202         780 :                                                                aTreeMatchContext.mDocument,
    2203         780 :                                                                aTreeMatchContext.mForStyling,
    2204             :                                                                aNodeMatchContext.mStateMask,
    2205             :                                                                &setSlowSelectorFlag,
    2206         780 :                                                                aDependence);
    2207         780 :         if (setSlowSelectorFlag) {
    2208           0 :           aElement->SetFlags(NODE_HAS_SLOW_SELECTOR);
    2209             :         }
    2210             : 
    2211         780 :         if (!matched) {
    2212         590 :           return false;
    2213             :         }
    2214             :       }
    2215             :     }
    2216             :   }
    2217             : 
    2218       74375 :   bool result = true;
    2219       74375 :   if (aSelector->mAttrList) {
    2220             :     // test for attribute match
    2221       56070 :     if (!aElement->HasAttrs()) {
    2222             :       // if no attributes on the content, no match
    2223         418 :       return false;
    2224             :     }
    2225       55652 :     result = true;
    2226       55652 :     nsAttrSelector* attr = aSelector->mAttrList;
    2227             :     nsIAtom* matchAttribute;
    2228             : 
    2229         430 :     do {
    2230             :       bool isHTML =
    2231       56082 :         (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTMLElement());
    2232       56082 :       matchAttribute = isHTML ? attr->mLowercaseAttr : attr->mCasedAttr;
    2233       56082 :       if (attr->mNameSpace == kNameSpaceID_Unknown) {
    2234             :         // Attr selector with a wildcard namespace.  We have to examine all
    2235             :         // the attributes on our content node....  This sort of selector is
    2236             :         // essentially a boolean OR, over all namespaces, of equivalent attr
    2237             :         // selectors with those namespaces.  So to evaluate whether it
    2238             :         // matches, evaluate for each namespace (the only namespaces that
    2239             :         // have a chance at matching, of course, are ones that the element
    2240             :         // actually has attributes in), short-circuiting if we ever match.
    2241           0 :         result = false;
    2242             :         const nsAttrName* attrName;
    2243           0 :         for (uint32_t i = 0; (attrName = aElement->GetAttrNameAt(i)); ++i) {
    2244           0 :           if (attrName->LocalName() != matchAttribute) {
    2245           0 :             continue;
    2246             :           }
    2247           0 :           if (attr->mFunction == NS_ATTR_FUNC_SET) {
    2248           0 :             result = true;
    2249             :           } else {
    2250           0 :             nsAutoString value;
    2251             : #ifdef DEBUG
    2252             :             bool hasAttr =
    2253             : #endif
    2254           0 :               aElement->GetAttr(attrName->NamespaceID(),
    2255           0 :                                 attrName->LocalName(), value);
    2256           0 :             NS_ASSERTION(hasAttr, "GetAttrNameAt lied");
    2257           0 :             result = AttrMatchesValue(attr, value, isHTML);
    2258             :           }
    2259             : 
    2260             :           // At this point |result| has been set by us
    2261             :           // explicitly in this loop.  If it's false, we may still match
    2262             :           // -- the content may have another attribute with the same name but
    2263             :           // in a different namespace.  But if it's true, we are done (we
    2264             :           // can short-circuit the boolean OR described above).
    2265           0 :           if (result) {
    2266           0 :             break;
    2267             :           }
    2268             :         }
    2269             :       }
    2270       56082 :       else if (attr->mFunction == NS_ATTR_FUNC_EQUALS) {
    2271             :         result =
    2272             :           aElement->
    2273       42438 :           AttrValueIs(attr->mNameSpace, matchAttribute, attr->mValue,
    2274       42438 :                       attr->IsValueCaseSensitive(isHTML) ? eCaseMatters
    2275       42438 :                                                          : eIgnoreCase);
    2276             :       }
    2277       13644 :       else if (!aElement->HasAttr(attr->mNameSpace, matchAttribute)) {
    2278       12919 :         result = false;
    2279             :       }
    2280         725 :       else if (attr->mFunction != NS_ATTR_FUNC_SET) {
    2281         412 :         nsAutoString value;
    2282             : #ifdef DEBUG
    2283             :         bool hasAttr =
    2284             : #endif
    2285         206 :           aElement->GetAttr(attr->mNameSpace, matchAttribute, value);
    2286         206 :         NS_ASSERTION(hasAttr, "HasAttr lied");
    2287         206 :         result = AttrMatchesValue(attr, value, isHTML);
    2288             :       }
    2289             : 
    2290       56082 :       attr = attr->mNext;
    2291       56082 :     } while (attr && result);
    2292             :   }
    2293             : 
    2294             :   // apply SelectorMatches to the negated selectors in the chain
    2295       73957 :   if (!isNegated) {
    2296       74692 :     for (nsCSSSelector *negation = aSelector->mNegations;
    2297       76701 :          result && negation; negation = negation->mNegations) {
    2298        2009 :       bool dependence = false;
    2299        2009 :       result = !SelectorMatches(aElement, negation, aNodeMatchContext,
    2300             :                                 aTreeMatchContext,
    2301             :                                 SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT,
    2302             :                                 &dependence);
    2303             :       // If the selector does match due to the dependence on
    2304             :       // aNodeMatchContext.mStateMask, then we want to keep result true
    2305             :       // so that the final result of SelectorMatches is true.  Doing so
    2306             :       // tells StateEnumFunc that there is a dependence on the state.
    2307        2009 :       result = result || dependence;
    2308             :     }
    2309             :   }
    2310       73957 :   return result;
    2311             : }
    2312             : 
    2313             : #undef STATE_CHECK
    2314             : 
    2315             : #ifdef DEBUG
    2316             : static bool
    2317       11332 : HasPseudoClassSelectorArgsWithCombinators(nsCSSSelector* aSelector)
    2318             : {
    2319       11332 :   for (nsPseudoClassList* p = aSelector->mPseudoClassList; p; p = p->mNext) {
    2320           0 :     if (nsCSSPseudoClasses::HasSelectorListArg(p->mType)) {
    2321           0 :       for (nsCSSSelectorList* l = p->u.mSelectors; l; l = l->mNext) {
    2322           0 :         if (l->mSelectors->mNext) {
    2323           0 :           return true;
    2324             :         }
    2325             :       }
    2326             :     }
    2327             :   }
    2328       11875 :   for (nsCSSSelector* n = aSelector->mNegations; n; n = n->mNegations) {
    2329         543 :     if (n->mNext) {
    2330           0 :       return true;
    2331             :     }
    2332             :   }
    2333       11332 :   return false;
    2334             : }
    2335             : #endif
    2336             : 
    2337             : /* static */ bool
    2338       11332 : nsCSSRuleProcessor::RestrictedSelectorMatches(
    2339             :     Element* aElement,
    2340             :     nsCSSSelector* aSelector,
    2341             :     TreeMatchContext& aTreeMatchContext)
    2342             : {
    2343       11332 :   MOZ_ASSERT(aSelector->IsRestrictedSelector(),
    2344             :              "aSelector must not have a pseudo-element");
    2345             : 
    2346       11332 :   NS_WARNING_ASSERTION(
    2347             :     !HasPseudoClassSelectorArgsWithCombinators(aSelector),
    2348             :     "processing eRestyle_SomeDescendants can be slow if pseudo-classes with "
    2349             :     "selector arguments can now have combinators in them");
    2350             : 
    2351             :   // We match aSelector as if :visited and :link both match visited and
    2352             :   // unvisited links.
    2353             : 
    2354             :   NodeMatchContext nodeContext(EventStates(),
    2355       11332 :                                nsCSSRuleProcessor::IsLink(aElement));
    2356       11332 :   if (nodeContext.mIsRelevantLink) {
    2357           0 :     aTreeMatchContext.SetHaveRelevantLink();
    2358             :   }
    2359       11332 :   aTreeMatchContext.ResetForUnvisitedMatching();
    2360             :   bool matches = SelectorMatches(aElement, aSelector, nodeContext,
    2361       11332 :                                  aTreeMatchContext, SelectorMatchesFlags::NONE);
    2362       11332 :   if (nodeContext.mIsRelevantLink) {
    2363           0 :     aTreeMatchContext.ResetForVisitedMatching();
    2364           0 :     if (SelectorMatches(aElement, aSelector, nodeContext, aTreeMatchContext,
    2365             :                         SelectorMatchesFlags::NONE)) {
    2366           0 :       matches = true;
    2367             :     }
    2368             :   }
    2369       11332 :   return matches;
    2370             : }
    2371             : 
    2372             : // Right now, there are four operators:
    2373             : //   ' ', the descendant combinator, is greedy
    2374             : //   '~', the indirect adjacent sibling combinator, is greedy
    2375             : //   '+' and '>', the direct adjacent sibling and child combinators, are not
    2376             : #define NS_IS_GREEDY_OPERATOR(ch) \
    2377             :   ((ch) == char16_t(' ') || (ch) == char16_t('~'))
    2378             : 
    2379             : /**
    2380             :  * Flags for SelectorMatchesTree.
    2381             :  */
    2382             : enum SelectorMatchesTreeFlags {
    2383             :   // Whether we still have not found the closest ancestor link element and
    2384             :   // thus have to check the current element for it.
    2385             :   eLookForRelevantLink = 0x1,
    2386             : 
    2387             :   // Whether SelectorMatchesTree should check for, and return true upon
    2388             :   // finding, an ancestor element that has an eRestyle_SomeDescendants
    2389             :   // restyle hint pending.
    2390             :   eMatchOnConditionalRestyleAncestor = 0x2,
    2391             : };
    2392             : 
    2393             : static bool
    2394        7439 : SelectorMatchesTree(Element* aPrevElement,
    2395             :                     nsCSSSelector* aSelector,
    2396             :                     TreeMatchContext& aTreeMatchContext,
    2397             :                     SelectorMatchesTreeFlags aFlags)
    2398             : {
    2399        7439 :   MOZ_ASSERT(!aSelector || !aSelector->IsPseudoElement());
    2400        7439 :   nsCSSSelector* selector = aSelector;
    2401        7439 :   Element* prevElement = aPrevElement;
    2402       26241 :   while (selector) { // check compound selectors
    2403       15198 :     NS_ASSERTION(!selector->mNext ||
    2404             :                  selector->mNext->mOperator != char16_t(0),
    2405             :                  "compound selector without combinator");
    2406             : 
    2407             :     // If after the previous selector match we are now outside the
    2408             :     // current style scope, we don't need to match any further.
    2409       15198 :     if (aTreeMatchContext.mForScopedStyle &&
    2410           0 :         !aTreeMatchContext.IsWithinStyleScopeForSelectorMatching()) {
    2411        5797 :       return false;
    2412             :     }
    2413             : 
    2414             :     // for adjacent sibling combinators, the content to test against the
    2415             :     // selector is the previous sibling *element*
    2416       15198 :     Element* element = nullptr;
    2417       30305 :     if (char16_t('+') == selector->mOperator ||
    2418       15107 :         char16_t('~') == selector->mOperator) {
    2419             :       // The relevant link must be an ancestor of the node being matched.
    2420         140 :       aFlags = SelectorMatchesTreeFlags(aFlags & ~eLookForRelevantLink);
    2421         140 :       nsIContent* parent = prevElement->GetParent();
    2422         140 :       if (parent) {
    2423         140 :         if (aTreeMatchContext.mForStyling)
    2424         140 :           parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
    2425             : 
    2426         140 :         element = prevElement->GetPreviousElementSibling();
    2427         140 :       }
    2428             :     }
    2429             :     // for descendant combinators and child combinators, the element
    2430             :     // to test against is the parent
    2431             :     else {
    2432       15058 :       nsIContent *content = prevElement->GetParent();
    2433       15058 :       if (prevElement->IsRootOfUseElementShadowTree()) {
    2434             :         // 'prevElement' is the shadow root of an use-element shadow tree.
    2435             :         // According to the spec, we should not match rules cross the shadow
    2436             :         // DOM boundary.
    2437          46 :         content = nullptr;
    2438             :       }
    2439             :       // GetParent could return a document fragment; we only want
    2440             :       // element parents.
    2441       15058 :       if (content && content->IsElement()) {
    2442       13780 :         element = content->AsElement();
    2443       13780 :         if (aTreeMatchContext.mForScopedStyle) {
    2444             :           // We are moving up to the parent element; tell the
    2445             :           // TreeMatchContext, so that in case this element is the
    2446             :           // style scope element, selector matching stops before we
    2447             :           // traverse further up the tree.
    2448           0 :           aTreeMatchContext.PopStyleScopeForSelectorMatching(element);
    2449             :         }
    2450             : 
    2451             :         // Compatibility hack: First try matching this selector as though the
    2452             :         // <xbl:children> element wasn't in the tree to allow old selectors
    2453             :         // were written before <xbl:children> participated in CSS selector
    2454             :         // matching to work.
    2455       13780 :         if (selector->mOperator == '>' && element->IsActiveChildrenElement()) {
    2456           0 :           Element* styleScope = aTreeMatchContext.mCurrentStyleScope;
    2457           0 :           if (SelectorMatchesTree(element, selector, aTreeMatchContext,
    2458             :                                   aFlags)) {
    2459             :             // It matched, don't try matching on the <xbl:children> element at
    2460             :             // all.
    2461           0 :             return true;
    2462             :           }
    2463             :           // We want to reset mCurrentStyleScope on aTreeMatchContext
    2464             :           // back to its state before the SelectorMatchesTree call, in
    2465             :           // case that call happens to traverse past the style scope element
    2466             :           // and sets it to null.
    2467           0 :           aTreeMatchContext.mCurrentStyleScope = styleScope;
    2468             :         }
    2469             :       }
    2470             :     }
    2471       15198 :     if (!element) {
    2472        1294 :       return false;
    2473             :     }
    2474       14396 :     if ((aFlags & eMatchOnConditionalRestyleAncestor) &&
    2475         492 :         element->HasFlag(ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR)) {
    2476             :       // If we're looking at an element that we already generated an
    2477             :       // eRestyle_SomeDescendants restyle hint for, then we should pretend
    2478             :       // that we matched here, because we don't know what the values of
    2479             :       // attributes on |element| were at the time we generated the
    2480             :       // eRestyle_SomeDescendants.  This causes AttributeEnumFunc and
    2481             :       // HasStateDependentStyle below to generate a restyle hint for the
    2482             :       // change we're currently looking at, as we don't know whether the LHS
    2483             :       // of the selector we looked up matches or not.  (We only pass in aFlags
    2484             :       // to cause us to look for eRestyle_SomeDescendants here under
    2485             :       // AttributeEnumFunc and HasStateDependentStyle.)
    2486          14 :       return true;
    2487             :     }
    2488       27170 :     const bool isRelevantLink = (aFlags & eLookForRelevantLink) &&
    2489       27170 :                                 nsCSSRuleProcessor::IsLink(element);
    2490       13890 :     NodeMatchContext nodeContext(EventStates(), isRelevantLink);
    2491       13890 :     if (isRelevantLink) {
    2492             :       // If we find an ancestor of the matched node that is a link
    2493             :       // during the matching process, then it's the relevant link (see
    2494             :       // constructor call above).
    2495             :       // Since we are still matching against selectors that contain
    2496             :       // :visited (they'll just fail), we will always find such a node
    2497             :       // during the selector matching process if there is a relevant
    2498             :       // link that can influence selector matching.
    2499           0 :       aFlags = SelectorMatchesTreeFlags(aFlags & ~eLookForRelevantLink);
    2500           0 :       aTreeMatchContext.SetHaveRelevantLink();
    2501             :     }
    2502       13890 :     if (SelectorMatches(element, selector, nodeContext, aTreeMatchContext,
    2503             :                         SelectorMatchesFlags::NONE)) {
    2504             :       // to avoid greedy matching, we need to recur if this is a
    2505             :       // descendant or general sibling combinator and the next
    2506             :       // combinator is different, but we can make an exception for
    2507             :       // sibling, then parent, since a sibling's parent is always the
    2508             :       // same.
    2509        3294 :       if (NS_IS_GREEDY_OPERATOR(selector->mOperator) &&
    2510         833 :           selector->mNext &&
    2511          18 :           selector->mNext->mOperator != selector->mOperator &&
    2512           0 :           !(selector->mOperator == '~' &&
    2513           0 :             NS_IS_ANCESTOR_OPERATOR(selector->mNext->mOperator))) {
    2514             : 
    2515             :         // pretend the selector didn't match, and step through content
    2516             :         // while testing the same selector
    2517             : 
    2518             :         // This approach is slightly strange in that when it recurs
    2519             :         // it tests from the top of the content tree, down.  This
    2520             :         // doesn't matter much for performance since most selectors
    2521             :         // don't match.  (If most did, it might be faster...)
    2522           0 :         Element* styleScope = aTreeMatchContext.mCurrentStyleScope;
    2523           0 :         if (SelectorMatchesTree(element, selector, aTreeMatchContext, aFlags)) {
    2524           0 :           return true;
    2525             :         }
    2526             :         // We want to reset mCurrentStyleScope on aTreeMatchContext
    2527             :         // back to its state before the SelectorMatchesTree call, in
    2528             :         // case that call happens to traverse past the style scope element
    2529             :         // and sets it to null.
    2530           0 :         aTreeMatchContext.mCurrentStyleScope = styleScope;
    2531             :       }
    2532        2479 :       selector = selector->mNext;
    2533             :     }
    2534             :     else {
    2535             :       // for adjacent sibling and child combinators, if we didn't find
    2536             :       // a match, we're done
    2537       11411 :       if (!NS_IS_GREEDY_OPERATOR(selector->mOperator)) {
    2538        4489 :         return false;  // parent was required to match
    2539             :       }
    2540             :     }
    2541        9401 :     prevElement = element;
    2542             :   }
    2543        1642 :   return true; // all the selectors matched.
    2544             : }
    2545             : 
    2546             : static inline
    2547      187198 : void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector,
    2548             :                      ElementDependentRuleProcessorData* data, NodeMatchContext& nodeContext,
    2549             :                      AncestorFilter *ancestorFilter)
    2550             : {
    2551      187198 :   if (nodeContext.mIsRelevantLink) {
    2552           0 :     data->mTreeMatchContext.SetHaveRelevantLink();
    2553             :   }
    2554      354989 :   if (ancestorFilter &&
    2555      167791 :       !ancestorFilter->MightHaveMatchingAncestor<RuleValue::eMaxAncestorHashes>(
    2556             :           value.mAncestorSelectorHashes)) {
    2557             :     // We won't match; nothing else to do here
    2558      130500 :     return;
    2559             :   }
    2560      121948 :   if (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement,
    2561             :                                                                 data->mScope)) {
    2562             :     // The selector is for a rule in a scoped style sheet, and the subject
    2563             :     // of the selector matching is not in its scope.
    2564           0 :     return;
    2565             :   }
    2566      121948 :   nsCSSSelector* selector = aSelector;
    2567      121948 :   if (selector->IsPseudoElement()) {
    2568             :     PseudoElementRuleProcessorData* pdata =
    2569         256 :       static_cast<PseudoElementRuleProcessorData*>(data);
    2570         256 :     if (!pdata->mPseudoElement && selector->mPseudoClassList) {
    2571             :       // We can get here when calling getComputedStyle(aElt, aPseudo) if:
    2572             :       //
    2573             :       //   * aPseudo is a pseudo-element that supports a user action
    2574             :       //     pseudo-class, like "::placeholder";
    2575             :       //   * there is a style rule that uses a pseudo-class on this
    2576             :       //     pseudo-element in the document, like ::placeholder:hover; and
    2577             :       //   * aElt does not have such a pseudo-element.
    2578             :       //
    2579             :       // We know that the selector can't match, since there is no element for
    2580             :       // the user action pseudo-class to match against.
    2581           0 :       return;
    2582             :     }
    2583         256 :     if (!StateSelectorMatches(pdata->mPseudoElement, aSelector, nodeContext,
    2584             :                               data->mTreeMatchContext,
    2585             :                               SelectorMatchesFlags::NONE)) {
    2586           0 :       return;
    2587             :     }
    2588         256 :     selector = selector->mNext;
    2589             :   }
    2590             : 
    2591      121948 :   SelectorMatchesFlags selectorFlags = SelectorMatchesFlags::NONE;
    2592      121948 :   if (aSelector->IsPseudoElement()) {
    2593         256 :     selectorFlags |= SelectorMatchesFlags::HAS_PSEUDO_ELEMENT;
    2594             :   }
    2595      121948 :   if (SelectorMatches(data->mElement, selector, nodeContext,
    2596             :                       data->mTreeMatchContext, selectorFlags)) {
    2597       16201 :     nsCSSSelector *next = selector->mNext;
    2598       23368 :     if (!next ||
    2599        7167 :         SelectorMatchesTree(data->mElement, next,
    2600             :                             data->mTreeMatchContext,
    2601        7167 :                             nodeContext.mIsRelevantLink ?
    2602             :                               SelectorMatchesTreeFlags(0) :
    2603             :                               eLookForRelevantLink)) {
    2604       10475 :       css::Declaration* declaration = value.mRule->GetDeclaration();
    2605       10475 :       declaration->SetImmutable();
    2606       10475 :       data->mRuleWalker->Forward(declaration);
    2607             :       // nsStyleSet will deal with the !important rule
    2608             :     }
    2609             :   }
    2610             : }
    2611             : 
    2612             : /* virtual */ void
    2613        6605 : nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData)
    2614             : {
    2615        6605 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2616             : 
    2617        6605 :   if (cascade) {
    2618             :     NodeMatchContext nodeContext(EventStates(),
    2619        6605 :                                  nsCSSRuleProcessor::IsLink(aData->mElement));
    2620        6605 :     cascade->mRuleHash.EnumerateAllRules(aData->mElement, aData, nodeContext);
    2621             :   }
    2622        6605 : }
    2623             : 
    2624             : /* virtual */ void
    2625        3570 : nsCSSRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData)
    2626             : {
    2627        3570 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2628             : 
    2629        3570 :   if (cascade) {
    2630             :     RuleHash* ruleHash = cascade->mPseudoElementRuleHashes[
    2631        3570 :       static_cast<CSSPseudoElementTypeBase>(aData->mPseudoType)];
    2632        3570 :     if (ruleHash) {
    2633             :       NodeMatchContext nodeContext(EventStates(),
    2634        2163 :                                    nsCSSRuleProcessor::IsLink(aData->mElement));
    2635        2163 :       ruleHash->EnumerateAllRules(aData->mElement, aData, nodeContext);
    2636             :     }
    2637             :   }
    2638        3570 : }
    2639             : 
    2640             : /* virtual */ void
    2641         311 : nsCSSRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData)
    2642             : {
    2643         311 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2644             : 
    2645         311 :   if (cascade && cascade->mAnonBoxRules.EntryCount()) {
    2646             :     auto entry = static_cast<RuleHashTagTableEntry*>
    2647         210 :                             (cascade->mAnonBoxRules.Search(aData->mPseudoTag));
    2648         210 :     if (entry) {
    2649         180 :       nsTArray<RuleValue>& rules = entry->mRules;
    2650         369 :       for (RuleValue *value = rules.Elements(), *end = value + rules.Length();
    2651         369 :            value != end; ++value) {
    2652         189 :         css::Declaration* declaration = value->mRule->GetDeclaration();
    2653         189 :         declaration->SetImmutable();
    2654         189 :         aData->mRuleWalker->Forward(declaration);
    2655             :       }
    2656             :     }
    2657             :   }
    2658         311 : }
    2659             : 
    2660             : #ifdef MOZ_XUL
    2661             : /* virtual */ void
    2662           0 : nsCSSRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData)
    2663             : {
    2664           0 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2665             : 
    2666           0 :   if (cascade && cascade->mXULTreeRules.EntryCount()) {
    2667             :     auto entry = static_cast<RuleHashTagTableEntry*>
    2668           0 :                             (cascade->mXULTreeRules.Search(aData->mPseudoTag));
    2669           0 :     if (entry) {
    2670             :       NodeMatchContext nodeContext(EventStates(),
    2671           0 :                                    nsCSSRuleProcessor::IsLink(aData->mElement));
    2672           0 :       nsTArray<RuleValue>& rules = entry->mRules;
    2673           0 :       for (RuleValue *value = rules.Elements(), *end = value + rules.Length();
    2674           0 :            value != end; ++value) {
    2675           0 :         if (aData->mComparator->PseudoMatches(value->mSelector)) {
    2676           0 :           ContentEnumFunc(*value, value->mSelector->mNext, aData, nodeContext,
    2677           0 :                           nullptr);
    2678             :         }
    2679             :       }
    2680             :     }
    2681             :   }
    2682           0 : }
    2683             : #endif
    2684             : 
    2685       18462 : static inline nsRestyleHint RestyleHintForOp(char16_t oper)
    2686             : {
    2687       18462 :   if (oper == char16_t('+') || oper == char16_t('~')) {
    2688           0 :     return eRestyle_LaterSiblings;
    2689             :   }
    2690             : 
    2691       18462 :   if (oper != char16_t(0)) {
    2692        3704 :     return eRestyle_Subtree;
    2693             :   }
    2694             : 
    2695       14758 :   return eRestyle_Self;
    2696             : }
    2697             : 
    2698             : nsRestyleHint
    2699         137 : nsCSSRuleProcessor::HasStateDependentStyle(ElementDependentRuleProcessorData* aData,
    2700             :                                            Element* aStatefulElement,
    2701             :                                            CSSPseudoElementType aPseudoType,
    2702             :                                            EventStates aStateMask)
    2703             : {
    2704         137 :   MOZ_ASSERT(!aData->mTreeMatchContext.mForScopedStyle,
    2705             :              "mCurrentStyleScope will need to be saved and restored after the "
    2706             :              "SelectorMatchesTree call");
    2707             : 
    2708             :   bool isPseudoElement =
    2709         137 :     aPseudoType != CSSPseudoElementType::NotPseudo;
    2710             : 
    2711         137 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2712             : 
    2713             :   // Look up the content node in the state rule list, which points to
    2714             :   // any (CSS2 definition) simple selector (whether or not it is the
    2715             :   // subject) that has a state pseudo-class on it.  This means that this
    2716             :   // code will be matching selectors that aren't real selectors in any
    2717             :   // stylesheet (e.g., if there is a selector "body > p:hover > a", then
    2718             :   // "body > p:hover" will be in |cascade->mStateSelectors|).  Note that
    2719             :   // |ComputeSelectorStateDependence| below determines which selectors are in
    2720             :   // |cascade->mStateSelectors|.
    2721         137 :   nsRestyleHint hint = nsRestyleHint(0);
    2722         137 :   if (cascade) {
    2723         137 :     StateSelector *iter = cascade->mStateSelectors.Elements(),
    2724         137 :                   *end = iter + cascade->mStateSelectors.Length();
    2725         137 :     NodeMatchContext nodeContext(aStateMask, false);
    2726       37061 :     for(; iter != end; ++iter) {
    2727       18462 :       nsCSSSelector* selector = iter->mSelector;
    2728       18462 :       EventStates states = iter->mStates;
    2729             : 
    2730       18462 :       if (selector->IsPseudoElement() != isPseudoElement) {
    2731           0 :         continue;
    2732             :       }
    2733             : 
    2734             :       nsCSSSelector* selectorForPseudo;
    2735       18462 :       if (isPseudoElement) {
    2736           0 :         if (selector->PseudoType() != aPseudoType) {
    2737           0 :           continue;
    2738             :         }
    2739           0 :         selectorForPseudo = selector;
    2740           0 :         selector = selector->mNext;
    2741             :       }
    2742             : 
    2743       18462 :       nsRestyleHint possibleChange = RestyleHintForOp(selector->mOperator);
    2744       18462 :       SelectorMatchesFlags selectorFlags = SelectorMatchesFlags::UNKNOWN;
    2745             : 
    2746             :       // If hint already includes all the bits of possibleChange,
    2747             :       // don't bother calling SelectorMatches, since even if it returns false
    2748             :       // hint won't change.
    2749             :       // Also don't bother calling SelectorMatches if none of the
    2750             :       // states passed in are relevant here.
    2751       86733 :       if ((possibleChange & ~hint) &&
    2752       29388 :           states.HasAtLeastOneOfStates(aStateMask) &&
    2753             :           // We can optimize away testing selectors that only involve :hover, a
    2754             :           // namespace, and a tag name against nodes that don't have the
    2755             :           // NodeHasRelevantHoverRules flag: such a selector didn't match
    2756             :           // the tag name or namespace the first time around (since the :hover
    2757             :           // didn't set the NodeHasRelevantHoverRules flag), so it won't
    2758             :           // match it now.  Check for our selector only having :hover states, or
    2759             :           // the element having the hover rules flag, or the selector having
    2760             :           // some sort of non-namespace, non-tagname data in it.
    2761       38537 :           (states != NS_EVENT_STATE_HOVER ||
    2762        7144 :            aStatefulElement->HasRelevantHoverRules() ||
    2763        6612 :            selector->mIDList || selector->mClassList ||
    2764             :            // We generally expect an mPseudoClassList, since we have a :hover.
    2765             :            // The question is whether we have anything else in there.
    2766        1008 :            (selector->mPseudoClassList &&
    2767         980 :             (selector->mPseudoClassList->mNext ||
    2768         476 :              selector->mPseudoClassList->mType !=
    2769         448 :                CSSPseudoClassType::hover)) ||
    2770        5977 :            selector->mAttrList || selector->mNegations) &&
    2771        5333 :           (!isPseudoElement ||
    2772           0 :            StateSelectorMatches(aStatefulElement, selectorForPseudo,
    2773             :                                 nodeContext, aData->mTreeMatchContext,
    2774        5333 :                                 selectorFlags, nullptr, aStateMask)) &&
    2775        5333 :           SelectorMatches(aData->mElement, selector, nodeContext,
    2776       36930 :                           aData->mTreeMatchContext, selectorFlags) &&
    2777           6 :           SelectorMatchesTree(aData->mElement, selector->mNext,
    2778             :                               aData->mTreeMatchContext,
    2779             :                               eMatchOnConditionalRestyleAncestor))
    2780             :       {
    2781           6 :         hint = nsRestyleHint(hint | possibleChange);
    2782             :       }
    2783             :     }
    2784             :   }
    2785         137 :   return hint;
    2786             : }
    2787             : 
    2788             : nsRestyleHint
    2789         137 : nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData)
    2790             : {
    2791             :   return HasStateDependentStyle(aData,
    2792         137 :                                 aData->mElement,
    2793             :                                 CSSPseudoElementType::NotPseudo,
    2794         137 :                                 aData->mStateMask);
    2795             : }
    2796             : 
    2797             : nsRestyleHint
    2798           0 : nsCSSRuleProcessor::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData)
    2799             : {
    2800           0 :   return HasStateDependentStyle(aData,
    2801           0 :                                 aData->mPseudoElement,
    2802             :                                 aData->mPseudoType,
    2803           0 :                                 aData->mStateMask);
    2804             : }
    2805             : 
    2806             : bool
    2807          27 : nsCSSRuleProcessor::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
    2808             : {
    2809          27 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2810             : 
    2811          27 :   return cascade && cascade->mSelectorDocumentStates.HasAtLeastOneOfStates(aData->mStateMask);
    2812             : }
    2813             : 
    2814             : struct AttributeEnumData {
    2815        1525 :   AttributeEnumData(AttributeRuleProcessorData *aData,
    2816             :                     RestyleHintData& aRestyleHintData)
    2817        1525 :     : data(aData), change(nsRestyleHint(0)), hintData(aRestyleHintData) {}
    2818             : 
    2819             :   AttributeRuleProcessorData *data;
    2820             :   nsRestyleHint change;
    2821             :   RestyleHintData& hintData;
    2822             : };
    2823             : 
    2824             : 
    2825             : static inline nsRestyleHint
    2826       14066 : RestyleHintForSelectorWithAttributeChange(nsRestyleHint aCurrentHint,
    2827             :                                           nsCSSSelector* aSelector,
    2828             :                                           nsCSSSelector* aRightmostSelector)
    2829             : {
    2830       14066 :   MOZ_ASSERT(aSelector);
    2831             : 
    2832       14066 :   char16_t oper = aSelector->mOperator;
    2833             : 
    2834       14066 :   if (oper == char16_t('+') || oper == char16_t('~')) {
    2835          82 :     return eRestyle_LaterSiblings;
    2836             :   }
    2837             : 
    2838       13984 :   if (oper == char16_t(':')) {
    2839         282 :     return eRestyle_Subtree;
    2840             :   }
    2841             : 
    2842       13702 :   if (oper != char16_t(0)) {
    2843             :     // Check whether the selector is in a form that supports
    2844             :     // eRestyle_SomeDescendants.  If it isn't, return eRestyle_Subtree.
    2845             : 
    2846        5135 :     if (aCurrentHint & eRestyle_Subtree) {
    2847             :       // No point checking, since we'll end up restyling the whole
    2848             :       // subtree anyway.
    2849         277 :       return eRestyle_Subtree;
    2850             :     }
    2851             : 
    2852        4858 :     if (!aRightmostSelector) {
    2853             :       // aSelector wasn't a top-level selector, which means we were inside
    2854             :       // a :not() or :-moz-any().  We don't support that.
    2855         499 :       return eRestyle_Subtree;
    2856             :     }
    2857             : 
    2858        4359 :     MOZ_ASSERT(aSelector != aRightmostSelector,
    2859             :                "if aSelector == aRightmostSelector then we should have "
    2860             :                "no operator");
    2861             : 
    2862             :     // Check that aRightmostSelector can be passed to RestrictedSelectorMatches.
    2863        4359 :     if (!aRightmostSelector->IsRestrictedSelector()) {
    2864          48 :       return eRestyle_Subtree;
    2865             :     }
    2866             : 
    2867             :     // We also don't support pseudo-elements on any of the selectors
    2868             :     // between aRightmostSelector and aSelector.
    2869             :     // XXX Can we lift this restriction, so that we don't have to loop
    2870             :     // over all the selectors?
    2871        5539 :     for (nsCSSSelector* sel = aRightmostSelector->mNext;
    2872        5539 :          sel != aSelector;
    2873        1228 :          sel = sel->mNext) {
    2874        1228 :       MOZ_ASSERT(sel, "aSelector must be reachable from aRightmostSelector");
    2875        1228 :       if (sel->PseudoType() != CSSPseudoElementType::NotPseudo) {
    2876           0 :         return eRestyle_Subtree;
    2877             :       }
    2878             :     }
    2879             : 
    2880        4311 :     return eRestyle_SomeDescendants;
    2881             :   }
    2882             : 
    2883        8567 :   return eRestyle_Self;
    2884             : }
    2885             : 
    2886             : static void
    2887       14066 : AttributeEnumFunc(nsCSSSelector* aSelector,
    2888             :                   nsCSSSelector* aRightmostSelector,
    2889             :                   AttributeEnumData* aData)
    2890             : {
    2891       14066 :   AttributeRuleProcessorData *data = aData->data;
    2892             : 
    2893       14066 :   if (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement,
    2894             :                                                                 data->mScope)) {
    2895             :     // The selector is for a rule in a scoped style sheet, and the subject
    2896             :     // of the selector matching is not in its scope.
    2897           0 :     return;
    2898             :   }
    2899             : 
    2900             :   nsRestyleHint possibleChange =
    2901       14066 :     RestyleHintForSelectorWithAttributeChange(aData->change,
    2902       14066 :                                               aSelector, aRightmostSelector);
    2903             : 
    2904             :   // If, ignoring eRestyle_SomeDescendants, enumData->change already includes
    2905             :   // all the bits of possibleChange, don't bother calling SelectorMatches, since
    2906             :   // even if it returns false enumData->change won't change.  If possibleChange
    2907             :   // has eRestyle_SomeDescendants, we need to call SelectorMatches(Tree)
    2908             :   // regardless as it might give us new selectors to append to
    2909             :   // mSelectorsForDescendants.
    2910       14066 :   NodeMatchContext nodeContext(EventStates(), false);
    2911       41004 :   if (((possibleChange & (~(aData->change) | eRestyle_SomeDescendants))) &&
    2912       12872 :       SelectorMatches(data->mElement, aSelector, nodeContext,
    2913       14329 :                       data->mTreeMatchContext, SelectorMatchesFlags::UNKNOWN) &&
    2914         263 :       SelectorMatchesTree(data->mElement, aSelector->mNext,
    2915             :                           data->mTreeMatchContext,
    2916             :                           eMatchOnConditionalRestyleAncestor)) {
    2917         206 :     aData->change = nsRestyleHint(aData->change | possibleChange);
    2918         206 :     if (possibleChange & eRestyle_SomeDescendants) {
    2919         104 :       aData->hintData.mSelectorsForDescendants.AppendElement(aRightmostSelector);
    2920             :     }
    2921             :   }
    2922             : }
    2923             : 
    2924             : static MOZ_ALWAYS_INLINE void
    2925         508 : EnumerateSelectors(nsTArray<SelectorPair>& aSelectors, AttributeEnumData* aData)
    2926             : {
    2927         508 :   SelectorPair *iter = aSelectors.Elements(),
    2928         508 :                *end = iter + aSelectors.Length();
    2929       26016 :   for (; iter != end; ++iter) {
    2930       12754 :     AttributeEnumFunc(iter->mSelector, iter->mRightmostSelector, aData);
    2931             :   }
    2932         508 : }
    2933             : 
    2934             : static MOZ_ALWAYS_INLINE void
    2935          52 : EnumerateSelectors(nsTArray<nsCSSSelector*>& aSelectors, AttributeEnumData* aData)
    2936             : {
    2937          52 :   nsCSSSelector **iter = aSelectors.Elements(),
    2938          52 :                 **end = iter + aSelectors.Length();
    2939        2676 :   for (; iter != end; ++iter) {
    2940        1312 :     AttributeEnumFunc(*iter, nullptr, aData);
    2941             :   }
    2942          52 : }
    2943             : 
    2944             : nsRestyleHint
    2945        1525 : nsCSSRuleProcessor::HasAttributeDependentStyle(
    2946             :     AttributeRuleProcessorData* aData,
    2947             :     RestyleHintData& aRestyleHintDataResult)
    2948             : {
    2949             :   //  We could try making use of aData->mModType, but :not rules make it a bit
    2950             :   //  of a pain to do so...  So just ignore it for now.
    2951             : 
    2952        1525 :   AttributeEnumData data(aData, aRestyleHintDataResult);
    2953             : 
    2954             :   // Don't do our special handling of certain attributes if the attr
    2955             :   // hasn't changed yet.
    2956        1525 :   if (aData->mAttrHasChanged) {
    2957             :     // check for the lwtheme and lwthemetextcolor attribute on root XUL elements
    2958        2274 :     if ((aData->mAttribute == nsGkAtoms::lwtheme ||
    2959         758 :          aData->mAttribute == nsGkAtoms::lwthemetextcolor) &&
    2960         758 :         aData->mElement->GetNameSpaceID() == kNameSpaceID_XUL &&
    2961           0 :         aData->mElement == aData->mElement->OwnerDoc()->GetRootElement())
    2962             :       {
    2963           0 :         data.change = nsRestyleHint(data.change | eRestyle_Subtree);
    2964             :       }
    2965             : 
    2966             :     // We don't know the namespace of the attribute, and xml:lang applies to
    2967             :     // all elements.  If the lang attribute changes, we need to restyle our
    2968             :     // whole subtree, since the :lang selector on our descendants can examine
    2969             :     // our lang attribute.
    2970         758 :     if (aData->mAttribute == nsGkAtoms::lang) {
    2971           0 :       data.change = nsRestyleHint(data.change | eRestyle_Subtree);
    2972             :     }
    2973             :   }
    2974             : 
    2975        1525 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2976             : 
    2977             :   // Since we get both before and after notifications for attributes, we
    2978             :   // don't have to ignore aData->mAttribute while matching.  Just check
    2979             :   // whether we have selectors relevant to aData->mAttribute that we
    2980             :   // match.  If this is the before change notification, that will catch
    2981             :   // rules we might stop matching; if the after change notification, the
    2982             :   // ones we might have started matching.
    2983        1525 :   if (cascade) {
    2984        1525 :     if (aData->mAttribute == nsGkAtoms::id) {
    2985           6 :       nsIAtom* id = aData->mElement->GetID();
    2986           6 :       if (id) {
    2987             :         auto entry =
    2988           3 :           static_cast<AtomSelectorEntry*>(cascade->mIdSelectors.Search(id));
    2989           3 :         if (entry) {
    2990           0 :           EnumerateSelectors(entry->mSelectors, &data);
    2991             :         }
    2992             :       }
    2993             : 
    2994           6 :       EnumerateSelectors(cascade->mPossiblyNegatedIDSelectors, &data);
    2995             :     }
    2996             : 
    2997        1571 :     if (aData->mAttribute == nsGkAtoms::_class &&
    2998          46 :         aData->mNameSpaceID == kNameSpaceID_None) {
    2999          46 :       const nsAttrValue* otherClasses = aData->mOtherValue;
    3000          46 :       NS_ASSERTION(otherClasses ||
    3001             :                    aData->mModType == nsIDOMMutationEvent::REMOVAL,
    3002             :                    "All class values should be StoresOwnData and parsed"
    3003             :                    "via Element::BeforeSetAttr, so available here");
    3004             :       // For WillChange, enumerate classes that will be removed to see which
    3005             :       // rules apply before the change.
    3006             :       // For Changed, enumerate classes that have been added to see which rules
    3007             :       // apply after the change.
    3008             :       // In both cases we're interested in the classes that are currently on
    3009             :       // the element but not in mOtherValue.
    3010          46 :       const nsAttrValue* elementClasses = aData->mElement->GetClasses();
    3011          46 :       if (elementClasses) {
    3012          35 :         int32_t atomCount = elementClasses->GetAtomCount();
    3013          35 :         if (atomCount > 0) {
    3014          70 :           nsTHashtable<nsPtrHashKey<nsIAtom>> otherClassesTable;
    3015          35 :           if (otherClasses) {
    3016          35 :             int32_t otherClassesCount = otherClasses->GetAtomCount();
    3017          71 :             for (int32_t i = 0; i < otherClassesCount; ++i) {
    3018          36 :               otherClassesTable.PutEntry(otherClasses->AtomAt(i));
    3019             :             }
    3020             :           }
    3021          82 :           for (int32_t i = 0; i < atomCount; ++i) {
    3022          47 :             nsIAtom* curClass = elementClasses->AtomAt(i);
    3023          47 :             if (!otherClassesTable.Contains(curClass)) {
    3024             :               auto entry =
    3025             :                 static_cast<AtomSelectorEntry*>
    3026          23 :                            (cascade->mClassSelectors.Search(curClass));
    3027          23 :               if (entry) {
    3028           8 :                 EnumerateSelectors(entry->mSelectors, &data);
    3029             :               }
    3030             :             }
    3031             :           }
    3032             :         }
    3033             :       }
    3034             : 
    3035          46 :       EnumerateSelectors(cascade->mPossiblyNegatedClassSelectors, &data);
    3036             :     }
    3037             : 
    3038             :     auto entry =
    3039             :       static_cast<AtomSelectorEntry*>
    3040        1525 :                  (cascade->mAttributeSelectors.Search(aData->mAttribute));
    3041        1525 :     if (entry) {
    3042         500 :       EnumerateSelectors(entry->mSelectors, &data);
    3043             :     }
    3044             :   }
    3045             : 
    3046        1525 :   return data.change;
    3047             : }
    3048             : 
    3049             : /* virtual */ bool
    3050          97 : nsCSSRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext)
    3051             : {
    3052             :   // We don't want to do anything if there aren't any sets of rules
    3053             :   // cached yet, since we should not build the rule cascade too early
    3054             :   // (e.g., before we know whether the quirk style sheet should be
    3055             :   // enabled).  And if there's nothing cached, it doesn't matter if
    3056             :   // anything changed.  But in the cases where it does matter, we've
    3057             :   // cached a previous cache key to test against, instead of our current
    3058             :   // rule cascades.  See bug 448281 and bug 1089417.
    3059          97 :   MOZ_ASSERT(!(mRuleCascades && mPreviousCacheKey));
    3060          97 :   RuleCascadeData *old = mRuleCascades;
    3061          97 :   if (old) {
    3062          97 :     RefreshRuleCascade(aPresContext);
    3063          97 :     return (old != mRuleCascades);
    3064             :   }
    3065             : 
    3066           0 :   if (mPreviousCacheKey) {
    3067             :     // RefreshRuleCascade will get rid of mPreviousCacheKey anyway to
    3068             :     // maintain the invariant that we can't have both an mRuleCascades
    3069             :     // and an mPreviousCacheKey.  But we need to hold it a little
    3070             :     // longer.
    3071             :     UniquePtr<nsMediaQueryResultCacheKey> previousCacheKey(
    3072           0 :       Move(mPreviousCacheKey));
    3073           0 :     RefreshRuleCascade(aPresContext);
    3074             : 
    3075             :     // This test is a bit pessimistic since the cache key's operator==
    3076             :     // just does list comparison rather than set comparison, but it
    3077             :     // should catch all the cases we care about (i.e., where the cascade
    3078             :     // order hasn't changed).  Other cases will do a restyle anyway, so
    3079             :     // we shouldn't need to worry about posting a second.
    3080           0 :     return !mRuleCascades || // all sheets gone, but we had sheets before
    3081           0 :            mRuleCascades->mCacheKey != *previousCacheKey;
    3082             :   }
    3083             : 
    3084           0 :   return false;
    3085             : }
    3086             : 
    3087             : UniquePtr<nsMediaQueryResultCacheKey>
    3088          33 : nsCSSRuleProcessor::CloneMQCacheKey()
    3089             : {
    3090          33 :   MOZ_ASSERT(!(mRuleCascades && mPreviousCacheKey));
    3091             : 
    3092          33 :   RuleCascadeData* c = mRuleCascades;
    3093          33 :   if (!c) {
    3094             :     // We might have an mPreviousCacheKey.  It already comes from a call
    3095             :     // to CloneMQCacheKey, so don't bother checking
    3096             :     // HasFeatureConditions().
    3097          28 :     if (mPreviousCacheKey) {
    3098           0 :       NS_ASSERTION(mPreviousCacheKey->HasFeatureConditions(),
    3099             :                    "we shouldn't have a previous cache key unless it has "
    3100             :                    "feature conditions");
    3101           0 :       return MakeUnique<nsMediaQueryResultCacheKey>(*mPreviousCacheKey);
    3102             :     }
    3103             : 
    3104          28 :     return UniquePtr<nsMediaQueryResultCacheKey>();
    3105             :   }
    3106             : 
    3107           5 :   if (!c->mCacheKey.HasFeatureConditions()) {
    3108           0 :     return UniquePtr<nsMediaQueryResultCacheKey>();
    3109             :   }
    3110             : 
    3111           5 :   return MakeUnique<nsMediaQueryResultCacheKey>(c->mCacheKey);
    3112             : }
    3113             : 
    3114             : /* virtual */ size_t
    3115           5 : nsCSSRuleProcessor::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
    3116             : {
    3117           5 :   size_t n = 0;
    3118           5 :   n += mSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
    3119           7 :   for (RuleCascadeData* cascade = mRuleCascades; cascade;
    3120           2 :        cascade = cascade->mNext) {
    3121           2 :     n += cascade->SizeOfIncludingThis(aMallocSizeOf);
    3122             :   }
    3123             : 
    3124           5 :   return n;
    3125             : }
    3126             : 
    3127             : /* virtual */ size_t
    3128           5 : nsCSSRuleProcessor::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
    3129             : {
    3130           5 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    3131             : }
    3132             : 
    3133             : // Append all the currently-active font face rules to aArray.  Return
    3134             : // true for success and false for failure.
    3135             : bool
    3136          16 : nsCSSRuleProcessor::AppendFontFaceRules(
    3137             :                               nsPresContext *aPresContext,
    3138             :                               nsTArray<nsFontFaceRuleContainer>& aArray)
    3139             : {
    3140          16 :   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
    3141             : 
    3142          16 :   if (cascade) {
    3143          16 :     if (!aArray.AppendElements(cascade->mFontFaceRules))
    3144           0 :       return false;
    3145             :   }
    3146             : 
    3147          16 :   return true;
    3148             : }
    3149             : 
    3150             : nsCSSKeyframesRule*
    3151           0 : nsCSSRuleProcessor::KeyframesRuleForName(nsPresContext* aPresContext,
    3152             :                                          const nsString& aName)
    3153             : {
    3154           0 :   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
    3155             : 
    3156           0 :   if (cascade) {
    3157           0 :     return cascade->mKeyframesRuleTable.Get(aName);
    3158             :   }
    3159             : 
    3160           0 :   return nullptr;
    3161             : }
    3162             : 
    3163             : nsCSSCounterStyleRule*
    3164           0 : nsCSSRuleProcessor::CounterStyleRuleForName(nsPresContext* aPresContext,
    3165             :                                             nsIAtom* aName)
    3166             : {
    3167           0 :   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
    3168             : 
    3169           0 :   if (cascade) {
    3170           0 :     return cascade->mCounterStyleRuleTable.Get(aName);
    3171             :   }
    3172             : 
    3173           0 :   return nullptr;
    3174             : }
    3175             : 
    3176             : // Append all the currently-active page rules to aArray.  Return
    3177             : // true for success and false for failure.
    3178             : bool
    3179           0 : nsCSSRuleProcessor::AppendPageRules(
    3180             :                               nsPresContext* aPresContext,
    3181             :                               nsTArray<nsCSSPageRule*>& aArray)
    3182             : {
    3183           0 :   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
    3184             : 
    3185           0 :   if (cascade) {
    3186           0 :     if (!aArray.AppendElements(cascade->mPageRules)) {
    3187           0 :       return false;
    3188             :     }
    3189             :   }
    3190             : 
    3191           0 :   return true;
    3192             : }
    3193             : 
    3194             : bool
    3195           0 : nsCSSRuleProcessor::AppendFontFeatureValuesRules(
    3196             :                               nsPresContext *aPresContext,
    3197             :                               nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
    3198             : {
    3199           0 :   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
    3200             : 
    3201           0 :   if (cascade) {
    3202           0 :     if (!aArray.AppendElements(cascade->mFontFeatureValuesRules))
    3203           0 :       return false;
    3204             :   }
    3205             : 
    3206           0 :   return true;
    3207             : }
    3208             : 
    3209             : nsresult
    3210          15 : nsCSSRuleProcessor::ClearRuleCascades()
    3211             : {
    3212          15 :   if (!mPreviousCacheKey) {
    3213          15 :     mPreviousCacheKey = CloneMQCacheKey();
    3214             :   }
    3215             : 
    3216             :   // No need to remove the rule processor from the RuleProcessorCache here,
    3217             :   // since CSSStyleSheet::ClearRuleCascades will have called
    3218             :   // RuleProcessorCache::RemoveSheet() passing itself, which will catch
    3219             :   // this rule processor (and any others for different @-moz-document
    3220             :   // cache key results).
    3221          15 :   MOZ_ASSERT(!RuleProcessorCache::HasRuleProcessor(this));
    3222             : 
    3223             : #ifdef DEBUG
    3224             :   // For shared rule processors, if we've already gathered document
    3225             :   // rules, then they will now be out of date.  We don't actually need
    3226             :   // them to be up-to-date (see the comment in RefreshRuleCascade), so
    3227             :   // record their invalidity so we can assert if we try to use them.
    3228          15 :   if (!mMustGatherDocumentRules) {
    3229          15 :     mDocumentRulesAndCacheKeyValid = false;
    3230             :   }
    3231             : #endif
    3232             : 
    3233             :   // We rely on our caller (perhaps indirectly) to do something that
    3234             :   // will rebuild style data and the user font set (either
    3235             :   // nsIPresShell::RestyleForCSSRuleChanges or
    3236             :   // nsPresContext::RebuildAllStyleData).
    3237          15 :   RuleCascadeData *data = mRuleCascades;
    3238          15 :   mRuleCascades = nullptr;
    3239          17 :   while (data) {
    3240           1 :     RuleCascadeData *next = data->mNext;
    3241           1 :     delete data;
    3242           1 :     data = next;
    3243             :   }
    3244          15 :   return NS_OK;
    3245             : }
    3246             : 
    3247             : 
    3248             : // This function should return the set of states that this selector
    3249             : // depends on; this is used to implement HasStateDependentStyle.  It
    3250             : // does NOT recur down into things like :not and :-moz-any.
    3251             : inline
    3252       26598 : EventStates ComputeSelectorStateDependence(nsCSSSelector& aSelector)
    3253             : {
    3254       26598 :   EventStates states;
    3255       32174 :   for (nsPseudoClassList* pseudoClass = aSelector.mPseudoClassList;
    3256       37750 :        pseudoClass; pseudoClass = pseudoClass->mNext) {
    3257             :     // Tree pseudo-elements overload mPseudoClassList for things that
    3258             :     // aren't pseudo-classes.
    3259        5576 :     if (pseudoClass->mType >= CSSPseudoClassType::Count) {
    3260           0 :       continue;
    3261             :     }
    3262             : 
    3263        5576 :     auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
    3264        5576 :     states |= sPseudoClassStateDependences[idx];
    3265             :   }
    3266       26598 :   return states;
    3267             : }
    3268             : 
    3269             : static bool
    3270       24905 : AddSelector(RuleCascadeData* aCascade,
    3271             :             // The part between combinators at the top level of the selector
    3272             :             nsCSSSelector* aSelectorInTopLevel,
    3273             :             // The part we should look through (might be in :not or :-moz-any())
    3274             :             nsCSSSelector* aSelectorPart,
    3275             :             // The right-most selector at the top level
    3276             :             nsCSSSelector* aRightmostSelector)
    3277             : {
    3278             :   // It's worth noting that this loop over negations isn't quite
    3279             :   // optimal for two reasons.  One, we could add something to one of
    3280             :   // these lists twice, which means we'll check it twice, but I don't
    3281             :   // think that's worth worrying about.   (We do the same for multiple
    3282             :   // attribute selectors on the same attribute.)  Two, we don't really
    3283             :   // need to check negations past the first in the current
    3284             :   // implementation (and they're rare as well), but that might change
    3285             :   // in the future if :not() is extended.
    3286       51503 :   for (nsCSSSelector* negation = aSelectorPart; negation;
    3287       26598 :        negation = negation->mNegations) {
    3288             :     // Track both document states and attribute dependence in pseudo-classes.
    3289       32174 :     for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList;
    3290       37750 :          pseudoClass; pseudoClass = pseudoClass->mNext) {
    3291        5576 :       switch (pseudoClass->mType) {
    3292             :         case CSSPseudoClassType::mozLocaleDir: {
    3293         313 :           aCascade->mSelectorDocumentStates |= NS_DOCUMENT_STATE_RTL_LOCALE;
    3294         313 :           break;
    3295             :         }
    3296             :         case CSSPseudoClassType::mozWindowInactive: {
    3297          15 :           aCascade->mSelectorDocumentStates |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
    3298          15 :           break;
    3299             :         }
    3300             :         case CSSPseudoClassType::mozTableBorderNonzero: {
    3301             :           nsTArray<SelectorPair> *array =
    3302          56 :             aCascade->AttributeListFor(nsGkAtoms::border);
    3303          56 :           if (!array) {
    3304           0 :             return false;
    3305             :           }
    3306         112 :           array->AppendElement(SelectorPair(aSelectorInTopLevel,
    3307          56 :                                             aRightmostSelector));
    3308          56 :           break;
    3309             :         }
    3310             :         default: {
    3311        5192 :           break;
    3312             :         }
    3313             :       }
    3314             :     }
    3315             : 
    3316             :     // Build mStateSelectors.
    3317       26598 :     EventStates dependentStates = ComputeSelectorStateDependence(*negation);
    3318       26598 :     if (!dependentStates.IsEmpty()) {
    3319        1912 :       aCascade->mStateSelectors.AppendElement(
    3320        3824 :         nsCSSRuleProcessor::StateSelector(dependentStates,
    3321        1912 :                                           aSelectorInTopLevel));
    3322             :     }
    3323             : 
    3324             :     // Build mIDSelectors
    3325       26598 :     if (negation == aSelectorInTopLevel) {
    3326       27887 :       for (nsAtomList* curID = negation->mIDList; curID;
    3327        5197 :            curID = curID->mNext) {
    3328             :         auto entry = static_cast<AtomSelectorEntry*>
    3329        5197 :           (aCascade->mIdSelectors.Add(curID->mAtom, fallible));
    3330        5197 :         if (entry) {
    3331       10394 :           entry->mSelectors.AppendElement(SelectorPair(aSelectorInTopLevel,
    3332        5197 :                                                        aRightmostSelector));
    3333             :         }
    3334             :       }
    3335        3908 :     } else if (negation->mIDList) {
    3336         650 :       aCascade->mPossiblyNegatedIDSelectors.AppendElement(aSelectorInTopLevel);
    3337             :     }
    3338             : 
    3339             :     // Build mClassSelectors
    3340       26598 :     if (negation == aSelectorInTopLevel) {
    3341       29712 :       for (nsAtomList* curClass = negation->mClassList; curClass;
    3342        7022 :            curClass = curClass->mNext) {
    3343             :         auto entry = static_cast<AtomSelectorEntry*>
    3344        7022 :           (aCascade->mClassSelectors.Add(curClass->mAtom, fallible));
    3345        7022 :         if (entry) {
    3346       14044 :           entry->mSelectors.AppendElement(SelectorPair(aSelectorInTopLevel,
    3347        7022 :                                                        aRightmostSelector));
    3348             :         }
    3349             :       }
    3350        3908 :     } else if (negation->mClassList) {
    3351         169 :       aCascade->mPossiblyNegatedClassSelectors.AppendElement(aSelectorInTopLevel);
    3352             :     }
    3353             : 
    3354             :     // Build mAttributeSelectors.
    3355       33752 :     for (nsAttrSelector *attr = negation->mAttrList; attr;
    3356        7154 :          attr = attr->mNext) {
    3357             :       nsTArray<SelectorPair> *array =
    3358        7154 :         aCascade->AttributeListFor(attr->mCasedAttr);
    3359        7154 :       if (!array) {
    3360           0 :         return false;
    3361             :       }
    3362       14308 :       array->AppendElement(SelectorPair(aSelectorInTopLevel,
    3363        7154 :                                         aRightmostSelector));
    3364        7154 :       if (attr->mLowercaseAttr != attr->mCasedAttr) {
    3365         250 :         array = aCascade->AttributeListFor(attr->mLowercaseAttr);
    3366         250 :         if (!array) {
    3367           0 :           return false;
    3368             :         }
    3369         500 :         array->AppendElement(SelectorPair(aSelectorInTopLevel,
    3370         250 :                                           aRightmostSelector));
    3371             :       }
    3372             :     }
    3373             : 
    3374             :     // Recur through any :-moz-any selectors
    3375       32174 :     for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList;
    3376       37750 :          pseudoClass; pseudoClass = pseudoClass->mNext) {
    3377        5576 :       if (pseudoClass->mType == CSSPseudoClassType::any) {
    3378        2760 :         for (nsCSSSelectorList *l = pseudoClass->u.mSelectors; l; l = l->mNext) {
    3379        2215 :           nsCSSSelector *s = l->mSelectors;
    3380        2215 :           if (!AddSelector(aCascade, aSelectorInTopLevel, s,
    3381             :                            aRightmostSelector)) {
    3382           0 :             return false;
    3383             :           }
    3384             :         }
    3385             :       }
    3386             :     }
    3387             :   }
    3388             : 
    3389       24905 :   return true;
    3390             : }
    3391             : 
    3392             : static bool
    3393       14586 : AddRule(RuleSelectorPair* aRuleInfo, RuleCascadeData* aCascade)
    3394             : {
    3395       14586 :   RuleCascadeData * const cascade = aCascade;
    3396             : 
    3397             :   // Build the rule hash.
    3398       14586 :   CSSPseudoElementType pseudoType = aRuleInfo->mSelector->PseudoType();
    3399       14586 :   if (MOZ_LIKELY(pseudoType == CSSPseudoElementType::NotPseudo)) {
    3400       13444 :     cascade->mRuleHash.AppendRule(*aRuleInfo);
    3401        1142 :   } else if (pseudoType < CSSPseudoElementType::Count) {
    3402             :     RuleHash*& ruleHash = cascade->mPseudoElementRuleHashes[
    3403         696 :       static_cast<CSSPseudoElementTypeBase>(pseudoType)];
    3404         696 :     if (!ruleHash) {
    3405         169 :       ruleHash = new RuleHash(cascade->mQuirksMode);
    3406         169 :       if (!ruleHash) {
    3407             :         // Out of memory; give up
    3408           0 :         return false;
    3409             :       }
    3410             :     }
    3411         696 :     NS_ASSERTION(aRuleInfo->mSelector->mNext,
    3412             :                  "Must have mNext; parser screwed up");
    3413         696 :     NS_ASSERTION(aRuleInfo->mSelector->mNext->mOperator == ':',
    3414             :                  "Unexpected mNext combinator");
    3415         696 :     ruleHash->AppendRule(*aRuleInfo);
    3416         446 :   } else if (pseudoType == CSSPseudoElementType::InheritingAnonBox ||
    3417             :              pseudoType == CSSPseudoElementType::NonInheritingAnonBox) {
    3418         340 :     NS_ASSERTION(!aRuleInfo->mSelector->mCasedTag &&
    3419             :                  !aRuleInfo->mSelector->mIDList &&
    3420             :                  !aRuleInfo->mSelector->mClassList &&
    3421             :                  !aRuleInfo->mSelector->mPseudoClassList &&
    3422             :                  !aRuleInfo->mSelector->mAttrList &&
    3423             :                  !aRuleInfo->mSelector->mNegations &&
    3424             :                  !aRuleInfo->mSelector->mNext &&
    3425             :                  aRuleInfo->mSelector->mNameSpace == kNameSpaceID_Unknown,
    3426             :                  "Parser messed up with anon box selector");
    3427             : 
    3428             :     // Index doesn't matter here, since we'll just be walking these
    3429             :     // rules in order; just pass 0.
    3430         340 :     AppendRuleToTagTable(&cascade->mAnonBoxRules,
    3431         340 :                          aRuleInfo->mSelector->mLowercaseTag,
    3432         680 :                          RuleValue(*aRuleInfo, 0, aCascade->mQuirksMode));
    3433             :   } else {
    3434             : #ifdef MOZ_XUL
    3435         106 :     NS_ASSERTION(pseudoType == CSSPseudoElementType::XULTree,
    3436             :                  "Unexpected pseudo type");
    3437             :     // Index doesn't matter here, since we'll just be walking these
    3438             :     // rules in order; just pass 0.
    3439         106 :     AppendRuleToTagTable(&cascade->mXULTreeRules,
    3440         106 :                          aRuleInfo->mSelector->mLowercaseTag,
    3441         212 :                          RuleValue(*aRuleInfo, 0, aCascade->mQuirksMode));
    3442             : #else
    3443             :     NS_NOTREACHED("Unexpected pseudo type");
    3444             : #endif
    3445             :   }
    3446             : 
    3447       38194 :   for (nsCSSSelector* selector = aRuleInfo->mSelector;
    3448       61802 :            selector; selector = selector->mNext) {
    3449       23608 :     if (selector->IsPseudoElement()) {
    3450        1142 :       CSSPseudoElementType pseudo = selector->PseudoType();
    3451        1838 :       if (pseudo >= CSSPseudoElementType::Count ||
    3452         696 :           !nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudo)) {
    3453         918 :         NS_ASSERTION(!selector->mNegations, "Shouldn't have negations");
    3454             :         // We do store selectors ending with pseudo-elements that allow :hover
    3455             :         // and :active after them in the hashtables corresponding to that
    3456             :         // selector's mNext (i.e. the thing that matches against the element),
    3457             :         // but we want to make sure that selectors for any other kinds of
    3458             :         // pseudo-elements don't end up in the hashtables.  In particular, tree
    3459             :         // pseudos store strange things in mPseudoClassList that we don't want
    3460             :         // to try to match elements against.
    3461         918 :         continue;
    3462             :       }
    3463             :     }
    3464       22690 :     if (!AddSelector(cascade, selector, selector, aRuleInfo->mSelector)) {
    3465           0 :       return false;
    3466             :     }
    3467             :   }
    3468             : 
    3469       14586 :   return true;
    3470             : }
    3471             : 
    3472             : struct PerWeightDataListItem : public RuleSelectorPair {
    3473       14586 :   PerWeightDataListItem(css::StyleRule* aRule, nsCSSSelector* aSelector)
    3474       14586 :     : RuleSelectorPair(aRule, aSelector)
    3475       14586 :     , mNext(nullptr)
    3476       14586 :   {}
    3477             :   // No destructor; these are arena-allocated
    3478             : 
    3479             : 
    3480             :   // Placement new to arena allocate the PerWeightDataListItem
    3481       14586 :   void *operator new(size_t aSize, CascadeAllocator &aArena) CPP_THROW_NEW {
    3482       14586 :     return aArena.Allocate(aSize, fallible);
    3483             :   }
    3484             : 
    3485             :   PerWeightDataListItem *mNext;
    3486             : };
    3487             : 
    3488             : struct PerWeightData {
    3489        1116 :   PerWeightData()
    3490        1116 :     : mRuleSelectorPairs(nullptr)
    3491        1116 :     , mTail(&mRuleSelectorPairs)
    3492        1116 :   {}
    3493             : 
    3494             :   int32_t mWeight;
    3495             :   PerWeightDataListItem *mRuleSelectorPairs;
    3496             :   PerWeightDataListItem **mTail;
    3497             : };
    3498             : 
    3499         558 : struct RuleByWeightEntry : public PLDHashEntryHdr {
    3500             :   PerWeightData data; // mWeight is key, mRuleSelectorPairs are value
    3501             : };
    3502             : 
    3503             : static PLDHashNumber
    3504       14586 : HashIntKey(const void *key)
    3505             : {
    3506       14586 :   return HashGeneric(key);
    3507             : }
    3508             : 
    3509             : static bool
    3510       14028 : MatchWeightEntry(const PLDHashEntryHdr *hdr, const void *key)
    3511             : {
    3512       14028 :   const RuleByWeightEntry *entry = (const RuleByWeightEntry *)hdr;
    3513       14028 :   return entry->data.mWeight == NS_PTR_TO_INT32(key);
    3514             : }
    3515             : 
    3516             : static void
    3517         558 : InitWeightEntry(PLDHashEntryHdr *hdr, const void *key)
    3518             : {
    3519         558 :   RuleByWeightEntry* entry = static_cast<RuleByWeightEntry*>(hdr);
    3520         558 :   new (KnownNotNull, entry) RuleByWeightEntry();
    3521         558 : }
    3522             : 
    3523             : static const PLDHashTableOps gRulesByWeightOps = {
    3524             :     HashIntKey,
    3525             :     MatchWeightEntry,
    3526             :     PLDHashTable::MoveEntryStub,
    3527             :     PLDHashTable::ClearEntryStub,
    3528             :     InitWeightEntry
    3529             : };
    3530             : 
    3531             : struct CascadeEnumData {
    3532          42 :   CascadeEnumData(nsPresContext* aPresContext,
    3533             :                   nsTArray<nsFontFaceRuleContainer>& aFontFaceRules,
    3534             :                   nsTArray<nsCSSKeyframesRule*>& aKeyframesRules,
    3535             :                   nsTArray<nsCSSFontFeatureValuesRule*>& aFontFeatureValuesRules,
    3536             :                   nsTArray<nsCSSPageRule*>& aPageRules,
    3537             :                   nsTArray<nsCSSCounterStyleRule*>& aCounterStyleRules,
    3538             :                   nsTArray<css::DocumentRule*>& aDocumentRules,
    3539             :                   nsMediaQueryResultCacheKey& aKey,
    3540             :                   nsDocumentRuleResultCacheKey& aDocumentKey,
    3541             :                   SheetType aSheetType,
    3542             :                   bool aMustGatherDocumentRules)
    3543          42 :     : mPresContext(aPresContext),
    3544             :       mFontFaceRules(aFontFaceRules),
    3545             :       mKeyframesRules(aKeyframesRules),
    3546             :       mFontFeatureValuesRules(aFontFeatureValuesRules),
    3547             :       mPageRules(aPageRules),
    3548             :       mCounterStyleRules(aCounterStyleRules),
    3549             :       mDocumentRules(aDocumentRules),
    3550             :       mCacheKey(aKey),
    3551             :       mDocumentCacheKey(aDocumentKey),
    3552             :       mRulesByWeight(&gRulesByWeightOps, sizeof(RuleByWeightEntry), 32),
    3553             :       mSheetType(aSheetType),
    3554          42 :       mMustGatherDocumentRules(aMustGatherDocumentRules)
    3555             :   {
    3556          42 :   }
    3557             : 
    3558          42 :   ~CascadeEnumData()
    3559          42 :   {
    3560          42 :   }
    3561             : 
    3562             :   nsPresContext* mPresContext;
    3563             :   nsTArray<nsFontFaceRuleContainer>& mFontFaceRules;
    3564             :   nsTArray<nsCSSKeyframesRule*>& mKeyframesRules;
    3565             :   nsTArray<nsCSSFontFeatureValuesRule*>& mFontFeatureValuesRules;
    3566             :   nsTArray<nsCSSPageRule*>& mPageRules;
    3567             :   nsTArray<nsCSSCounterStyleRule*>& mCounterStyleRules;
    3568             :   nsTArray<css::DocumentRule*>& mDocumentRules;
    3569             :   nsMediaQueryResultCacheKey& mCacheKey;
    3570             :   nsDocumentRuleResultCacheKey& mDocumentCacheKey;
    3571             :   // We want page-sized arenas so there's no fragmentation involved.
    3572             :   CascadeAllocator  mArena;
    3573             :   // Hooray, a manual PLDHashTable since nsClassHashtable doesn't
    3574             :   // provide a getter that gives me a *reference* to the value.
    3575             :   PLDHashTable mRulesByWeight; // of PerWeightDataListItem linked lists
    3576             :   SheetType mSheetType;
    3577             :   bool mMustGatherDocumentRules;
    3578             : };
    3579             : 
    3580             : /**
    3581             :  * Recursively traverses rules in order to:
    3582             :  *  (1) add any @-moz-document rules into data->mDocumentRules.
    3583             :  *  (2) record any @-moz-document rules whose conditions evaluate to true
    3584             :  *      on data->mDocumentCacheKey.
    3585             :  *
    3586             :  * See also CascadeRuleEnumFunc below, which calls us via
    3587             :  * EnumerateRulesForwards.  If modifying this function you may need to
    3588             :  * update CascadeRuleEnumFunc too.
    3589             :  */
    3590             : static bool
    3591          79 : GatherDocRuleEnumFunc(css::Rule* aRule, void* aData)
    3592             : {
    3593          79 :   CascadeEnumData* data = (CascadeEnumData*)aData;
    3594          79 :   int32_t type = aRule->GetType();
    3595             : 
    3596          79 :   MOZ_ASSERT(data->mMustGatherDocumentRules,
    3597             :              "should only call GatherDocRuleEnumFunc if "
    3598             :              "mMustGatherDocumentRules is true");
    3599             : 
    3600          79 :   if (css::Rule::MEDIA_RULE == type ||
    3601             :       css::Rule::SUPPORTS_RULE == type) {
    3602           0 :     css::GroupRule* groupRule = static_cast<css::GroupRule*>(aRule);
    3603           0 :     if (!groupRule->EnumerateRulesForwards(GatherDocRuleEnumFunc, aData)) {
    3604           0 :       return false;
    3605           0 :     }
    3606             :   }
    3607          79 :   else if (css::Rule::DOCUMENT_RULE == type) {
    3608           0 :     css::DocumentRule* docRule = static_cast<css::DocumentRule*>(aRule);
    3609           0 :     if (!data->mDocumentRules.AppendElement(docRule)) {
    3610           0 :       return false;
    3611             :     }
    3612           0 :     if (docRule->UseForPresentation(data->mPresContext)) {
    3613           0 :       if (!data->mDocumentCacheKey.AddMatchingRule(docRule)) {
    3614           0 :         return false;
    3615             :       }
    3616             :     }
    3617           0 :     if (!docRule->EnumerateRulesForwards(GatherDocRuleEnumFunc, aData)) {
    3618           0 :       return false;
    3619             :     }
    3620             :   }
    3621          79 :   return true;
    3622             : }
    3623             : 
    3624             : /*
    3625             :  * This enumerates style rules in a sheet (and recursively into any
    3626             :  * grouping rules) in order to:
    3627             :  *  (1) add any style rules, in order, into data->mRulesByWeight (for
    3628             :  *      the primary CSS cascade), where they are separated by weight
    3629             :  *      but kept in order per-weight, and
    3630             :  *  (2) add any @font-face rules, in order, into data->mFontFaceRules.
    3631             :  *  (3) add any @keyframes rules, in order, into data->mKeyframesRules.
    3632             :  *  (4) add any @font-feature-value rules, in order,
    3633             :  *      into data->mFontFeatureValuesRules.
    3634             :  *  (5) add any @page rules, in order, into data->mPageRules.
    3635             :  *  (6) add any @counter-style rules, in order, into data->mCounterStyleRules.
    3636             :  *  (7) add any @-moz-document rules into data->mDocumentRules.
    3637             :  *  (8) record any @-moz-document rules whose conditions evaluate to true
    3638             :  *      on data->mDocumentCacheKey.
    3639             :  *
    3640             :  * See also GatherDocRuleEnumFunc above, which we call to traverse into
    3641             :  * @-moz-document rules even if their (or an ancestor's) condition
    3642             :  * fails.  This means we might look at the result of some @-moz-document
    3643             :  * rules that don't actually affect whether a RuleProcessorCache lookup
    3644             :  * is a hit or a miss.  The presence of @-moz-document rules inside
    3645             :  * @media etc. rules should be rare, and looking at all of them in the
    3646             :  * sheets lets us avoid the complication of having different document
    3647             :  * cache key results for different media.
    3648             :  *
    3649             :  * If modifying this function you may need to update
    3650             :  * GatherDocRuleEnumFunc too.
    3651             :  */
    3652             : static bool
    3653        9629 : CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
    3654             : {
    3655        9629 :   CascadeEnumData* data = (CascadeEnumData*)aData;
    3656        9629 :   int32_t type = aRule->GetType();
    3657        9629 :   MOZ_ASSERT(type != css::Rule::IMPORT_RULE,
    3658             :              "@import rule must not be handled here");
    3659             : 
    3660        9629 :   if (css::Rule::STYLE_RULE == type) {
    3661        8667 :     css::StyleRule* styleRule = static_cast<css::StyleRule*>(aRule);
    3662             : 
    3663       23253 :     for (nsCSSSelectorList *sel = styleRule->Selector();
    3664       37839 :          sel; sel = sel->mNext) {
    3665       14586 :       int32_t weight = sel->mWeight;
    3666             :       auto entry = static_cast<RuleByWeightEntry*>
    3667       14586 :         (data->mRulesByWeight.Add(NS_INT32_TO_PTR(weight), fallible));
    3668       14586 :       if (!entry)
    3669           0 :         return false;
    3670       14586 :       entry->data.mWeight = weight;
    3671             :       // entry->data.mRuleSelectorPairs should be linked in forward order;
    3672             :       // entry->data.mTail is the slot to write to.
    3673             :       auto* newItem =
    3674       14586 :         new (data->mArena) PerWeightDataListItem(styleRule, sel->mSelectors);
    3675       14586 :       if (newItem) {
    3676       14586 :         *(entry->data.mTail) = newItem;
    3677       14586 :         entry->data.mTail = &newItem->mNext;
    3678             :       }
    3679             :     }
    3680             :   }
    3681         962 :   else if (css::Rule::MEDIA_RULE == type ||
    3682             :            css::Rule::SUPPORTS_RULE == type) {
    3683         149 :     css::GroupRule* groupRule = static_cast<css::GroupRule*>(aRule);
    3684             :     const bool use =
    3685         149 :       groupRule->UseForPresentation(data->mPresContext, data->mCacheKey);
    3686         149 :     if (use || data->mMustGatherDocumentRules) {
    3687         133 :       if (!groupRule->EnumerateRulesForwards(use ? CascadeRuleEnumFunc :
    3688             :                                                    GatherDocRuleEnumFunc,
    3689             :                                              aData)) {
    3690           0 :         return false;
    3691             :       }
    3692         149 :     }
    3693             :   }
    3694         813 :   else if (css::Rule::DOCUMENT_RULE == type) {
    3695           8 :     css::DocumentRule* docRule = static_cast<css::DocumentRule*>(aRule);
    3696           8 :     if (data->mMustGatherDocumentRules) {
    3697           7 :       if (!data->mDocumentRules.AppendElement(docRule)) {
    3698           0 :         return false;
    3699             :       }
    3700             :     }
    3701           8 :     const bool use = docRule->UseForPresentation(data->mPresContext);
    3702           8 :     if (use && data->mMustGatherDocumentRules) {
    3703           4 :       if (!data->mDocumentCacheKey.AddMatchingRule(docRule)) {
    3704           0 :         return false;
    3705             :       }
    3706             :     }
    3707           8 :     if (use || data->mMustGatherDocumentRules) {
    3708           7 :       if (!docRule->EnumerateRulesForwards(use ? CascadeRuleEnumFunc
    3709             :                                                : GatherDocRuleEnumFunc,
    3710             :                                            aData)) {
    3711           0 :         return false;
    3712             :       }
    3713             :     }
    3714             :   }
    3715         805 :   else if (css::Rule::FONT_FACE_RULE == type) {
    3716           0 :     nsCSSFontFaceRule *fontFaceRule = static_cast<nsCSSFontFaceRule*>(aRule);
    3717           0 :     nsFontFaceRuleContainer *ptr = data->mFontFaceRules.AppendElement();
    3718           0 :     if (!ptr)
    3719           0 :       return false;
    3720           0 :     ptr->mRule = fontFaceRule;
    3721           0 :     ptr->mSheetType = data->mSheetType;
    3722             :   }
    3723         805 :   else if (css::Rule::KEYFRAMES_RULE == type) {
    3724             :     nsCSSKeyframesRule *keyframesRule =
    3725          93 :       static_cast<nsCSSKeyframesRule*>(aRule);
    3726          93 :     if (!data->mKeyframesRules.AppendElement(keyframesRule)) {
    3727           0 :       return false;
    3728             :     }
    3729             :   }
    3730         712 :   else if (css::Rule::FONT_FEATURE_VALUES_RULE == type) {
    3731             :     nsCSSFontFeatureValuesRule *fontFeatureValuesRule =
    3732           0 :       static_cast<nsCSSFontFeatureValuesRule*>(aRule);
    3733           0 :     if (!data->mFontFeatureValuesRules.AppendElement(fontFeatureValuesRule)) {
    3734           0 :       return false;
    3735             :     }
    3736             :   }
    3737         712 :   else if (css::Rule::PAGE_RULE == type) {
    3738           0 :     nsCSSPageRule* pageRule = static_cast<nsCSSPageRule*>(aRule);
    3739           0 :     if (!data->mPageRules.AppendElement(pageRule)) {
    3740           0 :       return false;
    3741             :     }
    3742             :   }
    3743         712 :   else if (css::Rule::COUNTER_STYLE_RULE == type) {
    3744             :     nsCSSCounterStyleRule* counterStyleRule =
    3745         552 :       static_cast<nsCSSCounterStyleRule*>(aRule);
    3746         552 :     if (!data->mCounterStyleRules.AppendElement(counterStyleRule)) {
    3747           0 :       return false;
    3748             :     }
    3749             :   }
    3750        9629 :   return true;
    3751             : }
    3752             : 
    3753             : /* static */ bool
    3754         144 : nsCSSRuleProcessor::CascadeSheet(CSSStyleSheet* aSheet, CascadeEnumData* aData)
    3755             : {
    3756         432 :   if (aSheet->IsApplicable() &&
    3757         288 :       aSheet->UseForPresentation(aData->mPresContext, aData->mCacheKey) &&
    3758         144 :       aSheet->mInner) {
    3759         144 :     auto& rules = aSheet->Inner()->mOrderedRules;
    3760         144 :     uint32_t i = 0, len = rules.Length();
    3761         160 :     for (; i < len; i++) {
    3762         152 :       if (rules[i]->GetType() != css::Rule::IMPORT_RULE) {
    3763         144 :         break;
    3764             :       }
    3765             :     }
    3766             : 
    3767         144 :     if (i > 0) {
    3768             :       // Collect stylesheets from @import rules. It is done in reverse
    3769             :       // order so that we can avoid cascading duplicate sheets.
    3770          16 :       nsTArray<StyleSheet*> childSheets(i);
    3771          16 :       nsTHashtable<nsPtrHashKey<StyleSheet>> childSheetSet(i);
    3772          16 :       for (uint32_t j = i; j > 0; j--) {
    3773           8 :         auto importRule = static_cast<css::ImportRule*>(rules[j - 1]);
    3774           8 :         StyleSheet* sheet = importRule->GetStyleSheet();
    3775             :         // There are two cases we want to ignore an import rule:
    3776             :         // 1. the import rule does not have stylesheet connected because
    3777             :         //    it fails in security check or there is a loop involved.
    3778             :         // 2. the sheet has been referenced by another import rule at a
    3779             :         //    later position.
    3780           8 :         if (sheet && !childSheetSet.Contains(sheet)) {
    3781           8 :           childSheets.AppendElement(sheet);
    3782           8 :           childSheetSet.PutEntry(sheet);
    3783             :         }
    3784             :       }
    3785             :       // Now cascade all sheets listed.
    3786          16 :       for (StyleSheet* child : Reversed(childSheets)) {
    3787           8 :         CascadeSheet(child->AsGecko(), aData);
    3788             :       }
    3789             :     }
    3790             : 
    3791       18844 :     for (; i < len; i++) {
    3792        9350 :       if (!CascadeRuleEnumFunc(rules[i], aData)) {
    3793           0 :         return false;
    3794             :       }
    3795             :     }
    3796             :   }
    3797         144 :   return true;
    3798             : }
    3799             : 
    3800        2194 : static int CompareWeightData(const void* aArg1, const void* aArg2,
    3801             :                              void* closure)
    3802             : {
    3803        2194 :   const PerWeightData* arg1 = static_cast<const PerWeightData*>(aArg1);
    3804        2194 :   const PerWeightData* arg2 = static_cast<const PerWeightData*>(aArg2);
    3805        2194 :   return arg1->mWeight - arg2->mWeight; // put lower weight first
    3806             : }
    3807             : 
    3808             : RuleCascadeData*
    3809       12201 : nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext)
    3810             : {
    3811             :   // FIXME:  Make this infallible!
    3812             : 
    3813             :   // If anything changes about the presentation context, we will be
    3814             :   // notified.  Otherwise, our cache is valid if mLastPresContext
    3815             :   // matches aPresContext.  (The only rule processors used for multiple
    3816             :   // pres contexts are for XBL.  These rule processors are probably less
    3817             :   // likely to have @media rules, and thus the cache is pretty likely to
    3818             :   // hit instantly even when we're switching between pres contexts.)
    3819             : 
    3820       12201 :   if (!mRuleCascades || aPresContext != mLastPresContext) {
    3821          79 :     RefreshRuleCascade(aPresContext);
    3822             :   }
    3823       12201 :   mLastPresContext = aPresContext;
    3824             : 
    3825       12201 :   return mRuleCascades;
    3826             : }
    3827             : 
    3828             : void
    3829         176 : nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
    3830             : {
    3831             :   // Having RuleCascadeData objects be per-medium (over all variation
    3832             :   // caused by media queries, handled through mCacheKey) works for now
    3833             :   // since nsCSSRuleProcessor objects are per-document.  (For a given
    3834             :   // set of stylesheets they can vary based on medium (@media) or
    3835             :   // document (@-moz-document).)
    3836             : 
    3837         356 :   for (RuleCascadeData **cascadep = &mRuleCascades, *cascade;
    3838         180 :        (cascade = *cascadep); cascadep = &cascade->mNext) {
    3839         136 :     if (cascade->mCacheKey.Matches(aPresContext)) {
    3840             :       // Ensure that the current one is always mRuleCascades.
    3841         134 :       *cascadep = cascade->mNext;
    3842         134 :       cascade->mNext = mRuleCascades;
    3843         134 :       mRuleCascades = cascade;
    3844             : 
    3845         134 :       return;
    3846             :     }
    3847             :   }
    3848             : 
    3849             :   // We're going to make a new rule cascade; this means that we should
    3850             :   // now stop using the previous cache key that we're holding on to from
    3851             :   // the last time we had rule cascades.
    3852          42 :   mPreviousCacheKey = nullptr;
    3853             : 
    3854          42 :   if (mSheets.Length() != 0) {
    3855             :     nsAutoPtr<RuleCascadeData> newCascade(
    3856          42 :       new RuleCascadeData(aPresContext->Medium(),
    3857         126 :                           eCompatibility_NavQuirks == aPresContext->CompatibilityMode()));
    3858          42 :     if (newCascade) {
    3859          42 :       CascadeEnumData data(aPresContext, newCascade->mFontFaceRules,
    3860          42 :                            newCascade->mKeyframesRules,
    3861          42 :                            newCascade->mFontFeatureValuesRules,
    3862          42 :                            newCascade->mPageRules,
    3863          42 :                            newCascade->mCounterStyleRules,
    3864             :                            mDocumentRules,
    3865          42 :                            newCascade->mCacheKey,
    3866             :                            mDocumentCacheKey,
    3867             :                            mSheetType,
    3868         336 :                            mMustGatherDocumentRules);
    3869             : 
    3870         178 :       for (uint32_t i = 0; i < mSheets.Length(); ++i) {
    3871         136 :         if (!CascadeSheet(mSheets.ElementAt(i), &data))
    3872           0 :           return; /* out of memory */
    3873             :       }
    3874             : 
    3875             :       // Sort the hash table of per-weight linked lists by weight.
    3876          42 :       uint32_t weightCount = data.mRulesByWeight.EntryCount();
    3877          84 :       auto weightArray = MakeUnique<PerWeightData[]>(weightCount);
    3878          42 :       int32_t j = 0;
    3879         600 :       for (auto iter = data.mRulesByWeight.Iter(); !iter.Done(); iter.Next()) {
    3880         558 :         auto entry = static_cast<const RuleByWeightEntry*>(iter.Get());
    3881         558 :         weightArray[j++] = entry->data;
    3882             :       }
    3883          42 :       NS_QuickSort(weightArray.get(), weightCount, sizeof(PerWeightData),
    3884          42 :                    CompareWeightData, nullptr);
    3885             : 
    3886             :       // Put things into the rule hash.
    3887             :       // The primary sort is by weight...
    3888         600 :       for (uint32_t i = 0; i < weightCount; ++i) {
    3889             :         // and the secondary sort is by order.  mRuleSelectorPairs is already in
    3890             :         // the right order..
    3891       15144 :         for (PerWeightDataListItem *cur = weightArray[i].mRuleSelectorPairs;
    3892       15144 :              cur;
    3893       14586 :              cur = cur->mNext) {
    3894       14586 :           if (!AddRule(cur, newCascade))
    3895           0 :             return; /* out of memory */
    3896             :         }
    3897             :       }
    3898             : 
    3899             :       // Build mKeyframesRuleTable.
    3900         135 :       for (nsTArray<nsCSSKeyframesRule*>::size_type i = 0,
    3901          42 :              iEnd = newCascade->mKeyframesRules.Length(); i < iEnd; ++i) {
    3902          93 :         nsCSSKeyframesRule* rule = newCascade->mKeyframesRules[i];
    3903          93 :         newCascade->mKeyframesRuleTable.Put(rule->GetName(), rule);
    3904             :       }
    3905             : 
    3906             :       // Build mCounterStyleRuleTable
    3907         594 :       for (nsTArray<nsCSSCounterStyleRule*>::size_type i = 0,
    3908          42 :            iEnd = newCascade->mCounterStyleRules.Length(); i < iEnd; ++i) {
    3909         552 :         nsCSSCounterStyleRule* rule = newCascade->mCounterStyleRules[i];
    3910         552 :         newCascade->mCounterStyleRuleTable.Put(rule->Name(), rule);
    3911             :       }
    3912             : 
    3913             :       // mMustGatherDocumentRules controls whether we build mDocumentRules
    3914             :       // and mDocumentCacheKey so that they can be used as keys by the
    3915             :       // RuleProcessorCache, as obtained by TakeDocumentRulesAndCacheKey
    3916             :       // later.  We set it to false just below so that we only do this
    3917             :       // the first time we build a RuleProcessorCache for a shared rule
    3918             :       // processor.
    3919             :       //
    3920             :       // An up-to-date mDocumentCacheKey is only needed if we
    3921             :       // are still in the RuleProcessorCache (as we store a copy of the
    3922             :       // cache key in the RuleProcessorCache), and an up-to-date
    3923             :       // mDocumentRules is only needed at the time TakeDocumentRulesAndCacheKey
    3924             :       // is called, which is immediately after the rule processor is created
    3925             :       // (by nsStyleSet).
    3926             :       //
    3927             :       // Note that when nsCSSRuleProcessor::ClearRuleCascades is called,
    3928             :       // by CSSStyleSheet::ClearRuleCascades, we will have called
    3929             :       // RuleProcessorCache::RemoveSheet, which will remove the rule
    3930             :       // processor from the cache.  (This is because the list of document
    3931             :       // rules now may not match the one used as they key in the
    3932             :       // RuleProcessorCache.)
    3933             :       //
    3934             :       // Thus, as we'll no longer be in the RuleProcessorCache, and we won't
    3935             :       // have TakeDocumentRulesAndCacheKey called on us, we don't need to ensure
    3936             :       // mDocumentCacheKey and mDocumentRules are up-to-date after the
    3937             :       // first time GetRuleCascade is called.
    3938          42 :       if (mMustGatherDocumentRules) {
    3939          10 :         mDocumentRules.Sort();
    3940          10 :         mDocumentCacheKey.Finalize();
    3941          10 :         mMustGatherDocumentRules = false;
    3942             : #ifdef DEBUG
    3943          10 :         mDocumentRulesAndCacheKeyValid = true;
    3944             : #endif
    3945             :       }
    3946             : 
    3947             :       // Ensure that the current one is always mRuleCascades.
    3948          42 :       newCascade->mNext = mRuleCascades;
    3949          42 :       mRuleCascades = newCascade.forget();
    3950             :     }
    3951             :   }
    3952          42 :   return;
    3953             : }
    3954             : 
    3955             : /* static */ bool
    3956        1332 : nsCSSRuleProcessor::SelectorListMatches(Element* aElement,
    3957             :                                         TreeMatchContext& aTreeMatchContext,
    3958             :                                         nsCSSSelectorList* aSelectorList)
    3959             : {
    3960        1332 :   MOZ_ASSERT(!aTreeMatchContext.mForScopedStyle,
    3961             :              "mCurrentStyleScope will need to be saved and restored after the "
    3962             :              "SelectorMatchesTree call");
    3963             : 
    3964        3992 :   while (aSelectorList) {
    3965        1341 :     nsCSSSelector* sel = aSelectorList->mSelectors;
    3966        1341 :     NS_ASSERTION(sel, "Should have *some* selectors");
    3967        1341 :     NS_ASSERTION(!sel->IsPseudoElement(), "Shouldn't have been called");
    3968        1341 :     NodeMatchContext nodeContext(EventStates(), false);
    3969        1341 :     if (SelectorMatches(aElement, sel, nodeContext, aTreeMatchContext,
    3970             :                         SelectorMatchesFlags::NONE)) {
    3971          11 :       nsCSSSelector* next = sel->mNext;
    3972          14 :       if (!next ||
    3973           3 :           SelectorMatchesTree(aElement, next, aTreeMatchContext,
    3974             :                               SelectorMatchesTreeFlags(0))) {
    3975          11 :         return true;
    3976             :       }
    3977             :     }
    3978             : 
    3979        1330 :     aSelectorList = aSelectorList->mNext;
    3980             :   }
    3981             : 
    3982        1321 :   return false;
    3983             : }
    3984             : 
    3985             : void
    3986          10 : nsCSSRuleProcessor::TakeDocumentRulesAndCacheKey(
    3987             :     nsPresContext* aPresContext,
    3988             :     nsTArray<css::DocumentRule*>& aDocumentRules,
    3989             :     nsDocumentRuleResultCacheKey& aCacheKey)
    3990             : {
    3991          10 :   MOZ_ASSERT(mIsShared);
    3992             : 
    3993          10 :   GetRuleCascade(aPresContext);
    3994          10 :   MOZ_ASSERT(mDocumentRulesAndCacheKeyValid);
    3995             : 
    3996          10 :   aDocumentRules.Clear();
    3997          10 :   aDocumentRules.SwapElements(mDocumentRules);
    3998          10 :   aCacheKey.Swap(mDocumentCacheKey);
    3999             : 
    4000             : #ifdef DEBUG
    4001          10 :   mDocumentRulesAndCacheKeyValid = false;
    4002             : #endif
    4003          10 : }
    4004             : 
    4005             : void
    4006          34 : nsCSSRuleProcessor::AddStyleSetRef()
    4007             : {
    4008          34 :   MOZ_ASSERT(mIsShared);
    4009          34 :   if (++mStyleSetRefCnt == 1) {
    4010          10 :     RuleProcessorCache::StopTracking(this);
    4011             :   }
    4012          34 : }
    4013             : 
    4014             : void
    4015           9 : nsCSSRuleProcessor::ReleaseStyleSetRef()
    4016             : {
    4017           9 :   MOZ_ASSERT(mIsShared);
    4018           9 :   MOZ_ASSERT(mStyleSetRefCnt > 0);
    4019           9 :   if (--mStyleSetRefCnt == 0 && mInRuleProcessorCache) {
    4020           3 :     RuleProcessorCache::StartTracking(this);
    4021             :   }
    4022           9 : }
    4023             : 
    4024             : // TreeMatchContext and AncestorFilter out of line methods
    4025             : void
    4026         141 : TreeMatchContext::InitAncestors(Element *aElement)
    4027             : {
    4028         141 :   MOZ_ASSERT(!mAncestorFilter.mFilter);
    4029         141 :   MOZ_ASSERT(mAncestorFilter.mHashes.IsEmpty());
    4030         141 :   MOZ_ASSERT(mStyleScopes.IsEmpty());
    4031             : 
    4032         141 :   mAncestorFilter.mFilter = new AncestorFilter::Filter();
    4033             : 
    4034         141 :   if (MOZ_LIKELY(aElement)) {
    4035         107 :     MOZ_ASSERT(aElement->GetUncomposedDoc() ||
    4036             :                aElement->HasFlag(NODE_IS_IN_SHADOW_TREE),
    4037             :                "aElement must be in the document or in shadow tree "
    4038             :                "for the assumption that GetParentNode() is non-null "
    4039             :                "on all element ancestors of aElement to be true");
    4040             :     // Collect up the ancestors
    4041         214 :     AutoTArray<Element*, 50> ancestors;
    4042         107 :     Element* cur = aElement;
    4043         559 :     do {
    4044         666 :       ancestors.AppendElement(cur);
    4045         666 :       cur = cur->GetParentElementCrossingShadowRoot();
    4046         666 :     } while (cur);
    4047             : 
    4048             :     // Now push them in reverse order.
    4049         773 :     for (uint32_t i = ancestors.Length(); i-- != 0; ) {
    4050         666 :       mAncestorFilter.PushAncestor(ancestors[i]);
    4051         666 :       PushStyleScope(ancestors[i]);
    4052             :     }
    4053             :   }
    4054         141 : }
    4055             : 
    4056             : void
    4057           0 : TreeMatchContext::InitStyleScopes(Element* aElement)
    4058             : {
    4059           0 :   MOZ_ASSERT(mStyleScopes.IsEmpty());
    4060             : 
    4061           0 :   if (MOZ_LIKELY(aElement)) {
    4062             :     // Collect up the ancestors
    4063           0 :     AutoTArray<Element*, 50> ancestors;
    4064           0 :     Element* cur = aElement;
    4065           0 :     do {
    4066           0 :       ancestors.AppendElement(cur);
    4067           0 :       cur = cur->GetParentElementCrossingShadowRoot();
    4068           0 :     } while (cur);
    4069             : 
    4070             :     // Now push them in reverse order.
    4071           0 :     for (uint32_t i = ancestors.Length(); i-- != 0; ) {
    4072           0 :       PushStyleScope(ancestors[i]);
    4073             :     }
    4074             :   }
    4075           0 : }
    4076             : 
    4077             : void
    4078        1873 : AncestorFilter::PushAncestor(Element *aElement)
    4079             : {
    4080        1873 :   MOZ_ASSERT(mFilter);
    4081             : 
    4082        1873 :   uint32_t oldLength = mHashes.Length();
    4083             : 
    4084        1873 :   mPopTargets.AppendElement(oldLength);
    4085             : #ifdef DEBUG
    4086        1873 :   mElements.AppendElement(aElement);
    4087             : #endif
    4088        1873 :   mHashes.AppendElement(aElement->NodeInfo()->NameAtom()->hash());
    4089        1873 :   nsIAtom *id = aElement->GetID();
    4090        1873 :   if (id) {
    4091        1085 :     mHashes.AppendElement(id->hash());
    4092             :   }
    4093        1873 :   const nsAttrValue *classes = aElement->GetClasses();
    4094        1873 :   if (classes) {
    4095         823 :     uint32_t classCount = classes->GetAtomCount();
    4096        1854 :     for (uint32_t i = 0; i < classCount; ++i) {
    4097        1031 :       mHashes.AppendElement(classes->AtomAt(i)->hash());
    4098             :     }
    4099             :   }
    4100             : 
    4101        1873 :   uint32_t newLength = mHashes.Length();
    4102        5862 :   for (uint32_t i = oldLength; i < newLength; ++i) {
    4103        3989 :     mFilter->add(mHashes[i]);
    4104             :   }
    4105        1873 : }
    4106             : 
    4107             : void
    4108        1207 : AncestorFilter::PopAncestor()
    4109             : {
    4110        1207 :   MOZ_ASSERT(!mPopTargets.IsEmpty());
    4111        1207 :   MOZ_ASSERT(mPopTargets.Length() == mElements.Length());
    4112             : 
    4113        1207 :   uint32_t popTargetLength = mPopTargets.Length();
    4114        1207 :   uint32_t newLength = mPopTargets[popTargetLength-1];
    4115             : 
    4116        1207 :   mPopTargets.TruncateLength(popTargetLength-1);
    4117             : #ifdef DEBUG
    4118        1207 :   mElements.TruncateLength(popTargetLength-1);
    4119             : #endif
    4120             : 
    4121        1207 :   uint32_t oldLength = mHashes.Length();
    4122        3753 :   for (uint32_t i = newLength; i < oldLength; ++i) {
    4123        2546 :     mFilter->remove(mHashes[i]);
    4124             :   }
    4125        1207 :   mHashes.TruncateLength(newLength);
    4126        1207 : }
    4127             : 
    4128             : #ifdef DEBUG
    4129             : void
    4130        5002 : AncestorFilter::AssertHasAllAncestors(Element *aElement) const
    4131             : {
    4132        5002 :   Element* cur = aElement->GetParentElementCrossingShadowRoot();
    4133       65170 :   while (cur) {
    4134       30084 :     MOZ_ASSERT(mElements.Contains(cur));
    4135       30084 :     cur = cur->GetParentElementCrossingShadowRoot();
    4136             :   }
    4137        5002 : }
    4138             : 
    4139             : void
    4140      136014 : TreeMatchContext::AssertHasAllStyleScopes(Element* aElement) const
    4141             : {
    4142      136014 :   if (aElement->IsInNativeAnonymousSubtree()) {
    4143             :     // Document style sheets are never applied to native anonymous content,
    4144             :     // so it's not possible for them to be in a <style scoped> scope.
    4145        1242 :     return;
    4146             :   }
    4147      134772 :   Element* cur = aElement->GetParentElementCrossingShadowRoot();
    4148     1699704 :   while (cur) {
    4149      782466 :     if (cur->IsScopedStyleRoot()) {
    4150           0 :       MOZ_ASSERT(mStyleScopes.Contains(cur));
    4151             :     }
    4152      782466 :     cur = cur->GetParentElementCrossingShadowRoot();
    4153             :   }
    4154             : }
    4155             : #endif

Generated by: LCOV version 1.13