LCOV - code coverage report
Current view: directory - layout/style - nsCSSRuleProcessor.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1254 89 7.1 %
Date: 2012-06-02 Functions: 122 16 13.1 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   L. David Baron <dbaron@dbaron.org>
      25                 :  *   Daniel Glazman <glazman@netscape.com>
      26                 :  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
      27                 :  *   Rob Arnold <robarnold@mozilla.com>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      31                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : /*
      44                 :  * style rule processor for CSS style sheets, responsible for selector
      45                 :  * matching and cascading
      46                 :  */
      47                 : 
      48                 : #include "mozilla/Util.h"
      49                 : 
      50                 : #include "nsCSSRuleProcessor.h"
      51                 : #include "nsRuleProcessorData.h"
      52                 : 
      53                 : #define PL_ARENA_CONST_ALIGN_MASK 7
      54                 : // We want page-sized arenas so there's no fragmentation involved.
      55                 : #define NS_CASCADEENUMDATA_ARENA_BLOCK_SIZE (4096)
      56                 : #include "plarena.h"
      57                 : 
      58                 : #include "nsCRT.h"
      59                 : #include "nsIAtom.h"
      60                 : #include "pldhash.h"
      61                 : #include "nsHashtable.h"
      62                 : #include "nsICSSPseudoComparator.h"
      63                 : #include "mozilla/css/StyleRule.h"
      64                 : #include "mozilla/css/GroupRule.h"
      65                 : #include "nsIDocument.h"
      66                 : #include "nsPresContext.h"
      67                 : #include "nsEventStateManager.h"
      68                 : #include "nsGkAtoms.h"
      69                 : #include "nsString.h"
      70                 : #include "nsUnicharUtils.h"
      71                 : #include "nsDOMError.h"
      72                 : #include "nsRuleWalker.h"
      73                 : #include "nsCSSPseudoClasses.h"
      74                 : #include "nsCSSPseudoElements.h"
      75                 : #include "nsIContent.h"
      76                 : #include "nsCOMPtr.h"
      77                 : #include "nsHashKeys.h"
      78                 : #include "nsStyleUtil.h"
      79                 : #include "nsQuickSort.h"
      80                 : #include "nsAttrValue.h"
      81                 : #include "nsAttrName.h"
      82                 : #include "nsServiceManagerUtils.h"
      83                 : #include "nsTArray.h"
      84                 : #include "nsContentUtils.h"
      85                 : #include "nsIMediaList.h"
      86                 : #include "nsCSSRules.h"
      87                 : #include "nsIPrincipal.h"
      88                 : #include "nsStyleSet.h"
      89                 : #include "prlog.h"
      90                 : #include "nsIObserverService.h"
      91                 : #include "nsIPrivateBrowsingService.h"
      92                 : #include "nsNetCID.h"
      93                 : #include "mozilla/Services.h"
      94                 : #include "mozilla/dom/Element.h"
      95                 : #include "nsGenericElement.h"
      96                 : #include "nsNthIndexCache.h"
      97                 : #include "mozilla/Preferences.h"
      98                 : #include "mozilla/LookAndFeel.h"
      99                 : 
     100                 : using namespace mozilla;
     101                 : using namespace mozilla::dom;
     102                 : 
     103                 : #define VISITED_PSEUDO_PREF "layout.css.visited_links_enabled"
     104                 : 
     105                 : static bool gSupportVisitedPseudo = true;
     106                 : 
     107                 : static nsTArray< nsCOMPtr<nsIAtom> >* sSystemMetrics = 0;
     108                 : 
     109                 : #ifdef XP_WIN
     110                 : PRUint8 nsCSSRuleProcessor::sWinThemeId = LookAndFeel::eWindowsTheme_Generic;
     111                 : #endif
     112                 : 
     113                 : /**
     114                 :  * A struct representing a given CSS rule and a particular selector
     115                 :  * from that rule's selector list.
     116                 :  */
     117                 : struct RuleSelectorPair {
     118               0 :   RuleSelectorPair(css::StyleRule* aRule, nsCSSSelector* aSelector)
     119               0 :     : mRule(aRule), mSelector(aSelector) {}
     120                 :   // If this class ever grows a destructor, deal with
     121                 :   // PerWeightDataListItem appropriately.
     122                 : 
     123                 :   css::StyleRule*   mRule;
     124                 :   nsCSSSelector*    mSelector; // which of |mRule|'s selectors
     125                 : };
     126                 : 
     127                 : #define NS_IS_ANCESTOR_OPERATOR(ch) \
     128                 :   ((ch) == PRUnichar(' ') || (ch) == PRUnichar('>'))
     129                 : 
     130                 : /**
     131                 :  * A struct representing a particular rule in an ordered list of rules
     132                 :  * (the ordering depending on the weight of mSelector and the order of
     133                 :  * our rules to start with).
     134                 :  */
     135               0 : struct RuleValue : RuleSelectorPair {
     136                 :   enum {
     137                 :     eMaxAncestorHashes = 4
     138                 :   };
     139                 : 
     140               0 :   RuleValue(const RuleSelectorPair& aRuleSelectorPair, PRInt32 aIndex,
     141                 :             bool aQuirksMode) :
     142                 :     RuleSelectorPair(aRuleSelectorPair),
     143               0 :     mIndex(aIndex)
     144                 :   {
     145               0 :     CollectAncestorHashes(aQuirksMode);
     146               0 :   }
     147                 : 
     148                 :   PRInt32 mIndex; // High index means high weight/order.
     149                 :   uint32_t mAncestorSelectorHashes[eMaxAncestorHashes];
     150                 : 
     151                 : private:
     152               0 :   void CollectAncestorHashes(bool aQuirksMode) {
     153                 :     // Collect up our mAncestorSelectorHashes.  It's not clear whether it's
     154                 :     // better to stop once we've found eMaxAncestorHashes of them or to keep
     155                 :     // going and preferentially collect information from selectors higher up the
     156                 :     // chain...  Let's do the former for now.
     157               0 :     size_t hashIndex = 0;
     158               0 :     for (nsCSSSelector* sel = mSelector->mNext; sel; sel = sel->mNext) {
     159               0 :       if (!NS_IS_ANCESTOR_OPERATOR(sel->mOperator)) {
     160                 :         // |sel| is going to select something that's not actually one of our
     161                 :         // ancestors, so don't add it to mAncestorSelectorHashes.  But keep
     162                 :         // going, because it'll select a sibling of one of our ancestors, so its
     163                 :         // ancestors would be our ancestors too.
     164               0 :         continue;
     165                 :       }
     166                 : 
     167                 :       // Now sel is supposed to select one of our ancestors.  Grab
     168                 :       // whatever info we can from it into mAncestorSelectorHashes.
     169                 :       // But in qurks mode, don't grab IDs and classes because those
     170                 :       // need to be matched case-insensitively.
     171               0 :       if (!aQuirksMode) {
     172               0 :         nsAtomList* ids = sel->mIDList;
     173               0 :         while (ids) {
     174               0 :           mAncestorSelectorHashes[hashIndex++] = ids->mAtom->hash();
     175               0 :           if (hashIndex == eMaxAncestorHashes) {
     176               0 :             return;
     177                 :           }
     178               0 :           ids = ids->mNext;
     179                 :         }
     180                 : 
     181               0 :         nsAtomList* classes = sel->mClassList;
     182               0 :         while (classes) {
     183               0 :           mAncestorSelectorHashes[hashIndex++] = classes->mAtom->hash();
     184               0 :           if (hashIndex == eMaxAncestorHashes) {
     185               0 :             return;
     186                 :           }
     187               0 :           classes = classes->mNext;
     188                 :         }
     189                 :       }
     190                 : 
     191                 :       // Only put in the tag name if it's all-lowercase.  Otherwise we run into
     192                 :       // trouble because we may test the wrong one of mLowercaseTag and
     193                 :       // mCasedTag against the filter.
     194               0 :       if (sel->mLowercaseTag && sel->mCasedTag == sel->mLowercaseTag) {
     195               0 :         mAncestorSelectorHashes[hashIndex++] = sel->mLowercaseTag->hash();
     196               0 :         if (hashIndex == eMaxAncestorHashes) {
     197               0 :           return;
     198                 :         }
     199                 :       }
     200                 :     }
     201                 : 
     202               0 :     while (hashIndex != eMaxAncestorHashes) {
     203               0 :       mAncestorSelectorHashes[hashIndex++] = 0;
     204                 :     }
     205                 :   }
     206                 : };
     207                 : 
     208                 : // ------------------------------
     209                 : // Rule hash table
     210                 : //
     211                 : 
     212                 : // Uses any of the sets of ops below.
     213               0 : struct RuleHashTableEntry : public PLDHashEntryHdr {
     214                 :   // If you add members that have heap allocated memory be sure to change the
     215                 :   // logic in SizeOfRuleHashTableEntry().
     216                 :   // Auto length 1, because we always have at least one entry in mRules.
     217                 :   nsAutoTArray<RuleValue, 1> mRules;
     218                 : };
     219                 : 
     220               0 : struct RuleHashTagTableEntry : public RuleHashTableEntry {
     221                 :   // If you add members that have heap allocated memory be sure to change the
     222                 :   // logic in RuleHash::SizeOf{In,Ex}cludingThis.
     223                 :   nsCOMPtr<nsIAtom> mTag;
     224                 : };
     225                 : 
     226                 : static PLDHashNumber
     227               0 : RuleHash_CIHashKey(PLDHashTable *table, const void *key)
     228                 : {
     229               0 :   nsIAtom *atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     230                 : 
     231               0 :   nsAutoString str;
     232               0 :   atom->ToString(str);
     233               0 :   nsContentUtils::ASCIIToLower(str);
     234               0 :   return HashString(str);
     235                 : }
     236                 : 
     237                 : typedef nsIAtom*
     238                 : (* RuleHashGetKey) (PLDHashTable *table, const PLDHashEntryHdr *entry);
     239                 : 
     240                 : struct RuleHashTableOps {
     241                 :   PLDHashTableOps ops;
     242                 :   // Extra callback to avoid duplicating the matchEntry callback for
     243                 :   // each table.  (There used to be a getKey callback in
     244                 :   // PLDHashTableOps.)
     245                 :   RuleHashGetKey getKey;
     246                 : };
     247                 : 
     248                 : inline const RuleHashTableOps*
     249               0 : ToLocalOps(const PLDHashTableOps *aOps)
     250                 : {
     251                 :   return (const RuleHashTableOps*)
     252               0 :            (((const char*) aOps) - offsetof(RuleHashTableOps, ops));
     253                 : }
     254                 : 
     255                 : static bool
     256               0 : RuleHash_CIMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
     257                 :                       const void *key)
     258                 : {
     259                 :   nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>
     260               0 :                                               (key));
     261                 :   // Use our extra |getKey| callback to avoid code duplication.
     262               0 :   nsIAtom *entry_atom = ToLocalOps(table->ops)->getKey(table, hdr);
     263                 : 
     264                 :   // Check for case-sensitive match first.
     265               0 :   if (match_atom == entry_atom)
     266               0 :     return true;
     267                 : 
     268                 :   // Use EqualsIgnoreASCIICase instead of full on unicode case conversion
     269                 :   // in order to save on performance. This is only used in quirks mode
     270                 :   // anyway.
     271                 : 
     272                 :   return
     273               0 :     nsContentUtils::EqualsIgnoreASCIICase(nsDependentAtomString(entry_atom),
     274               0 :                                           nsDependentAtomString(match_atom));
     275                 : }
     276                 : 
     277                 : static bool
     278               0 : RuleHash_CSMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
     279                 :                       const void *key)
     280                 : {
     281                 :   nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>
     282               0 :                                               (key));
     283                 :   // Use our extra |getKey| callback to avoid code duplication.
     284               0 :   nsIAtom *entry_atom = ToLocalOps(table->ops)->getKey(table, hdr);
     285                 : 
     286               0 :   return match_atom == entry_atom;
     287                 : }
     288                 : 
     289                 : static bool
     290               0 : RuleHash_InitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
     291                 :                    const void *key)
     292                 : {
     293               0 :   RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(hdr);
     294               0 :   new (entry) RuleHashTableEntry();
     295               0 :   return true;
     296                 : }
     297                 : 
     298                 : static void
     299               0 : RuleHash_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
     300                 : {
     301               0 :   RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(hdr);
     302               0 :   entry->~RuleHashTableEntry();
     303               0 : }
     304                 : 
     305                 : static void
     306               0 : RuleHash_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
     307                 :                    PLDHashEntryHdr *to)
     308                 : {
     309               0 :   NS_PRECONDITION(from != to, "This is not going to work!");
     310                 :   RuleHashTableEntry *oldEntry =
     311                 :     const_cast<RuleHashTableEntry*>(
     312               0 :       static_cast<const RuleHashTableEntry*>(from));
     313               0 :   RuleHashTableEntry *newEntry = new (to) RuleHashTableEntry();
     314               0 :   newEntry->mRules.SwapElements(oldEntry->mRules);
     315               0 :   oldEntry->~RuleHashTableEntry();
     316               0 : }
     317                 : 
     318                 : static bool
     319               0 : RuleHash_TagTable_MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
     320                 :                       const void *key)
     321                 : {
     322                 :   nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>
     323               0 :                                               (key));
     324               0 :   nsIAtom *entry_atom = static_cast<const RuleHashTagTableEntry*>(hdr)->mTag;
     325                 : 
     326               0 :   return match_atom == entry_atom;
     327                 : }
     328                 : 
     329                 : static bool
     330               0 : RuleHash_TagTable_InitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
     331                 :                             const void *key)
     332                 : {
     333               0 :   RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>(hdr);
     334               0 :   new (entry) RuleHashTagTableEntry();
     335               0 :   entry->mTag = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     336               0 :   return true;
     337                 : }
     338                 : 
     339                 : static void
     340               0 : RuleHash_TagTable_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
     341                 : {
     342               0 :   RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>(hdr);
     343               0 :   entry->~RuleHashTagTableEntry();
     344               0 : }
     345                 : 
     346                 : static void
     347               0 : RuleHash_TagTable_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
     348                 :                             PLDHashEntryHdr *to)
     349                 : {
     350               0 :   NS_PRECONDITION(from != to, "This is not going to work!");
     351                 :   RuleHashTagTableEntry *oldEntry =
     352                 :     const_cast<RuleHashTagTableEntry*>(
     353               0 :       static_cast<const RuleHashTagTableEntry*>(from));
     354               0 :   RuleHashTagTableEntry *newEntry = new (to) RuleHashTagTableEntry();
     355               0 :   newEntry->mTag.swap(oldEntry->mTag);
     356               0 :   newEntry->mRules.SwapElements(oldEntry->mRules);
     357               0 :   oldEntry->~RuleHashTagTableEntry();
     358               0 : }
     359                 : 
     360                 : static nsIAtom*
     361               0 : RuleHash_ClassTable_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
     362                 : {
     363                 :   const RuleHashTableEntry *entry =
     364               0 :     static_cast<const RuleHashTableEntry*>(hdr);
     365               0 :   return entry->mRules[0].mSelector->mClassList->mAtom;
     366                 : }
     367                 : 
     368                 : static nsIAtom*
     369               0 : RuleHash_IdTable_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
     370                 : {
     371                 :   const RuleHashTableEntry *entry =
     372               0 :     static_cast<const RuleHashTableEntry*>(hdr);
     373               0 :   return entry->mRules[0].mSelector->mIDList->mAtom;
     374                 : }
     375                 : 
     376                 : static PLDHashNumber
     377               0 : RuleHash_NameSpaceTable_HashKey(PLDHashTable *table, const void *key)
     378                 : {
     379               0 :   return NS_PTR_TO_INT32(key);
     380                 : }
     381                 : 
     382                 : static bool
     383               0 : RuleHash_NameSpaceTable_MatchEntry(PLDHashTable *table,
     384                 :                                    const PLDHashEntryHdr *hdr,
     385                 :                                    const void *key)
     386                 : {
     387                 :   const RuleHashTableEntry *entry =
     388               0 :     static_cast<const RuleHashTableEntry*>(hdr);
     389                 : 
     390                 :   return NS_PTR_TO_INT32(key) ==
     391               0 :          entry->mRules[0].mSelector->mNameSpace;
     392                 : }
     393                 : 
     394                 : static const PLDHashTableOps RuleHash_TagTable_Ops = {
     395                 :   PL_DHashAllocTable,
     396                 :   PL_DHashFreeTable,
     397                 :   PL_DHashVoidPtrKeyStub,
     398                 :   RuleHash_TagTable_MatchEntry,
     399                 :   RuleHash_TagTable_MoveEntry,
     400                 :   RuleHash_TagTable_ClearEntry,
     401                 :   PL_DHashFinalizeStub,
     402                 :   RuleHash_TagTable_InitEntry
     403                 : };
     404                 : 
     405                 : // Case-sensitive ops.
     406                 : static const RuleHashTableOps RuleHash_ClassTable_CSOps = {
     407                 :   {
     408                 :   PL_DHashAllocTable,
     409                 :   PL_DHashFreeTable,
     410                 :   PL_DHashVoidPtrKeyStub,
     411                 :   RuleHash_CSMatchEntry,
     412                 :   RuleHash_MoveEntry,
     413                 :   RuleHash_ClearEntry,
     414                 :   PL_DHashFinalizeStub,
     415                 :   RuleHash_InitEntry
     416                 :   },
     417                 :   RuleHash_ClassTable_GetKey
     418                 : };
     419                 : 
     420                 : // Case-insensitive ops.
     421                 : static const RuleHashTableOps RuleHash_ClassTable_CIOps = {
     422                 :   {
     423                 :   PL_DHashAllocTable,
     424                 :   PL_DHashFreeTable,
     425                 :   RuleHash_CIHashKey,
     426                 :   RuleHash_CIMatchEntry,
     427                 :   RuleHash_MoveEntry,
     428                 :   RuleHash_ClearEntry,
     429                 :   PL_DHashFinalizeStub,
     430                 :   RuleHash_InitEntry
     431                 :   },
     432                 :   RuleHash_ClassTable_GetKey
     433                 : };
     434                 : 
     435                 : // Case-sensitive ops.
     436                 : static const RuleHashTableOps RuleHash_IdTable_CSOps = {
     437                 :   {
     438                 :   PL_DHashAllocTable,
     439                 :   PL_DHashFreeTable,
     440                 :   PL_DHashVoidPtrKeyStub,
     441                 :   RuleHash_CSMatchEntry,
     442                 :   RuleHash_MoveEntry,
     443                 :   RuleHash_ClearEntry,
     444                 :   PL_DHashFinalizeStub,
     445                 :   RuleHash_InitEntry
     446                 :   },
     447                 :   RuleHash_IdTable_GetKey
     448                 : };
     449                 : 
     450                 : // Case-insensitive ops.
     451                 : static const RuleHashTableOps RuleHash_IdTable_CIOps = {
     452                 :   {
     453                 :   PL_DHashAllocTable,
     454                 :   PL_DHashFreeTable,
     455                 :   RuleHash_CIHashKey,
     456                 :   RuleHash_CIMatchEntry,
     457                 :   RuleHash_MoveEntry,
     458                 :   RuleHash_ClearEntry,
     459                 :   PL_DHashFinalizeStub,
     460                 :   RuleHash_InitEntry
     461                 :   },
     462                 :   RuleHash_IdTable_GetKey
     463                 : };
     464                 : 
     465                 : static const PLDHashTableOps RuleHash_NameSpaceTable_Ops = {
     466                 :   PL_DHashAllocTable,
     467                 :   PL_DHashFreeTable,
     468                 :   RuleHash_NameSpaceTable_HashKey,
     469                 :   RuleHash_NameSpaceTable_MatchEntry,
     470                 :   RuleHash_MoveEntry,
     471                 :   RuleHash_ClearEntry,
     472                 :   PL_DHashFinalizeStub,
     473                 :   RuleHash_InitEntry
     474                 : };
     475                 : 
     476                 : #undef RULE_HASH_STATS
     477                 : #undef PRINT_UNIVERSAL_RULES
     478                 : 
     479                 : #ifdef RULE_HASH_STATS
     480                 : #define RULE_HASH_STAT_INCREMENT(var_) PR_BEGIN_MACRO ++(var_); PR_END_MACRO
     481                 : #else
     482                 : #define RULE_HASH_STAT_INCREMENT(var_) PR_BEGIN_MACRO PR_END_MACRO
     483                 : #endif
     484                 : 
     485                 : struct NodeMatchContext;
     486                 : 
     487                 : class RuleHash {
     488                 : public:
     489                 :   RuleHash(bool aQuirksMode);
     490                 :   ~RuleHash();
     491                 :   void AppendRule(const RuleSelectorPair &aRuleInfo);
     492                 :   void EnumerateAllRules(Element* aElement, RuleProcessorData* aData,
     493                 :                          NodeMatchContext& aNodeMatchContext);
     494                 : 
     495                 :   size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
     496                 :   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
     497                 : 
     498                 : protected:
     499                 :   typedef nsTArray<RuleValue> RuleValueList;
     500                 :   void AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
     501                 :                          const RuleSelectorPair& aRuleInfo);
     502                 :   void AppendUniversalRule(const RuleSelectorPair& aRuleInfo);
     503                 : 
     504                 :   PRInt32     mRuleCount;
     505                 :   // The hashtables are lazily initialized; we use a null .ops to
     506                 :   // indicate that they need initialization.
     507                 :   PLDHashTable mIdTable;
     508                 :   PLDHashTable mClassTable;
     509                 :   PLDHashTable mTagTable;
     510                 :   PLDHashTable mNameSpaceTable;
     511                 :   RuleValueList mUniversalRules;
     512                 : 
     513                 :   struct EnumData {
     514                 :     const RuleValue* mCurValue;
     515                 :     const RuleValue* mEnd;
     516                 :   };
     517                 :   EnumData* mEnumList;
     518                 :   PRInt32   mEnumListSize;
     519                 : 
     520                 :   bool mQuirksMode;
     521                 : 
     522               0 :   inline EnumData ToEnumData(const RuleValueList& arr) {
     523               0 :     EnumData data = { arr.Elements(), arr.Elements() + arr.Length() };
     524                 :     return data;
     525                 :   }
     526                 : 
     527                 : #ifdef RULE_HASH_STATS
     528                 :   PRUint32    mUniversalSelectors;
     529                 :   PRUint32    mNameSpaceSelectors;
     530                 :   PRUint32    mTagSelectors;
     531                 :   PRUint32    mClassSelectors;
     532                 :   PRUint32    mIdSelectors;
     533                 : 
     534                 :   PRUint32    mElementsMatched;
     535                 : 
     536                 :   PRUint32    mElementUniversalCalls;
     537                 :   PRUint32    mElementNameSpaceCalls;
     538                 :   PRUint32    mElementTagCalls;
     539                 :   PRUint32    mElementClassCalls;
     540                 :   PRUint32    mElementIdCalls;
     541                 : #endif // RULE_HASH_STATS
     542                 : };
     543                 : 
     544               0 : RuleHash::RuleHash(bool aQuirksMode)
     545                 :   : mRuleCount(0),
     546                 :     mUniversalRules(nsnull),
     547                 :     mEnumList(nsnull), mEnumListSize(0),
     548               0 :     mQuirksMode(aQuirksMode)
     549                 : #ifdef RULE_HASH_STATS
     550                 :     ,
     551                 :     mUniversalSelectors(0),
     552                 :     mNameSpaceSelectors(0),
     553                 :     mTagSelectors(0),
     554                 :     mClassSelectors(0),
     555                 :     mIdSelectors(0),
     556                 :     mElementsMatched(0),
     557                 :     mElementUniversalCalls(0),
     558                 :     mElementNameSpaceCalls(0),
     559                 :     mElementTagCalls(0),
     560                 :     mElementClassCalls(0),
     561                 :     mElementIdCalls(0)
     562                 : #endif
     563                 : {
     564               0 :   MOZ_COUNT_CTOR(RuleHash);
     565                 : 
     566               0 :   mTagTable.ops = nsnull;
     567               0 :   mIdTable.ops = nsnull;
     568               0 :   mClassTable.ops = nsnull;
     569               0 :   mNameSpaceTable.ops = nsnull;
     570               0 : }
     571                 : 
     572               0 : RuleHash::~RuleHash()
     573                 : {
     574               0 :   MOZ_COUNT_DTOR(RuleHash);
     575                 : #ifdef RULE_HASH_STATS
     576                 :   printf(
     577                 : "RuleHash(%p):\n"
     578                 : "  Selectors: Universal (%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
     579                 : "  Content Nodes: Elements(%u)\n"
     580                 : "  Element Calls: Universal(%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
     581                 :          static_cast<void*>(this),
     582                 :          mUniversalSelectors, mNameSpaceSelectors, mTagSelectors,
     583                 :            mClassSelectors, mIdSelectors,
     584                 :          mElementsMatched,
     585                 :          mElementUniversalCalls, mElementNameSpaceCalls, mElementTagCalls,
     586                 :            mElementClassCalls, mElementIdCalls);
     587                 : #ifdef PRINT_UNIVERSAL_RULES
     588                 :   {
     589                 :     if (mUniversalRules.Length() > 0) {
     590                 :       printf("  Universal rules:\n");
     591                 :       for (PRUint32 i = 0; i < mUniversalRules.Length(); ++i) {
     592                 :         RuleValue* value = &(mUniversalRules[i]);
     593                 :         nsAutoString selectorText;
     594                 :         PRUint32 lineNumber = value->mRule->GetLineNumber();
     595                 :         nsCOMPtr<nsIStyleSheet> sheet;
     596                 :         value->mRule->GetStyleSheet(*getter_AddRefs(sheet));
     597                 :         nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheet);
     598                 :         value->mSelector->ToString(selectorText, cssSheet);
     599                 : 
     600                 :         printf("    line %d, %s\n",
     601                 :                lineNumber, NS_ConvertUTF16toUTF8(selectorText).get());
     602                 :       }
     603                 :     }
     604                 :   }
     605                 : #endif // PRINT_UNIVERSAL_RULES
     606                 : #endif // RULE_HASH_STATS
     607                 :   // Rule Values are arena allocated no need to delete them. Their destructor
     608                 :   // isn't doing any cleanup. So we dont even bother to enumerate through
     609                 :   // the hash tables and call their destructors.
     610               0 :   if (nsnull != mEnumList) {
     611               0 :     delete [] mEnumList;
     612                 :   }
     613                 :   // delete arena for strings and small objects
     614               0 :   if (mIdTable.ops) {
     615               0 :     PL_DHashTableFinish(&mIdTable);
     616                 :   }
     617               0 :   if (mClassTable.ops) {
     618               0 :     PL_DHashTableFinish(&mClassTable);
     619                 :   }
     620               0 :   if (mTagTable.ops) {
     621               0 :     PL_DHashTableFinish(&mTagTable);
     622                 :   }
     623               0 :   if (mNameSpaceTable.ops) {
     624               0 :     PL_DHashTableFinish(&mNameSpaceTable);
     625                 :   }
     626               0 : }
     627                 : 
     628               0 : void RuleHash::AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
     629                 :                                  const RuleSelectorPair& aRuleInfo)
     630                 : {
     631                 :   // Get a new or existing entry.
     632                 :   RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
     633               0 :                                          (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
     634               0 :   if (!entry)
     635               0 :     return;
     636               0 :   entry->mRules.AppendElement(RuleValue(aRuleInfo, mRuleCount++, mQuirksMode));
     637                 : }
     638                 : 
     639                 : static void
     640               0 : AppendRuleToTagTable(PLDHashTable* aTable, nsIAtom* aKey,
     641                 :                      const RuleValue& aRuleInfo)
     642                 : {
     643                 :   // Get a new or exisiting entry
     644                 :   RuleHashTagTableEntry *entry = static_cast<RuleHashTagTableEntry*>
     645               0 :     (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
     646               0 :   if (!entry)
     647               0 :     return;
     648                 : 
     649               0 :   entry->mRules.AppendElement(aRuleInfo);
     650                 : }
     651                 : 
     652               0 : void RuleHash::AppendUniversalRule(const RuleSelectorPair& aRuleInfo)
     653                 : {
     654               0 :   mUniversalRules.AppendElement(RuleValue(aRuleInfo, mRuleCount++, mQuirksMode));
     655               0 : }
     656                 : 
     657               0 : void RuleHash::AppendRule(const RuleSelectorPair& aRuleInfo)
     658                 : {
     659               0 :   nsCSSSelector *selector = aRuleInfo.mSelector;
     660               0 :   if (nsnull != selector->mIDList) {
     661               0 :     if (!mIdTable.ops) {
     662                 :       PL_DHashTableInit(&mIdTable,
     663                 :                         mQuirksMode ? &RuleHash_IdTable_CIOps.ops
     664                 :                                     : &RuleHash_IdTable_CSOps.ops,
     665               0 :                         nsnull, sizeof(RuleHashTableEntry), 16);
     666                 :     }
     667               0 :     AppendRuleToTable(&mIdTable, selector->mIDList->mAtom, aRuleInfo);
     668                 :     RULE_HASH_STAT_INCREMENT(mIdSelectors);
     669                 :   }
     670               0 :   else if (nsnull != selector->mClassList) {
     671               0 :     if (!mClassTable.ops) {
     672                 :       PL_DHashTableInit(&mClassTable,
     673                 :                         mQuirksMode ? &RuleHash_ClassTable_CIOps.ops
     674                 :                                     : &RuleHash_ClassTable_CSOps.ops,
     675               0 :                         nsnull, sizeof(RuleHashTableEntry), 16);
     676                 :     }
     677               0 :     AppendRuleToTable(&mClassTable, selector->mClassList->mAtom, aRuleInfo);
     678                 :     RULE_HASH_STAT_INCREMENT(mClassSelectors);
     679                 :   }
     680               0 :   else if (selector->mLowercaseTag) {
     681               0 :     RuleValue ruleValue(aRuleInfo, mRuleCount++, mQuirksMode);
     682               0 :     if (!mTagTable.ops) {
     683                 :       PL_DHashTableInit(&mTagTable, &RuleHash_TagTable_Ops, nsnull,
     684               0 :                         sizeof(RuleHashTagTableEntry), 16);
     685                 :     }
     686               0 :     AppendRuleToTagTable(&mTagTable, selector->mLowercaseTag, ruleValue);
     687                 :     RULE_HASH_STAT_INCREMENT(mTagSelectors);
     688               0 :     if (selector->mCasedTag && 
     689               0 :         selector->mCasedTag != selector->mLowercaseTag) {
     690               0 :       AppendRuleToTagTable(&mTagTable, selector->mCasedTag, ruleValue);
     691                 :       RULE_HASH_STAT_INCREMENT(mTagSelectors);
     692                 :     }
     693                 :   }
     694               0 :   else if (kNameSpaceID_Unknown != selector->mNameSpace) {
     695               0 :     if (!mNameSpaceTable.ops) {
     696                 :       PL_DHashTableInit(&mNameSpaceTable, &RuleHash_NameSpaceTable_Ops, nsnull,
     697               0 :                         sizeof(RuleHashTableEntry), 16);
     698                 :     }
     699                 :     AppendRuleToTable(&mNameSpaceTable,
     700               0 :                       NS_INT32_TO_PTR(selector->mNameSpace), aRuleInfo);
     701                 :     RULE_HASH_STAT_INCREMENT(mNameSpaceSelectors);
     702                 :   }
     703                 :   else {  // universal tag selector
     704               0 :     AppendUniversalRule(aRuleInfo);
     705                 :     RULE_HASH_STAT_INCREMENT(mUniversalSelectors);
     706                 :   }
     707               0 : }
     708                 : 
     709                 : // this should cover practically all cases so we don't need to reallocate
     710                 : #define MIN_ENUM_LIST_SIZE 8
     711                 : 
     712                 : #ifdef RULE_HASH_STATS
     713                 : #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
     714                 :   (var_) += (list_).Length()
     715                 : #else
     716                 : #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
     717                 :   PR_BEGIN_MACRO PR_END_MACRO
     718                 : #endif
     719                 : 
     720                 : static inline
     721                 : void ContentEnumFunc(const RuleValue &value, nsCSSSelector* selector,
     722                 :                      RuleProcessorData* data, NodeMatchContext& nodeContext,
     723                 :                      AncestorFilter *ancestorFilter);
     724                 : 
     725               0 : void RuleHash::EnumerateAllRules(Element* aElement, RuleProcessorData* aData,
     726                 :                                  NodeMatchContext& aNodeContext)
     727                 : {
     728               0 :   PRInt32 nameSpace = aElement->GetNameSpaceID();
     729               0 :   nsIAtom* tag = aElement->Tag();
     730               0 :   nsIAtom* id = aElement->GetID();
     731               0 :   const nsAttrValue* classList = aElement->GetClasses();
     732                 : 
     733               0 :   NS_ABORT_IF_FALSE(tag, "How could we not have a tag?");
     734                 : 
     735               0 :   PRInt32 classCount = classList ? classList->GetAtomCount() : 0;
     736                 : 
     737                 :   // assume 1 universal, tag, id, and namespace, rather than wasting
     738                 :   // time counting
     739               0 :   PRInt32 testCount = classCount + 4;
     740                 : 
     741               0 :   if (mEnumListSize < testCount) {
     742               0 :     delete [] mEnumList;
     743               0 :     mEnumListSize = NS_MAX(testCount, MIN_ENUM_LIST_SIZE);
     744               0 :     mEnumList = new EnumData[mEnumListSize];
     745                 :   }
     746                 : 
     747               0 :   PRInt32 valueCount = 0;
     748                 :   RULE_HASH_STAT_INCREMENT(mElementsMatched);
     749                 : 
     750               0 :   if (mUniversalRules.Length() != 0) { // universal rules
     751               0 :     mEnumList[valueCount++] = ToEnumData(mUniversalRules);
     752                 :     RULE_HASH_STAT_INCREMENT_LIST_COUNT(mUniversalRules, mElementUniversalCalls);
     753                 :   }
     754                 :   // universal rules within the namespace
     755               0 :   if (kNameSpaceID_Unknown != nameSpace && mNameSpaceTable.ops) {
     756                 :     RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
     757                 :                                            (PL_DHashTableOperate(&mNameSpaceTable, NS_INT32_TO_PTR(nameSpace),
     758               0 :                              PL_DHASH_LOOKUP));
     759               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
     760               0 :       mEnumList[valueCount++] = ToEnumData(entry->mRules);
     761                 :       RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementNameSpaceCalls);
     762                 :     }
     763                 :   }
     764               0 :   if (mTagTable.ops) {
     765                 :     RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
     766               0 :                                            (PL_DHashTableOperate(&mTagTable, tag, PL_DHASH_LOOKUP));
     767               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
     768               0 :       mEnumList[valueCount++] = ToEnumData(entry->mRules);
     769                 :       RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementTagCalls);
     770                 :     }
     771                 :   }
     772               0 :   if (id && mIdTable.ops) {
     773                 :     RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
     774               0 :                                            (PL_DHashTableOperate(&mIdTable, id, PL_DHASH_LOOKUP));
     775               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
     776               0 :       mEnumList[valueCount++] = ToEnumData(entry->mRules);
     777                 :       RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementIdCalls);
     778                 :     }
     779                 :   }
     780               0 :   if (mClassTable.ops) {
     781               0 :     for (PRInt32 index = 0; index < classCount; ++index) {
     782                 :       RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
     783               0 :                                              (PL_DHashTableOperate(&mClassTable, classList->AtomAt(index),
     784               0 :                              PL_DHASH_LOOKUP));
     785               0 :       if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
     786               0 :         mEnumList[valueCount++] = ToEnumData(entry->mRules);
     787                 :         RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementClassCalls);
     788                 :       }
     789                 :     }
     790                 :   }
     791               0 :   NS_ASSERTION(valueCount <= testCount, "values exceeded list size");
     792                 : 
     793               0 :   if (valueCount > 0) {
     794                 :     AncestorFilter *filter =
     795               0 :       aData->mTreeMatchContext.mAncestorFilter.HasFilter() ?
     796               0 :         &aData->mTreeMatchContext.mAncestorFilter : nsnull;
     797                 : #ifdef DEBUG
     798               0 :     if (filter) {
     799               0 :       filter->AssertHasAllAncestors(aElement);
     800                 :     }
     801                 : #endif
     802                 :     // Merge the lists while there are still multiple lists to merge.
     803               0 :     while (valueCount > 1) {
     804               0 :       PRInt32 valueIndex = 0;
     805               0 :       PRInt32 lowestRuleIndex = mEnumList[valueIndex].mCurValue->mIndex;
     806               0 :       for (PRInt32 index = 1; index < valueCount; ++index) {
     807               0 :         PRInt32 ruleIndex = mEnumList[index].mCurValue->mIndex;
     808               0 :         if (ruleIndex < lowestRuleIndex) {
     809               0 :           valueIndex = index;
     810               0 :           lowestRuleIndex = ruleIndex;
     811                 :         }
     812                 :       }
     813               0 :       const RuleValue *cur = mEnumList[valueIndex].mCurValue;
     814               0 :       ContentEnumFunc(*cur, cur->mSelector, aData, aNodeContext, filter);
     815               0 :       cur++;
     816               0 :       if (cur == mEnumList[valueIndex].mEnd) {
     817               0 :         mEnumList[valueIndex] = mEnumList[--valueCount];
     818                 :       } else {
     819               0 :         mEnumList[valueIndex].mCurValue = cur;
     820                 :       }
     821                 :     }
     822                 : 
     823                 :     // Fast loop over single value.
     824               0 :     for (const RuleValue *value = mEnumList[0].mCurValue,
     825               0 :                          *end = mEnumList[0].mEnd;
     826                 :          value != end; ++value) {
     827               0 :       ContentEnumFunc(*value, value->mSelector, aData, aNodeContext, filter);
     828                 :     }
     829                 :   }
     830               0 : }
     831                 : 
     832                 : static size_t
     833               0 : SizeOfRuleHashTableEntry(PLDHashEntryHdr* aHdr, nsMallocSizeOfFun aMallocSizeOf, void *)
     834                 : {
     835               0 :   RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(aHdr);
     836               0 :   return entry->mRules.SizeOfExcludingThis(aMallocSizeOf);
     837                 : }
     838                 : 
     839                 : size_t
     840               0 : RuleHash::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
     841                 : {
     842               0 :   size_t n = 0;
     843                 : 
     844               0 :   if (mIdTable.ops) {
     845                 :     n += PL_DHashTableSizeOfExcludingThis(&mIdTable,
     846                 :                                           SizeOfRuleHashTableEntry,
     847               0 :                                           aMallocSizeOf);
     848                 :   }
     849                 : 
     850               0 :   if (mClassTable.ops) {
     851                 :     n += PL_DHashTableSizeOfExcludingThis(&mClassTable,
     852                 :                                           SizeOfRuleHashTableEntry,
     853               0 :                                           aMallocSizeOf);
     854                 :   }
     855                 : 
     856               0 :   if (mTagTable.ops) {
     857                 :     n += PL_DHashTableSizeOfExcludingThis(&mTagTable,
     858                 :                                           SizeOfRuleHashTableEntry,
     859               0 :                                           aMallocSizeOf);
     860                 :   }
     861                 : 
     862               0 :   if (mNameSpaceTable.ops) {
     863                 :     n += PL_DHashTableSizeOfExcludingThis(&mNameSpaceTable,
     864                 :                                           SizeOfRuleHashTableEntry,
     865               0 :                                           aMallocSizeOf);
     866                 :   }
     867                 : 
     868               0 :   n += mUniversalRules.SizeOfExcludingThis(aMallocSizeOf);
     869                 : 
     870               0 :   return n;
     871                 : }
     872                 : 
     873                 : size_t
     874               0 : RuleHash::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
     875                 : {
     876               0 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     877                 : }
     878                 : 
     879                 : //--------------------------------
     880                 : 
     881                 : // A hash table mapping atoms to lists of selectors
     882               0 : struct AtomSelectorEntry : public PLDHashEntryHdr {
     883                 :   nsIAtom *mAtom;
     884                 :   // Auto length 2, because a decent fraction of these arrays ends up
     885                 :   // with 2 elements, and each entry is cheap.
     886                 :   nsAutoTArray<nsCSSSelector*, 2> mSelectors;
     887                 : };
     888                 : 
     889                 : static void
     890               0 : AtomSelector_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
     891                 : {
     892               0 :   (static_cast<AtomSelectorEntry*>(hdr))->~AtomSelectorEntry();
     893               0 : }
     894                 : 
     895                 : static bool
     896               0 : AtomSelector_InitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
     897                 :                        const void *key)
     898                 : {
     899               0 :   AtomSelectorEntry *entry = static_cast<AtomSelectorEntry*>(hdr);
     900               0 :   new (entry) AtomSelectorEntry();
     901               0 :   entry->mAtom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
     902               0 :   return true;
     903                 : }
     904                 : 
     905                 : static void
     906               0 : AtomSelector_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
     907                 :                        PLDHashEntryHdr *to)
     908                 : {
     909               0 :   NS_PRECONDITION(from != to, "This is not going to work!");
     910                 :   AtomSelectorEntry *oldEntry =
     911               0 :     const_cast<AtomSelectorEntry*>(static_cast<const AtomSelectorEntry*>(from));
     912               0 :   AtomSelectorEntry *newEntry = new (to) AtomSelectorEntry();
     913               0 :   newEntry->mAtom = oldEntry->mAtom;
     914               0 :   newEntry->mSelectors.SwapElements(oldEntry->mSelectors);
     915               0 :   oldEntry->~AtomSelectorEntry();
     916               0 : }
     917                 : 
     918                 : static nsIAtom*
     919               0 : AtomSelector_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
     920                 : {
     921               0 :   const AtomSelectorEntry *entry = static_cast<const AtomSelectorEntry*>(hdr);
     922               0 :   return entry->mAtom;
     923                 : }
     924                 : 
     925                 : // Case-sensitive ops.
     926                 : static const PLDHashTableOps AtomSelector_CSOps = {
     927                 :   PL_DHashAllocTable,
     928                 :   PL_DHashFreeTable,
     929                 :   PL_DHashVoidPtrKeyStub,
     930                 :   PL_DHashMatchEntryStub,
     931                 :   AtomSelector_MoveEntry,
     932                 :   AtomSelector_ClearEntry,
     933                 :   PL_DHashFinalizeStub,
     934                 :   AtomSelector_InitEntry
     935                 : };
     936                 : 
     937                 : // Case-insensitive ops.
     938                 : static const RuleHashTableOps AtomSelector_CIOps = {
     939                 :   {
     940                 :   PL_DHashAllocTable,
     941                 :   PL_DHashFreeTable,
     942                 :   RuleHash_CIHashKey,
     943                 :   RuleHash_CIMatchEntry,
     944                 :   AtomSelector_MoveEntry,
     945                 :   AtomSelector_ClearEntry,
     946                 :   PL_DHashFinalizeStub,
     947                 :   AtomSelector_InitEntry
     948                 :   },
     949                 :   AtomSelector_GetKey
     950                 : };
     951                 : 
     952                 : //--------------------------------
     953                 : 
     954                 : struct RuleCascadeData {
     955               0 :   RuleCascadeData(nsIAtom *aMedium, bool aQuirksMode)
     956                 :     : mRuleHash(aQuirksMode),
     957                 :       mStateSelectors(),
     958                 :       mSelectorDocumentStates(0),
     959                 :       mCacheKey(aMedium),
     960                 :       mNext(nsnull),
     961               0 :       mQuirksMode(aQuirksMode)
     962                 :   {
     963                 :     // mAttributeSelectors is matching on the attribute _name_, not the value,
     964                 :     // and we case-fold names at parse-time, so this is a case-sensitive match.
     965                 :     PL_DHashTableInit(&mAttributeSelectors, &AtomSelector_CSOps, nsnull,
     966               0 :                       sizeof(AtomSelectorEntry), 16);
     967                 :     PL_DHashTableInit(&mAnonBoxRules, &RuleHash_TagTable_Ops, nsnull,
     968               0 :                       sizeof(RuleHashTagTableEntry), 16);
     969                 :     PL_DHashTableInit(&mIdSelectors,
     970                 :                       aQuirksMode ? &AtomSelector_CIOps.ops :
     971                 :                                     &AtomSelector_CSOps,
     972               0 :                       nsnull, sizeof(AtomSelectorEntry), 16);
     973                 :     PL_DHashTableInit(&mClassSelectors,
     974                 :                       aQuirksMode ? &AtomSelector_CIOps.ops :
     975                 :                                     &AtomSelector_CSOps,
     976               0 :                       nsnull, sizeof(AtomSelectorEntry), 16);
     977               0 :     memset(mPseudoElementRuleHashes, 0, sizeof(mPseudoElementRuleHashes));
     978                 : #ifdef MOZ_XUL
     979                 :     PL_DHashTableInit(&mXULTreeRules, &RuleHash_TagTable_Ops, nsnull,
     980               0 :                       sizeof(RuleHashTagTableEntry), 16);
     981                 : #endif
     982               0 :   }
     983                 : 
     984               0 :   ~RuleCascadeData()
     985               0 :   {
     986               0 :     PL_DHashTableFinish(&mAttributeSelectors);
     987               0 :     PL_DHashTableFinish(&mAnonBoxRules);
     988               0 :     PL_DHashTableFinish(&mIdSelectors);
     989               0 :     PL_DHashTableFinish(&mClassSelectors);
     990                 : #ifdef MOZ_XUL
     991               0 :     PL_DHashTableFinish(&mXULTreeRules);
     992                 : #endif
     993               0 :     for (PRUint32 i = 0; i < ArrayLength(mPseudoElementRuleHashes); ++i) {
     994               0 :       delete mPseudoElementRuleHashes[i];
     995                 :     }
     996               0 :   }
     997                 : 
     998                 :   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
     999                 : 
    1000                 :   RuleHash                 mRuleHash;
    1001                 :   RuleHash*
    1002                 :     mPseudoElementRuleHashes[nsCSSPseudoElements::ePseudo_PseudoElementCount];
    1003                 :   nsTArray<nsCSSRuleProcessor::StateSelector>  mStateSelectors;
    1004                 :   nsEventStates            mSelectorDocumentStates;
    1005                 :   PLDHashTable             mClassSelectors;
    1006                 :   PLDHashTable             mIdSelectors;
    1007                 :   nsTArray<nsCSSSelector*> mPossiblyNegatedClassSelectors;
    1008                 :   nsTArray<nsCSSSelector*> mPossiblyNegatedIDSelectors;
    1009                 :   PLDHashTable             mAttributeSelectors;
    1010                 :   PLDHashTable             mAnonBoxRules;
    1011                 : #ifdef MOZ_XUL
    1012                 :   PLDHashTable             mXULTreeRules;
    1013                 : #endif
    1014                 : 
    1015                 :   nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
    1016                 :   nsTArray<nsCSSKeyframesRule*> mKeyframesRules;
    1017                 : 
    1018                 :   // Looks up or creates the appropriate list in |mAttributeSelectors|.
    1019                 :   // Returns null only on allocation failure.
    1020                 :   nsTArray<nsCSSSelector*>* AttributeListFor(nsIAtom* aAttribute);
    1021                 : 
    1022                 :   nsMediaQueryResultCacheKey mCacheKey;
    1023                 :   RuleCascadeData*  mNext; // for a different medium
    1024                 : 
    1025                 :   const bool mQuirksMode;
    1026                 : };
    1027                 : 
    1028                 : static size_t
    1029               0 : SizeOfSelectorsEntry(PLDHashEntryHdr* aHdr, nsMallocSizeOfFun aMallocSizeOf, void *)
    1030                 : {
    1031               0 :   AtomSelectorEntry* entry = static_cast<AtomSelectorEntry*>(aHdr);
    1032               0 :   return entry->mSelectors.SizeOfExcludingThis(aMallocSizeOf);
    1033                 : }
    1034                 : 
    1035                 : size_t
    1036               0 : RuleCascadeData::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
    1037                 : {
    1038               0 :   size_t n = aMallocSizeOf(this);
    1039                 : 
    1040               0 :   n += mRuleHash.SizeOfExcludingThis(aMallocSizeOf);
    1041               0 :   for (PRUint32 i = 0; i < ArrayLength(mPseudoElementRuleHashes); ++i) {
    1042               0 :     if (mPseudoElementRuleHashes[i])
    1043               0 :       n += mPseudoElementRuleHashes[i]->SizeOfIncludingThis(aMallocSizeOf);
    1044                 :   }
    1045                 : 
    1046               0 :   n += mStateSelectors.SizeOfExcludingThis(aMallocSizeOf);
    1047                 : 
    1048                 :   n += PL_DHashTableSizeOfExcludingThis(&mIdSelectors,
    1049               0 :                                         SizeOfSelectorsEntry, aMallocSizeOf);
    1050                 :   n += PL_DHashTableSizeOfExcludingThis(&mClassSelectors,
    1051               0 :                                         SizeOfSelectorsEntry, aMallocSizeOf);
    1052                 : 
    1053               0 :   n += mPossiblyNegatedClassSelectors.SizeOfExcludingThis(aMallocSizeOf);
    1054               0 :   n += mPossiblyNegatedIDSelectors.SizeOfExcludingThis(aMallocSizeOf);
    1055                 : 
    1056                 :   n += PL_DHashTableSizeOfExcludingThis(&mAttributeSelectors,
    1057               0 :                                         SizeOfSelectorsEntry, aMallocSizeOf);
    1058                 :   n += PL_DHashTableSizeOfExcludingThis(&mAnonBoxRules,
    1059               0 :                                         SizeOfRuleHashTableEntry, aMallocSizeOf);
    1060                 : #ifdef MOZ_XUL
    1061                 :   n += PL_DHashTableSizeOfExcludingThis(&mXULTreeRules,
    1062               0 :                                         SizeOfRuleHashTableEntry, aMallocSizeOf);
    1063                 : #endif
    1064                 : 
    1065               0 :   n += mFontFaceRules.SizeOfExcludingThis(aMallocSizeOf);
    1066               0 :   n += mKeyframesRules.SizeOfExcludingThis(aMallocSizeOf);
    1067                 : 
    1068               0 :   return n;
    1069                 : }
    1070                 : 
    1071                 : nsTArray<nsCSSSelector*>*
    1072               0 : RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
    1073                 : {
    1074                 :   AtomSelectorEntry *entry =
    1075                 :     static_cast<AtomSelectorEntry*>
    1076                 :                (PL_DHashTableOperate(&mAttributeSelectors, aAttribute,
    1077               0 :                                      PL_DHASH_ADD));
    1078               0 :   if (!entry)
    1079               0 :     return nsnull;
    1080               0 :   return &entry->mSelectors;
    1081                 : }
    1082                 : 
    1083                 : class nsPrivateBrowsingObserver : nsIObserver,
    1084                 :                                   nsSupportsWeakReference
    1085            1403 : {
    1086                 : public:
    1087                 :   nsPrivateBrowsingObserver();
    1088                 : 
    1089                 :   NS_DECL_ISUPPORTS
    1090                 :   NS_DECL_NSIOBSERVER
    1091                 : 
    1092                 :   void Init();
    1093               0 :   bool InPrivateBrowsing() const { return mInPrivateBrowsing; }
    1094                 : 
    1095                 : private:
    1096                 :   bool mInPrivateBrowsing;
    1097                 : };
    1098                 : 
    1099           13762 : NS_IMPL_ISUPPORTS2(nsPrivateBrowsingObserver, nsIObserver, nsISupportsWeakReference)
    1100                 : 
    1101            1404 : nsPrivateBrowsingObserver::nsPrivateBrowsingObserver()
    1102            1404 :   : mInPrivateBrowsing(false)
    1103                 : {
    1104            1404 : }
    1105                 : 
    1106                 : void
    1107            1404 : nsPrivateBrowsingObserver::Init()
    1108                 : {
    1109                 :   nsCOMPtr<nsIObserverService> observerService =
    1110            2808 :     mozilla::services::GetObserverService();
    1111            1404 :   if (observerService) {
    1112            1404 :     observerService->AddObserver(this, "profile-after-change", true);
    1113            1404 :     observerService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
    1114                 :   }
    1115            1404 : }
    1116                 : 
    1117                 : nsresult
    1118             141 : nsPrivateBrowsingObserver::Observe(nsISupports *aSubject,
    1119                 :                                    const char *aTopic,
    1120                 :                                    const PRUnichar *aData)
    1121                 : {
    1122             141 :   if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) {
    1123             141 :     if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).get())) {
    1124              74 :       mInPrivateBrowsing = true;
    1125                 :     } else {
    1126              67 :       mInPrivateBrowsing = false;
    1127                 :     }
    1128                 :   }
    1129               0 :   else if (!strcmp(aTopic, "profile-after-change")) {
    1130                 :     nsCOMPtr<nsIPrivateBrowsingService> pbService =
    1131               0 :       do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
    1132               0 :     if (pbService)
    1133               0 :       pbService->GetPrivateBrowsingEnabled(&mInPrivateBrowsing);
    1134                 :   }
    1135             141 :   return NS_OK;
    1136                 : }
    1137                 : 
    1138                 : static nsPrivateBrowsingObserver *gPrivateBrowsingObserver = nsnull;
    1139                 : 
    1140                 : // -------------------------------
    1141                 : // CSS Style rule processor implementation
    1142                 : //
    1143                 : 
    1144               0 : nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets,
    1145                 :                                        PRUint8 aSheetType)
    1146                 :   : mSheets(aSheets)
    1147                 :   , mRuleCascades(nsnull)
    1148                 :   , mLastPresContext(nsnull)
    1149               0 :   , mSheetType(aSheetType)
    1150                 : {
    1151               0 :   for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) {
    1152               0 :     mSheets[i]->AddRuleProcessor(this);
    1153                 :   }
    1154               0 : }
    1155                 : 
    1156               0 : nsCSSRuleProcessor::~nsCSSRuleProcessor()
    1157                 : {
    1158               0 :   for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) {
    1159               0 :     mSheets[i]->DropRuleProcessor(this);
    1160                 :   }
    1161               0 :   mSheets.Clear();
    1162               0 :   ClearRuleCascades();
    1163               0 : }
    1164                 : 
    1165               0 : NS_IMPL_ISUPPORTS1(nsCSSRuleProcessor, nsIStyleRuleProcessor)
    1166                 : 
    1167                 : /* static */ nsresult
    1168            1404 : nsCSSRuleProcessor::Startup()
    1169                 : {
    1170                 :   Preferences::AddBoolVarCache(&gSupportVisitedPseudo, VISITED_PSEUDO_PREF,
    1171            1404 :                                true);
    1172                 : 
    1173            1404 :   gPrivateBrowsingObserver = new nsPrivateBrowsingObserver();
    1174            1404 :   NS_ENSURE_TRUE(gPrivateBrowsingObserver, NS_ERROR_OUT_OF_MEMORY);
    1175            1404 :   NS_ADDREF(gPrivateBrowsingObserver);
    1176            1404 :   gPrivateBrowsingObserver->Init();
    1177                 : 
    1178            1404 :   return NS_OK;
    1179                 : }
    1180                 : 
    1181                 : static bool
    1182               0 : InitSystemMetrics()
    1183                 : {
    1184               0 :   NS_ASSERTION(!sSystemMetrics, "already initialized");
    1185                 : 
    1186               0 :   sSystemMetrics = new nsTArray< nsCOMPtr<nsIAtom> >;
    1187               0 :   NS_ENSURE_TRUE(sSystemMetrics, false);
    1188                 : 
    1189                 :   /***************************************************************************
    1190                 :    * ANY METRICS ADDED HERE SHOULD ALSO BE ADDED AS MEDIA QUERIES IN         *
    1191                 :    * nsMediaFeatures.cpp                                                     *
    1192                 :    ***************************************************************************/
    1193                 : 
    1194                 :   PRInt32 metricResult =
    1195               0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollArrowStyle);
    1196               0 :   if (metricResult & LookAndFeel::eScrollArrow_StartBackward) {
    1197               0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_start_backward);
    1198                 :   }
    1199               0 :   if (metricResult & LookAndFeel::eScrollArrow_StartForward) {
    1200               0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_start_forward);
    1201                 :   }
    1202               0 :   if (metricResult & LookAndFeel::eScrollArrow_EndBackward) {
    1203               0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_end_backward);
    1204                 :   }
    1205               0 :   if (metricResult & LookAndFeel::eScrollArrow_EndForward) {
    1206               0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_end_forward);
    1207                 :   }
    1208                 : 
    1209                 :   metricResult =
    1210               0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollSliderStyle);
    1211               0 :   if (metricResult != LookAndFeel::eScrollThumbStyle_Normal) {
    1212               0 :     sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_thumb_proportional);
    1213                 :   }
    1214                 : 
    1215                 :   metricResult =
    1216               0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ImagesInMenus);
    1217               0 :   if (metricResult) {
    1218               0 :     sSystemMetrics->AppendElement(nsGkAtoms::images_in_menus);
    1219                 :   }
    1220                 : 
    1221                 :   metricResult =
    1222               0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_ImagesInButtons);
    1223               0 :   if (metricResult) {
    1224               0 :     sSystemMetrics->AppendElement(nsGkAtoms::images_in_buttons);
    1225                 :   }
    1226                 : 
    1227                 :   metricResult =
    1228               0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_MenuBarDrag);
    1229               0 :   if (metricResult) {
    1230               0 :     sSystemMetrics->AppendElement(nsGkAtoms::menubar_drag);
    1231                 :   }
    1232                 : 
    1233                 :   nsresult rv =
    1234               0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsDefaultTheme, &metricResult);
    1235               0 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1236               0 :     sSystemMetrics->AppendElement(nsGkAtoms::windows_default_theme);
    1237                 :   }
    1238                 : 
    1239               0 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacGraphiteTheme, &metricResult);
    1240               0 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1241               0 :     sSystemMetrics->AppendElement(nsGkAtoms::mac_graphite_theme);
    1242                 :   }
    1243                 : 
    1244               0 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacLionTheme, &metricResult);
    1245               0 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1246               0 :     sSystemMetrics->AppendElement(nsGkAtoms::mac_lion_theme);
    1247                 :   }
    1248                 : 
    1249               0 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_DWMCompositor, &metricResult);
    1250               0 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1251               0 :     sSystemMetrics->AppendElement(nsGkAtoms::windows_compositor);
    1252                 :   }
    1253                 : 
    1254               0 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsClassic, &metricResult);
    1255               0 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1256               0 :     sSystemMetrics->AppendElement(nsGkAtoms::windows_classic);
    1257                 :   }
    1258                 : 
    1259               0 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_TouchEnabled, &metricResult);
    1260               0 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1261               0 :     sSystemMetrics->AppendElement(nsGkAtoms::touch_enabled);
    1262                 :   }
    1263                 :  
    1264               0 :   rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MaemoClassic, &metricResult);
    1265               0 :   if (NS_SUCCEEDED(rv) && metricResult) {
    1266               0 :     sSystemMetrics->AppendElement(nsGkAtoms::maemo_classic);
    1267                 :   }
    1268                 : 
    1269                 : #ifdef XP_WIN
    1270                 :   if (NS_SUCCEEDED(
    1271                 :         LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsThemeIdentifier,
    1272                 :                             &metricResult))) {
    1273                 :     nsCSSRuleProcessor::SetWindowsThemeIdentifier(static_cast<PRUint8>(metricResult));
    1274                 :     switch(metricResult) {
    1275                 :       case LookAndFeel::eWindowsTheme_Aero:
    1276                 :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_aero);
    1277                 :         break;
    1278                 :       case LookAndFeel::eWindowsTheme_LunaBlue:
    1279                 :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_blue);
    1280                 :         break;
    1281                 :       case LookAndFeel::eWindowsTheme_LunaOlive:
    1282                 :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_olive);
    1283                 :         break;
    1284                 :       case LookAndFeel::eWindowsTheme_LunaSilver:
    1285                 :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_luna_silver);
    1286                 :         break;
    1287                 :       case LookAndFeel::eWindowsTheme_Royale:
    1288                 :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_royale);
    1289                 :         break;
    1290                 :       case LookAndFeel::eWindowsTheme_Zune:
    1291                 :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_zune);
    1292                 :         break;
    1293                 :       case LookAndFeel::eWindowsTheme_Generic:
    1294                 :         sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_generic);
    1295                 :         break;
    1296                 :     }
    1297                 :   }
    1298                 : #endif
    1299                 : 
    1300               0 :   return true;
    1301                 : }
    1302                 : 
    1303                 : /* static */ void
    1304            1403 : nsCSSRuleProcessor::FreeSystemMetrics()
    1305                 : {
    1306            1403 :   delete sSystemMetrics;
    1307            1403 :   sSystemMetrics = nsnull;
    1308            1403 : }
    1309                 : 
    1310                 : /* static */ void
    1311            1403 : nsCSSRuleProcessor::Shutdown()
    1312                 : {
    1313            1403 :   FreeSystemMetrics();
    1314                 :   // Make sure we don't crash if Shutdown is called before Init
    1315            1403 :   NS_IF_RELEASE(gPrivateBrowsingObserver);
    1316            1403 : }
    1317                 : 
    1318                 : /* static */ bool
    1319               0 : nsCSSRuleProcessor::HasSystemMetric(nsIAtom* aMetric)
    1320                 : {
    1321               0 :   if (!sSystemMetrics && !InitSystemMetrics()) {
    1322               0 :     return false;
    1323                 :   }
    1324               0 :   return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
    1325                 : }
    1326                 : 
    1327                 : #ifdef XP_WIN
    1328                 : /* static */ PRUint8
    1329                 : nsCSSRuleProcessor::GetWindowsThemeIdentifier()
    1330                 : {
    1331                 :   if (!sSystemMetrics)
    1332                 :     InitSystemMetrics();
    1333                 :   return sWinThemeId;
    1334                 : }
    1335                 : #endif
    1336                 : 
    1337                 : /* static */
    1338                 : nsEventStates
    1339               0 : nsCSSRuleProcessor::GetContentState(Element* aElement)
    1340                 : {
    1341               0 :   nsEventStates state = aElement->StyleState();
    1342                 : 
    1343                 :   // If we are not supposed to mark visited links as such, be sure to
    1344                 :   // flip the bits appropriately.  We want to do this here, rather
    1345                 :   // than in GetContentStateForVisitedHandling, so that we don't
    1346                 :   // expose that :visited support is disabled to the Web page.
    1347               0 :   if (state.HasState(NS_EVENT_STATE_VISITED) &&
    1348               0 :       (!gSupportVisitedPseudo ||
    1349               0 :        aElement->OwnerDoc()->IsBeingUsedAsImage() ||
    1350               0 :        gPrivateBrowsingObserver->InPrivateBrowsing())) {
    1351               0 :     state &= ~NS_EVENT_STATE_VISITED;
    1352               0 :     state |= NS_EVENT_STATE_UNVISITED;
    1353                 :   }
    1354                 :   return state;
    1355                 : }
    1356                 : 
    1357                 : /* static */
    1358                 : bool
    1359               0 : nsCSSRuleProcessor::IsLink(Element* aElement)
    1360                 : {
    1361               0 :   nsEventStates state = aElement->StyleState();
    1362               0 :   return state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
    1363                 : }
    1364                 : 
    1365                 : /* static */
    1366                 : nsEventStates
    1367               0 : nsCSSRuleProcessor::GetContentStateForVisitedHandling(
    1368                 :                      Element* aElement,
    1369                 :                      nsRuleWalker::VisitedHandlingType aVisitedHandling,
    1370                 :                      bool aIsRelevantLink)
    1371                 : {
    1372               0 :   nsEventStates contentState = GetContentState(aElement);
    1373               0 :   if (contentState.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) {
    1374               0 :     NS_ABORT_IF_FALSE(IsLink(aElement), "IsLink() should match state");
    1375               0 :     contentState &= ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
    1376               0 :     if (aIsRelevantLink) {
    1377               0 :       switch (aVisitedHandling) {
    1378                 :         case nsRuleWalker::eRelevantLinkUnvisited:
    1379               0 :           contentState |= NS_EVENT_STATE_UNVISITED;
    1380               0 :           break;
    1381                 :         case nsRuleWalker::eRelevantLinkVisited:
    1382               0 :           contentState |= NS_EVENT_STATE_VISITED;
    1383               0 :           break;
    1384                 :         case nsRuleWalker::eLinksVisitedOrUnvisited:
    1385               0 :           contentState |= NS_EVENT_STATE_UNVISITED | NS_EVENT_STATE_VISITED;
    1386               0 :           break;
    1387                 :       }
    1388                 :     } else {
    1389               0 :       contentState |= NS_EVENT_STATE_UNVISITED;
    1390                 :     }
    1391                 :   }
    1392                 :   return contentState;
    1393                 : }
    1394                 : 
    1395                 : /**
    1396                 :  * A |NodeMatchContext| has data about matching a selector (without
    1397                 :  * combinators) against a single node.  It contains only input to the
    1398                 :  * matching.
    1399                 :  *
    1400                 :  * Unlike |RuleProcessorData|, which is similar, a |NodeMatchContext|
    1401                 :  * can vary depending on the selector matching process.  In other words,
    1402                 :  * there might be multiple NodeMatchContexts corresponding to a single
    1403                 :  * node, but only one possible RuleProcessorData.
    1404                 :  */
    1405                 : struct NodeMatchContext {
    1406                 :   // In order to implement nsCSSRuleProcessor::HasStateDependentStyle,
    1407                 :   // we need to be able to see if a node might match an
    1408                 :   // event-state-dependent selector for any value of that event state.
    1409                 :   // So mStateMask contains the states that should NOT be tested.
    1410                 :   //
    1411                 :   // NOTE: For |aStateMask| to work correctly, it's important that any
    1412                 :   // change that changes multiple state bits include all those state
    1413                 :   // bits in the notification.  Otherwise, if multiple states change but
    1414                 :   // we do separate notifications then we might determine the style is
    1415                 :   // not state-dependent when it really is (e.g., determining that a
    1416                 :   // :hover:active rule no longer matches when both states are unset).
    1417                 :   const nsEventStates mStateMask;
    1418                 : 
    1419                 :   // Is this link the unique link whose visitedness can affect the style
    1420                 :   // of the node being matched?  (That link is the nearest link to the
    1421                 :   // node being matched that is itself or an ancestor.)
    1422                 :   //
    1423                 :   // Always false when TreeMatchContext::mForStyling is false.  (We
    1424                 :   // could figure it out for SelectorListMatches, but we're starting
    1425                 :   // from the middle of the selector list when doing
    1426                 :   // Has{Attribute,State}DependentStyle, so we can't tell.  So when
    1427                 :   // mForStyling is false, we have to assume we don't know.)
    1428                 :   const bool mIsRelevantLink;
    1429                 : 
    1430            1796 :   NodeMatchContext(nsEventStates aStateMask, bool aIsRelevantLink)
    1431                 :     : mStateMask(aStateMask)
    1432            1796 :     , mIsRelevantLink(aIsRelevantLink)
    1433                 :   {
    1434            1796 :   }
    1435                 : };
    1436                 : 
    1437               0 : static bool ValueIncludes(const nsSubstring& aValueList,
    1438                 :                             const nsSubstring& aValue,
    1439                 :                             const nsStringComparator& aComparator)
    1440                 : {
    1441               0 :   const PRUnichar *p = aValueList.BeginReading(),
    1442               0 :               *p_end = aValueList.EndReading();
    1443                 : 
    1444               0 :   while (p < p_end) {
    1445                 :     // skip leading space
    1446               0 :     while (p != p_end && nsContentUtils::IsHTMLWhitespace(*p))
    1447               0 :       ++p;
    1448                 : 
    1449               0 :     const PRUnichar *val_start = p;
    1450                 : 
    1451                 :     // look for space or end
    1452               0 :     while (p != p_end && !nsContentUtils::IsHTMLWhitespace(*p))
    1453               0 :       ++p;
    1454                 : 
    1455               0 :     const PRUnichar *val_end = p;
    1456                 : 
    1457               0 :     if (val_start < val_end &&
    1458               0 :         aValue.Equals(Substring(val_start, val_end), aComparator))
    1459               0 :       return true;
    1460                 : 
    1461               0 :     ++p; // we know the next character is not whitespace
    1462                 :   }
    1463               0 :   return false;
    1464                 : }
    1465                 : 
    1466                 : // Return whether we should apply a "global" (i.e., universal-tag)
    1467                 : // selector for event states in quirks mode.  Note that
    1468                 : // |IsLink()| is checked separately by the caller, so we return
    1469                 : // false for |nsGkAtoms::a|, which here means a named anchor.
    1470               0 : inline bool IsQuirkEventSensitive(nsIAtom *aContentTag)
    1471                 : {
    1472                 :   return bool ((nsGkAtoms::button == aContentTag) ||
    1473                 :                  (nsGkAtoms::img == aContentTag)    ||
    1474                 :                  (nsGkAtoms::input == aContentTag)  ||
    1475                 :                  (nsGkAtoms::label == aContentTag)  ||
    1476                 :                  (nsGkAtoms::select == aContentTag) ||
    1477               0 :                  (nsGkAtoms::textarea == aContentTag));
    1478                 : }
    1479                 : 
    1480                 : 
    1481                 : static inline bool
    1482               0 : IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
    1483                 :                    bool aWhitespaceIsSignificant)
    1484                 : {
    1485                 :   return nsStyleUtil::IsSignificantChild(aChild, aTextIsSignificant,
    1486               0 :                                          aWhitespaceIsSignificant);
    1487                 : }
    1488                 : 
    1489                 : // This function is to be called once we have fetched a value for an attribute
    1490                 : // whose namespace and name match those of aAttrSelector.  This function
    1491                 : // performs comparisons on the value only, based on aAttrSelector->mFunction.
    1492               0 : static bool AttrMatchesValue(const nsAttrSelector* aAttrSelector,
    1493                 :                                const nsString& aValue, bool isHTML)
    1494                 : {
    1495               0 :   NS_PRECONDITION(aAttrSelector, "Must have an attribute selector");
    1496                 : 
    1497                 :   // http://lists.w3.org/Archives/Public/www-style/2008Apr/0038.html
    1498                 :   // *= (CONTAINSMATCH) ~= (INCLUDES) ^= (BEGINSMATCH) $= (ENDSMATCH)
    1499                 :   // all accept the empty string, but match nothing.
    1500               0 :   if (aAttrSelector->mValue.IsEmpty() &&
    1501                 :       (aAttrSelector->mFunction == NS_ATTR_FUNC_INCLUDES ||
    1502                 :        aAttrSelector->mFunction == NS_ATTR_FUNC_ENDSMATCH ||
    1503                 :        aAttrSelector->mFunction == NS_ATTR_FUNC_BEGINSMATCH ||
    1504                 :        aAttrSelector->mFunction == NS_ATTR_FUNC_CONTAINSMATCH))
    1505               0 :     return false;
    1506                 : 
    1507               0 :   const nsDefaultStringComparator defaultComparator;
    1508               0 :   const nsASCIICaseInsensitiveStringComparator ciComparator;
    1509                 :   const nsStringComparator& comparator =
    1510               0 :       (aAttrSelector->mCaseSensitive || !isHTML)
    1511                 :                 ? static_cast<const nsStringComparator&>(defaultComparator)
    1512               0 :                 : static_cast<const nsStringComparator&>(ciComparator);
    1513                 : 
    1514               0 :   switch (aAttrSelector->mFunction) {
    1515                 :     case NS_ATTR_FUNC_EQUALS: 
    1516               0 :       return aValue.Equals(aAttrSelector->mValue, comparator);
    1517                 :     case NS_ATTR_FUNC_INCLUDES: 
    1518               0 :       return ValueIncludes(aValue, aAttrSelector->mValue, comparator);
    1519                 :     case NS_ATTR_FUNC_DASHMATCH: 
    1520               0 :       return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
    1521                 :     case NS_ATTR_FUNC_ENDSMATCH:
    1522               0 :       return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
    1523                 :     case NS_ATTR_FUNC_BEGINSMATCH:
    1524               0 :       return StringBeginsWith(aValue, aAttrSelector->mValue, comparator);
    1525                 :     case NS_ATTR_FUNC_CONTAINSMATCH:
    1526               0 :       return FindInReadable(aAttrSelector->mValue, aValue, comparator);
    1527                 :     default:
    1528               0 :       NS_NOTREACHED("Shouldn't be ending up here");
    1529               0 :       return false;
    1530                 :   }
    1531                 : }
    1532                 : 
    1533                 : static inline bool
    1534               0 : edgeChildMatches(Element* aElement, TreeMatchContext& aTreeMatchContext,
    1535                 :                  bool checkFirst, bool checkLast)
    1536                 : {
    1537               0 :   nsIContent *parent = aElement->GetParent();
    1538               0 :   if (!parent) {
    1539               0 :     return false;
    1540                 :   }
    1541                 : 
    1542               0 :   if (aTreeMatchContext.mForStyling)
    1543               0 :     parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
    1544                 : 
    1545               0 :   return (!checkFirst ||
    1546                 :           aTreeMatchContext.mNthIndexCache.
    1547               0 :             GetNthIndex(aElement, false, false, true) == 1) &&
    1548               0 :          (!checkLast ||
    1549                 :           aTreeMatchContext.mNthIndexCache.
    1550               0 :             GetNthIndex(aElement, false, true, true) == 1);
    1551                 : }
    1552                 : 
    1553                 : static inline bool
    1554               0 : nthChildGenericMatches(Element* aElement,
    1555                 :                        TreeMatchContext& aTreeMatchContext,
    1556                 :                        nsPseudoClassList* pseudoClass,
    1557                 :                        bool isOfType, bool isFromEnd)
    1558                 : {
    1559               0 :   nsIContent *parent = aElement->GetParent();
    1560               0 :   if (!parent) {
    1561               0 :     return false;
    1562                 :   }
    1563                 : 
    1564               0 :   if (aTreeMatchContext.mForStyling) {
    1565               0 :     if (isFromEnd)
    1566               0 :       parent->SetFlags(NODE_HAS_SLOW_SELECTOR);
    1567                 :     else
    1568               0 :       parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
    1569                 :   }
    1570                 : 
    1571                 :   const PRInt32 index = aTreeMatchContext.mNthIndexCache.
    1572               0 :     GetNthIndex(aElement, isOfType, isFromEnd, false);
    1573               0 :   if (index <= 0) {
    1574                 :     // Node is anonymous content (not really a child of its parent).
    1575               0 :     return false;
    1576                 :   }
    1577                 : 
    1578               0 :   const PRInt32 a = pseudoClass->u.mNumbers[0];
    1579               0 :   const PRInt32 b = pseudoClass->u.mNumbers[1];
    1580                 :   // result should be true if there exists n >= 0 such that
    1581                 :   // a * n + b == index.
    1582               0 :   if (a == 0) {
    1583               0 :     return b == index;
    1584                 :   }
    1585                 : 
    1586                 :   // Integer division in C does truncation (towards 0).  So
    1587                 :   // check that the result is nonnegative, and that there was no
    1588                 :   // truncation.
    1589               0 :   const PRInt32 n = (index - b) / a;
    1590               0 :   return n >= 0 && (a * n == index - b);
    1591                 : }
    1592                 : 
    1593                 : static inline bool
    1594               0 : edgeOfTypeMatches(Element* aElement, TreeMatchContext& aTreeMatchContext,
    1595                 :                   bool checkFirst, bool checkLast)
    1596                 : {
    1597               0 :   nsIContent *parent = aElement->GetParent();
    1598               0 :   if (!parent) {
    1599               0 :     return false;
    1600                 :   }
    1601                 : 
    1602               0 :   if (aTreeMatchContext.mForStyling) {
    1603               0 :     if (checkLast)
    1604               0 :       parent->SetFlags(NODE_HAS_SLOW_SELECTOR);
    1605                 :     else
    1606               0 :       parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
    1607                 :   }
    1608                 : 
    1609               0 :   return (!checkFirst ||
    1610                 :           aTreeMatchContext.mNthIndexCache.
    1611               0 :             GetNthIndex(aElement, true, false, true) == 1) &&
    1612               0 :          (!checkLast ||
    1613                 :           aTreeMatchContext.mNthIndexCache.
    1614               0 :             GetNthIndex(aElement, true, true, true) == 1);
    1615                 : }
    1616                 : 
    1617                 : static inline bool
    1618               0 : checkGenericEmptyMatches(Element* aElement,
    1619                 :                          TreeMatchContext& aTreeMatchContext,
    1620                 :                          bool isWhitespaceSignificant)
    1621                 : {
    1622               0 :   nsIContent *child = nsnull;
    1623               0 :   PRInt32 index = -1;
    1624                 : 
    1625               0 :   if (aTreeMatchContext.mForStyling)
    1626               0 :     aElement->SetFlags(NODE_HAS_EMPTY_SELECTOR);
    1627                 : 
    1628               0 :   do {
    1629               0 :     child = aElement->GetChildAt(++index);
    1630                 :     // stop at first non-comment (and non-whitespace for
    1631                 :     // :-moz-only-whitespace) node        
    1632               0 :   } while (child && !IsSignificantChild(child, true, isWhitespaceSignificant));
    1633               0 :   return (child == nsnull);
    1634                 : }
    1635                 : 
    1636                 : // An array of the states that are relevant for various pseudoclasses.
    1637            1464 : static const nsEventStates sPseudoClassStates[] = {
    1638                 : #define CSS_PSEUDO_CLASS(_name, _value)         \
    1639                 :   nsEventStates(),
    1640                 : #define CSS_STATE_PSEUDO_CLASS(_name, _value, _states) \
    1641                 :   _states,
    1642                 : #include "nsCSSPseudoClassList.h"
    1643                 : #undef CSS_STATE_PSEUDO_CLASS
    1644                 : #undef CSS_PSEUDO_CLASS
    1645                 :   // Add more entries for our fake values to make sure we can't
    1646                 :   // index out of bounds into this array no matter what.
    1647                 :   nsEventStates(),
    1648                 :   nsEventStates()
    1649            1464 : };
    1650                 : MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(sPseudoClassStates) ==
    1651                 :                   nsCSSPseudoClasses::ePseudoClass_NotPseudoClass + 1,
    1652                 :                   "ePseudoClass_NotPseudoClass is no longer at the end of"
    1653                 :                   "sPseudoClassStates");
    1654                 : 
    1655                 : // |aDependence| has two functions:
    1656                 : //  * when non-null, it indicates that we're processing a negation,
    1657                 : //    which is done only when SelectorMatches calls itself recursively
    1658                 : //  * what it points to should be set to true whenever a test is skipped
    1659                 : //    because of aStateMask
    1660            1796 : static bool SelectorMatches(Element* aElement,
    1661                 :                               nsCSSSelector* aSelector,
    1662                 :                               NodeMatchContext& aNodeMatchContext,
    1663                 :                               TreeMatchContext& aTreeMatchContext,
    1664                 :                               bool* const aDependence = nsnull)
    1665                 : 
    1666                 : {
    1667            1796 :   NS_PRECONDITION(!aSelector->IsPseudoElement(),
    1668                 :                   "Pseudo-element snuck into SelectorMatches?");
    1669            1796 :   NS_ABORT_IF_FALSE(aTreeMatchContext.mForStyling ||
    1670                 :                     !aNodeMatchContext.mIsRelevantLink,
    1671                 :                     "mIsRelevantLink should be set to false when mForStyling "
    1672                 :                     "is false since we don't know how to set it correctly in "
    1673                 :                     "Has(Attribute|State)DependentStyle");
    1674                 : 
    1675                 :   // namespace/tag match
    1676                 :   // optimization : bail out early if we can
    1677            1796 :   if ((kNameSpaceID_Unknown != aSelector->mNameSpace &&
    1678               0 :        aElement->GetNameSpaceID() != aSelector->mNameSpace))
    1679               0 :     return false;
    1680                 : 
    1681            1796 :   if (aSelector->mLowercaseTag) {
    1682                 :     nsIAtom* selectorTag =
    1683               0 :       (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTML()) ?
    1684            1796 :         aSelector->mLowercaseTag : aSelector->mCasedTag;
    1685            1796 :     if (selectorTag != aElement->Tag()) {
    1686            1468 :       return false;
    1687                 :     }
    1688                 :   }
    1689                 : 
    1690             328 :   nsAtomList* IDList = aSelector->mIDList;
    1691             328 :   if (IDList) {
    1692               0 :     nsIAtom* id = aElement->GetID();
    1693               0 :     if (id) {
    1694                 :       // case sensitivity: bug 93371
    1695                 :       const bool isCaseSensitive =
    1696               0 :         aTreeMatchContext.mCompatMode != eCompatibility_NavQuirks;
    1697                 : 
    1698               0 :       if (isCaseSensitive) {
    1699               0 :         do {
    1700               0 :           if (IDList->mAtom != id) {
    1701               0 :             return false;
    1702                 :           }
    1703               0 :           IDList = IDList->mNext;
    1704                 :         } while (IDList);
    1705                 :       } else {
    1706                 :         // Use EqualsIgnoreASCIICase instead of full on unicode case conversion
    1707                 :         // in order to save on performance. This is only used in quirks mode
    1708                 :         // anyway.
    1709               0 :         nsDependentAtomString id1Str(id);
    1710               0 :         do {
    1711               0 :           if (!nsContentUtils::EqualsIgnoreASCIICase(id1Str,
    1712               0 :                  nsDependentAtomString(IDList->mAtom))) {
    1713               0 :             return false;
    1714                 :           }
    1715               0 :           IDList = IDList->mNext;
    1716                 :         } while (IDList);
    1717                 :       }
    1718                 :     } else {
    1719                 :       // Element has no id but we have an id selector
    1720               0 :       return false;
    1721                 :     }
    1722                 :   }
    1723                 : 
    1724             328 :   nsAtomList* classList = aSelector->mClassList;
    1725             328 :   if (classList) {
    1726                 :     // test for class match
    1727               0 :     const nsAttrValue *elementClasses = aElement->GetClasses();
    1728               0 :     if (!elementClasses) {
    1729                 :       // Element has no classes but we have a class selector
    1730               0 :       return false;
    1731                 :     }
    1732                 : 
    1733                 :     // case sensitivity: bug 93371
    1734                 :     const bool isCaseSensitive =
    1735               0 :       aTreeMatchContext.mCompatMode != eCompatibility_NavQuirks;
    1736                 : 
    1737               0 :     while (classList) {
    1738               0 :       if (!elementClasses->Contains(classList->mAtom,
    1739                 :                                     isCaseSensitive ?
    1740               0 :                                       eCaseMatters : eIgnoreCase)) {
    1741               0 :         return false;
    1742                 :       }
    1743               0 :       classList = classList->mNext;
    1744                 :     }
    1745                 :   }
    1746                 : 
    1747             328 :   const bool isNegated = (aDependence != nsnull);
    1748                 :   // The selectors for which we set node bits are, unfortunately, early
    1749                 :   // in this function (because they're pseudo-classes, which are
    1750                 :   // generally quick to test, and thus earlier).  If they were later,
    1751                 :   // we'd probably avoid setting those bits in more cases where setting
    1752                 :   // them is unnecessary.
    1753             328 :   NS_ASSERTION(aNodeMatchContext.mStateMask.IsEmpty() ||
    1754                 :                !aTreeMatchContext.mForStyling,
    1755                 :                "mForStyling must be false if we're just testing for "
    1756                 :                "state-dependence");
    1757                 : 
    1758                 :   // test for pseudo class match
    1759             328 :   for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
    1760                 :        pseudoClass; pseudoClass = pseudoClass->mNext) {
    1761               0 :     nsEventStates statesToCheck = sPseudoClassStates[pseudoClass->mType];
    1762               0 :     if (statesToCheck.IsEmpty()) {
    1763                 :       // keep the cases here in the same order as the list in
    1764                 :       // nsCSSPseudoClassList.h
    1765               0 :       switch (pseudoClass->mType) {
    1766                 :       case nsCSSPseudoClasses::ePseudoClass_empty:
    1767               0 :         if (!checkGenericEmptyMatches(aElement, aTreeMatchContext, true)) {
    1768               0 :           return false;
    1769                 :         }
    1770               0 :         break;
    1771                 : 
    1772                 :       case nsCSSPseudoClasses::ePseudoClass_mozOnlyWhitespace:
    1773               0 :         if (!checkGenericEmptyMatches(aElement, aTreeMatchContext, false)) {
    1774               0 :           return false;
    1775                 :         }
    1776               0 :         break;
    1777                 : 
    1778                 :       case nsCSSPseudoClasses::ePseudoClass_mozEmptyExceptChildrenWithLocalname:
    1779                 :         {
    1780               0 :           NS_ASSERTION(pseudoClass->u.mString, "Must have string!");
    1781               0 :           nsIContent *child = nsnull;
    1782               0 :           PRInt32 index = -1;
    1783                 : 
    1784               0 :           if (aTreeMatchContext.mForStyling)
    1785                 :             // FIXME:  This isn't sufficient to handle:
    1786                 :             //   :-moz-empty-except-children-with-localname() + E
    1787                 :             //   :-moz-empty-except-children-with-localname() ~ E
    1788                 :             // because we don't know to restyle the grandparent of the
    1789                 :             // inserted/removed element (as in bug 534804 for :empty).
    1790               0 :             aElement->SetFlags(NODE_HAS_SLOW_SELECTOR);
    1791               0 :           do {
    1792               0 :             child = aElement->GetChildAt(++index);
    1793                 :           } while (child &&
    1794               0 :                    (!IsSignificantChild(child, true, false) ||
    1795               0 :                     (child->GetNameSpaceID() == aElement->GetNameSpaceID() &&
    1796               0 :                      child->Tag()->Equals(nsDependentString(pseudoClass->u.mString)))));
    1797               0 :           if (child != nsnull) {
    1798               0 :             return false;
    1799                 :           }
    1800                 :         }
    1801               0 :         break;
    1802                 : 
    1803                 :       case nsCSSPseudoClasses::ePseudoClass_lang:
    1804                 :         {
    1805               0 :           NS_ASSERTION(nsnull != pseudoClass->u.mString, "null lang parameter");
    1806               0 :           if (!pseudoClass->u.mString || !*pseudoClass->u.mString) {
    1807               0 :             return false;
    1808                 :           }
    1809                 : 
    1810                 :           // We have to determine the language of the current element.  Since
    1811                 :           // this is currently no property and since the language is inherited
    1812                 :           // from the parent we have to be prepared to look at all parent
    1813                 :           // nodes.  The language itself is encoded in the LANG attribute.
    1814               0 :           nsAutoString language;
    1815               0 :           aElement->GetLang(language);
    1816               0 :           if (!language.IsEmpty()) {
    1817               0 :             if (!nsStyleUtil::DashMatchCompare(language,
    1818               0 :                                                nsDependentString(pseudoClass->u.mString),
    1819               0 :                                                nsASCIICaseInsensitiveStringComparator())) {
    1820               0 :               return false;
    1821                 :             }
    1822                 :             // This pseudo-class matched; move on to the next thing
    1823                 :             break;
    1824                 :           }
    1825                 : 
    1826               0 :           nsIDocument* doc = aTreeMatchContext.mDocument;
    1827               0 :           if (doc) {
    1828                 :             // Try to get the language from the HTTP header or if this
    1829                 :             // is missing as well from the preferences.
    1830                 :             // The content language can be a comma-separated list of
    1831                 :             // language codes.
    1832               0 :             doc->GetContentLanguage(language);
    1833                 : 
    1834               0 :             nsDependentString langString(pseudoClass->u.mString);
    1835               0 :             language.StripWhitespace();
    1836               0 :             PRInt32 begin = 0;
    1837               0 :             PRInt32 len = language.Length();
    1838               0 :             while (begin < len) {
    1839               0 :               PRInt32 end = language.FindChar(PRUnichar(','), begin);
    1840               0 :               if (end == kNotFound) {
    1841               0 :                 end = len;
    1842                 :               }
    1843               0 :               if (nsStyleUtil::DashMatchCompare(Substring(language, begin,
    1844               0 :                                                           end-begin),
    1845                 :                                                 langString,
    1846               0 :                                                 nsASCIICaseInsensitiveStringComparator())) {
    1847               0 :                 break;
    1848                 :               }
    1849               0 :               begin = end + 1;
    1850                 :             }
    1851               0 :             if (begin < len) {
    1852                 :               // This pseudo-class matched
    1853                 :               break;
    1854                 :             }
    1855                 :           }
    1856                 : 
    1857               0 :           return false;
    1858                 :         }
    1859                 :         break;
    1860                 : 
    1861                 :       case nsCSSPseudoClasses::ePseudoClass_mozBoundElement:
    1862               0 :         if (aTreeMatchContext.mScopedRoot != aElement) {
    1863               0 :           return false;
    1864                 :         }
    1865               0 :         break;
    1866                 : 
    1867                 :       case nsCSSPseudoClasses::ePseudoClass_root:
    1868               0 :         if (aElement->GetParent() ||
    1869               0 :             aElement != aElement->OwnerDoc()->GetRootElement()) {
    1870               0 :           return false;
    1871                 :         }
    1872               0 :         break;
    1873                 : 
    1874                 :       case nsCSSPseudoClasses::ePseudoClass_any:
    1875                 :         {
    1876                 :           nsCSSSelectorList *l;
    1877               0 :           for (l = pseudoClass->u.mSelectors; l; l = l->mNext) {
    1878               0 :             nsCSSSelector *s = l->mSelectors;
    1879               0 :             NS_ABORT_IF_FALSE(!s->mNext && !s->IsPseudoElement(),
    1880                 :                               "parser failed");
    1881               0 :             if (SelectorMatches(aElement, s, aNodeMatchContext,
    1882                 :                                 aTreeMatchContext)) {
    1883               0 :               break;
    1884                 :             }
    1885                 :           }
    1886               0 :           if (!l) {
    1887               0 :             return false;
    1888                 :           }
    1889                 :         }
    1890               0 :         break;
    1891                 : 
    1892                 :       case nsCSSPseudoClasses::ePseudoClass_firstChild:
    1893               0 :         if (!edgeChildMatches(aElement, aTreeMatchContext, true, false)) {
    1894               0 :           return false;
    1895                 :         }
    1896               0 :         break;
    1897                 : 
    1898                 :       case nsCSSPseudoClasses::ePseudoClass_firstNode:
    1899                 :         {
    1900               0 :           nsIContent *firstNode = nsnull;
    1901               0 :           nsIContent *parent = aElement->GetParent();
    1902               0 :           if (parent) {
    1903               0 :             if (aTreeMatchContext.mForStyling)
    1904               0 :               parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
    1905                 : 
    1906               0 :             PRInt32 index = -1;
    1907               0 :             do {
    1908               0 :               firstNode = parent->GetChildAt(++index);
    1909                 :               // stop at first non-comment and non-whitespace node
    1910                 :             } while (firstNode &&
    1911               0 :                      !IsSignificantChild(firstNode, true, false));
    1912                 :           }
    1913               0 :           if (aElement != firstNode) {
    1914               0 :             return false;
    1915                 :           }
    1916                 :         }
    1917               0 :         break;
    1918                 : 
    1919                 :       case nsCSSPseudoClasses::ePseudoClass_lastChild:
    1920               0 :         if (!edgeChildMatches(aElement, aTreeMatchContext, false, true)) {
    1921               0 :           return false;
    1922                 :         }
    1923               0 :         break;
    1924                 : 
    1925                 :       case nsCSSPseudoClasses::ePseudoClass_lastNode:
    1926                 :         {
    1927               0 :           nsIContent *lastNode = nsnull;
    1928               0 :           nsIContent *parent = aElement->GetParent();
    1929               0 :           if (parent) {
    1930               0 :             if (aTreeMatchContext.mForStyling)
    1931               0 :               parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
    1932                 :             
    1933               0 :             PRUint32 index = parent->GetChildCount();
    1934               0 :             do {
    1935               0 :               lastNode = parent->GetChildAt(--index);
    1936                 :               // stop at first non-comment and non-whitespace node
    1937                 :             } while (lastNode &&
    1938               0 :                      !IsSignificantChild(lastNode, true, false));
    1939                 :           }
    1940               0 :           if (aElement != lastNode) {
    1941               0 :             return false;
    1942                 :           }
    1943                 :         }
    1944               0 :         break;
    1945                 : 
    1946                 :       case nsCSSPseudoClasses::ePseudoClass_onlyChild:
    1947               0 :         if (!edgeChildMatches(aElement, aTreeMatchContext, true, true)) {
    1948               0 :           return false;
    1949                 :         }
    1950               0 :         break;
    1951                 : 
    1952                 :       case nsCSSPseudoClasses::ePseudoClass_firstOfType:
    1953               0 :         if (!edgeOfTypeMatches(aElement, aTreeMatchContext, true, false)) {
    1954               0 :           return false;
    1955                 :         }
    1956               0 :         break;
    1957                 : 
    1958                 :       case nsCSSPseudoClasses::ePseudoClass_lastOfType:
    1959               0 :         if (!edgeOfTypeMatches(aElement, aTreeMatchContext, false, true)) {
    1960               0 :           return false;
    1961                 :         }
    1962               0 :         break;
    1963                 : 
    1964                 :       case nsCSSPseudoClasses::ePseudoClass_onlyOfType:
    1965               0 :         if (!edgeOfTypeMatches(aElement, aTreeMatchContext, true, true)) {
    1966               0 :           return false;
    1967                 :         }
    1968               0 :         break;
    1969                 : 
    1970                 :       case nsCSSPseudoClasses::ePseudoClass_nthChild:
    1971               0 :         if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
    1972               0 :                                     false, false)) {
    1973               0 :           return false;
    1974                 :         }
    1975               0 :         break;
    1976                 : 
    1977                 :       case nsCSSPseudoClasses::ePseudoClass_nthLastChild:
    1978               0 :         if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
    1979               0 :                                     false, true)) {
    1980               0 :           return false;
    1981                 :         }
    1982               0 :       break;
    1983                 : 
    1984                 :       case nsCSSPseudoClasses::ePseudoClass_nthOfType:
    1985               0 :         if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
    1986               0 :                                     true, false)) {
    1987               0 :           return false;
    1988                 :         }
    1989               0 :         break;
    1990                 : 
    1991                 :       case nsCSSPseudoClasses::ePseudoClass_nthLastOfType:
    1992               0 :         if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
    1993               0 :                                     true, true)) {
    1994               0 :           return false;
    1995                 :         }
    1996               0 :         break;
    1997                 : 
    1998                 :       case nsCSSPseudoClasses::ePseudoClass_mozHasHandlerRef:
    1999                 :         {
    2000               0 :           nsIContent *child = nsnull;
    2001               0 :           PRInt32 index = -1;
    2002                 : 
    2003               0 :           do {
    2004               0 :             child = aElement->GetChildAt(++index);
    2005               0 :             if (child && child->IsHTML() &&
    2006               0 :                 child->Tag() == nsGkAtoms::param &&
    2007                 :                 child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
    2008               0 :                                    NS_LITERAL_STRING("pluginurl"),
    2009               0 :                                    eIgnoreCase)) {
    2010               0 :               break;
    2011                 :             }
    2012                 :           } while (child);
    2013               0 :           if (!child) {
    2014               0 :             return false;
    2015                 :           }
    2016                 :         }
    2017               0 :         break;
    2018                 : 
    2019                 :       case nsCSSPseudoClasses::ePseudoClass_mozIsHTML:
    2020               0 :         if (!aTreeMatchContext.mIsHTMLDocument || !aElement->IsHTML()) {
    2021               0 :           return false;
    2022                 :         }
    2023               0 :         break;
    2024                 : 
    2025                 :       case nsCSSPseudoClasses::ePseudoClass_mozSystemMetric:
    2026                 :         {
    2027               0 :           nsCOMPtr<nsIAtom> metric = do_GetAtom(pseudoClass->u.mString);
    2028               0 :           if (!nsCSSRuleProcessor::HasSystemMetric(metric)) {
    2029               0 :             return false;
    2030                 :           }
    2031                 :         }
    2032               0 :         break;
    2033                 : 
    2034                 :       case nsCSSPseudoClasses::ePseudoClass_mozLocaleDir:
    2035                 :         {
    2036                 :           bool docIsRTL =
    2037               0 :             aTreeMatchContext.mDocument->GetDocumentState().
    2038               0 :               HasState(NS_DOCUMENT_STATE_RTL_LOCALE);
    2039                 : 
    2040               0 :           nsDependentString dirString(pseudoClass->u.mString);
    2041               0 :           NS_ASSERTION(dirString.EqualsLiteral("ltr") ||
    2042                 :                        dirString.EqualsLiteral("rtl"),
    2043                 :                        "invalid value for -moz-locale-dir");
    2044                 : 
    2045               0 :           if (dirString.EqualsLiteral("rtl") != docIsRTL) {
    2046               0 :             return false;
    2047                 :           }
    2048                 :         }
    2049               0 :         break;
    2050                 : 
    2051                 :       case nsCSSPseudoClasses::ePseudoClass_mozLWTheme:
    2052                 :         {
    2053               0 :           if (aTreeMatchContext.mDocument->GetDocumentLWTheme() <=
    2054                 :                 nsIDocument::Doc_Theme_None) {
    2055               0 :             return false;
    2056                 :           }
    2057                 :         }
    2058               0 :         break;
    2059                 : 
    2060                 :       case nsCSSPseudoClasses::ePseudoClass_mozLWThemeBrightText:
    2061                 :         {
    2062               0 :           if (aTreeMatchContext.mDocument->GetDocumentLWTheme() !=
    2063                 :                 nsIDocument::Doc_Theme_Bright) {
    2064               0 :             return false;
    2065                 :           }
    2066                 :         }
    2067               0 :         break;
    2068                 : 
    2069                 :       case nsCSSPseudoClasses::ePseudoClass_mozLWThemeDarkText:
    2070                 :         {
    2071               0 :           if (aTreeMatchContext.mDocument->GetDocumentLWTheme() !=
    2072                 :                 nsIDocument::Doc_Theme_Dark) {
    2073               0 :             return false;
    2074                 :           }
    2075                 :         }
    2076               0 :         break;
    2077                 : 
    2078                 :       case nsCSSPseudoClasses::ePseudoClass_mozWindowInactive:
    2079               0 :         if (!aTreeMatchContext.mDocument->GetDocumentState().
    2080               0 :                HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
    2081               0 :           return false;
    2082                 :         }
    2083               0 :         break;
    2084                 : 
    2085                 :       case nsCSSPseudoClasses::ePseudoClass_mozTableBorderNonzero:
    2086                 :         {
    2087               0 :           if (!aElement->IsHTML(nsGkAtoms::table)) {
    2088               0 :             return false;
    2089                 :           }
    2090               0 :           nsGenericElement *ge = static_cast<nsGenericElement*>(aElement);
    2091               0 :           const nsAttrValue *val = ge->GetParsedAttr(nsGkAtoms::border);
    2092               0 :           if (!val ||
    2093               0 :               (val->Type() == nsAttrValue::eInteger &&
    2094               0 :                val->GetIntegerValue() == 0)) {
    2095               0 :             return false;
    2096                 :           }
    2097                 :         }
    2098               0 :         break;
    2099                 : 
    2100                 :       default:
    2101               0 :         NS_ABORT_IF_FALSE(false, "How did that happen?");
    2102                 :       }
    2103                 :     } else {
    2104                 :       // Bit-based pseudo-classes
    2105               0 :       if (statesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE) &&
    2106                 :           aTreeMatchContext.mCompatMode == eCompatibility_NavQuirks &&
    2107                 :           // global selector:
    2108               0 :           !aSelector->HasTagSelector() && !aSelector->mIDList && 
    2109               0 :           !aSelector->mClassList && !aSelector->mAttrList &&
    2110                 :           // This (or the other way around) both make :not() asymmetric
    2111                 :           // in quirks mode (and it's hard to work around since we're
    2112                 :           // testing the current mNegations, not the first
    2113                 :           // (unnegated)). This at least makes it closer to the spec.
    2114               0 :           !isNegated &&
    2115                 :           // important for |IsQuirkEventSensitive|:
    2116               0 :           aElement->IsHTML() && !nsCSSRuleProcessor::IsLink(aElement) &&
    2117               0 :           !IsQuirkEventSensitive(aElement->Tag())) {
    2118                 :         // In quirks mode, only make certain elements sensitive to
    2119                 :         // selectors ":hover" and ":active".
    2120               0 :         return false;
    2121                 :       } else {
    2122               0 :         if (aTreeMatchContext.mForStyling &&
    2123               0 :             statesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER)) {
    2124                 :           // Mark the element as having :hover-dependent style
    2125               0 :           aElement->SetFlags(NODE_HAS_RELEVANT_HOVER_RULES);
    2126                 :         }
    2127               0 :         if (aNodeMatchContext.mStateMask.HasAtLeastOneOfStates(statesToCheck)) {
    2128               0 :           if (aDependence)
    2129               0 :             *aDependence = true;
    2130                 :         } else {
    2131                 :           nsEventStates contentState =
    2132                 :             nsCSSRuleProcessor::GetContentStateForVisitedHandling(
    2133                 :                                          aElement,
    2134                 :                                          aTreeMatchContext.VisitedHandling(),
    2135               0 :                                          aNodeMatchContext.mIsRelevantLink);
    2136               0 :           if (!contentState.HasAtLeastOneOfStates(statesToCheck)) {
    2137               0 :             return false;
    2138                 :           }
    2139                 :         }
    2140                 :       }
    2141                 :     }
    2142                 :   }
    2143                 : 
    2144             328 :   bool result = true;
    2145             328 :   if (aSelector->mAttrList) {
    2146                 :     // test for attribute match
    2147               0 :     PRUint32 attrCount = aElement->GetAttrCount();
    2148               0 :     if (attrCount == 0) {
    2149                 :       // if no attributes on the content, no match
    2150               0 :       return false;
    2151                 :     } else {
    2152               0 :       result = true;
    2153               0 :       nsAttrSelector* attr = aSelector->mAttrList;
    2154                 :       nsIAtom* matchAttribute;
    2155                 : 
    2156               0 :       do {
    2157                 :         bool isHTML =
    2158               0 :           (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTML());
    2159               0 :         matchAttribute = isHTML ? attr->mLowercaseAttr : attr->mCasedAttr;
    2160               0 :         if (attr->mNameSpace == kNameSpaceID_Unknown) {
    2161                 :           // Attr selector with a wildcard namespace.  We have to examine all
    2162                 :           // the attributes on our content node....  This sort of selector is
    2163                 :           // essentially a boolean OR, over all namespaces, of equivalent attr
    2164                 :           // selectors with those namespaces.  So to evaluate whether it
    2165                 :           // matches, evaluate for each namespace (the only namespaces that
    2166                 :           // have a chance at matching, of course, are ones that the element
    2167                 :           // actually has attributes in), short-circuiting if we ever match.
    2168               0 :           result = false;
    2169               0 :           for (PRUint32 i = 0; i < attrCount; ++i) {
    2170               0 :             const nsAttrName* attrName = aElement->GetAttrNameAt(i);
    2171               0 :             NS_ASSERTION(attrName, "GetAttrCount lied or GetAttrNameAt failed");
    2172               0 :             if (attrName->LocalName() != matchAttribute) {
    2173               0 :               continue;
    2174                 :             }
    2175               0 :             if (attr->mFunction == NS_ATTR_FUNC_SET) {
    2176               0 :               result = true;
    2177                 :             } else {
    2178               0 :               nsAutoString value;
    2179                 : #ifdef DEBUG
    2180                 :               bool hasAttr =
    2181                 : #endif
    2182                 :                 aElement->GetAttr(attrName->NamespaceID(),
    2183               0 :                                   attrName->LocalName(), value);
    2184               0 :               NS_ASSERTION(hasAttr, "GetAttrNameAt lied");
    2185               0 :               result = AttrMatchesValue(attr, value, isHTML);
    2186                 :             }
    2187                 : 
    2188                 :             // At this point |result| has been set by us
    2189                 :             // explicitly in this loop.  If it's false, we may still match
    2190                 :             // -- the content may have another attribute with the same name but
    2191                 :             // in a different namespace.  But if it's true, we are done (we
    2192                 :             // can short-circuit the boolean OR described above).
    2193               0 :             if (result) {
    2194               0 :               break;
    2195                 :             }
    2196                 :           }
    2197                 :         }
    2198               0 :         else if (attr->mFunction == NS_ATTR_FUNC_EQUALS) {
    2199                 :           result =
    2200                 :             aElement->
    2201                 :               AttrValueIs(attr->mNameSpace, matchAttribute, attr->mValue,
    2202                 :                           (!isHTML || attr->mCaseSensitive) ? eCaseMatters
    2203               0 :                                                             : eIgnoreCase);
    2204                 :         }
    2205               0 :         else if (!aElement->HasAttr(attr->mNameSpace, matchAttribute)) {
    2206               0 :           result = false;
    2207                 :         }
    2208               0 :         else if (attr->mFunction != NS_ATTR_FUNC_SET) {
    2209               0 :           nsAutoString value;
    2210                 : #ifdef DEBUG
    2211                 :           bool hasAttr =
    2212                 : #endif
    2213               0 :               aElement->GetAttr(attr->mNameSpace, matchAttribute, value);
    2214               0 :           NS_ASSERTION(hasAttr, "HasAttr lied");
    2215               0 :           result = AttrMatchesValue(attr, value, isHTML);
    2216                 :         }
    2217                 :         
    2218               0 :         attr = attr->mNext;
    2219                 :       } while (attr && result);
    2220                 :     }
    2221                 :   }
    2222                 : 
    2223                 :   // apply SelectorMatches to the negated selectors in the chain
    2224             328 :   if (!isNegated) {
    2225             328 :     for (nsCSSSelector *negation = aSelector->mNegations;
    2226                 :          result && negation; negation = negation->mNegations) {
    2227               0 :       bool dependence = false;
    2228                 :       result = !SelectorMatches(aElement, negation, aNodeMatchContext,
    2229               0 :                                 aTreeMatchContext, &dependence);
    2230                 :       // If the selector does match due to the dependence on aStateMask,
    2231                 :       // then we want to keep result true so that the final result of
    2232                 :       // SelectorMatches is true.  Doing so tells StateEnumFunc that
    2233                 :       // there is a dependence on the state.
    2234               0 :       result = result || dependence;
    2235                 :     }
    2236                 :   }
    2237             328 :   return result;
    2238                 : }
    2239                 : 
    2240                 : #undef STATE_CHECK
    2241                 : 
    2242                 : // Right now, there are four operators:
    2243                 : //   ' ', the descendant combinator, is greedy
    2244                 : //   '~', the indirect adjacent sibling combinator, is greedy
    2245                 : //   '+' and '>', the direct adjacent sibling and child combinators, are not
    2246                 : #define NS_IS_GREEDY_OPERATOR(ch) \
    2247                 :   ((ch) == PRUnichar(' ') || (ch) == PRUnichar('~'))
    2248                 : 
    2249             164 : static bool SelectorMatchesTree(Element* aPrevElement,
    2250                 :                                   nsCSSSelector* aSelector,
    2251                 :                                   TreeMatchContext& aTreeMatchContext,
    2252                 :                                   bool aLookForRelevantLink)
    2253                 : {
    2254             164 :   nsCSSSelector* selector = aSelector;
    2255             164 :   Element* prevElement = aPrevElement;
    2256             492 :   while (selector) { // check compound selectors
    2257             164 :     NS_ASSERTION(!selector->mNext ||
    2258                 :                  selector->mNext->mOperator != PRUnichar(0),
    2259                 :                  "compound selector without combinator");
    2260                 : 
    2261                 :     // for adjacent sibling combinators, the content to test against the
    2262                 :     // selector is the previous sibling *element*
    2263             164 :     Element* element = nsnull;
    2264             164 :     if (PRUnichar('+') == selector->mOperator ||
    2265                 :         PRUnichar('~') == selector->mOperator) {
    2266                 :       // The relevant link must be an ancestor of the node being matched.
    2267               0 :       aLookForRelevantLink = false;
    2268               0 :       nsIContent* parent = prevElement->GetParent();
    2269               0 :       if (parent) {
    2270               0 :         if (aTreeMatchContext.mForStyling)
    2271               0 :           parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
    2272                 : 
    2273               0 :         PRInt32 index = parent->IndexOf(prevElement);
    2274               0 :         while (0 <= --index) {
    2275               0 :           nsIContent* content = parent->GetChildAt(index);
    2276               0 :           if (content->IsElement()) {
    2277               0 :             element = content->AsElement();
    2278               0 :             break;
    2279                 :           }
    2280                 :         }
    2281               0 :       }
    2282                 :     }
    2283                 :     // for descendant combinators and child combinators, the element
    2284                 :     // to test against is the parent
    2285                 :     else {
    2286             164 :       nsIContent *content = prevElement->GetParent();
    2287                 :       // GetParent could return a document fragment; we only want
    2288                 :       // element parents.
    2289             164 :       if (content && content->IsElement()) {
    2290             164 :         element = content->AsElement();
    2291                 :       }
    2292                 :     }
    2293             164 :     if (!element) {
    2294               0 :       return false;
    2295                 :     }
    2296                 :     NodeMatchContext nodeContext(nsEventStates(),
    2297                 :                                  aLookForRelevantLink &&
    2298             164 :                                    nsCSSRuleProcessor::IsLink(element));
    2299             164 :     if (nodeContext.mIsRelevantLink) {
    2300                 :       // If we find an ancestor of the matched node that is a link
    2301                 :       // during the matching process, then it's the relevant link (see
    2302                 :       // constructor call above).
    2303                 :       // Since we are still matching against selectors that contain
    2304                 :       // :visited (they'll just fail), we will always find such a node
    2305                 :       // during the selector matching process if there is a relevant
    2306                 :       // link that can influence selector matching.
    2307               0 :       aLookForRelevantLink = false;
    2308               0 :       aTreeMatchContext.SetHaveRelevantLink();
    2309                 :     }
    2310             164 :     if (SelectorMatches(element, selector, nodeContext, aTreeMatchContext)) {
    2311                 :       // to avoid greedy matching, we need to recur if this is a
    2312                 :       // descendant or general sibling combinator and the next
    2313                 :       // combinator is different, but we can make an exception for
    2314                 :       // sibling, then parent, since a sibling's parent is always the
    2315                 :       // same.
    2316             164 :       if (NS_IS_GREEDY_OPERATOR(selector->mOperator) &&
    2317                 :           selector->mNext &&
    2318                 :           selector->mNext->mOperator != selector->mOperator &&
    2319                 :           !(selector->mOperator == '~' &&
    2320               0 :             NS_IS_ANCESTOR_OPERATOR(selector->mNext->mOperator))) {
    2321                 : 
    2322                 :         // pretend the selector didn't match, and step through content
    2323                 :         // while testing the same selector
    2324                 : 
    2325                 :         // This approach is slightly strange in that when it recurs
    2326                 :         // it tests from the top of the content tree, down.  This
    2327                 :         // doesn't matter much for performance since most selectors
    2328                 :         // don't match.  (If most did, it might be faster...)
    2329               0 :         if (SelectorMatchesTree(element, selector, aTreeMatchContext,
    2330               0 :                                 aLookForRelevantLink)) {
    2331               0 :           return true;
    2332                 :         }
    2333                 :       }
    2334             164 :       selector = selector->mNext;
    2335                 :     }
    2336                 :     else {
    2337                 :       // for adjacent sibling and child combinators, if we didn't find
    2338                 :       // a match, we're done
    2339               0 :       if (!NS_IS_GREEDY_OPERATOR(selector->mOperator)) {
    2340               0 :         return false;  // parent was required to match
    2341                 :       }
    2342                 :     }
    2343             164 :     prevElement = element;
    2344                 :   }
    2345             164 :   return true; // all the selectors matched.
    2346                 : }
    2347                 : 
    2348                 : static inline
    2349               0 : void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector,
    2350                 :                      RuleProcessorData* data, NodeMatchContext& nodeContext,
    2351                 :                      AncestorFilter *ancestorFilter)
    2352                 : {
    2353               0 :   if (nodeContext.mIsRelevantLink) {
    2354               0 :     data->mTreeMatchContext.SetHaveRelevantLink();
    2355                 :   }
    2356               0 :   if (ancestorFilter &&
    2357                 :       !ancestorFilter->MightHaveMatchingAncestor<RuleValue::eMaxAncestorHashes>(
    2358               0 :           value.mAncestorSelectorHashes)) {
    2359                 :     // We won't match; nothing else to do here
    2360               0 :     return;
    2361                 :   }
    2362               0 :   if (SelectorMatches(data->mElement, aSelector, nodeContext,
    2363               0 :                       data->mTreeMatchContext)) {
    2364               0 :     nsCSSSelector *next = aSelector->mNext;
    2365               0 :     if (!next || SelectorMatchesTree(data->mElement, next,
    2366                 :                                      data->mTreeMatchContext,
    2367               0 :                                      !nodeContext.mIsRelevantLink)) {
    2368               0 :       css::StyleRule *rule = value.mRule;
    2369               0 :       rule->RuleMatched();
    2370               0 :       data->mRuleWalker->Forward(rule);
    2371                 :       // nsStyleSet will deal with the !important rule
    2372                 :     }
    2373                 :   }
    2374                 : }
    2375                 : 
    2376                 : /* virtual */ void
    2377               0 : nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData)
    2378                 : {
    2379               0 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2380                 : 
    2381               0 :   if (cascade) {
    2382                 :     NodeMatchContext nodeContext(nsEventStates(),
    2383               0 :                                  nsCSSRuleProcessor::IsLink(aData->mElement));
    2384               0 :     cascade->mRuleHash.EnumerateAllRules(aData->mElement, aData, nodeContext);
    2385                 :   }
    2386               0 : }
    2387                 : 
    2388                 : /* virtual */ void
    2389               0 : nsCSSRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData)
    2390                 : {
    2391               0 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2392                 : 
    2393               0 :   if (cascade) {
    2394               0 :     RuleHash* ruleHash = cascade->mPseudoElementRuleHashes[aData->mPseudoType];
    2395               0 :     if (ruleHash) {
    2396                 :       NodeMatchContext nodeContext(nsEventStates(),
    2397               0 :                                    nsCSSRuleProcessor::IsLink(aData->mElement));
    2398               0 :       ruleHash->EnumerateAllRules(aData->mElement, aData, nodeContext);
    2399                 :     }
    2400                 :   }
    2401               0 : }
    2402                 : 
    2403                 : /* virtual */ void
    2404               0 : nsCSSRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData)
    2405                 : {
    2406               0 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2407                 : 
    2408               0 :   if (cascade && cascade->mAnonBoxRules.entryCount) {
    2409                 :     RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>
    2410                 :       (PL_DHashTableOperate(&cascade->mAnonBoxRules, aData->mPseudoTag,
    2411               0 :                             PL_DHASH_LOOKUP));
    2412               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
    2413               0 :       nsTArray<RuleValue>& rules = entry->mRules;
    2414               0 :       for (RuleValue *value = rules.Elements(), *end = value + rules.Length();
    2415                 :            value != end; ++value) {
    2416               0 :         value->mRule->RuleMatched();
    2417               0 :         aData->mRuleWalker->Forward(value->mRule);
    2418                 :       }
    2419                 :     }
    2420                 :   }
    2421               0 : }
    2422                 : 
    2423                 : #ifdef MOZ_XUL
    2424                 : /* virtual */ void
    2425               0 : nsCSSRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData)
    2426                 : {
    2427               0 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2428                 : 
    2429               0 :   if (cascade && cascade->mXULTreeRules.entryCount) {
    2430                 :     RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>
    2431                 :       (PL_DHashTableOperate(&cascade->mXULTreeRules, aData->mPseudoTag,
    2432               0 :                             PL_DHASH_LOOKUP));
    2433               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
    2434                 :       NodeMatchContext nodeContext(nsEventStates(),
    2435               0 :                                    nsCSSRuleProcessor::IsLink(aData->mElement));
    2436               0 :       nsTArray<RuleValue>& rules = entry->mRules;
    2437               0 :       for (RuleValue *value = rules.Elements(), *end = value + rules.Length();
    2438                 :            value != end; ++value) {
    2439               0 :         if (aData->mComparator->PseudoMatches(value->mSelector)) {
    2440                 :           ContentEnumFunc(*value, value->mSelector->mNext, aData, nodeContext,
    2441               0 :                           nsnull);
    2442                 :         }
    2443                 :       }
    2444                 :     }
    2445                 :   }
    2446               0 : }
    2447                 : #endif
    2448                 : 
    2449               0 : static inline nsRestyleHint RestyleHintForOp(PRUnichar oper)
    2450                 : {
    2451               0 :   if (oper == PRUnichar('+') || oper == PRUnichar('~')) {
    2452               0 :     return eRestyle_LaterSiblings;
    2453                 :   }
    2454                 : 
    2455               0 :   if (oper != PRUnichar(0)) {
    2456               0 :     return eRestyle_Subtree;
    2457                 :   }
    2458                 : 
    2459               0 :   return eRestyle_Self;
    2460                 : }
    2461                 : 
    2462                 : nsRestyleHint
    2463               0 : nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData)
    2464                 : {
    2465               0 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2466                 : 
    2467                 :   // Look up the content node in the state rule list, which points to
    2468                 :   // any (CSS2 definition) simple selector (whether or not it is the
    2469                 :   // subject) that has a state pseudo-class on it.  This means that this
    2470                 :   // code will be matching selectors that aren't real selectors in any
    2471                 :   // stylesheet (e.g., if there is a selector "body > p:hover > a", then
    2472                 :   // "body > p:hover" will be in |cascade->mStateSelectors|).  Note that
    2473                 :   // |ComputeSelectorStateDependence| below determines which selectors are in
    2474                 :   // |cascade->mStateSelectors|.
    2475               0 :   nsRestyleHint hint = nsRestyleHint(0);
    2476               0 :   if (cascade) {
    2477               0 :     StateSelector *iter = cascade->mStateSelectors.Elements(),
    2478               0 :                   *end = iter + cascade->mStateSelectors.Length();
    2479               0 :     NodeMatchContext nodeContext(aData->mStateMask, false);
    2480               0 :     for(; iter != end; ++iter) {
    2481               0 :       nsCSSSelector* selector = iter->mSelector;
    2482               0 :       nsEventStates states = iter->mStates;
    2483                 : 
    2484               0 :       nsRestyleHint possibleChange = RestyleHintForOp(selector->mOperator);
    2485                 : 
    2486                 :       // If hint already includes all the bits of possibleChange,
    2487                 :       // don't bother calling SelectorMatches, since even if it returns false
    2488                 :       // hint won't change.
    2489                 :       // Also don't bother calling SelectorMatches if none of the
    2490                 :       // states passed in are relevant here.
    2491               0 :       if ((possibleChange & ~hint) &&
    2492               0 :           states.HasAtLeastOneOfStates(aData->mStateMask) &&
    2493                 :           SelectorMatches(aData->mElement, selector, nodeContext,
    2494               0 :                           aData->mTreeMatchContext) &&
    2495                 :           SelectorMatchesTree(aData->mElement, selector->mNext,
    2496                 :                               aData->mTreeMatchContext,
    2497               0 :                               false))
    2498                 :       {
    2499               0 :         hint = nsRestyleHint(hint | possibleChange);
    2500                 :       }
    2501                 :     }
    2502                 :   }
    2503               0 :   return hint;
    2504                 : }
    2505                 : 
    2506                 : bool
    2507               0 : nsCSSRuleProcessor::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
    2508                 : {
    2509               0 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2510                 : 
    2511               0 :   return cascade && cascade->mSelectorDocumentStates.HasAtLeastOneOfStates(aData->mStateMask);
    2512                 : }
    2513                 : 
    2514                 : struct AttributeEnumData {
    2515               0 :   AttributeEnumData(AttributeRuleProcessorData *aData)
    2516               0 :     : data(aData), change(nsRestyleHint(0)) {}
    2517                 : 
    2518                 :   AttributeRuleProcessorData *data;
    2519                 :   nsRestyleHint change;
    2520                 : };
    2521                 : 
    2522                 : 
    2523                 : static void
    2524               0 : AttributeEnumFunc(nsCSSSelector* aSelector, AttributeEnumData* aData)
    2525                 : {
    2526               0 :   AttributeRuleProcessorData *data = aData->data;
    2527                 : 
    2528               0 :   nsRestyleHint possibleChange = RestyleHintForOp(aSelector->mOperator);
    2529                 : 
    2530                 :   // If enumData->change already includes all the bits of possibleChange, don't
    2531                 :   // bother calling SelectorMatches, since even if it returns false
    2532                 :   // enumData->change won't change.
    2533               0 :   NodeMatchContext nodeContext(nsEventStates(), false);
    2534               0 :   if ((possibleChange & ~(aData->change)) &&
    2535                 :       SelectorMatches(data->mElement, aSelector, nodeContext,
    2536               0 :                       data->mTreeMatchContext) &&
    2537                 :       SelectorMatchesTree(data->mElement, aSelector->mNext,
    2538               0 :                           data->mTreeMatchContext, false)) {
    2539               0 :     aData->change = nsRestyleHint(aData->change | possibleChange);
    2540                 :   }
    2541               0 : }
    2542                 : 
    2543                 : nsRestyleHint
    2544               0 : nsCSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
    2545                 : {
    2546                 :   //  We could try making use of aData->mModType, but :not rules make it a bit
    2547                 :   //  of a pain to do so...  So just ignore it for now.
    2548                 : 
    2549               0 :   AttributeEnumData data(aData);
    2550                 : 
    2551                 :   // Don't do our special handling of certain attributes if the attr
    2552                 :   // hasn't changed yet.
    2553               0 :   if (aData->mAttrHasChanged) {
    2554                 :     // check for the lwtheme and lwthemetextcolor attribute on root XUL elements
    2555               0 :     if ((aData->mAttribute == nsGkAtoms::lwtheme ||
    2556                 :          aData->mAttribute == nsGkAtoms::lwthemetextcolor) &&
    2557               0 :         aData->mElement->GetNameSpaceID() == kNameSpaceID_XUL &&
    2558               0 :         aData->mElement == aData->mElement->OwnerDoc()->GetRootElement())
    2559                 :       {
    2560               0 :         data.change = nsRestyleHint(data.change | eRestyle_Subtree);
    2561                 :       }
    2562                 : 
    2563                 :     // We don't know the namespace of the attribute, and xml:lang applies to
    2564                 :     // all elements.  If the lang attribute changes, we need to restyle our
    2565                 :     // whole subtree, since the :lang selector on our descendants can examine
    2566                 :     // our lang attribute.
    2567               0 :     if (aData->mAttribute == nsGkAtoms::lang) {
    2568               0 :       data.change = nsRestyleHint(data.change | eRestyle_Subtree);
    2569                 :     }
    2570                 :   }
    2571                 : 
    2572               0 :   RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
    2573                 : 
    2574                 :   // Since we get both before and after notifications for attributes, we
    2575                 :   // don't have to ignore aData->mAttribute while matching.  Just check
    2576                 :   // whether we have selectors relevant to aData->mAttribute that we
    2577                 :   // match.  If this is the before change notification, that will catch
    2578                 :   // rules we might stop matching; if the after change notification, the
    2579                 :   // ones we might have started matching.
    2580               0 :   if (cascade) {
    2581               0 :     if (aData->mAttribute == aData->mElement->GetIDAttributeName()) {
    2582               0 :       nsIAtom* id = aData->mElement->GetID();
    2583               0 :       if (id) {
    2584                 :         AtomSelectorEntry *entry =
    2585                 :           static_cast<AtomSelectorEntry*>
    2586                 :                      (PL_DHashTableOperate(&cascade->mIdSelectors,
    2587               0 :                                            id, PL_DHASH_LOOKUP));
    2588               0 :         if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
    2589               0 :           nsCSSSelector **iter = entry->mSelectors.Elements(),
    2590               0 :                         **end = iter + entry->mSelectors.Length();
    2591               0 :           for(; iter != end; ++iter) {
    2592               0 :             AttributeEnumFunc(*iter, &data);
    2593                 :           }
    2594                 :         }
    2595                 :       }
    2596                 : 
    2597               0 :       nsCSSSelector **iter = cascade->mPossiblyNegatedIDSelectors.Elements(),
    2598               0 :                     **end = iter + cascade->mPossiblyNegatedIDSelectors.Length();
    2599               0 :       for(; iter != end; ++iter) {
    2600               0 :         AttributeEnumFunc(*iter, &data);
    2601                 :       }
    2602                 :     }
    2603                 :     
    2604               0 :     if (aData->mAttribute == aData->mElement->GetClassAttributeName()) {
    2605               0 :       const nsAttrValue* elementClasses = aData->mElement->GetClasses();
    2606               0 :       if (elementClasses) {
    2607               0 :         PRInt32 atomCount = elementClasses->GetAtomCount();
    2608               0 :         for (PRInt32 i = 0; i < atomCount; ++i) {
    2609               0 :           nsIAtom* curClass = elementClasses->AtomAt(i);
    2610                 :           AtomSelectorEntry *entry =
    2611                 :             static_cast<AtomSelectorEntry*>
    2612                 :                        (PL_DHashTableOperate(&cascade->mClassSelectors,
    2613               0 :                                              curClass, PL_DHASH_LOOKUP));
    2614               0 :           if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
    2615               0 :             nsCSSSelector **iter = entry->mSelectors.Elements(),
    2616               0 :                           **end = iter + entry->mSelectors.Length();
    2617               0 :             for(; iter != end; ++iter) {
    2618               0 :               AttributeEnumFunc(*iter, &data);
    2619                 :             }
    2620                 :           }
    2621                 :         }
    2622                 :       }
    2623                 : 
    2624               0 :       nsCSSSelector **iter = cascade->mPossiblyNegatedClassSelectors.Elements(),
    2625                 :                     **end = iter +
    2626               0 :                               cascade->mPossiblyNegatedClassSelectors.Length();
    2627               0 :       for (; iter != end; ++iter) {
    2628               0 :         AttributeEnumFunc(*iter, &data);
    2629                 :       }
    2630                 :     }
    2631                 : 
    2632                 :     AtomSelectorEntry *entry =
    2633                 :       static_cast<AtomSelectorEntry*>
    2634                 :                  (PL_DHashTableOperate(&cascade->mAttributeSelectors,
    2635               0 :                                        aData->mAttribute, PL_DHASH_LOOKUP));
    2636               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
    2637               0 :       nsCSSSelector **iter = entry->mSelectors.Elements(),
    2638               0 :                     **end = iter + entry->mSelectors.Length();
    2639               0 :       for(; iter != end; ++iter) {
    2640               0 :         AttributeEnumFunc(*iter, &data);
    2641                 :       }
    2642                 :     }
    2643                 :   }
    2644                 : 
    2645               0 :   return data.change;
    2646                 : }
    2647                 : 
    2648                 : /* virtual */ bool
    2649               0 : nsCSSRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext)
    2650                 : {
    2651               0 :   RuleCascadeData *old = mRuleCascades;
    2652                 :   // We don't want to do anything if there aren't any sets of rules
    2653                 :   // cached yet (or somebody cleared them and is thus responsible for
    2654                 :   // rebuilding things), since we should not build the rule cascade too
    2655                 :   // early (e.g., before we know whether the quirk style sheet should be
    2656                 :   // enabled).  And if there's nothing cached, it doesn't matter if
    2657                 :   // anything changed.  See bug 448281.
    2658               0 :   if (old) {
    2659               0 :     RefreshRuleCascade(aPresContext);
    2660                 :   }
    2661               0 :   return (old != mRuleCascades);
    2662                 : }
    2663                 : 
    2664                 : /* virtual */ size_t
    2665               0 : nsCSSRuleProcessor::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
    2666                 : {
    2667               0 :   size_t n = 0;
    2668               0 :   n += mSheets.SizeOfExcludingThis(aMallocSizeOf);
    2669               0 :   for (RuleCascadeData* cascade = mRuleCascades; cascade;
    2670                 :        cascade = cascade->mNext) {
    2671               0 :     n += cascade->SizeOfIncludingThis(aMallocSizeOf);
    2672                 :   }
    2673                 : 
    2674               0 :   return n;
    2675                 : }
    2676                 : 
    2677                 : /* virtual */ size_t
    2678               0 : nsCSSRuleProcessor::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
    2679                 : {
    2680               0 :   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    2681                 : }
    2682                 : 
    2683                 : // Append all the currently-active font face rules to aArray.  Return
    2684                 : // true for success and false for failure.
    2685                 : bool
    2686               0 : nsCSSRuleProcessor::AppendFontFaceRules(
    2687                 :                               nsPresContext *aPresContext,
    2688                 :                               nsTArray<nsFontFaceRuleContainer>& aArray)
    2689                 : {
    2690               0 :   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
    2691                 : 
    2692               0 :   if (cascade) {
    2693               0 :     if (!aArray.AppendElements(cascade->mFontFaceRules))
    2694               0 :       return false;
    2695                 :   }
    2696                 :   
    2697               0 :   return true;
    2698                 : }
    2699                 : 
    2700                 : // Append all the currently-active keyframes rules to aArray.  Return
    2701                 : // true for success and false for failure.
    2702                 : bool
    2703               0 : nsCSSRuleProcessor::AppendKeyframesRules(
    2704                 :                               nsPresContext *aPresContext,
    2705                 :                               nsTArray<nsCSSKeyframesRule*>& aArray)
    2706                 : {
    2707               0 :   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
    2708                 : 
    2709               0 :   if (cascade) {
    2710               0 :     if (!aArray.AppendElements(cascade->mKeyframesRules))
    2711               0 :       return false;
    2712                 :   }
    2713                 :   
    2714               0 :   return true;
    2715                 : }
    2716                 : 
    2717                 : nsresult
    2718               0 : nsCSSRuleProcessor::ClearRuleCascades()
    2719                 : {
    2720                 :   // We rely on our caller (perhaps indirectly) to do something that
    2721                 :   // will rebuild style data and the user font set (either
    2722                 :   // nsIPresShell::ReconstructStyleData or
    2723                 :   // nsPresContext::RebuildAllStyleData).
    2724               0 :   RuleCascadeData *data = mRuleCascades;
    2725               0 :   mRuleCascades = nsnull;
    2726               0 :   while (data) {
    2727               0 :     RuleCascadeData *next = data->mNext;
    2728               0 :     delete data;
    2729               0 :     data = next;
    2730                 :   }
    2731               0 :   return NS_OK;
    2732                 : }
    2733                 : 
    2734                 : 
    2735                 : // This function should return the set of states that this selector
    2736                 : // depends on; this is used to implement HasStateDependentStyle.  It
    2737                 : // does NOT recur down into things like :not and :-moz-any.
    2738                 : inline
    2739               0 : nsEventStates ComputeSelectorStateDependence(nsCSSSelector& aSelector)
    2740                 : {
    2741               0 :   nsEventStates states;
    2742               0 :   for (nsPseudoClassList* pseudoClass = aSelector.mPseudoClassList;
    2743                 :        pseudoClass; pseudoClass = pseudoClass->mNext) {
    2744                 :     // Tree pseudo-elements overload mPseudoClassList for things that
    2745                 :     // aren't pseudo-classes.
    2746               0 :     if (pseudoClass->mType >= nsCSSPseudoClasses::ePseudoClass_Count) {
    2747               0 :       continue;
    2748                 :     }
    2749               0 :     states |= sPseudoClassStates[pseudoClass->mType];
    2750                 :   }
    2751                 :   return states;
    2752                 : }
    2753                 : 
    2754                 : static bool
    2755               0 : AddSelector(RuleCascadeData* aCascade,
    2756                 :             // The part between combinators at the top level of the selector
    2757                 :             nsCSSSelector* aSelectorInTopLevel,
    2758                 :             // The part we should look through (might be in :not or :-moz-any())
    2759                 :             nsCSSSelector* aSelectorPart)
    2760                 : {
    2761                 :   // It's worth noting that this loop over negations isn't quite
    2762                 :   // optimal for two reasons.  One, we could add something to one of
    2763                 :   // these lists twice, which means we'll check it twice, but I don't
    2764                 :   // think that's worth worrying about.   (We do the same for multiple
    2765                 :   // attribute selectors on the same attribute.)  Two, we don't really
    2766                 :   // need to check negations past the first in the current
    2767                 :   // implementation (and they're rare as well), but that might change
    2768                 :   // in the future if :not() is extended.
    2769               0 :   for (nsCSSSelector* negation = aSelectorPart; negation;
    2770                 :        negation = negation->mNegations) {
    2771                 :     // Track both document states and attribute dependence in pseudo-classes.
    2772               0 :     for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList;
    2773                 :          pseudoClass; pseudoClass = pseudoClass->mNext) {
    2774               0 :       switch (pseudoClass->mType) {
    2775                 :         case nsCSSPseudoClasses::ePseudoClass_mozLocaleDir: {
    2776               0 :           aCascade->mSelectorDocumentStates |= NS_DOCUMENT_STATE_RTL_LOCALE;
    2777               0 :           break;
    2778                 :         }
    2779                 :         case nsCSSPseudoClasses::ePseudoClass_mozWindowInactive: {
    2780               0 :           aCascade->mSelectorDocumentStates |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
    2781               0 :           break;
    2782                 :         }
    2783                 :         case nsCSSPseudoClasses::ePseudoClass_mozTableBorderNonzero: {
    2784                 :           nsTArray<nsCSSSelector*> *array =
    2785               0 :             aCascade->AttributeListFor(nsGkAtoms::border);
    2786               0 :           if (!array) {
    2787               0 :             return false;
    2788                 :           }
    2789               0 :           array->AppendElement(aSelectorInTopLevel);
    2790               0 :           break;
    2791                 :         }
    2792                 :         default: {
    2793               0 :           break;
    2794                 :         }
    2795                 :       }
    2796                 :     }
    2797                 : 
    2798                 :     // Build mStateSelectors.
    2799               0 :     nsEventStates dependentStates = ComputeSelectorStateDependence(*negation);
    2800               0 :     if (!dependentStates.IsEmpty()) {
    2801                 :       aCascade->mStateSelectors.AppendElement(
    2802                 :         nsCSSRuleProcessor::StateSelector(dependentStates,
    2803               0 :                                           aSelectorInTopLevel));
    2804                 :     }
    2805                 : 
    2806                 :     // Build mIDSelectors
    2807               0 :     if (negation == aSelectorInTopLevel) {
    2808               0 :       for (nsAtomList* curID = negation->mIDList; curID;
    2809                 :            curID = curID->mNext) {
    2810                 :         AtomSelectorEntry *entry =
    2811                 :           static_cast<AtomSelectorEntry*>(PL_DHashTableOperate(&aCascade->mIdSelectors,
    2812                 :                                                                curID->mAtom,
    2813               0 :                                                                PL_DHASH_ADD));
    2814               0 :         if (entry) {
    2815               0 :           entry->mSelectors.AppendElement(aSelectorInTopLevel);
    2816                 :         }
    2817                 :       }
    2818               0 :     } else if (negation->mIDList) {
    2819               0 :       aCascade->mPossiblyNegatedIDSelectors.AppendElement(aSelectorInTopLevel);
    2820                 :     }
    2821                 : 
    2822                 :     // Build mClassSelectors
    2823               0 :     if (negation == aSelectorInTopLevel) {
    2824               0 :       for (nsAtomList* curClass = negation->mClassList; curClass;
    2825                 :            curClass = curClass->mNext) {
    2826                 :         AtomSelectorEntry *entry =
    2827                 :           static_cast<AtomSelectorEntry*>(PL_DHashTableOperate(&aCascade->mClassSelectors,
    2828                 :                                                                curClass->mAtom,
    2829               0 :                                                                PL_DHASH_ADD));
    2830               0 :         if (entry) {
    2831               0 :           entry->mSelectors.AppendElement(aSelectorInTopLevel);
    2832                 :         }
    2833                 :       }
    2834               0 :     } else if (negation->mClassList) {
    2835               0 :       aCascade->mPossiblyNegatedClassSelectors.AppendElement(aSelectorInTopLevel);
    2836                 :     }
    2837                 : 
    2838                 :     // Build mAttributeSelectors.
    2839               0 :     for (nsAttrSelector *attr = negation->mAttrList; attr;
    2840                 :          attr = attr->mNext) {
    2841                 :       nsTArray<nsCSSSelector*> *array =
    2842               0 :         aCascade->AttributeListFor(attr->mCasedAttr);
    2843               0 :       if (!array) {
    2844               0 :         return false;
    2845                 :       }
    2846               0 :       array->AppendElement(aSelectorInTopLevel);
    2847               0 :       if (attr->mLowercaseAttr != attr->mCasedAttr) {
    2848               0 :         array = aCascade->AttributeListFor(attr->mLowercaseAttr);
    2849               0 :         if (!array) {
    2850               0 :           return false;
    2851                 :         }
    2852               0 :         array->AppendElement(aSelectorInTopLevel);
    2853                 :       }
    2854                 :     }
    2855                 : 
    2856                 :     // Recur through any :-moz-any selectors
    2857               0 :     for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList;
    2858                 :          pseudoClass; pseudoClass = pseudoClass->mNext) {
    2859               0 :       if (pseudoClass->mType == nsCSSPseudoClasses::ePseudoClass_any) {
    2860               0 :         for (nsCSSSelectorList *l = pseudoClass->u.mSelectors; l; l = l->mNext) {
    2861               0 :           nsCSSSelector *s = l->mSelectors;
    2862               0 :           if (!AddSelector(aCascade, aSelectorInTopLevel, s)) {
    2863               0 :             return false;
    2864                 :           }
    2865                 :         }
    2866                 :       }
    2867                 :     }
    2868                 :   }
    2869                 : 
    2870               0 :   return true;
    2871                 : }
    2872                 : 
    2873                 : static bool
    2874               0 : AddRule(RuleSelectorPair* aRuleInfo, RuleCascadeData* aCascade)
    2875                 : {
    2876               0 :   RuleCascadeData * const cascade = aCascade;
    2877                 : 
    2878                 :   // Build the rule hash.
    2879               0 :   nsCSSPseudoElements::Type pseudoType = aRuleInfo->mSelector->PseudoType();
    2880               0 :   if (NS_LIKELY(pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement)) {
    2881               0 :     cascade->mRuleHash.AppendRule(*aRuleInfo);
    2882               0 :   } else if (pseudoType < nsCSSPseudoElements::ePseudo_PseudoElementCount) {
    2883               0 :     RuleHash*& ruleHash = cascade->mPseudoElementRuleHashes[pseudoType];
    2884               0 :     if (!ruleHash) {
    2885               0 :       ruleHash = new RuleHash(cascade->mQuirksMode);
    2886               0 :       if (!ruleHash) {
    2887                 :         // Out of memory; give up
    2888               0 :         return false;
    2889                 :       }
    2890                 :     }
    2891               0 :     NS_ASSERTION(aRuleInfo->mSelector->mNext,
    2892                 :                  "Must have mNext; parser screwed up");
    2893               0 :     NS_ASSERTION(aRuleInfo->mSelector->mNext->mOperator == '>',
    2894                 :                  "Unexpected mNext combinator");
    2895               0 :     aRuleInfo->mSelector = aRuleInfo->mSelector->mNext;
    2896               0 :     ruleHash->AppendRule(*aRuleInfo);
    2897               0 :   } else if (pseudoType == nsCSSPseudoElements::ePseudo_AnonBox) {
    2898               0 :     NS_ASSERTION(!aRuleInfo->mSelector->mCasedTag &&
    2899                 :                  !aRuleInfo->mSelector->mIDList &&
    2900                 :                  !aRuleInfo->mSelector->mClassList &&
    2901                 :                  !aRuleInfo->mSelector->mPseudoClassList &&
    2902                 :                  !aRuleInfo->mSelector->mAttrList &&
    2903                 :                  !aRuleInfo->mSelector->mNegations &&
    2904                 :                  !aRuleInfo->mSelector->mNext &&
    2905                 :                  aRuleInfo->mSelector->mNameSpace == kNameSpaceID_Unknown,
    2906                 :                  "Parser messed up with anon box selector");
    2907                 : 
    2908                 :     // Index doesn't matter here, since we'll just be walking these
    2909                 :     // rules in order; just pass 0.
    2910                 :     AppendRuleToTagTable(&cascade->mAnonBoxRules,
    2911                 :                          aRuleInfo->mSelector->mLowercaseTag,
    2912               0 :                          RuleValue(*aRuleInfo, 0, aCascade->mQuirksMode));
    2913                 :   } else {
    2914                 : #ifdef MOZ_XUL
    2915               0 :     NS_ASSERTION(pseudoType == nsCSSPseudoElements::ePseudo_XULTree,
    2916                 :                  "Unexpected pseudo type");
    2917                 :     // Index doesn't matter here, since we'll just be walking these
    2918                 :     // rules in order; just pass 0.
    2919                 :     AppendRuleToTagTable(&cascade->mXULTreeRules,
    2920                 :                          aRuleInfo->mSelector->mLowercaseTag,
    2921               0 :                          RuleValue(*aRuleInfo, 0, aCascade->mQuirksMode));
    2922                 : #else
    2923                 :     NS_NOTREACHED("Unexpected pseudo type");
    2924                 : #endif
    2925                 :   }
    2926                 : 
    2927               0 :   for (nsCSSSelector* selector = aRuleInfo->mSelector;
    2928                 :            selector; selector = selector->mNext) {
    2929               0 :     if (selector->IsPseudoElement()) {
    2930               0 :       NS_ASSERTION(!selector->mNegations, "Shouldn't have negations");
    2931                 :       // Make sure these selectors don't end up in the hashtables we use to
    2932                 :       // match against actual elements, no matter what.  Normally they wouldn't
    2933                 :       // anyway, but trees overload mPseudoClassList with weird stuff.
    2934               0 :       continue;
    2935                 :     }
    2936               0 :     if (!AddSelector(cascade, selector, selector)) {
    2937               0 :       return false;
    2938                 :     }
    2939                 :   }
    2940                 : 
    2941               0 :   return true;
    2942                 : }
    2943                 : 
    2944                 : struct PerWeightDataListItem : public RuleSelectorPair {
    2945               0 :   PerWeightDataListItem(css::StyleRule* aRule, nsCSSSelector* aSelector)
    2946                 :     : RuleSelectorPair(aRule, aSelector)
    2947               0 :     , mNext(nsnull)
    2948               0 :   {}
    2949                 :   // No destructor; these are arena-allocated
    2950                 : 
    2951                 : 
    2952                 :   // Placement new to arena allocate the PerWeightDataListItem
    2953               0 :   void *operator new(size_t aSize, PLArenaPool &aArena) CPP_THROW_NEW {
    2954                 :     void *mem;
    2955               0 :     PL_ARENA_ALLOCATE(mem, &aArena, aSize);
    2956               0 :     return mem;
    2957                 :   }
    2958                 : 
    2959                 :   PerWeightDataListItem *mNext;
    2960                 : };
    2961                 : 
    2962                 : struct PerWeightData {
    2963               0 :   PerWeightData()
    2964                 :     : mRuleSelectorPairs(nsnull)
    2965               0 :     , mTail(&mRuleSelectorPairs)
    2966               0 :   {}
    2967                 : 
    2968                 :   PRInt32 mWeight;
    2969                 :   PerWeightDataListItem *mRuleSelectorPairs;
    2970                 :   PerWeightDataListItem **mTail;
    2971                 : };
    2972                 : 
    2973               0 : struct RuleByWeightEntry : public PLDHashEntryHdr {
    2974                 :   PerWeightData data; // mWeight is key, mRuleSelectorPairs are value
    2975                 : };
    2976                 : 
    2977                 : static PLDHashNumber
    2978               0 : HashIntKey(PLDHashTable *table, const void *key)
    2979                 : {
    2980               0 :   return PLDHashNumber(NS_PTR_TO_INT32(key));
    2981                 : }
    2982                 : 
    2983                 : static bool
    2984               0 : MatchWeightEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
    2985                 :                  const void *key)
    2986                 : {
    2987               0 :   const RuleByWeightEntry *entry = (const RuleByWeightEntry *)hdr;
    2988               0 :   return entry->data.mWeight == NS_PTR_TO_INT32(key);
    2989                 : }
    2990                 : 
    2991                 : static bool
    2992               0 : InitWeightEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
    2993                 :                 const void *key)
    2994                 : {
    2995               0 :   RuleByWeightEntry* entry = static_cast<RuleByWeightEntry*>(hdr);
    2996               0 :   new (entry) RuleByWeightEntry();
    2997               0 :   return true;
    2998                 : }
    2999                 : 
    3000                 : static PLDHashTableOps gRulesByWeightOps = {
    3001                 :     PL_DHashAllocTable,
    3002                 :     PL_DHashFreeTable,
    3003                 :     HashIntKey,
    3004                 :     MatchWeightEntry,
    3005                 :     PL_DHashMoveEntryStub,
    3006                 :     PL_DHashClearEntryStub,
    3007                 :     PL_DHashFinalizeStub,
    3008                 :     InitWeightEntry
    3009                 : };
    3010                 : 
    3011                 : struct CascadeEnumData {
    3012               0 :   CascadeEnumData(nsPresContext* aPresContext,
    3013                 :                   nsTArray<nsFontFaceRuleContainer>& aFontFaceRules,
    3014                 :                   nsTArray<nsCSSKeyframesRule*>& aKeyframesRules,
    3015                 :                   nsMediaQueryResultCacheKey& aKey,
    3016                 :                   PRUint8 aSheetType)
    3017                 :     : mPresContext(aPresContext),
    3018                 :       mFontFaceRules(aFontFaceRules),
    3019                 :       mKeyframesRules(aKeyframesRules),
    3020                 :       mCacheKey(aKey),
    3021               0 :       mSheetType(aSheetType)
    3022                 :   {
    3023               0 :     if (!PL_DHashTableInit(&mRulesByWeight, &gRulesByWeightOps, nsnull,
    3024               0 :                           sizeof(RuleByWeightEntry), 64))
    3025               0 :       mRulesByWeight.ops = nsnull;
    3026                 : 
    3027                 :     // Initialize our arena
    3028               0 :     PL_INIT_ARENA_POOL(&mArena, "CascadeEnumDataArena",
    3029               0 :                        NS_CASCADEENUMDATA_ARENA_BLOCK_SIZE);
    3030               0 :   }
    3031                 : 
    3032               0 :   ~CascadeEnumData()
    3033                 :   {
    3034               0 :     if (mRulesByWeight.ops)
    3035               0 :       PL_DHashTableFinish(&mRulesByWeight);
    3036               0 :     PL_FinishArenaPool(&mArena);
    3037               0 :   }
    3038                 : 
    3039                 :   nsPresContext* mPresContext;
    3040                 :   nsTArray<nsFontFaceRuleContainer>& mFontFaceRules;
    3041                 :   nsTArray<nsCSSKeyframesRule*>& mKeyframesRules;
    3042                 :   nsMediaQueryResultCacheKey& mCacheKey;
    3043                 :   PLArenaPool mArena;
    3044                 :   // Hooray, a manual PLDHashTable since nsClassHashtable doesn't
    3045                 :   // provide a getter that gives me a *reference* to the value.
    3046                 :   PLDHashTable mRulesByWeight; // of PerWeightDataListItem linked lists
    3047                 :   PRUint8 mSheetType;
    3048                 : };
    3049                 : 
    3050                 : /*
    3051                 :  * This enumerates style rules in a sheet (and recursively into any
    3052                 :  * grouping rules) in order to:
    3053                 :  *  (1) add any style rules, in order, into data->mRulesByWeight (for
    3054                 :  *      the primary CSS cascade), where they are separated by weight
    3055                 :  *      but kept in order per-weight, and
    3056                 :  *  (2) add any @font-face rules, in order, into data->mFontFaceRules.
    3057                 :  *  (3) add any @keyframes rules, in order, into data->mKeyframesRules.
    3058                 :  */
    3059                 : static bool
    3060               0 : CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
    3061                 : {
    3062               0 :   CascadeEnumData* data = (CascadeEnumData*)aData;
    3063               0 :   PRInt32 type = aRule->GetType();
    3064                 : 
    3065               0 :   if (css::Rule::STYLE_RULE == type) {
    3066               0 :     css::StyleRule* styleRule = static_cast<css::StyleRule*>(aRule);
    3067                 : 
    3068               0 :     for (nsCSSSelectorList *sel = styleRule->Selector();
    3069                 :          sel; sel = sel->mNext) {
    3070               0 :       PRInt32 weight = sel->mWeight;
    3071                 :       RuleByWeightEntry *entry = static_cast<RuleByWeightEntry*>(
    3072                 :         PL_DHashTableOperate(&data->mRulesByWeight, NS_INT32_TO_PTR(weight),
    3073               0 :                              PL_DHASH_ADD));
    3074               0 :       if (!entry)
    3075               0 :         return false;
    3076               0 :       entry->data.mWeight = weight;
    3077                 :       // entry->data.mRuleSelectorPairs should be linked in forward order;
    3078                 :       // entry->data.mTail is the slot to write to.
    3079                 :       PerWeightDataListItem *newItem =
    3080               0 :         new (data->mArena) PerWeightDataListItem(styleRule, sel->mSelectors);
    3081               0 :       if (newItem) {
    3082               0 :         *(entry->data.mTail) = newItem;
    3083               0 :         entry->data.mTail = &newItem->mNext;
    3084                 :       }
    3085                 :     }
    3086                 :   }
    3087               0 :   else if (css::Rule::MEDIA_RULE == type ||
    3088                 :            css::Rule::DOCUMENT_RULE == type) {
    3089               0 :     css::GroupRule* groupRule = static_cast<css::GroupRule*>(aRule);
    3090               0 :     if (groupRule->UseForPresentation(data->mPresContext, data->mCacheKey))
    3091               0 :       if (!groupRule->EnumerateRulesForwards(CascadeRuleEnumFunc, aData))
    3092               0 :         return false;
    3093                 :   }
    3094               0 :   else if (css::Rule::FONT_FACE_RULE == type) {
    3095               0 :     nsCSSFontFaceRule *fontFaceRule = static_cast<nsCSSFontFaceRule*>(aRule);
    3096               0 :     nsFontFaceRuleContainer *ptr = data->mFontFaceRules.AppendElement();
    3097               0 :     if (!ptr)
    3098               0 :       return false;
    3099               0 :     ptr->mRule = fontFaceRule;
    3100               0 :     ptr->mSheetType = data->mSheetType;
    3101                 :   }
    3102               0 :   else if (css::Rule::KEYFRAMES_RULE == type) {
    3103                 :     nsCSSKeyframesRule *keyframesRule =
    3104               0 :       static_cast<nsCSSKeyframesRule*>(aRule);
    3105               0 :     if (!data->mKeyframesRules.AppendElement(keyframesRule)) {
    3106               0 :       return false;
    3107                 :     }
    3108                 :   }
    3109                 : 
    3110               0 :   return true;
    3111                 : }
    3112                 : 
    3113                 : /* static */ bool
    3114               0 : nsCSSRuleProcessor::CascadeSheet(nsCSSStyleSheet* aSheet, CascadeEnumData* aData)
    3115                 : {
    3116               0 :   if (aSheet->IsApplicable() &&
    3117               0 :       aSheet->UseForPresentation(aData->mPresContext, aData->mCacheKey) &&
    3118                 :       aSheet->mInner) {
    3119               0 :     nsCSSStyleSheet* child = aSheet->mInner->mFirstChild;
    3120               0 :     while (child) {
    3121               0 :       CascadeSheet(child, aData);
    3122               0 :       child = child->mNext;
    3123                 :     }
    3124                 : 
    3125               0 :     if (!aSheet->mInner->mOrderedRules.EnumerateForwards(CascadeRuleEnumFunc,
    3126               0 :                                                          aData))
    3127               0 :       return false;
    3128                 :   }
    3129               0 :   return true;
    3130                 : }
    3131                 : 
    3132               0 : static int CompareWeightData(const void* aArg1, const void* aArg2,
    3133                 :                              void* closure)
    3134                 : {
    3135               0 :   const PerWeightData* arg1 = static_cast<const PerWeightData*>(aArg1);
    3136               0 :   const PerWeightData* arg2 = static_cast<const PerWeightData*>(aArg2);
    3137               0 :   return arg1->mWeight - arg2->mWeight; // put lower weight first
    3138                 : }
    3139                 : 
    3140                 : 
    3141                 : struct FillWeightArrayData {
    3142               0 :   FillWeightArrayData(PerWeightData* aArrayData) :
    3143                 :     mIndex(0),
    3144               0 :     mWeightArray(aArrayData)
    3145                 :   {
    3146               0 :   }
    3147                 :   PRInt32 mIndex;
    3148                 :   PerWeightData* mWeightArray;
    3149                 : };
    3150                 : 
    3151                 : 
    3152                 : static PLDHashOperator
    3153               0 : FillWeightArray(PLDHashTable *table, PLDHashEntryHdr *hdr,
    3154                 :                 PRUint32 number, void *arg)
    3155                 : {
    3156               0 :   FillWeightArrayData* data = static_cast<FillWeightArrayData*>(arg);
    3157               0 :   const RuleByWeightEntry *entry = (const RuleByWeightEntry *)hdr;
    3158                 : 
    3159               0 :   data->mWeightArray[data->mIndex++] = entry->data;
    3160                 : 
    3161               0 :   return PL_DHASH_NEXT;
    3162                 : }
    3163                 : 
    3164                 : RuleCascadeData*
    3165               0 : nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext)
    3166                 : {
    3167                 :   // If anything changes about the presentation context, we will be
    3168                 :   // notified.  Otherwise, our cache is valid if mLastPresContext
    3169                 :   // matches aPresContext.  (The only rule processors used for multiple
    3170                 :   // pres contexts are for XBL.  These rule processors are probably less
    3171                 :   // likely to have @media rules, and thus the cache is pretty likely to
    3172                 :   // hit instantly even when we're switching between pres contexts.)
    3173                 : 
    3174               0 :   if (!mRuleCascades || aPresContext != mLastPresContext) {
    3175               0 :     RefreshRuleCascade(aPresContext);
    3176                 :   }
    3177               0 :   mLastPresContext = aPresContext;
    3178                 : 
    3179               0 :   return mRuleCascades;
    3180                 : }
    3181                 : 
    3182                 : void
    3183               0 : nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
    3184                 : {
    3185                 :   // Having RuleCascadeData objects be per-medium (over all variation
    3186                 :   // caused by media queries, handled through mCacheKey) works for now
    3187                 :   // since nsCSSRuleProcessor objects are per-document.  (For a given
    3188                 :   // set of stylesheets they can vary based on medium (@media) or
    3189                 :   // document (@-moz-document).)
    3190                 : 
    3191               0 :   for (RuleCascadeData **cascadep = &mRuleCascades, *cascade;
    3192                 :        (cascade = *cascadep); cascadep = &cascade->mNext) {
    3193               0 :     if (cascade->mCacheKey.Matches(aPresContext)) {
    3194                 :       // Ensure that the current one is always mRuleCascades.
    3195               0 :       *cascadep = cascade->mNext;
    3196               0 :       cascade->mNext = mRuleCascades;
    3197               0 :       mRuleCascades = cascade;
    3198                 : 
    3199               0 :       return;
    3200                 :     }
    3201                 :   }
    3202                 : 
    3203               0 :   if (mSheets.Length() != 0) {
    3204                 :     nsAutoPtr<RuleCascadeData> newCascade(
    3205                 :       new RuleCascadeData(aPresContext->Medium(),
    3206               0 :                           eCompatibility_NavQuirks == aPresContext->CompatibilityMode()));
    3207               0 :     if (newCascade) {
    3208               0 :       CascadeEnumData data(aPresContext, newCascade->mFontFaceRules,
    3209               0 :                            newCascade->mKeyframesRules,
    3210               0 :                            newCascade->mCacheKey,
    3211               0 :                            mSheetType);
    3212               0 :       if (!data.mRulesByWeight.ops)
    3213                 :         return; /* out of memory */
    3214                 : 
    3215               0 :       for (PRUint32 i = 0; i < mSheets.Length(); ++i) {
    3216               0 :         if (!CascadeSheet(mSheets.ElementAt(i), &data))
    3217                 :           return; /* out of memory */
    3218                 :       }
    3219                 : 
    3220                 :       // Sort the hash table of per-weight linked lists by weight.
    3221               0 :       PRUint32 weightCount = data.mRulesByWeight.entryCount;
    3222               0 :       nsAutoArrayPtr<PerWeightData> weightArray(new PerWeightData[weightCount]);
    3223               0 :       FillWeightArrayData fwData(weightArray);
    3224               0 :       PL_DHashTableEnumerate(&data.mRulesByWeight, FillWeightArray, &fwData);
    3225                 :       NS_QuickSort(weightArray, weightCount, sizeof(PerWeightData),
    3226               0 :                    CompareWeightData, nsnull);
    3227                 : 
    3228                 :       // Put things into the rule hash.
    3229                 :       // The primary sort is by weight...
    3230               0 :       for (PRUint32 i = 0; i < weightCount; ++i) {
    3231                 :         // and the secondary sort is by order.  mRuleSelectorPairs is already in
    3232                 :         // the right order..
    3233               0 :         for (PerWeightDataListItem *cur = weightArray[i].mRuleSelectorPairs;
    3234                 :              cur;
    3235                 :              cur = cur->mNext) {
    3236               0 :           if (!AddRule(cur, newCascade))
    3237                 :             return; /* out of memory */
    3238                 :         }
    3239                 :       }
    3240                 : 
    3241                 :       // Ensure that the current one is always mRuleCascades.
    3242               0 :       newCascade->mNext = mRuleCascades;
    3243               0 :       mRuleCascades = newCascade.forget();
    3244                 :     }
    3245                 :   }
    3246               0 :   return;
    3247                 : }
    3248                 : 
    3249                 : /* static */ bool
    3250            1632 : nsCSSRuleProcessor::SelectorListMatches(Element* aElement,
    3251                 :                                         TreeMatchContext& aTreeMatchContext,
    3252                 :                                         nsCSSSelectorList* aSelectorList)
    3253                 : {
    3254            4732 :   while (aSelectorList) {
    3255            1632 :     nsCSSSelector* sel = aSelectorList->mSelectors;
    3256            1632 :     NS_ASSERTION(sel, "Should have *some* selectors");
    3257            1632 :     NS_ASSERTION(!sel->IsPseudoElement(), "Shouldn't have been called");
    3258            1632 :     NodeMatchContext nodeContext(nsEventStates(), false);
    3259            1632 :     if (SelectorMatches(aElement, sel, nodeContext, aTreeMatchContext)) {
    3260             164 :       nsCSSSelector* next = sel->mNext;
    3261             328 :       if (!next ||
    3262             164 :           SelectorMatchesTree(aElement, next, aTreeMatchContext, false)) {
    3263             164 :         return true;
    3264                 :       }
    3265                 :     }
    3266                 : 
    3267            1468 :     aSelectorList = aSelectorList->mNext;
    3268                 :   }
    3269                 : 
    3270            1468 :   return false;
    3271                 : }
    3272                 : 
    3273                 : // AncestorFilter out of line methods
    3274                 : void
    3275               0 : AncestorFilter::Init(Element *aElement)
    3276                 : {
    3277               0 :   MOZ_ASSERT(!mFilter);
    3278               0 :   MOZ_ASSERT(mHashes.IsEmpty());
    3279                 : 
    3280               0 :   mFilter = new Filter();
    3281                 : 
    3282               0 :   if (NS_LIKELY(aElement)) {
    3283               0 :     MOZ_ASSERT(aElement->IsInDoc(),
    3284                 :                "aElement must be in the document for the assumption that "
    3285                 :                "GetNodeParent() is non-null on all element ancestors of "
    3286               0 :                "aElement to be true");
    3287                 :     // Collect up the ancestors
    3288               0 :     nsAutoTArray<Element*, 50> ancestors;
    3289               0 :     Element* cur = aElement;
    3290               0 :     do {
    3291               0 :       ancestors.AppendElement(cur);
    3292               0 :       nsINode* parent = cur->GetNodeParent();
    3293               0 :       if (!parent->IsElement()) {
    3294                 :         break;
    3295                 :       }
    3296               0 :       cur = parent->AsElement();
    3297                 :     } while (true);
    3298                 : 
    3299                 :     // Now push them in reverse order.
    3300               0 :     for (PRUint32 i = ancestors.Length(); i-- != 0; ) {
    3301               0 :       PushAncestor(ancestors[i]);
    3302                 :     }
    3303                 :   }
    3304               0 : }
    3305                 : 
    3306                 : void
    3307               0 : AncestorFilter::PushAncestor(Element *aElement)
    3308                 : {
    3309               0 :   MOZ_ASSERT(mFilter);
    3310                 : 
    3311               0 :   PRUint32 oldLength = mHashes.Length();
    3312                 : 
    3313               0 :   mPopTargets.AppendElement(oldLength);
    3314                 : #ifdef DEBUG
    3315               0 :   mElements.AppendElement(aElement);
    3316                 : #endif
    3317               0 :   mHashes.AppendElement(aElement->Tag()->hash());
    3318               0 :   nsIAtom *id = aElement->GetID();
    3319               0 :   if (id) {
    3320               0 :     mHashes.AppendElement(id->hash());
    3321                 :   }
    3322               0 :   const nsAttrValue *classes = aElement->GetClasses();
    3323               0 :   if (classes) {
    3324               0 :     PRUint32 classCount = classes->GetAtomCount();
    3325               0 :     for (PRUint32 i = 0; i < classCount; ++i) {
    3326               0 :       mHashes.AppendElement(classes->AtomAt(i)->hash());
    3327                 :     }
    3328                 :   }
    3329                 : 
    3330               0 :   PRUint32 newLength = mHashes.Length();
    3331               0 :   for (PRUint32 i = oldLength; i < newLength; ++i) {
    3332               0 :     mFilter->add(mHashes[i]);
    3333                 :   }
    3334               0 : }
    3335                 : 
    3336                 : void
    3337               0 : AncestorFilter::PopAncestor()
    3338                 : {
    3339               0 :   MOZ_ASSERT(!mPopTargets.IsEmpty());
    3340               0 :   MOZ_ASSERT(mPopTargets.Length() == mElements.Length());
    3341                 : 
    3342               0 :   PRUint32 popTargetLength = mPopTargets.Length();
    3343               0 :   PRUint32 newLength = mPopTargets[popTargetLength-1];
    3344                 : 
    3345               0 :   mPopTargets.TruncateLength(popTargetLength-1);
    3346                 : #ifdef DEBUG
    3347               0 :   mElements.TruncateLength(popTargetLength-1);
    3348                 : #endif
    3349                 : 
    3350               0 :   PRUint32 oldLength = mHashes.Length();
    3351               0 :   for (PRUint32 i = newLength; i < oldLength; ++i) {
    3352               0 :     mFilter->remove(mHashes[i]);
    3353                 :   }
    3354               0 :   mHashes.TruncateLength(newLength);
    3355               0 : }
    3356                 : 
    3357                 : #ifdef DEBUG
    3358                 : void
    3359               0 : AncestorFilter::AssertHasAllAncestors(Element *aElement) const
    3360                 : {
    3361               0 :   nsINode* cur = aElement->GetNodeParent();
    3362               0 :   while (cur && cur->IsElement()) {
    3363               0 :     MOZ_ASSERT(mElements.Contains(cur));
    3364               0 :     cur = cur->GetNodeParent();
    3365                 :   }
    3366            4392 : }
    3367                 : #endif

Generated by: LCOV version 1.7