layout/style/nsStyleSet.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7  * the container for the style sheets that apply to a presentation, and
     8  * the internal API that the style system exposes for creating (and
     9  * potentially re-creating) style contexts
    10  */
    12 #include "mozilla/ArrayUtils.h"
    13 #include "mozilla/EventStates.h"
    14 #include "mozilla/MemoryReporting.h"
    16 #include "nsStyleSet.h"
    17 #include "nsCSSStyleSheet.h"
    18 #include "nsIDocumentInlines.h"
    19 #include "nsRuleWalker.h"
    20 #include "nsStyleContext.h"
    21 #include "mozilla/css/StyleRule.h"
    22 #include "nsCSSAnonBoxes.h"
    23 #include "nsCSSPseudoElements.h"
    24 #include "nsCSSRuleProcessor.h"
    25 #include "nsDataHashtable.h"
    26 #include "nsIContent.h"
    27 #include "nsRuleData.h"
    28 #include "nsRuleProcessorData.h"
    29 #include "nsTransitionManager.h"
    30 #include "nsAnimationManager.h"
    31 #include "nsStyleSheetService.h"
    32 #include "mozilla/dom/Element.h"
    33 #include "GeckoProfiler.h"
    34 #include "nsHTMLCSSStyleSheet.h"
    35 #include "nsHTMLStyleSheet.h"
    36 #include "nsCSSRules.h"
    38 using namespace mozilla;
    39 using namespace mozilla::dom;
    41 NS_IMPL_ISUPPORTS(nsEmptyStyleRule, nsIStyleRule)
    43 /* virtual */ void
    44 nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
    45 {
    46 }
    48 #ifdef DEBUG
    49 /* virtual */ void
    50 nsEmptyStyleRule::List(FILE* out, int32_t aIndent) const
    51 {
    52   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
    53   fputs("[empty style rule] {}\n", out);
    54 }
    55 #endif
    57 NS_IMPL_ISUPPORTS(nsInitialStyleRule, nsIStyleRule)
    59 /* virtual */ void
    60 nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
    61 {
    62   // Iterate over the property groups
    63   for (nsStyleStructID sid = nsStyleStructID(0);
    64        sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
    65     if (aRuleData->mSIDs & (1 << sid)) {
    66       // Iterate over nsCSSValues within the property group
    67       nsCSSValue * const value_start =
    68         aRuleData->mValueStorage + aRuleData->mValueOffsets[sid];
    69       for (nsCSSValue *value = value_start,
    70            *value_end = value + nsCSSProps::PropertyCountInStruct(sid);
    71            value != value_end; ++value) {
    72         // If MathML is disabled take care not to set MathML properties (or we
    73         // will trigger assertions in nsRuleNode)
    74         if (sid == eStyleStruct_Font &&
    75             !aRuleData->mPresContext->Document()->GetMathMLEnabled()) {
    76           size_t index = value - value_start;
    77           if (index == nsCSSProps::PropertyIndexInStruct(
    78                           eCSSProperty_script_level) ||
    79               index == nsCSSProps::PropertyIndexInStruct(
    80                           eCSSProperty_script_size_multiplier) ||
    81               index == nsCSSProps::PropertyIndexInStruct(
    82                           eCSSProperty_script_min_size) ||
    83               index == nsCSSProps::PropertyIndexInStruct(
    84                           eCSSProperty_math_variant) ||
    85               index == nsCSSProps::PropertyIndexInStruct(
    86                           eCSSProperty_math_display)) {
    87             continue;
    88           }
    89         }
    90         if (value->GetUnit() == eCSSUnit_Null) {
    91           value->SetInitialValue();
    92         }
    93       }
    94     }
    95   }
    96 }
    98 #ifdef DEBUG
    99 /* virtual */ void
   100 nsInitialStyleRule::List(FILE* out, int32_t aIndent) const
   101 {
   102   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
   103   fputs("[initial style rule] {}\n", out);
   104 }
   105 #endif
   107 NS_IMPL_ISUPPORTS(nsDisableTextZoomStyleRule, nsIStyleRule)
   109 /* virtual */ void
   110 nsDisableTextZoomStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
   111 {
   112   if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Font)))
   113     return;
   115   nsCSSValue* value = aRuleData->ValueForTextZoom();
   116   if (value->GetUnit() == eCSSUnit_Null)
   117     value->SetNoneValue();
   118 }
   120 #ifdef DEBUG
   121 /* virtual */ void
   122 nsDisableTextZoomStyleRule::List(FILE* out, int32_t aIndent) const
   123 {
   124   for (int32_t index = aIndent; --index >= 0; ) fputs("  ", out);
   125   fputs("[disable text zoom style rule] {}\n", out);
   126 }
   127 #endif
   129 static const nsStyleSet::sheetType gCSSSheetTypes[] = {
   130   // From lowest to highest in cascading order.
   131   nsStyleSet::eAgentSheet,
   132   nsStyleSet::eUserSheet,
   133   nsStyleSet::eDocSheet,
   134   nsStyleSet::eScopedDocSheet,
   135   nsStyleSet::eOverrideSheet
   136 };
   138 nsStyleSet::nsStyleSet()
   139   : mRuleTree(nullptr),
   140     mBatching(0),
   141     mInShutdown(false),
   142     mAuthorStyleDisabled(false),
   143     mInReconstruct(false),
   144     mInitFontFeatureValuesLookup(true),
   145     mDirty(0),
   146     mUnusedRuleNodeCount(0)
   147 {
   148 }
   150 size_t
   151 nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   152 {
   153   size_t n = aMallocSizeOf(this);
   155   for (int i = 0; i < eSheetTypeCount; i++) {
   156     if (mRuleProcessors[i]) {
   157       n += mRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
   158     }
   159     n += mSheets[i].SizeOfExcludingThis(nullptr, aMallocSizeOf);
   160   }
   162   for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
   163     n += mScopedDocSheetRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
   164   }
   165   n += mScopedDocSheetRuleProcessors.SizeOfExcludingThis(aMallocSizeOf);
   167   n += mRoots.SizeOfExcludingThis(aMallocSizeOf);
   168   n += mOldRuleTrees.SizeOfExcludingThis(aMallocSizeOf);
   170   return n;
   171 }
   173 void
   174 nsStyleSet::Init(nsPresContext *aPresContext)
   175 {
   176   mFirstLineRule = new nsEmptyStyleRule;
   177   mFirstLetterRule = new nsEmptyStyleRule;
   178   mPlaceholderRule = new nsEmptyStyleRule;
   179   mDisableTextZoomStyleRule = new nsDisableTextZoomStyleRule;
   181   mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
   183   GatherRuleProcessors(eAnimationSheet);
   184   GatherRuleProcessors(eTransitionSheet);
   185 }
   187 nsresult
   188 nsStyleSet::BeginReconstruct()
   189 {
   190   NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
   191   NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
   193   // Create a new rule tree root
   194   nsRuleNode* newTree =
   195     nsRuleNode::CreateRootNode(mRuleTree->PresContext());
   196   if (!newTree)
   197     return NS_ERROR_OUT_OF_MEMORY;
   199   // Save the old rule tree so we can destroy it later
   200   if (!mOldRuleTrees.AppendElement(mRuleTree)) {
   201     newTree->Destroy();
   202     return NS_ERROR_OUT_OF_MEMORY;
   203   }
   205   // We need to keep mRoots so that the rule tree GC will only free the
   206   // rule trees that really aren't referenced anymore (which should be
   207   // all of them, if there are no bugs in reresolution code).
   209   mInReconstruct = true;
   210   mRuleTree = newTree;
   212   return NS_OK;
   213 }
   215 void
   216 nsStyleSet::EndReconstruct()
   217 {
   218   NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
   219   mInReconstruct = false;
   220 #ifdef DEBUG
   221   for (int32_t i = mRoots.Length() - 1; i >= 0; --i) {
   222     nsRuleNode *n = mRoots[i]->RuleNode();
   223     while (n->GetParent()) {
   224       n = n->GetParent();
   225     }
   226     // Since nsStyleContext's mParent and mRuleNode are immutable, and
   227     // style contexts own their parents, and nsStyleContext asserts in
   228     // its constructor that the style context and its parent are in the
   229     // same rule tree, we don't need to check any of the children of
   230     // mRoots; we only need to check the rule nodes of mRoots
   231     // themselves.
   233     NS_ASSERTION(n == mRuleTree, "style context has old rule node");
   234   }
   235 #endif
   236   // This *should* destroy the only element of mOldRuleTrees, but in
   237   // case of some bugs (which would trigger the above assertions), it
   238   // won't.
   239   GCRuleTrees();
   240 }
   242 void
   243 nsStyleSet::SetQuirkStyleSheet(nsIStyleSheet* aQuirkStyleSheet)
   244 {
   245   NS_ASSERTION(aQuirkStyleSheet, "Must have quirk sheet if this is called");
   246   NS_ASSERTION(!mQuirkStyleSheet, "Multiple calls to SetQuirkStyleSheet?");
   247   NS_ASSERTION(mSheets[eAgentSheet].IndexOf(aQuirkStyleSheet) != -1,
   248                "Quirk style sheet not one of our agent sheets?");
   249   mQuirkStyleSheet = aQuirkStyleSheet;
   250 }
   252 typedef nsDataHashtable<nsPtrHashKey<nsINode>, uint32_t> ScopeDepthCache;
   254 // Returns the depth of a style scope element, with 1 being the depth of
   255 // a style scope element that has no ancestor style scope elements.  The
   256 // depth does not count intervening non-scope elements.
   257 static uint32_t
   258 GetScopeDepth(nsINode* aScopeElement, ScopeDepthCache& aCache)
   259 {
   260   nsINode* parent = aScopeElement->GetParent();
   261   if (!parent || !parent->IsElementInStyleScope()) {
   262     return 1;
   263   }
   265   uint32_t depth = aCache.Get(aScopeElement);
   266   if (!depth) {
   267     for (nsINode* n = parent; n; n = n->GetParent()) {
   268       if (n->IsScopedStyleRoot()) {
   269         depth = GetScopeDepth(n, aCache) + 1;
   270         aCache.Put(aScopeElement, depth);
   271         break;
   272       }
   273     }
   274   }
   275   return depth;
   276 }
   278 struct ScopedSheetOrder
   279 {
   280   nsCSSStyleSheet* mSheet;
   281   uint32_t mDepth;
   282   uint32_t mOrder;
   284   bool operator==(const ScopedSheetOrder& aRHS) const
   285   {
   286     return mDepth == aRHS.mDepth &&
   287            mOrder == aRHS.mOrder;
   288   }
   290   bool operator<(const ScopedSheetOrder& aRHS) const
   291   {
   292     if (mDepth != aRHS.mDepth) {
   293       return mDepth < aRHS.mDepth;
   294     }
   295     return mOrder < aRHS.mOrder;
   296   }
   297 };
   299 // Sorts aSheets such that style sheets for ancestor scopes come
   300 // before those for descendant scopes, and with sheets for a single
   301 // scope in document order.
   302 static void
   303 SortStyleSheetsByScope(nsTArray<nsCSSStyleSheet*>& aSheets)
   304 {
   305   uint32_t n = aSheets.Length();
   306   if (n == 1) {
   307     return;
   308   }
   310   ScopeDepthCache cache;
   312   nsTArray<ScopedSheetOrder> sheets;
   313   sheets.SetLength(n);
   315   // For each sheet, record the depth of its scope element and its original
   316   // document order.
   317   for (uint32_t i = 0; i < n; i++) {
   318     sheets[i].mSheet = aSheets[i];
   319     sheets[i].mDepth = GetScopeDepth(aSheets[i]->GetScopeElement(), cache);
   320     sheets[i].mOrder = i;
   321   }
   323   // Sort by depth first, then document order.
   324   sheets.Sort();
   326   for (uint32_t i = 0; i < n; i++) {
   327     aSheets[i] = sheets[i].mSheet;
   328   }
   329 }
   331 nsresult
   332 nsStyleSet::GatherRuleProcessors(sheetType aType)
   333 {
   334   mRuleProcessors[aType] = nullptr;
   335   if (aType == eScopedDocSheet) {
   336     for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
   337       nsIStyleRuleProcessor* processor = mScopedDocSheetRuleProcessors[i].get();
   338       Element* scope =
   339         static_cast<nsCSSRuleProcessor*>(processor)->GetScopeElement();
   340       scope->ClearIsScopedStyleRoot();
   341     }
   342     mScopedDocSheetRuleProcessors.Clear();
   343   }
   344   if (mAuthorStyleDisabled && (aType == eDocSheet || 
   345                                aType == eScopedDocSheet ||
   346                                aType == eStyleAttrSheet)) {
   347     // Don't regather if this level is disabled.  Note that we gather
   348     // preshint sheets no matter what, but then skip them for some
   349     // elements later if mAuthorStyleDisabled.
   350     return NS_OK;
   351   }
   352   switch (aType) {
   353     // handle the types for which have a rule processor that does not
   354     // implement the style sheet interface.
   355     case eAnimationSheet:
   356       MOZ_ASSERT(mSheets[aType].Count() == 0);
   357       mRuleProcessors[aType] = PresContext()->AnimationManager();
   358       return NS_OK;
   359     case eTransitionSheet:
   360       MOZ_ASSERT(mSheets[aType].Count() == 0);
   361       mRuleProcessors[aType] = PresContext()->TransitionManager();
   362       return NS_OK;
   363     case eStyleAttrSheet:
   364       MOZ_ASSERT(mSheets[aType].Count() == 0);
   365       mRuleProcessors[aType] = PresContext()->Document()->GetInlineStyleSheet();
   366       return NS_OK;
   367     case ePresHintSheet:
   368       MOZ_ASSERT(mSheets[aType].Count() == 0);
   369       mRuleProcessors[aType] = PresContext()->Document()->GetAttributeStyleSheet();
   370       return NS_OK;
   371     default:
   372       // keep going
   373       break;
   374   }
   375   if (aType == eScopedDocSheet) {
   376     // Create a rule processor for each scope.
   377     uint32_t count = mSheets[eScopedDocSheet].Count();
   378     if (count) {
   379       // Gather the scoped style sheets into an array as
   380       // nsCSSStyleSheets, and mark all of their scope elements
   381       // as scoped style roots.
   382       nsTArray<nsCSSStyleSheet*> sheets(count);
   383       for (uint32_t i = 0; i < count; i++) {
   384         nsRefPtr<nsCSSStyleSheet> sheet =
   385           do_QueryObject(mSheets[eScopedDocSheet].ObjectAt(i));
   386         sheets.AppendElement(sheet);
   388         Element* scope = sheet->GetScopeElement();
   389         scope->SetIsScopedStyleRoot();
   390       }
   392       // Sort the scoped style sheets so that those for the same scope are
   393       // adjacent and that ancestor scopes come before descendent scopes.
   394       SortStyleSheetsByScope(sheets);
   396       uint32_t start = 0, end;
   397       do {
   398         // Find the range of style sheets with the same scope.
   399         Element* scope = sheets[start]->GetScopeElement();
   400         end = start + 1;
   401         while (end < count && sheets[end]->GetScopeElement() == scope) {
   402           end++;
   403         }
   405         scope->SetIsScopedStyleRoot();
   407         // Create a rule processor for the scope.
   408         nsTArray< nsRefPtr<nsCSSStyleSheet> > sheetsForScope;
   409         sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
   410         mScopedDocSheetRuleProcessors.AppendElement
   411           (new nsCSSRuleProcessor(sheetsForScope, uint8_t(aType), scope));
   413         start = end;
   414       } while (start < count);
   415     }
   416     return NS_OK;
   417   }
   418   if (mSheets[aType].Count()) {
   419     switch (aType) {
   420       case eAgentSheet:
   421       case eUserSheet:
   422       case eDocSheet:
   423       case eOverrideSheet: {
   424         // levels containing CSS stylesheets (apart from eScopedDocSheet)
   425         nsCOMArray<nsIStyleSheet>& sheets = mSheets[aType];
   426         nsTArray<nsRefPtr<nsCSSStyleSheet> > cssSheets(sheets.Count());
   427         for (int32_t i = 0, i_end = sheets.Count(); i < i_end; ++i) {
   428           nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheets[i]);
   429           NS_ASSERTION(cssSheet, "not a CSS sheet");
   430           cssSheets.AppendElement(cssSheet);
   431         }
   432         mRuleProcessors[aType] =
   433           new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr);
   434       } break;
   436       default:
   437         // levels containing non-CSS stylesheets
   438         NS_ASSERTION(mSheets[aType].Count() == 1, "only one sheet per level");
   439         mRuleProcessors[aType] = do_QueryInterface(mSheets[aType][0]);
   440         break;
   441     }
   442   }
   444   return NS_OK;
   445 }
   447 static bool
   448 IsScopedStyleSheet(nsIStyleSheet* aSheet)
   449 {
   450   nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(aSheet);
   451   NS_ASSERTION(cssSheet, "expected aSheet to be an nsCSSStyleSheet");
   453   return cssSheet->GetScopeElement();
   454 }
   456 nsresult
   457 nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
   458 {
   459   NS_PRECONDITION(aSheet, "null arg");
   460   NS_ASSERTION(aSheet->IsApplicable(),
   461                "Inapplicable sheet being placed in style set");
   462   mSheets[aType].RemoveObject(aSheet);
   463   if (!mSheets[aType].AppendObject(aSheet))
   464     return NS_ERROR_OUT_OF_MEMORY;
   466   return DirtyRuleProcessors(aType);
   467 }
   469 nsresult
   470 nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
   471 {
   472   NS_PRECONDITION(aSheet, "null arg");
   473   NS_ASSERTION(aSheet->IsApplicable(),
   474                "Inapplicable sheet being placed in style set");
   475   mSheets[aType].RemoveObject(aSheet);
   476   if (!mSheets[aType].InsertObjectAt(aSheet, 0))
   477     return NS_ERROR_OUT_OF_MEMORY;
   479   return DirtyRuleProcessors(aType);
   480 }
   482 nsresult
   483 nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
   484 {
   485   NS_PRECONDITION(aSheet, "null arg");
   486   NS_ASSERTION(aSheet->IsComplete(),
   487                "Incomplete sheet being removed from style set");
   488   mSheets[aType].RemoveObject(aSheet);
   490   return DirtyRuleProcessors(aType);
   491 }
   493 nsresult
   494 nsStyleSet::ReplaceSheets(sheetType aType,
   495                           const nsCOMArray<nsIStyleSheet> &aNewSheets)
   496 {
   497   mSheets[aType].Clear();
   498   if (!mSheets[aType].AppendObjects(aNewSheets))
   499     return NS_ERROR_OUT_OF_MEMORY;
   501   return DirtyRuleProcessors(aType);
   502 }
   504 nsresult
   505 nsStyleSet::InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
   506                                    nsIStyleSheet *aReferenceSheet)
   507 {
   508   NS_PRECONDITION(aNewSheet && aReferenceSheet, "null arg");
   509   NS_ASSERTION(aNewSheet->IsApplicable(),
   510                "Inapplicable sheet being placed in style set");
   512   mSheets[aType].RemoveObject(aNewSheet);
   513   int32_t idx = mSheets[aType].IndexOf(aReferenceSheet);
   514   if (idx < 0)
   515     return NS_ERROR_INVALID_ARG;
   517   if (!mSheets[aType].InsertObjectAt(aNewSheet, idx))
   518     return NS_ERROR_OUT_OF_MEMORY;
   520   return DirtyRuleProcessors(aType);
   521 }
   523 nsresult
   524 nsStyleSet::DirtyRuleProcessors(sheetType aType)
   525 {
   526   if (!mBatching)
   527     return GatherRuleProcessors(aType);
   529   mDirty |= 1 << aType;
   530   return NS_OK;
   531 }
   533 bool
   534 nsStyleSet::GetAuthorStyleDisabled()
   535 {
   536   return mAuthorStyleDisabled;
   537 }
   539 nsresult
   540 nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
   541 {
   542   if (aStyleDisabled == !mAuthorStyleDisabled) {
   543     mAuthorStyleDisabled = aStyleDisabled;
   544     BeginUpdate();
   545     mDirty |= 1 << eDocSheet |
   546               1 << eScopedDocSheet |
   547               1 << eStyleAttrSheet;
   548     return EndUpdate();
   549   }
   550   return NS_OK;
   551 }
   553 // -------- Doc Sheets
   555 nsresult
   556 nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument)
   557 {
   558   NS_PRECONDITION(aSheet && aDocument, "null arg");
   559   NS_ASSERTION(aSheet->IsApplicable(),
   560                "Inapplicable sheet being placed in style set");
   562   sheetType type = IsScopedStyleSheet(aSheet) ?
   563                      eScopedDocSheet :
   564                      eDocSheet;
   565   nsCOMArray<nsIStyleSheet>& sheets = mSheets[type];
   567   sheets.RemoveObject(aSheet);
   568   nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
   570   // lowest index first
   571   int32_t newDocIndex = aDocument->GetIndexOfStyleSheet(aSheet);
   573   int32_t count = sheets.Count();
   574   int32_t index;
   575   for (index = 0; index < count; index++) {
   576     nsIStyleSheet* sheet = sheets.ObjectAt(index);
   577     int32_t sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
   578     if (sheetDocIndex > newDocIndex)
   579       break;
   581     // If the sheet is not owned by the document it can be an author
   582     // sheet registered at nsStyleSheetService or an additional author
   583     // sheet on the document, which means the new 
   584     // doc sheet should end up before it.
   585     if (sheetDocIndex < 0 &&
   586         ((sheetService &&
   587         sheetService->AuthorStyleSheets()->IndexOf(sheet) >= 0) ||
   588         sheet == aDocument->FirstAdditionalAuthorSheet()))
   589         break;
   590   }
   591   if (!sheets.InsertObjectAt(aSheet, index))
   592     return NS_ERROR_OUT_OF_MEMORY;
   594   return DirtyRuleProcessors(type);
   595 }
   597 nsresult
   598 nsStyleSet::RemoveDocStyleSheet(nsIStyleSheet *aSheet)
   599 {
   600   nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(aSheet);
   601   bool isScoped = cssSheet && cssSheet->GetScopeElement();
   602   return RemoveStyleSheet(isScoped ? eScopedDocSheet : eDocSheet, aSheet);
   603 }
   605 // Batching
   606 void
   607 nsStyleSet::BeginUpdate()
   608 {
   609   ++mBatching;
   610 }
   612 nsresult
   613 nsStyleSet::EndUpdate()
   614 {
   615   NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
   616   if (--mBatching) {
   617     // We're not completely done yet.
   618     return NS_OK;
   619   }
   621   for (int i = 0; i < eSheetTypeCount; ++i) {
   622     if (mDirty & (1 << i)) {
   623       nsresult rv = GatherRuleProcessors(sheetType(i));
   624       NS_ENSURE_SUCCESS(rv, rv);
   625     }
   626   }
   628   mDirty = 0;
   629   return NS_OK;
   630 }
   632 void
   633 nsStyleSet::EnableQuirkStyleSheet(bool aEnable)
   634 {
   635 #ifdef DEBUG
   636   bool oldEnabled;
   637   {
   638     nsCOMPtr<nsIDOMCSSStyleSheet> domSheet =
   639       do_QueryInterface(mQuirkStyleSheet);
   640     domSheet->GetDisabled(&oldEnabled);
   641     oldEnabled = !oldEnabled;
   642   }
   643 #endif
   644   mQuirkStyleSheet->SetEnabled(aEnable);
   645 #ifdef DEBUG
   646   // This should always be OK, since SetEnabled should call
   647   // ClearRuleCascades.
   648   // Note that we can hit this codepath multiple times when document.open()
   649   // (potentially implied) happens multiple times.
   650   if (mRuleProcessors[eAgentSheet] && aEnable != oldEnabled) {
   651     static_cast<nsCSSRuleProcessor*>(static_cast<nsIStyleRuleProcessor*>(
   652       mRuleProcessors[eAgentSheet]))->AssertQuirksChangeOK();
   653   }
   654 #endif
   655 }
   657 template<class T>
   658 static bool
   659 EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
   660 {
   661   T* data = static_cast<T*>(aData);
   662   aProcessor->RulesMatching(data);
   663   return true;
   664 }
   666 static inline bool
   667 IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
   668 {
   669   return !aRuleNode->IsRoot() &&
   670          (aRuleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
   671           aRuleNode->IsImportantRule());
   672 }
   674 static nsIStyleRule*
   675 GetAnimationRule(nsRuleNode *aRuleNode)
   676 {
   677   nsRuleNode *n = aRuleNode;
   678   while (IsMoreSpecificThanAnimation(n)) {
   679     n = n->GetParent();
   680   }
   682   if (n->IsRoot() || n->GetLevel() != nsStyleSet::eAnimationSheet) {
   683     return nullptr;
   684   }
   686   return n->GetRule();
   687 }
   689 static nsRuleNode*
   690 ReplaceAnimationRule(nsRuleNode *aOldRuleNode,
   691                      nsIStyleRule *aOldAnimRule,
   692                      nsIStyleRule *aNewAnimRule)
   693 {
   694   nsTArray<nsRuleNode*> moreSpecificNodes;
   696   nsRuleNode *n = aOldRuleNode;
   697   while (IsMoreSpecificThanAnimation(n)) {
   698     moreSpecificNodes.AppendElement(n);
   699     n = n->GetParent();
   700   }
   702   if (aOldAnimRule) {
   703     NS_ABORT_IF_FALSE(n->GetRule() == aOldAnimRule, "wrong rule");
   704     NS_ABORT_IF_FALSE(n->GetLevel() == nsStyleSet::eAnimationSheet,
   705                       "wrong level");
   706     n = n->GetParent();
   707   }
   709   NS_ABORT_IF_FALSE(!IsMoreSpecificThanAnimation(n) &&
   710                     (n->IsRoot() ||
   711                      n->GetLevel() != nsStyleSet::eAnimationSheet),
   712                     "wrong level");
   714   if (aNewAnimRule) {
   715     n = n->Transition(aNewAnimRule, nsStyleSet::eAnimationSheet, false);
   716   }
   718   for (uint32_t i = moreSpecificNodes.Length(); i-- != 0; ) {
   719     nsRuleNode *oldNode = moreSpecificNodes[i];
   720     n = n->Transition(oldNode->GetRule(), oldNode->GetLevel(),
   721                       oldNode->IsImportantRule());
   722   }
   724   return n;
   725 }
   727 /**
   728  * |GetContext| implements sharing of style contexts (not just the data
   729  * on the rule nodes) between siblings and cousins of the same
   730  * generation.  (It works for cousins of the same generation since
   731  * |aParentContext| could itself be a shared context.)
   732  */
   733 already_AddRefed<nsStyleContext>
   734 nsStyleSet::GetContext(nsStyleContext* aParentContext,
   735                        nsRuleNode* aRuleNode,
   736                        // aVisitedRuleNode may be null; if it is null
   737                        // it means that we don't need to force creation
   738                        // of a StyleIfVisited.  (But if we make one
   739                        // because aParentContext has one, then aRuleNode
   740                        // should be used.)
   741                        nsRuleNode* aVisitedRuleNode,
   742                        nsIAtom* aPseudoTag,
   743                        nsCSSPseudoElements::Type aPseudoType,
   744                        Element* aElementForAnimation,
   745                        uint32_t aFlags)
   746 {
   747   NS_PRECONDITION((!aPseudoTag &&
   748                    aPseudoType ==
   749                      nsCSSPseudoElements::ePseudo_NotPseudoElement) ||
   750                   (aPseudoTag &&
   751                    nsCSSPseudoElements::GetPseudoType(aPseudoTag) ==
   752                      aPseudoType),
   753                   "Pseudo mismatch");
   755   if (aVisitedRuleNode == aRuleNode) {
   756     // No need to force creation of a visited style in this case.
   757     aVisitedRuleNode = nullptr;
   758   }
   760   // Ensure |aVisitedRuleNode != nullptr| corresponds to the need to
   761   // create an if-visited style context, and that in that case, we have
   762   // parentIfVisited set correctly.
   763   nsStyleContext *parentIfVisited =
   764     aParentContext ? aParentContext->GetStyleIfVisited() : nullptr;
   765   if (parentIfVisited) {
   766     if (!aVisitedRuleNode) {
   767       aVisitedRuleNode = aRuleNode;
   768     }
   769   } else {
   770     if (aVisitedRuleNode) {
   771       parentIfVisited = aParentContext;
   772     }
   773   }
   775   if (aFlags & eIsLink) {
   776     // If this node is a link, we want its visited's style context's
   777     // parent to be the regular style context of its parent, because
   778     // only the visitedness of the relevant link should influence style.
   779     parentIfVisited = aParentContext;
   780   }
   782   nsRefPtr<nsStyleContext> result;
   783   if (aParentContext)
   784     result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
   785                                                 aVisitedRuleNode,
   786                                                 aFlags & eIsVisitedLink);
   788 #ifdef NOISY_DEBUG
   789   if (result)
   790     fprintf(stdout, "--- SharedSC %d ---\n", ++gSharedCount);
   791   else
   792     fprintf(stdout, "+++ NewSC %d +++\n", ++gNewCount);
   793 #endif
   795   if (!result) {
   796     result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
   797                                 aRuleNode, aFlags & eSkipFlexItemStyleFixup);
   798     if (aVisitedRuleNode) {
   799       nsRefPtr<nsStyleContext> resultIfVisited =
   800         NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
   801                            aVisitedRuleNode,
   802                            aFlags & eSkipFlexItemStyleFixup);
   803       if (!parentIfVisited) {
   804         mRoots.AppendElement(resultIfVisited);
   805       }
   806       resultIfVisited->SetIsStyleIfVisited();
   807       result->SetStyleIfVisited(resultIfVisited.forget());
   809       bool relevantLinkVisited = (aFlags & eIsLink) ?
   810         (aFlags & eIsVisitedLink) :
   811         (aParentContext && aParentContext->RelevantLinkVisited());
   813       if (relevantLinkVisited) {
   814         result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
   815       }
   816     }
   817     if (!aParentContext) {
   818       mRoots.AppendElement(result);
   819     }
   820   }
   821   else {
   822     NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
   823     NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
   824   }
   826   if (aFlags & eDoAnimation) {
   827     // Normally the animation manager has already added the correct
   828     // style rule.  However, if the animation-name just changed, it
   829     // might have been wrong.  So ask it to double-check based on the
   830     // resulting style context.
   831     nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
   832     nsIStyleRule *animRule = PresContext()->AnimationManager()->
   833       CheckAnimationRule(result, aElementForAnimation);
   834     NS_ABORT_IF_FALSE(result->RuleNode() == aRuleNode,
   835                       "unexpected rule node");
   836     NS_ABORT_IF_FALSE(!result->GetStyleIfVisited() == !aVisitedRuleNode,
   837                       "unexpected visited rule node");
   838     NS_ABORT_IF_FALSE(!aVisitedRuleNode ||
   839                       result->GetStyleIfVisited()->RuleNode() ==
   840                         aVisitedRuleNode,
   841                       "unexpected visited rule node");
   842     NS_ABORT_IF_FALSE(!aVisitedRuleNode ||
   843                       oldAnimRule == GetAnimationRule(aVisitedRuleNode),
   844                       "animation rule mismatch between rule nodes");
   845     if (oldAnimRule != animRule) {
   846       nsRuleNode *ruleNode =
   847         ReplaceAnimationRule(aRuleNode, oldAnimRule, animRule);
   848       nsRuleNode *visitedRuleNode = aVisitedRuleNode
   849         ? ReplaceAnimationRule(aVisitedRuleNode, oldAnimRule, animRule)
   850         : nullptr;
   851       NS_ABORT_IF_FALSE(!visitedRuleNode ||
   852                         GetAnimationRule(ruleNode) ==
   853                           GetAnimationRule(visitedRuleNode),
   854                         "animation rule mismatch between rule nodes");
   855       result = GetContext(aParentContext, ruleNode, visitedRuleNode,
   856                           aPseudoTag, aPseudoType, nullptr,
   857                           aFlags & ~eDoAnimation);
   858     }
   859   }
   861   if (aElementForAnimation && aElementForAnimation->IsHTML(nsGkAtoms::body) &&
   862       aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement &&
   863       PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
   864     nsIDocument* doc = aElementForAnimation->GetCurrentDoc();
   865     if (doc && doc->GetBodyElement() == aElementForAnimation) {
   866       // Update the prescontext's body color
   867       PresContext()->SetBodyTextColor(result->StyleColor()->mColor);
   868     }
   869   }
   871   return result.forget();
   872 }
   874 void
   875 nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
   876                               nsRuleNode* aLastPrevLevelNode,
   877                               nsRuleWalker* aRuleWalker)
   878 {
   879   NS_ASSERTION(aCurrLevelNode &&
   880                aCurrLevelNode != aLastPrevLevelNode, "How did we get here?");
   882   nsAutoTArray<nsIStyleRule*, 16> importantRules;
   883   for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
   884        node = node->GetParent()) {
   885     // We guarantee that we never walk the root node here, so no need
   886     // to null-check GetRule().  Furthermore, it must be a CSS rule.
   887     NS_ASSERTION(nsRefPtr<css::StyleRule>(do_QueryObject(node->GetRule())),
   888                  "Unexpected non-CSS rule");
   890     nsIStyleRule* impRule =
   891       static_cast<css::StyleRule*>(node->GetRule())->GetImportantRule();
   892     if (impRule)
   893       importantRules.AppendElement(impRule);
   894   }
   896   NS_ASSERTION(importantRules.Length() != 0,
   897                "Why did we think there were important rules?");
   899   for (uint32_t i = importantRules.Length(); i-- != 0; ) {
   900     aRuleWalker->Forward(importantRules[i]);
   901   }
   902 }
   904 #ifdef DEBUG
   905 void
   906 nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
   907                                    nsRuleNode* aLastPrevLevelNode)
   908 {
   909   if (!aCurrLevelNode)
   910     return;
   912   for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
   913        node = node->GetParent()) {
   914     nsRefPtr<css::StyleRule> rule(do_QueryObject(node->GetRule()));
   915     NS_ASSERTION(rule, "Unexpected non-CSS rule");
   917     NS_ASSERTION(!rule->GetImportantRule(), "Unexpected important rule");
   918   }
   919 }
   921 void
   922 nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
   923                              nsRuleNode* aLastPrevLevelNode)
   924 {
   925   if (!aCurrLevelNode)
   926     return;
   928   for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
   929        node = node->GetParent()) {
   930     nsIStyleRule *rule = node->GetRule();
   931     nsRefPtr<css::StyleRule> cssRule(do_QueryObject(rule));
   932     NS_ASSERTION(!cssRule || !cssRule->Selector(), "Unexpected CSS rule");
   933   }
   934 }
   935 #endif
   937 // Enumerate the rules in a way that cares about the order of the rules.
   938 void
   939 nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc, 
   940                       RuleProcessorData* aData, Element* aElement,
   941                       nsRuleWalker* aRuleWalker)
   942 {
   943   PROFILER_LABEL("nsStyleSet", "FileRules");
   945   // Cascading order:
   946   // [least important]
   947   //  - UA normal rules                    = Agent        normal
   948   //  - User normal rules                  = User         normal
   949   //  - Presentation hints                 = PresHint     normal
   950   //  - Author normal rules                = Document     normal
   951   //  - Override normal rules              = Override     normal
   952   //  - animation rules                    = Animation    normal
   953   //  - Author !important rules            = Document     !important
   954   //  - Override !important rules          = Override     !important
   955   //  - User !important rules              = User         !important
   956   //  - UA !important rules                = Agent        !important
   957   //  - transition rules                   = Transition   normal
   958   // [most important]
   960   // Save off the last rule before we start walking our agent sheets;
   961   // this will be either the root or one of the restriction rules.
   962   nsRuleNode* lastRestrictionRN = aRuleWalker->CurrentNode();
   964   aRuleWalker->SetLevel(eAgentSheet, false, true);
   965   if (mRuleProcessors[eAgentSheet])
   966     (*aCollectorFunc)(mRuleProcessors[eAgentSheet], aData);
   967   nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
   968   bool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
   970   aRuleWalker->SetLevel(eUserSheet, false, true);
   971   bool skipUserStyles =
   972     aElement && aElement->IsInNativeAnonymousSubtree();
   973   if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
   974     (*aCollectorFunc)(mRuleProcessors[eUserSheet], aData);
   975   nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
   976   bool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
   978   aRuleWalker->SetLevel(ePresHintSheet, false, false);
   979   if (mRuleProcessors[ePresHintSheet])
   980     (*aCollectorFunc)(mRuleProcessors[ePresHintSheet], aData);
   981   nsRuleNode* lastPresHintRN = aRuleWalker->CurrentNode();
   983   aRuleWalker->SetLevel(eDocSheet, false, true);
   984   bool cutOffInheritance = false;
   985   if (mBindingManager && aElement) {
   986     // We can supply additional document-level sheets that should be walked.
   987     mBindingManager->WalkRules(aCollectorFunc,
   988                                static_cast<ElementDependentRuleProcessorData*>(aData),
   989                                &cutOffInheritance);
   990   }
   991   if (!skipUserStyles && !cutOffInheritance && // NOTE: different
   992       mRuleProcessors[eDocSheet])
   993     (*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
   994   nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
   995   bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
   996   nsTArray<nsRuleNode*> lastScopedRNs;
   997   nsTArray<bool> haveImportantScopedRules;
   998   bool haveAnyImportantScopedRules = false;
   999   if (!skipUserStyles && !cutOffInheritance &&
  1000       aElement && aElement->IsElementInStyleScope()) {
  1001     lastScopedRNs.SetLength(mScopedDocSheetRuleProcessors.Length());
  1002     haveImportantScopedRules.SetLength(mScopedDocSheetRuleProcessors.Length());
  1003     for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
  1004       aRuleWalker->SetLevel(eScopedDocSheet, false, true);
  1005       nsCSSRuleProcessor* processor =
  1006         static_cast<nsCSSRuleProcessor*>(mScopedDocSheetRuleProcessors[i].get());
  1007       aData->mScope = processor->GetScopeElement();
  1008       (*aCollectorFunc)(mScopedDocSheetRuleProcessors[i], aData);
  1009       lastScopedRNs[i] = aRuleWalker->CurrentNode();
  1010       haveImportantScopedRules[i] = !aRuleWalker->GetCheckForImportantRules();
  1011       haveAnyImportantScopedRules = haveAnyImportantScopedRules || haveImportantScopedRules[i];
  1013     aData->mScope = nullptr;
  1015   nsRuleNode* lastScopedRN = aRuleWalker->CurrentNode();
  1016   aRuleWalker->SetLevel(eStyleAttrSheet, false, true);
  1017   if (mRuleProcessors[eStyleAttrSheet])
  1018     (*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
  1019   nsRuleNode* lastStyleAttrRN = aRuleWalker->CurrentNode();
  1020   bool haveImportantStyleAttrRules = !aRuleWalker->GetCheckForImportantRules();
  1022   aRuleWalker->SetLevel(eOverrideSheet, false, true);
  1023   if (mRuleProcessors[eOverrideSheet])
  1024     (*aCollectorFunc)(mRuleProcessors[eOverrideSheet], aData);
  1025   nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
  1026   bool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
  1028   // This needs to match IsMoreSpecificThanAnimation() above.
  1029   aRuleWalker->SetLevel(eAnimationSheet, false, false);
  1030   (*aCollectorFunc)(mRuleProcessors[eAnimationSheet], aData);
  1032   if (haveAnyImportantScopedRules) {
  1033     for (uint32_t i = lastScopedRNs.Length(); i-- != 0; ) {
  1034       aRuleWalker->SetLevel(eScopedDocSheet, true, false);
  1035       nsRuleNode* startRN = lastScopedRNs[i];
  1036       nsRuleNode* endRN = i == 0 ? lastDocRN : lastScopedRNs[i - 1];
  1037       if (haveImportantScopedRules[i]) {
  1038         AddImportantRules(startRN, endRN, aRuleWalker);  // scoped
  1040 #ifdef DEBUG
  1041       else {
  1042         AssertNoImportantRules(startRN, endRN);
  1044 #endif
  1047 #ifdef DEBUG
  1048   else {
  1049     AssertNoImportantRules(lastScopedRN, lastDocRN);
  1051 #endif
  1053   if (haveImportantDocRules) {
  1054     aRuleWalker->SetLevel(eDocSheet, true, false);
  1055     AddImportantRules(lastDocRN, lastPresHintRN, aRuleWalker);  // doc
  1057 #ifdef DEBUG
  1058   else {
  1059     AssertNoImportantRules(lastDocRN, lastPresHintRN);
  1061 #endif
  1063   if (haveImportantStyleAttrRules) {
  1064     aRuleWalker->SetLevel(eStyleAttrSheet, true, false);
  1065     AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker);  // style attr
  1067 #ifdef DEBUG
  1068   else {
  1069     AssertNoImportantRules(lastStyleAttrRN, lastScopedRN);
  1071 #endif
  1073   if (haveImportantOverrideRules) {
  1074     aRuleWalker->SetLevel(eOverrideSheet, true, false);
  1075     AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker);  // override
  1077 #ifdef DEBUG
  1078   else {
  1079     AssertNoImportantRules(lastOvrRN, lastStyleAttrRN);
  1081 #endif
  1083 #ifdef DEBUG
  1084   AssertNoCSSRules(lastPresHintRN, lastUserRN);
  1085 #endif
  1087   if (haveImportantUserRules) {
  1088     aRuleWalker->SetLevel(eUserSheet, true, false);
  1089     AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
  1091 #ifdef DEBUG
  1092   else {
  1093     AssertNoImportantRules(lastUserRN, lastAgentRN);
  1095 #endif
  1097   if (haveImportantUARules) {
  1098     aRuleWalker->SetLevel(eAgentSheet, true, false);
  1099     AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
  1101 #ifdef DEBUG
  1102   else {
  1103     AssertNoImportantRules(lastAgentRN, lastRestrictionRN);
  1105 #endif
  1107 #ifdef DEBUG
  1108   AssertNoCSSRules(lastRestrictionRN, mRuleTree);
  1109 #endif
  1111 #ifdef DEBUG
  1112   nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
  1113 #endif
  1114   aRuleWalker->SetLevel(eTransitionSheet, false, false);
  1115   (*aCollectorFunc)(mRuleProcessors[eTransitionSheet], aData);
  1116 #ifdef DEBUG
  1117   AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
  1118 #endif
  1122 // Enumerate all the rules in a way that doesn't care about the order
  1123 // of the rules and doesn't walk !important-rules.
  1124 void
  1125 nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
  1126                                ElementDependentRuleProcessorData* aData,
  1127                                bool aWalkAllXBLStylesheets)
  1129   if (mRuleProcessors[eAgentSheet])
  1130     (*aFunc)(mRuleProcessors[eAgentSheet], aData);
  1132   bool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
  1133   if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
  1134     (*aFunc)(mRuleProcessors[eUserSheet], aData);
  1136   if (mRuleProcessors[ePresHintSheet])
  1137     (*aFunc)(mRuleProcessors[ePresHintSheet], aData);
  1139   bool cutOffInheritance = false;
  1140   if (mBindingManager) {
  1141     // We can supply additional document-level sheets that should be walked.
  1142     if (aWalkAllXBLStylesheets) {
  1143       mBindingManager->WalkAllRules(aFunc, aData);
  1144     } else {
  1145       mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
  1148   if (!skipUserStyles && !cutOffInheritance) {
  1149     if (mRuleProcessors[eDocSheet]) // NOTE: different
  1150       (*aFunc)(mRuleProcessors[eDocSheet], aData);
  1151     if (aData->mElement->IsElementInStyleScope()) {
  1152       for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++)
  1153         (*aFunc)(mScopedDocSheetRuleProcessors[i], aData);
  1156   if (mRuleProcessors[eStyleAttrSheet])
  1157     (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
  1158   if (mRuleProcessors[eOverrideSheet])
  1159     (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
  1160   (*aFunc)(mRuleProcessors[eAnimationSheet], aData);
  1161   (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
  1164 static void
  1165 InitStyleScopes(TreeMatchContext& aTreeContext, Element* aElement)
  1167   if (aElement->IsElementInStyleScope()) {
  1168     aTreeContext.InitStyleScopes(aElement->GetParentElement());
  1172 already_AddRefed<nsStyleContext>
  1173 nsStyleSet::ResolveStyleFor(Element* aElement,
  1174                             nsStyleContext* aParentContext)
  1176   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
  1177                                aElement->OwnerDoc());
  1178   InitStyleScopes(treeContext, aElement);
  1179   return ResolveStyleFor(aElement, aParentContext, treeContext);
  1182 already_AddRefed<nsStyleContext>
  1183 nsStyleSet::ResolveStyleFor(Element* aElement,
  1184                             nsStyleContext* aParentContext,
  1185                             TreeMatchContext& aTreeMatchContext)
  1187   NS_ENSURE_FALSE(mInShutdown, nullptr);
  1188   NS_ASSERTION(aElement, "aElement must not be null");
  1190   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1191   aTreeMatchContext.ResetForUnvisitedMatching();
  1192   ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker,
  1193                                 aTreeMatchContext);
  1194   WalkDisableTextZoomRule(aElement, &ruleWalker);
  1195   FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
  1196             &ruleWalker);
  1198   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1199   nsRuleNode *visitedRuleNode = nullptr;
  1201   if (aTreeMatchContext.HaveRelevantLink()) {
  1202     aTreeMatchContext.ResetForVisitedMatching();
  1203     ruleWalker.Reset();
  1204     FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
  1205               &ruleWalker);
  1206     visitedRuleNode = ruleWalker.CurrentNode();
  1209   uint32_t flags = eDoAnimation;
  1210   if (nsCSSRuleProcessor::IsLink(aElement)) {
  1211     flags |= eIsLink;
  1213   if (nsCSSRuleProcessor::GetContentState(aElement, aTreeMatchContext).
  1214                             HasState(NS_EVENT_STATE_VISITED)) {
  1215     flags |= eIsVisitedLink;
  1217   if (aTreeMatchContext.mSkippingFlexItemStyleFixup) {
  1218     flags |= eSkipFlexItemStyleFixup;
  1221   return GetContext(aParentContext, ruleNode, visitedRuleNode,
  1222                     nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
  1223                     aElement, flags);
  1226 already_AddRefed<nsStyleContext>
  1227 nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
  1228                                  const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules)
  1230   NS_ENSURE_FALSE(mInShutdown, nullptr);
  1232   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1233   // FIXME: Perhaps this should be passed in, but it probably doesn't
  1234   // matter.
  1235   ruleWalker.SetLevel(eDocSheet, false, false);
  1236   for (uint32_t i = 0; i < aRules.Length(); i++) {
  1237     ruleWalker.ForwardOnPossiblyCSSRule(aRules.ElementAt(i));
  1240   return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
  1241                     nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
  1242                     nullptr, eNoFlags);
  1245 already_AddRefed<nsStyleContext>
  1246 nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
  1247                                  nsStyleContext* aOldStyle,
  1248                                  const nsTArray<RuleAndLevel>& aRules)
  1250   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1251   for (int32_t i = aRules.Length() - 1; i >= 0; --i) {
  1252     ruleWalker.SetLevel(aRules[i].mLevel, false, false);
  1253     ruleWalker.ForwardOnPossiblyCSSRule(aRules[i].mRule);
  1256   uint32_t flags = eNoFlags;
  1257   if (aOldStyle->IsLinkContext()) {
  1258     flags |= eIsLink;
  1260   if (aOldStyle->RelevantLinkVisited()) {
  1261     flags |= eIsVisitedLink;
  1264   return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
  1265                     nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
  1266                     nullptr, flags);
  1269 already_AddRefed<nsStyleContext>
  1270 nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
  1271                                       const nsCOMArray<nsIStyleRule> &aRules)
  1273   NS_ENSURE_FALSE(mInShutdown, nullptr);
  1275   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1276   ruleWalker.SetCurrentNode(aBaseContext->RuleNode());
  1277   // FIXME: Perhaps this should be passed in, but it probably doesn't
  1278   // matter.
  1279   ruleWalker.SetLevel(eDocSheet, false, false);
  1280   for (int32_t i = 0; i < aRules.Count(); i++) {
  1281     ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
  1284   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1285   nsRuleNode *visitedRuleNode = nullptr;
  1287   if (aBaseContext->GetStyleIfVisited()) {
  1288     ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->RuleNode());
  1289     for (int32_t i = 0; i < aRules.Count(); i++) {
  1290       ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
  1292     visitedRuleNode = ruleWalker.CurrentNode();
  1295   uint32_t flags = eNoFlags;
  1296   if (aBaseContext->IsLinkContext()) {
  1297     flags |= eIsLink;
  1299   if (aBaseContext->RelevantLinkVisited()) {
  1300     flags |= eIsVisitedLink;
  1302   return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
  1303                     aBaseContext->GetPseudo(),
  1304                     aBaseContext->GetPseudoType(),
  1305                     nullptr, flags);
  1308 already_AddRefed<nsStyleContext>
  1309 nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
  1311   return GetContext(aParentContext, mRuleTree, nullptr,
  1312                     nsCSSAnonBoxes::mozNonElement,
  1313                     nsCSSPseudoElements::ePseudo_AnonBox, nullptr,
  1314                     eNoFlags);
  1317 void
  1318 nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType,
  1319                                 nsRuleWalker* aRuleWalker)
  1321   // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
  1322   aRuleWalker->SetLevel(eAgentSheet, false, false);
  1323   if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter)
  1324     aRuleWalker->Forward(mFirstLetterRule);
  1325   else if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLine)
  1326     aRuleWalker->Forward(mFirstLineRule);
  1327   else if (aPseudoType == nsCSSPseudoElements::ePseudo_mozPlaceholder)
  1328     aRuleWalker->Forward(mPlaceholderRule);
  1331 void
  1332 nsStyleSet::WalkDisableTextZoomRule(Element* aElement, nsRuleWalker* aRuleWalker)
  1334   aRuleWalker->SetLevel(eAgentSheet, false, false);
  1335   if (aElement->IsSVG(nsGkAtoms::text))
  1336     aRuleWalker->Forward(mDisableTextZoomStyleRule);
  1339 already_AddRefed<nsStyleContext>
  1340 nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
  1341                                       nsCSSPseudoElements::Type aType,
  1342                                       nsStyleContext* aParentContext,
  1343                                       Element* aPseudoElement)
  1345   NS_ENSURE_FALSE(mInShutdown, nullptr);
  1347   NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
  1348                "must have pseudo element type");
  1349   NS_ASSERTION(aParentElement, "Must have parent element");
  1351   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1352   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
  1353                                aParentElement->OwnerDoc());
  1354   InitStyleScopes(treeContext, aParentElement);
  1355   PseudoElementRuleProcessorData data(PresContext(), aParentElement,
  1356                                       &ruleWalker, aType, treeContext,
  1357                                       aPseudoElement);
  1358   WalkRestrictionRule(aType, &ruleWalker);
  1359   FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
  1360             aParentElement, &ruleWalker);
  1362   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1363   nsRuleNode *visitedRuleNode = nullptr;
  1365   if (treeContext.HaveRelevantLink()) {
  1366     treeContext.ResetForVisitedMatching();
  1367     ruleWalker.Reset();
  1368     WalkRestrictionRule(aType, &ruleWalker);
  1369     FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
  1370               aParentElement, &ruleWalker);
  1371     visitedRuleNode = ruleWalker.CurrentNode();
  1374   // For pseudos, |data.IsLink()| being true means that
  1375   // our parent node is a link.
  1376   uint32_t flags = eNoFlags;
  1377   if (aType == nsCSSPseudoElements::ePseudo_before ||
  1378       aType == nsCSSPseudoElements::ePseudo_after) {
  1379     flags |= eDoAnimation;
  1380   } else {
  1381     // Flex containers don't expect to have any pseudo-element children aside
  1382     // from ::before and ::after.  So if we have such a child, we're not
  1383     // actually in a flex container, and we should skip flex-item style fixup.
  1384     flags |= eSkipFlexItemStyleFixup;
  1387   return GetContext(aParentContext, ruleNode, visitedRuleNode,
  1388                     nsCSSPseudoElements::GetPseudoAtom(aType), aType,
  1389                     aParentElement, flags);
  1392 already_AddRefed<nsStyleContext>
  1393 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
  1394                                     nsCSSPseudoElements::Type aType,
  1395                                     nsStyleContext* aParentContext)
  1397   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
  1398                                aParentElement->OwnerDoc());
  1399   InitStyleScopes(treeContext, aParentElement);
  1400   return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
  1401                                  treeContext);
  1404 already_AddRefed<nsStyleContext>
  1405 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
  1406                                     nsCSSPseudoElements::Type aType,
  1407                                     nsStyleContext* aParentContext,
  1408                                     TreeMatchContext& aTreeMatchContext,
  1409                                     Element* aPseudoElement)
  1411   NS_ENSURE_FALSE(mInShutdown, nullptr);
  1413   NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
  1414                "must have pseudo element type");
  1415   NS_ASSERTION(aParentElement, "aParentElement must not be null");
  1417   nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
  1418   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1419   aTreeMatchContext.ResetForUnvisitedMatching();
  1420   PseudoElementRuleProcessorData data(PresContext(), aParentElement,
  1421                                       &ruleWalker, aType, aTreeMatchContext,
  1422                                       aPseudoElement);
  1423   WalkRestrictionRule(aType, &ruleWalker);
  1424   // not the root if there was a restriction rule
  1425   nsRuleNode *adjustedRoot = ruleWalker.CurrentNode();
  1426   FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
  1427             aParentElement, &ruleWalker);
  1429   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1430   if (ruleNode == adjustedRoot) {
  1431     return nullptr;
  1434   nsRuleNode *visitedRuleNode = nullptr;
  1436   if (aTreeMatchContext.HaveRelevantLink()) {
  1437     aTreeMatchContext.ResetForVisitedMatching();
  1438     ruleWalker.Reset();
  1439     WalkRestrictionRule(aType, &ruleWalker);
  1440     FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
  1441               aParentElement, &ruleWalker);
  1442     visitedRuleNode = ruleWalker.CurrentNode();
  1445   // For pseudos, |data.IsLink()| being true means that
  1446   // our parent node is a link.
  1447   uint32_t flags = eNoFlags;
  1448   if (aType == nsCSSPseudoElements::ePseudo_before ||
  1449       aType == nsCSSPseudoElements::ePseudo_after) {
  1450     flags |= eDoAnimation;
  1451   } else {
  1452     // Flex containers don't expect to have any pseudo-element children aside
  1453     // from ::before and ::after.  So if we have such a child, we're not
  1454     // actually in a flex container, and we should skip flex-item style fixup.
  1455     flags |= eSkipFlexItemStyleFixup;
  1458   nsRefPtr<nsStyleContext> result =
  1459     GetContext(aParentContext, ruleNode, visitedRuleNode,
  1460                pseudoTag, aType,
  1461                aParentElement, flags);
  1463   // For :before and :after pseudo-elements, having display: none or no
  1464   // 'content' property is equivalent to not having the pseudo-element
  1465   // at all.
  1466   if (result &&
  1467       (pseudoTag == nsCSSPseudoElements::before ||
  1468        pseudoTag == nsCSSPseudoElements::after)) {
  1469     const nsStyleDisplay *display = result->StyleDisplay();
  1470     const nsStyleContent *content = result->StyleContent();
  1471     // XXXldb What is contentCount for |content: ""|?
  1472     if (display->mDisplay == NS_STYLE_DISPLAY_NONE ||
  1473         content->ContentCount() == 0) {
  1474       result = nullptr;
  1478   return result.forget();
  1481 already_AddRefed<nsStyleContext>
  1482 nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
  1483                                      nsStyleContext* aParentContext)
  1485   NS_ENSURE_FALSE(mInShutdown, nullptr);
  1487 #ifdef DEBUG
  1488     bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag)
  1489 #ifdef MOZ_XUL
  1490                  && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
  1491 #endif
  1493     NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
  1494 #endif
  1496   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1497   AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
  1498   FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
  1499             &ruleWalker);
  1501   if (aPseudoTag == nsCSSAnonBoxes::pageContent) {
  1502     // Add any @page rules that are specified.
  1503     nsTArray<nsCSSPageRule*> rules;
  1504     nsTArray<css::ImportantRule*> importantRules;
  1505     nsPresContext* presContext = PresContext();
  1506     presContext->StyleSet()->AppendPageRules(presContext, rules);
  1507     for (uint32_t i = 0, i_end = rules.Length(); i != i_end; ++i) {
  1508       ruleWalker.Forward(rules[i]);
  1509       css::ImportantRule* importantRule = rules[i]->GetImportantRule();
  1510       if (importantRule) {
  1511         importantRules.AppendElement(importantRule);
  1514     for (uint32_t i = 0, i_end = importantRules.Length(); i != i_end; ++i) {
  1515       ruleWalker.Forward(importantRules[i]);
  1519   return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
  1520                     aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox,
  1521                     nullptr, eNoFlags);
  1524 #ifdef MOZ_XUL
  1525 already_AddRefed<nsStyleContext>
  1526 nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
  1527                                       nsIAtom* aPseudoTag,
  1528                                       nsStyleContext* aParentContext,
  1529                                       nsICSSPseudoComparator* aComparator)
  1531   NS_ENSURE_FALSE(mInShutdown, nullptr);
  1533   NS_ASSERTION(aPseudoTag, "must have pseudo tag");
  1534   NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
  1535                "Unexpected pseudo");
  1537   nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1538   TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
  1539                                aParentElement->OwnerDoc());
  1540   InitStyleScopes(treeContext, aParentElement);
  1541   XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
  1542                                 aPseudoTag, aComparator, treeContext);
  1543   FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
  1544             &ruleWalker);
  1546   nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1547   nsRuleNode *visitedRuleNode = nullptr;
  1549   if (treeContext.HaveRelevantLink()) {
  1550     treeContext.ResetForVisitedMatching();
  1551     ruleWalker.Reset();
  1552     FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data,
  1553               aParentElement, &ruleWalker);
  1554     visitedRuleNode = ruleWalker.CurrentNode();
  1557   return GetContext(aParentContext, ruleNode, visitedRuleNode,
  1558                     // For pseudos, |data.IsLink()| being true means that
  1559                     // our parent node is a link.
  1560                     aPseudoTag, nsCSSPseudoElements::ePseudo_XULTree,
  1561                     nullptr, eNoFlags);
  1563 #endif
  1565 bool
  1566 nsStyleSet::AppendFontFaceRules(nsPresContext* aPresContext,
  1567                                 nsTArray<nsFontFaceRuleContainer>& aArray)
  1569   NS_ENSURE_FALSE(mInShutdown, false);
  1571   for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
  1572     if (gCSSSheetTypes[i] == eScopedDocSheet)
  1573       continue;
  1574     nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
  1575                                     (mRuleProcessors[gCSSSheetTypes[i]].get());
  1576     if (ruleProc && !ruleProc->AppendFontFaceRules(aPresContext, aArray))
  1577       return false;
  1579   return true;
  1582 nsCSSKeyframesRule*
  1583 nsStyleSet::KeyframesRuleForName(nsPresContext* aPresContext,
  1584                                  const nsString& aName)
  1586   NS_ENSURE_FALSE(mInShutdown, nullptr);
  1588   for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
  1589     if (gCSSSheetTypes[i] == eScopedDocSheet)
  1590       continue;
  1591     nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
  1592                                     (mRuleProcessors[gCSSSheetTypes[i]].get());
  1593     if (!ruleProc)
  1594       continue;
  1595     nsCSSKeyframesRule* result =
  1596       ruleProc->KeyframesRuleForName(aPresContext, aName);
  1597     if (result)
  1598       return result;
  1600   return nullptr;
  1603 bool
  1604 nsStyleSet::AppendFontFeatureValuesRules(nsPresContext* aPresContext,
  1605                                  nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
  1607   NS_ENSURE_FALSE(mInShutdown, false);
  1609   for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
  1610     nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
  1611                                     (mRuleProcessors[gCSSSheetTypes[i]].get());
  1612     if (ruleProc &&
  1613         !ruleProc->AppendFontFeatureValuesRules(aPresContext, aArray))
  1615       return false;
  1618   return true;
  1621 already_AddRefed<gfxFontFeatureValueSet>
  1622 nsStyleSet::GetFontFeatureValuesLookup()
  1624   if (mInitFontFeatureValuesLookup) {
  1625     mInitFontFeatureValuesLookup = false;
  1627     nsTArray<nsCSSFontFeatureValuesRule*> rules;
  1628     AppendFontFeatureValuesRules(PresContext(), rules);
  1630     mFontFeatureValuesLookup = new gfxFontFeatureValueSet();
  1632     uint32_t i, numRules = rules.Length();
  1633     for (i = 0; i < numRules; i++) {
  1634       nsCSSFontFeatureValuesRule *rule = rules[i];
  1636       const nsTArray<nsString>& familyList = rule->GetFamilyList();
  1637       const nsTArray<gfxFontFeatureValueSet::FeatureValues>&
  1638         featureValues = rule->GetFeatureValues();
  1640       // for each family
  1641       uint32_t f, numFam;
  1643       numFam = familyList.Length();
  1644       for (f = 0; f < numFam; f++) {
  1645         const nsString& family = familyList.ElementAt(f);
  1646         nsAutoString silly(family);
  1647         mFontFeatureValuesLookup->AddFontFeatureValues(silly, featureValues);
  1652   nsRefPtr<gfxFontFeatureValueSet> lookup = mFontFeatureValuesLookup;
  1653   return lookup.forget();
  1656 bool
  1657 nsStyleSet::AppendPageRules(nsPresContext* aPresContext,
  1658                             nsTArray<nsCSSPageRule*>& aArray)
  1660   NS_ENSURE_FALSE(mInShutdown, false);
  1662   for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
  1663     if (gCSSSheetTypes[i] == eScopedDocSheet)
  1664       continue;
  1665     nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
  1666                                     (mRuleProcessors[gCSSSheetTypes[i]].get());
  1667     if (ruleProc && !ruleProc->AppendPageRules(aPresContext, aArray))
  1668       return false;
  1670   return true;
  1673 void
  1674 nsStyleSet::BeginShutdown(nsPresContext* aPresContext)
  1676   mInShutdown = 1;
  1677   mRoots.Clear(); // no longer valid, since we won't keep it up to date
  1680 void
  1681 nsStyleSet::Shutdown(nsPresContext* aPresContext)
  1683   mRuleTree->Destroy();
  1684   mRuleTree = nullptr;
  1686   // We can have old rule trees either because:
  1687   //   (1) we failed the assertions in EndReconstruct, or
  1688   //   (2) we're shutting down within a reconstruct (see bug 462392)
  1689   for (uint32_t i = mOldRuleTrees.Length(); i > 0; ) {
  1690     --i;
  1691     mOldRuleTrees[i]->Destroy();
  1693   mOldRuleTrees.Clear();
  1696 static const uint32_t kGCInterval = 300;
  1698 void
  1699 nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
  1700                                         nsStyleContext* aStyleContext)
  1702   if (mInShutdown)
  1703     return;
  1705   // Remove style contexts from mRoots even if mOldRuleTree is non-null.  This
  1706   // could be a style context from the new ruletree!
  1707   if (!aStyleContext->GetParent()) {
  1708     mRoots.RemoveElement(aStyleContext);
  1711   if (mInReconstruct)
  1712     return;
  1714   if (mUnusedRuleNodeCount >= kGCInterval) {
  1715     GCRuleTrees();
  1719 void
  1720 nsStyleSet::GCRuleTrees()
  1722   mUnusedRuleNodeCount = 0;
  1724   // Mark the style context tree by marking all style contexts which
  1725   // have no parent, which will mark all descendants.  This will reach
  1726   // style contexts in the undisplayed map and "additional style
  1727   // contexts" since they are descendants of the roots.
  1728   for (int32_t i = mRoots.Length() - 1; i >= 0; --i) {
  1729     mRoots[i]->Mark();
  1732   // Sweep the rule tree.
  1733 #ifdef DEBUG
  1734   bool deleted =
  1735 #endif
  1736     mRuleTree->Sweep();
  1737   NS_ASSERTION(!deleted, "Root node must not be gc'd");
  1739   // Sweep the old rule trees.
  1740   for (uint32_t i = mOldRuleTrees.Length(); i > 0; ) {
  1741     --i;
  1742     if (mOldRuleTrees[i]->Sweep()) {
  1743       // It was deleted, as it should be.
  1744       mOldRuleTrees.RemoveElementAt(i);
  1745     } else {
  1746       NS_NOTREACHED("old rule tree still referenced");
  1751 /**
  1752  * Return an equivalent to aRuleNode with both animation and transition
  1753  * rules removed, and post a restyle if needed.
  1754  */
  1755 static inline nsRuleNode*
  1756 SkipAnimationRules(nsRuleNode* aRuleNode, Element* aElement, bool isPseudo)
  1758   nsRuleNode* ruleNode = aRuleNode;
  1759   // The transition rule must be at the top of the cascade.
  1760   if (!ruleNode->IsRoot() &&
  1761       ruleNode->GetLevel() == nsStyleSet::eTransitionSheet) {
  1762     ruleNode = ruleNode->GetParent();
  1764   NS_ABORT_IF_FALSE(ruleNode->IsRoot() ||
  1765                     ruleNode->GetLevel() != nsStyleSet::eTransitionSheet,
  1766                     "can't have more than one transition rule");
  1768   // Use our existing ReplaceAnimationRule function to replace the
  1769   // animation rule, if present.
  1770   nsIStyleRule* animationRule = GetAnimationRule(ruleNode);
  1771   if (animationRule) {
  1772     ruleNode = ReplaceAnimationRule(ruleNode, animationRule, nullptr);
  1775   if (ruleNode != aRuleNode) {
  1776     NS_ASSERTION(aElement, "How can we have transition rules but no element?");
  1777     // Need to do an animation restyle, just like
  1778     // nsTransitionManager::WalkTransitionRule and
  1779     // nsAnimationManager::GetAnimationRule would.
  1780     nsRestyleHint hint = isPseudo ? eRestyle_Subtree : eRestyle_Self;
  1781     aRuleNode->PresContext()->PresShell()->RestyleForAnimation(aElement, hint);
  1783   return ruleNode;
  1786 already_AddRefed<nsStyleContext>
  1787 nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
  1788                                  nsStyleContext* aNewParentContext,
  1789                                  Element* aElement)
  1791   MOZ_ASSERT(aStyleContext, "aStyleContext must not be null");
  1793   // This short-circuit is OK because we don't call TryStartingTransition
  1794   // during style reresolution if the style context pointer hasn't changed.
  1795   if (aStyleContext->GetParent() == aNewParentContext) {
  1796     nsRefPtr<nsStyleContext> ret = aStyleContext;
  1797     return ret.forget();
  1800   nsIAtom* pseudoTag = aStyleContext->GetPseudo();
  1801   nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
  1802   nsRuleNode* ruleNode = aStyleContext->RuleNode();
  1804   // Skip transition rules as needed just like
  1805   // nsTransitionManager::WalkTransitionRule would.
  1806   bool skipAnimationRules = PresContext()->IsProcessingRestyles() &&
  1807     !PresContext()->IsProcessingAnimationStyleChange();
  1808   if (skipAnimationRules) {
  1809     // Make sure that we're not using transition rules or animation rules for
  1810     // our new style context.  If we need them, an animation restyle will
  1811     // provide.
  1812     ruleNode =
  1813       SkipAnimationRules(ruleNode, aElement,
  1814                          pseudoType !=
  1815                            nsCSSPseudoElements::ePseudo_NotPseudoElement);
  1818   nsRuleNode* visitedRuleNode = nullptr;
  1819   nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
  1820   // Reparenting a style context just changes where we inherit from,
  1821   // not what rules we match or what our DOM looks like.  In
  1822   // particular, it doesn't change whether this is a style context for
  1823   // a link.
  1824   if (visitedContext) {
  1825      visitedRuleNode = visitedContext->RuleNode();
  1826      // Again, skip transition rules as needed
  1827      if (skipAnimationRules) {
  1828       // FIXME do something here for animations?
  1829        visitedRuleNode =
  1830          SkipAnimationRules(visitedRuleNode, aElement,
  1831                             pseudoType !=
  1832                               nsCSSPseudoElements::ePseudo_NotPseudoElement);
  1836   uint32_t flags = eNoFlags;
  1837   if (aStyleContext->IsLinkContext()) {
  1838     flags |= eIsLink;
  1841   // If we're a style context for a link, then we already know whether
  1842   // our relevant link is visited, since that does not depend on our
  1843   // parent.  Otherwise, we need to match aNewParentContext.
  1844   bool relevantLinkVisited = aStyleContext->IsLinkContext() ?
  1845     aStyleContext->RelevantLinkVisited() :
  1846     aNewParentContext->RelevantLinkVisited();
  1848   if (relevantLinkVisited) {
  1849     flags |= eIsVisitedLink;
  1852   if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
  1853       pseudoType == nsCSSPseudoElements::ePseudo_before ||
  1854       pseudoType == nsCSSPseudoElements::ePseudo_after) {
  1855     flags |= eDoAnimation;
  1858   if (aElement && aElement->IsRootOfAnonymousSubtree()) {
  1859     // For anonymous subtree roots, don't tweak "display" value based on
  1860     // whether or not the parent is styled as a flex container. (If the parent
  1861     // has anonymous-subtree kids, then we know it's not actually going to get
  1862     // a flex container frame, anyway.)
  1863     flags |= eSkipFlexItemStyleFixup;
  1866   return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
  1867                     pseudoTag, pseudoType,
  1868                     aElement, flags);
  1871 struct MOZ_STACK_CLASS StatefulData : public StateRuleProcessorData {
  1872   StatefulData(nsPresContext* aPresContext, Element* aElement,
  1873                EventStates aStateMask, TreeMatchContext& aTreeMatchContext)
  1874     : StateRuleProcessorData(aPresContext, aElement, aStateMask,
  1875                              aTreeMatchContext),
  1876       mHint(nsRestyleHint(0))
  1877   {}
  1878   nsRestyleHint   mHint;
  1879 };
  1881 struct MOZ_STACK_CLASS StatefulPseudoElementData : public PseudoElementStateRuleProcessorData {
  1882   StatefulPseudoElementData(nsPresContext* aPresContext, Element* aElement,
  1883                EventStates aStateMask, nsCSSPseudoElements::Type aPseudoType,
  1884                TreeMatchContext& aTreeMatchContext, Element* aPseudoElement)
  1885     : PseudoElementStateRuleProcessorData(aPresContext, aElement, aStateMask,
  1886                                           aPseudoType, aTreeMatchContext,
  1887                                           aPseudoElement),
  1888       mHint(nsRestyleHint(0))
  1889   {}
  1890   nsRestyleHint   mHint;
  1891 };
  1893 static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
  1894                                          void *aData)
  1896   StatefulData* data = (StatefulData*)aData;
  1897   if (aProcessor->HasDocumentStateDependentStyle(data)) {
  1898     data->mHint = eRestyle_Self;
  1899     return false; // don't continue
  1901   return true; // continue
  1904 // Test if style is dependent on a document state.
  1905 bool
  1906 nsStyleSet::HasDocumentStateDependentStyle(nsPresContext* aPresContext,
  1907                                            nsIContent*    aContent,
  1908                                            EventStates    aStateMask)
  1910   if (!aContent || !aContent->IsElement())
  1911     return false;
  1913   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
  1914                                aContent->OwnerDoc());
  1915   InitStyleScopes(treeContext, aContent->AsElement());
  1916   StatefulData data(aPresContext, aContent->AsElement(), aStateMask,
  1917                     treeContext);
  1918   WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
  1919   return data.mHint != 0;
  1922 static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
  1923                                     void *aData)
  1925   StatefulData* data = (StatefulData*)aData;
  1926   nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
  1927   data->mHint = nsRestyleHint(data->mHint | hint);
  1928   return true; // continue
  1931 static bool SheetHasStatefulPseudoElementStyle(nsIStyleRuleProcessor* aProcessor,
  1932                                                void *aData)
  1934   StatefulPseudoElementData* data = (StatefulPseudoElementData*)aData;
  1935   nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
  1936   data->mHint = nsRestyleHint(data->mHint | hint);
  1937   return true; // continue
  1940 // Test if style is dependent on content state
  1941 nsRestyleHint
  1942 nsStyleSet::HasStateDependentStyle(nsPresContext*       aPresContext,
  1943                                    Element*             aElement,
  1944                                    EventStates          aStateMask)
  1946   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
  1947                                aElement->OwnerDoc());
  1948   InitStyleScopes(treeContext, aElement);
  1949   StatefulData data(aPresContext, aElement, aStateMask, treeContext);
  1950   WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
  1951   return data.mHint;
  1954 nsRestyleHint
  1955 nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
  1956                                    Element* aElement,
  1957                                    nsCSSPseudoElements::Type aPseudoType,
  1958                                    Element* aPseudoElement,
  1959                                    EventStates aStateMask)
  1961   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
  1962                                aElement->OwnerDoc());
  1963   InitStyleScopes(treeContext, aElement);
  1964   StatefulPseudoElementData data(aPresContext, aElement, aStateMask,
  1965                                  aPseudoType, treeContext, aPseudoElement);
  1966   WalkRuleProcessors(SheetHasStatefulPseudoElementStyle, &data, false);
  1967   return data.mHint;
  1970 struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
  1971   AttributeData(nsPresContext* aPresContext,
  1972                 Element* aElement, nsIAtom* aAttribute, int32_t aModType,
  1973                 bool aAttrHasChanged, TreeMatchContext& aTreeMatchContext)
  1974     : AttributeRuleProcessorData(aPresContext, aElement, aAttribute, aModType,
  1975                                  aAttrHasChanged, aTreeMatchContext),
  1976       mHint(nsRestyleHint(0))
  1977   {}
  1978   nsRestyleHint   mHint;
  1979 };
  1981 static bool
  1982 SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
  1984   AttributeData* data = (AttributeData*)aData;
  1985   nsRestyleHint hint = aProcessor->HasAttributeDependentStyle(data);
  1986   data->mHint = nsRestyleHint(data->mHint | hint);
  1987   return true; // continue
  1990 // Test if style is dependent on content state
  1991 nsRestyleHint
  1992 nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
  1993                                        Element*       aElement,
  1994                                        nsIAtom*       aAttribute,
  1995                                        int32_t        aModType,
  1996                                        bool           aAttrHasChanged)
  1998   TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
  1999                                aElement->OwnerDoc());
  2000   InitStyleScopes(treeContext, aElement);
  2001   AttributeData data(aPresContext, aElement, aAttribute,
  2002                      aModType, aAttrHasChanged, treeContext);
  2003   WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
  2004   return data.mHint;
  2007 bool
  2008 nsStyleSet::MediumFeaturesChanged(nsPresContext* aPresContext)
  2010   // We can't use WalkRuleProcessors without a content node.
  2011   bool stylesChanged = false;
  2012   for (uint32_t i = 0; i < ArrayLength(mRuleProcessors); ++i) {
  2013     nsIStyleRuleProcessor *processor = mRuleProcessors[i];
  2014     if (!processor) {
  2015       continue;
  2017     bool thisChanged = processor->MediumFeaturesChanged(aPresContext);
  2018     stylesChanged = stylesChanged || thisChanged;
  2020   for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); ++i) {
  2021     nsIStyleRuleProcessor *processor = mScopedDocSheetRuleProcessors[i];
  2022     bool thisChanged = processor->MediumFeaturesChanged(aPresContext);
  2023     stylesChanged = stylesChanged || thisChanged;
  2026   if (mBindingManager) {
  2027     bool thisChanged = false;
  2028     mBindingManager->MediumFeaturesChanged(aPresContext, &thisChanged);
  2029     stylesChanged = stylesChanged || thisChanged;
  2032   return stylesChanged;
  2035 nsCSSStyleSheet::EnsureUniqueInnerResult
  2036 nsStyleSet::EnsureUniqueInnerOnCSSSheets()
  2038   nsAutoTArray<nsCSSStyleSheet*, 32> queue;
  2039   for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
  2040     nsCOMArray<nsIStyleSheet> &sheets = mSheets[gCSSSheetTypes[i]];
  2041     for (uint32_t j = 0, j_end = sheets.Count(); j < j_end; ++j) {
  2042       nsCSSStyleSheet *sheet = static_cast<nsCSSStyleSheet*>(sheets[j]);
  2043       queue.AppendElement(sheet);
  2047   if (mBindingManager) {
  2048     mBindingManager->AppendAllSheets(queue);
  2051   nsCSSStyleSheet::EnsureUniqueInnerResult res =
  2052     nsCSSStyleSheet::eUniqueInner_AlreadyUnique;
  2053   while (!queue.IsEmpty()) {
  2054     uint32_t idx = queue.Length() - 1;
  2055     nsCSSStyleSheet *sheet = queue[idx];
  2056     queue.RemoveElementAt(idx);
  2058     nsCSSStyleSheet::EnsureUniqueInnerResult sheetRes =
  2059       sheet->EnsureUniqueInner();
  2060     if (sheetRes == nsCSSStyleSheet::eUniqueInner_ClonedInner) {
  2061       res = sheetRes;
  2064     // Enqueue all the sheet's children.
  2065     sheet->AppendAllChildSheets(queue);
  2067   return res;
  2070 nsIStyleRule*
  2071 nsStyleSet::InitialStyleRule()
  2073   if (!mInitialStyleRule) {
  2074     mInitialStyleRule = new nsInitialStyleRule;
  2076   return mInitialStyleRule;

mercurial