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/. */
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
12 #include "nsStyleSet.h"
14 #include "mozilla/ArrayUtils.h"
15 #include "mozilla/CSSStyleSheet.h"
16 #include "mozilla/EventStates.h"
17 #include "mozilla/MemoryReporting.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 "SVGAttrAnimationRuleProcessor.h"
37 #include "nsCSSRules.h"
38 #include "nsPrintfCString.h"
40 #include "RestyleManager.h"
42 using namespace mozilla
;
43 using namespace mozilla::dom
;
45 NS_IMPL_ISUPPORTS(nsEmptyStyleRule
, nsIStyleRule
)
48 nsEmptyStyleRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
54 nsEmptyStyleRule::List(FILE* out
, int32_t aIndent
) const
56 nsAutoCString indentStr
;
57 for (int32_t index
= aIndent
; --index
>= 0; ) {
58 indentStr
.AppendLiteral(" ");
60 fprintf_stderr(out
, "%s[empty style rule] {}\n", indentStr
.get());
64 NS_IMPL_ISUPPORTS(nsInitialStyleRule
, nsIStyleRule
)
67 nsInitialStyleRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
69 // Iterate over the property groups
70 for (nsStyleStructID sid
= nsStyleStructID(0);
71 sid
< nsStyleStructID_Length
; sid
= nsStyleStructID(sid
+ 1)) {
72 if (aRuleData
->mSIDs
& (1 << sid
)) {
73 // Iterate over nsCSSValues within the property group
74 nsCSSValue
* const value_start
=
75 aRuleData
->mValueStorage
+ aRuleData
->mValueOffsets
[sid
];
76 for (nsCSSValue
*value
= value_start
,
77 *value_end
= value
+ nsCSSProps::PropertyCountInStruct(sid
);
78 value
!= value_end
; ++value
) {
79 // If MathML is disabled take care not to set MathML properties (or we
80 // will trigger assertions in nsRuleNode)
81 if (sid
== eStyleStruct_Font
&&
82 !aRuleData
->mPresContext
->Document()->GetMathMLEnabled()) {
83 size_t index
= value
- value_start
;
84 if (index
== nsCSSProps::PropertyIndexInStruct(
85 eCSSProperty_script_level
) ||
86 index
== nsCSSProps::PropertyIndexInStruct(
87 eCSSProperty_script_size_multiplier
) ||
88 index
== nsCSSProps::PropertyIndexInStruct(
89 eCSSProperty_script_min_size
) ||
90 index
== nsCSSProps::PropertyIndexInStruct(
91 eCSSProperty_math_variant
) ||
92 index
== nsCSSProps::PropertyIndexInStruct(
93 eCSSProperty_math_display
)) {
97 if (value
->GetUnit() == eCSSUnit_Null
) {
98 value
->SetInitialValue();
107 nsInitialStyleRule::List(FILE* out
, int32_t aIndent
) const
109 nsAutoCString indentStr
;
110 for (int32_t index
= aIndent
; --index
>= 0; ) {
111 indentStr
.AppendLiteral(" ");
113 fprintf_stderr(out
, "%s[initial style rule] {}\n", indentStr
.get());
117 NS_IMPL_ISUPPORTS(nsDisableTextZoomStyleRule
, nsIStyleRule
)
120 nsDisableTextZoomStyleRule::MapRuleInfoInto(nsRuleData
* aRuleData
)
122 if (!(aRuleData
->mSIDs
& NS_STYLE_INHERIT_BIT(Font
)))
125 nsCSSValue
* value
= aRuleData
->ValueForTextZoom();
126 if (value
->GetUnit() == eCSSUnit_Null
)
127 value
->SetNoneValue();
132 nsDisableTextZoomStyleRule::List(FILE* out
, int32_t aIndent
) const
134 nsAutoCString indentStr
;
135 for (int32_t index
= aIndent
; --index
>= 0; ) {
136 indentStr
.AppendLiteral(" ");
138 fprintf_stderr(out
, "%s[disable text zoom style rule] {}\n", indentStr
.get());
142 static const nsStyleSet::sheetType gCSSSheetTypes
[] = {
143 // From lowest to highest in cascading order.
144 nsStyleSet::eAgentSheet
,
145 nsStyleSet::eUserSheet
,
146 nsStyleSet::eDocSheet
,
147 nsStyleSet::eScopedDocSheet
,
148 nsStyleSet::eOverrideSheet
151 nsStyleSet::nsStyleSet()
152 : mRuleTree(nullptr),
155 mAuthorStyleDisabled(false),
156 mInReconstruct(false),
157 mInitFontFeatureValuesLookup(true),
159 mUnusedRuleNodeCount(0)
164 nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const
166 size_t n
= aMallocSizeOf(this);
168 for (int i
= 0; i
< eSheetTypeCount
; i
++) {
169 if (mRuleProcessors
[i
]) {
170 n
+= mRuleProcessors
[i
]->SizeOfIncludingThis(aMallocSizeOf
);
172 // mSheets is a C-style array of nsCOMArrays. We do not own the sheets in
173 // the nsCOMArrays (either the nsLayoutStyleSheetCache singleton or our
174 // document owns them) so we do not count the sheets here (we pass nullptr
175 // as the aSizeOfElementIncludingThis argument). All we're doing here is
176 // counting the size of the nsCOMArrays' buffers.
177 n
+= mSheets
[i
].SizeOfExcludingThis(nullptr, aMallocSizeOf
);
180 for (uint32_t i
= 0; i
< mScopedDocSheetRuleProcessors
.Length(); i
++) {
181 n
+= mScopedDocSheetRuleProcessors
[i
]->SizeOfIncludingThis(aMallocSizeOf
);
183 n
+= mScopedDocSheetRuleProcessors
.SizeOfExcludingThis(aMallocSizeOf
);
185 n
+= mRoots
.SizeOfExcludingThis(aMallocSizeOf
);
186 n
+= mOldRuleTrees
.SizeOfExcludingThis(aMallocSizeOf
);
192 nsStyleSet::Init(nsPresContext
*aPresContext
)
194 mFirstLineRule
= new nsEmptyStyleRule
;
195 mFirstLetterRule
= new nsEmptyStyleRule
;
196 mPlaceholderRule
= new nsEmptyStyleRule
;
197 mDisableTextZoomStyleRule
= new nsDisableTextZoomStyleRule
;
199 mRuleTree
= nsRuleNode::CreateRootNode(aPresContext
);
201 // Make an explicit GatherRuleProcessors call for the levels that
202 // don't have style sheets. The other levels will have their calls
203 // triggered by DirtyRuleProcessors. (We should probably convert the
204 // ePresHintSheet and eStyleAttrSheet levels to work like this as
205 // well, and not implement nsIStyleSheet.)
206 GatherRuleProcessors(eAnimationSheet
);
207 GatherRuleProcessors(eTransitionSheet
);
208 GatherRuleProcessors(eSVGAttrAnimationSheet
);
212 nsStyleSet::BeginReconstruct()
214 NS_ASSERTION(!mInReconstruct
, "Unmatched begin/end?");
215 NS_ASSERTION(mRuleTree
, "Reconstructing before first construction?");
217 // Create a new rule tree root
218 nsRuleNode
* newTree
=
219 nsRuleNode::CreateRootNode(mRuleTree
->PresContext());
221 return NS_ERROR_OUT_OF_MEMORY
;
223 // Save the old rule tree so we can destroy it later
224 if (!mOldRuleTrees
.AppendElement(mRuleTree
)) {
226 return NS_ERROR_OUT_OF_MEMORY
;
229 // We need to keep mRoots so that the rule tree GC will only free the
230 // rule trees that really aren't referenced anymore (which should be
231 // all of them, if there are no bugs in reresolution code).
233 mInReconstruct
= true;
240 nsStyleSet::EndReconstruct()
242 NS_ASSERTION(mInReconstruct
, "Unmatched begin/end?");
243 mInReconstruct
= false;
245 for (int32_t i
= mRoots
.Length() - 1; i
>= 0; --i
) {
246 // Since nsStyleContext's mParent and mRuleNode are immutable, and
247 // style contexts own their parents, and nsStyleContext asserts in
248 // its constructor that the style context and its parent are in the
249 // same rule tree, we don't need to check any of the children of
250 // mRoots; we only need to check the rule nodes of mRoots
253 NS_ASSERTION(mRoots
[i
]->RuleNode()->RuleTree() == mRuleTree
,
254 "style context has old rule node");
257 // This *should* destroy the only element of mOldRuleTrees, but in
258 // case of some bugs (which would trigger the above assertions), it
264 nsStyleSet::SetQuirkStyleSheet(nsIStyleSheet
* aQuirkStyleSheet
)
266 NS_ASSERTION(aQuirkStyleSheet
, "Must have quirk sheet if this is called");
267 NS_ASSERTION(!mQuirkStyleSheet
, "Multiple calls to SetQuirkStyleSheet?");
268 NS_ASSERTION(mSheets
[eAgentSheet
].IndexOf(aQuirkStyleSheet
) != -1,
269 "Quirk style sheet not one of our agent sheets?");
270 mQuirkStyleSheet
= aQuirkStyleSheet
;
273 typedef nsDataHashtable
<nsPtrHashKey
<nsINode
>, uint32_t> ScopeDepthCache
;
275 // Returns the depth of a style scope element, with 1 being the depth of
276 // a style scope element that has no ancestor style scope elements. The
277 // depth does not count intervening non-scope elements.
279 GetScopeDepth(nsINode
* aScopeElement
, ScopeDepthCache
& aCache
)
281 nsINode
* parent
= aScopeElement
->GetParent();
282 if (!parent
|| !parent
->IsElementInStyleScope()) {
286 uint32_t depth
= aCache
.Get(aScopeElement
);
288 for (nsINode
* n
= parent
; n
; n
= n
->GetParent()) {
289 if (n
->IsScopedStyleRoot()) {
290 depth
= GetScopeDepth(n
, aCache
) + 1;
291 aCache
.Put(aScopeElement
, depth
);
299 struct ScopedSheetOrder
301 CSSStyleSheet
* mSheet
;
305 bool operator==(const ScopedSheetOrder
& aRHS
) const
307 return mDepth
== aRHS
.mDepth
&&
308 mOrder
== aRHS
.mOrder
;
311 bool operator<(const ScopedSheetOrder
& aRHS
) const
313 if (mDepth
!= aRHS
.mDepth
) {
314 return mDepth
< aRHS
.mDepth
;
316 return mOrder
< aRHS
.mOrder
;
320 // Sorts aSheets such that style sheets for ancestor scopes come
321 // before those for descendant scopes, and with sheets for a single
322 // scope in document order.
324 SortStyleSheetsByScope(nsTArray
<CSSStyleSheet
*>& aSheets
)
326 uint32_t n
= aSheets
.Length();
331 ScopeDepthCache cache
;
333 nsTArray
<ScopedSheetOrder
> sheets
;
336 // For each sheet, record the depth of its scope element and its original
338 for (uint32_t i
= 0; i
< n
; i
++) {
339 sheets
[i
].mSheet
= aSheets
[i
];
340 sheets
[i
].mDepth
= GetScopeDepth(aSheets
[i
]->GetScopeElement(), cache
);
341 sheets
[i
].mOrder
= i
;
344 // Sort by depth first, then document order.
347 for (uint32_t i
= 0; i
< n
; i
++) {
348 aSheets
[i
] = sheets
[i
].mSheet
;
353 nsStyleSet::GatherRuleProcessors(sheetType aType
)
355 nsCOMPtr
<nsIStyleRuleProcessor
> oldRuleProcessor(mRuleProcessors
[aType
]);
356 nsTArray
<nsCOMPtr
<nsIStyleRuleProcessor
>> oldScopedDocRuleProcessors
;
358 mRuleProcessors
[aType
] = nullptr;
359 if (aType
== eScopedDocSheet
) {
360 for (uint32_t i
= 0; i
< mScopedDocSheetRuleProcessors
.Length(); i
++) {
361 nsIStyleRuleProcessor
* processor
= mScopedDocSheetRuleProcessors
[i
].get();
363 static_cast<nsCSSRuleProcessor
*>(processor
)->GetScopeElement();
364 scope
->ClearIsScopedStyleRoot();
367 // Clear mScopedDocSheetRuleProcessors, but save it.
368 oldScopedDocRuleProcessors
.SwapElements(mScopedDocSheetRuleProcessors
);
370 if (mAuthorStyleDisabled
&& (aType
== eDocSheet
||
371 aType
== eScopedDocSheet
||
372 aType
== eStyleAttrSheet
)) {
373 // Don't regather if this level is disabled. Note that we gather
374 // preshint sheets no matter what, but then skip them for some
375 // elements later if mAuthorStyleDisabled.
379 // handle the types for which have a rule processor that does not
380 // implement the style sheet interface.
381 case eAnimationSheet
:
382 MOZ_ASSERT(mSheets
[aType
].IsEmpty());
383 mRuleProcessors
[aType
] = PresContext()->AnimationManager();
385 case eTransitionSheet
:
386 MOZ_ASSERT(mSheets
[aType
].IsEmpty());
387 mRuleProcessors
[aType
] = PresContext()->TransitionManager();
389 case eStyleAttrSheet
:
390 MOZ_ASSERT(mSheets
[aType
].IsEmpty());
391 mRuleProcessors
[aType
] = PresContext()->Document()->GetInlineStyleSheet();
394 MOZ_ASSERT(mSheets
[aType
].IsEmpty());
395 mRuleProcessors
[aType
] =
396 PresContext()->Document()->GetAttributeStyleSheet();
398 case eSVGAttrAnimationSheet
:
399 MOZ_ASSERT(mSheets
[aType
].IsEmpty());
400 mRuleProcessors
[aType
] =
401 PresContext()->Document()->GetSVGAttrAnimationRuleProcessor();
407 if (aType
== eScopedDocSheet
) {
408 // Create a rule processor for each scope.
409 uint32_t count
= mSheets
[eScopedDocSheet
].Count();
411 // Gather the scoped style sheets into an array as
412 // CSSStyleSheets, and mark all of their scope elements
413 // as scoped style roots.
414 nsTArray
<CSSStyleSheet
*> sheets(count
);
415 for (uint32_t i
= 0; i
< count
; i
++) {
416 nsRefPtr
<CSSStyleSheet
> sheet
=
417 do_QueryObject(mSheets
[eScopedDocSheet
].ObjectAt(i
));
418 sheets
.AppendElement(sheet
);
420 Element
* scope
= sheet
->GetScopeElement();
421 scope
->SetIsScopedStyleRoot();
424 // Sort the scoped style sheets so that those for the same scope are
425 // adjacent and that ancestor scopes come before descendent scopes.
426 SortStyleSheetsByScope(sheets
);
428 // Put the old scoped rule processors in a hashtable so that we
429 // can retrieve them efficiently, even in edge cases like the
430 // simultaneous removal and addition of a large number of elements
431 // with scoped sheets.
432 nsDataHashtable
<nsPtrHashKey
<Element
>,
433 nsCSSRuleProcessor
*> oldScopedRuleProcessorHash
;
434 for (size_t i
= oldScopedDocRuleProcessors
.Length(); i
-- != 0; ) {
435 nsCSSRuleProcessor
* oldRP
=
436 static_cast<nsCSSRuleProcessor
*>(oldScopedDocRuleProcessors
[i
].get());
437 Element
* scope
= oldRP
->GetScopeElement();
438 MOZ_ASSERT(!oldScopedRuleProcessorHash
.Get(scope
),
439 "duplicate rule processors for same scope element?");
440 oldScopedRuleProcessorHash
.Put(scope
, oldRP
);
443 uint32_t start
= 0, end
;
445 // Find the range of style sheets with the same scope.
446 Element
* scope
= sheets
[start
]->GetScopeElement();
448 while (end
< count
&& sheets
[end
]->GetScopeElement() == scope
) {
452 scope
->SetIsScopedStyleRoot();
454 // Create a rule processor for the scope.
455 nsTArray
<nsRefPtr
<CSSStyleSheet
>> sheetsForScope
;
456 sheetsForScope
.AppendElements(sheets
.Elements() + start
, end
- start
);
457 nsCSSRuleProcessor
* oldRP
= oldScopedRuleProcessorHash
.Get(scope
);
458 mScopedDocSheetRuleProcessors
.AppendElement
459 (new nsCSSRuleProcessor(sheetsForScope
, uint8_t(aType
), scope
,
463 } while (start
< count
);
467 if (mSheets
[aType
].Count()) {
472 case eOverrideSheet
: {
473 // levels containing CSS stylesheets (apart from eScopedDocSheet)
474 nsCOMArray
<nsIStyleSheet
>& sheets
= mSheets
[aType
];
475 nsTArray
<nsRefPtr
<CSSStyleSheet
>> cssSheets(sheets
.Count());
476 for (int32_t i
= 0, i_end
= sheets
.Count(); i
< i_end
; ++i
) {
477 nsRefPtr
<CSSStyleSheet
> cssSheet
= do_QueryObject(sheets
[i
]);
478 NS_ASSERTION(cssSheet
, "not a CSS sheet");
479 cssSheets
.AppendElement(cssSheet
);
481 mRuleProcessors
[aType
] =
482 new nsCSSRuleProcessor(cssSheets
, uint8_t(aType
), nullptr,
483 static_cast<nsCSSRuleProcessor
*>(
484 oldRuleProcessor
.get()));
488 // levels containing non-CSS stylesheets
489 NS_ASSERTION(mSheets
[aType
].Count() == 1, "only one sheet per level");
490 mRuleProcessors
[aType
] = do_QueryInterface(mSheets
[aType
][0]);
499 IsScopedStyleSheet(nsIStyleSheet
* aSheet
)
501 nsRefPtr
<CSSStyleSheet
> cssSheet
= do_QueryObject(aSheet
);
502 NS_ASSERTION(cssSheet
, "expected aSheet to be a CSSStyleSheet");
504 return cssSheet
->GetScopeElement();
508 nsStyleSet::AppendStyleSheet(sheetType aType
, nsIStyleSheet
*aSheet
)
510 NS_PRECONDITION(aSheet
, "null arg");
511 NS_ASSERTION(aSheet
->IsApplicable(),
512 "Inapplicable sheet being placed in style set");
513 mSheets
[aType
].RemoveObject(aSheet
);
514 if (!mSheets
[aType
].AppendObject(aSheet
))
515 return NS_ERROR_OUT_OF_MEMORY
;
517 return DirtyRuleProcessors(aType
);
521 nsStyleSet::PrependStyleSheet(sheetType aType
, nsIStyleSheet
*aSheet
)
523 NS_PRECONDITION(aSheet
, "null arg");
524 NS_ASSERTION(aSheet
->IsApplicable(),
525 "Inapplicable sheet being placed in style set");
526 mSheets
[aType
].RemoveObject(aSheet
);
527 if (!mSheets
[aType
].InsertObjectAt(aSheet
, 0))
528 return NS_ERROR_OUT_OF_MEMORY
;
530 return DirtyRuleProcessors(aType
);
534 nsStyleSet::RemoveStyleSheet(sheetType aType
, nsIStyleSheet
*aSheet
)
536 NS_PRECONDITION(aSheet
, "null arg");
537 NS_ASSERTION(aSheet
->IsComplete(),
538 "Incomplete sheet being removed from style set");
539 mSheets
[aType
].RemoveObject(aSheet
);
541 return DirtyRuleProcessors(aType
);
545 nsStyleSet::ReplaceSheets(sheetType aType
,
546 const nsCOMArray
<nsIStyleSheet
> &aNewSheets
)
548 mSheets
[aType
].Clear();
549 if (!mSheets
[aType
].AppendObjects(aNewSheets
))
550 return NS_ERROR_OUT_OF_MEMORY
;
552 return DirtyRuleProcessors(aType
);
556 nsStyleSet::InsertStyleSheetBefore(sheetType aType
, nsIStyleSheet
*aNewSheet
,
557 nsIStyleSheet
*aReferenceSheet
)
559 NS_PRECONDITION(aNewSheet
&& aReferenceSheet
, "null arg");
560 NS_ASSERTION(aNewSheet
->IsApplicable(),
561 "Inapplicable sheet being placed in style set");
563 mSheets
[aType
].RemoveObject(aNewSheet
);
564 int32_t idx
= mSheets
[aType
].IndexOf(aReferenceSheet
);
566 return NS_ERROR_INVALID_ARG
;
568 if (!mSheets
[aType
].InsertObjectAt(aNewSheet
, idx
))
569 return NS_ERROR_OUT_OF_MEMORY
;
571 return DirtyRuleProcessors(aType
);
575 nsStyleSet::DirtyRuleProcessors(sheetType aType
)
578 return GatherRuleProcessors(aType
);
580 mDirty
|= 1 << aType
;
585 nsStyleSet::GetAuthorStyleDisabled()
587 return mAuthorStyleDisabled
;
591 nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled
)
593 if (aStyleDisabled
== !mAuthorStyleDisabled
) {
594 mAuthorStyleDisabled
= aStyleDisabled
;
596 mDirty
|= 1 << eDocSheet
|
597 1 << eScopedDocSheet
|
598 1 << eStyleAttrSheet
;
604 // -------- Doc Sheets
607 nsStyleSet::AddDocStyleSheet(nsIStyleSheet
* aSheet
, nsIDocument
* aDocument
)
609 NS_PRECONDITION(aSheet
&& aDocument
, "null arg");
610 NS_ASSERTION(aSheet
->IsApplicable(),
611 "Inapplicable sheet being placed in style set");
613 sheetType type
= IsScopedStyleSheet(aSheet
) ?
616 nsCOMArray
<nsIStyleSheet
>& sheets
= mSheets
[type
];
618 sheets
.RemoveObject(aSheet
);
619 nsStyleSheetService
*sheetService
= nsStyleSheetService::GetInstance();
621 // lowest index first
622 int32_t newDocIndex
= aDocument
->GetIndexOfStyleSheet(aSheet
);
624 int32_t count
= sheets
.Count();
626 for (index
= 0; index
< count
; index
++) {
627 nsIStyleSheet
* sheet
= sheets
.ObjectAt(index
);
628 int32_t sheetDocIndex
= aDocument
->GetIndexOfStyleSheet(sheet
);
629 if (sheetDocIndex
> newDocIndex
)
632 // If the sheet is not owned by the document it can be an author
633 // sheet registered at nsStyleSheetService or an additional author
634 // sheet on the document, which means the new
635 // doc sheet should end up before it.
636 if (sheetDocIndex
< 0 &&
638 sheetService
->AuthorStyleSheets()->IndexOf(sheet
) >= 0) ||
639 sheet
== aDocument
->FirstAdditionalAuthorSheet()))
642 if (!sheets
.InsertObjectAt(aSheet
, index
))
643 return NS_ERROR_OUT_OF_MEMORY
;
645 return DirtyRuleProcessors(type
);
649 nsStyleSet::RemoveDocStyleSheet(nsIStyleSheet
*aSheet
)
651 nsRefPtr
<CSSStyleSheet
> cssSheet
= do_QueryObject(aSheet
);
652 bool isScoped
= cssSheet
&& cssSheet
->GetScopeElement();
653 return RemoveStyleSheet(isScoped
? eScopedDocSheet
: eDocSheet
, aSheet
);
658 nsStyleSet::BeginUpdate()
664 nsStyleSet::EndUpdate()
666 NS_ASSERTION(mBatching
> 0, "Unbalanced EndUpdate");
668 // We're not completely done yet.
672 for (int i
= 0; i
< eSheetTypeCount
; ++i
) {
673 if (mDirty
& (1 << i
)) {
674 nsresult rv
= GatherRuleProcessors(sheetType(i
));
675 NS_ENSURE_SUCCESS(rv
, rv
);
684 nsStyleSet::EnableQuirkStyleSheet(bool aEnable
)
686 if (!mQuirkStyleSheet
) {
687 // SVG-as-an-image doesn't load this sheet
693 nsCOMPtr
<nsIDOMCSSStyleSheet
> domSheet
=
694 do_QueryInterface(mQuirkStyleSheet
);
695 domSheet
->GetDisabled(&oldEnabled
);
696 oldEnabled
= !oldEnabled
;
699 mQuirkStyleSheet
->SetEnabled(aEnable
);
701 // This should always be OK, since SetEnabled should call
702 // ClearRuleCascades.
703 // Note that we can hit this codepath multiple times when document.open()
704 // (potentially implied) happens multiple times.
705 if (mRuleProcessors
[eAgentSheet
] && aEnable
!= oldEnabled
) {
706 static_cast<nsCSSRuleProcessor
*>(static_cast<nsIStyleRuleProcessor
*>(
707 mRuleProcessors
[eAgentSheet
]))->AssertQuirksChangeOK();
714 EnumRulesMatching(nsIStyleRuleProcessor
* aProcessor
, void* aData
)
716 T
* data
= static_cast<T
*>(aData
);
717 aProcessor
->RulesMatching(data
);
722 IsMoreSpecificThanAnimation(nsRuleNode
*aRuleNode
)
724 return !aRuleNode
->IsRoot() &&
725 (aRuleNode
->GetLevel() == nsStyleSet::eTransitionSheet
||
726 aRuleNode
->IsImportantRule());
730 GetAnimationRule(nsRuleNode
*aRuleNode
)
732 nsRuleNode
*n
= aRuleNode
;
733 while (IsMoreSpecificThanAnimation(n
)) {
737 if (n
->IsRoot() || n
->GetLevel() != nsStyleSet::eAnimationSheet
) {
745 ReplaceAnimationRule(nsRuleNode
*aOldRuleNode
,
746 nsIStyleRule
*aOldAnimRule
,
747 nsIStyleRule
*aNewAnimRule
)
749 nsTArray
<nsRuleNode
*> moreSpecificNodes
;
751 nsRuleNode
*n
= aOldRuleNode
;
752 while (IsMoreSpecificThanAnimation(n
)) {
753 moreSpecificNodes
.AppendElement(n
);
758 NS_ABORT_IF_FALSE(n
->GetRule() == aOldAnimRule
, "wrong rule");
759 NS_ABORT_IF_FALSE(n
->GetLevel() == nsStyleSet::eAnimationSheet
,
764 NS_ABORT_IF_FALSE(!IsMoreSpecificThanAnimation(n
) &&
766 n
->GetLevel() != nsStyleSet::eAnimationSheet
),
770 n
= n
->Transition(aNewAnimRule
, nsStyleSet::eAnimationSheet
, false);
773 for (uint32_t i
= moreSpecificNodes
.Length(); i
-- != 0; ) {
774 nsRuleNode
*oldNode
= moreSpecificNodes
[i
];
775 n
= n
->Transition(oldNode
->GetRule(), oldNode
->GetLevel(),
776 oldNode
->IsImportantRule());
783 * |GetContext| implements sharing of style contexts (not just the data
784 * on the rule nodes) between siblings and cousins of the same
785 * generation. (It works for cousins of the same generation since
786 * |aParentContext| could itself be a shared context.)
788 already_AddRefed
<nsStyleContext
>
789 nsStyleSet::GetContext(nsStyleContext
* aParentContext
,
790 nsRuleNode
* aRuleNode
,
791 // aVisitedRuleNode may be null; if it is null
792 // it means that we don't need to force creation
793 // of a StyleIfVisited. (But if we make one
794 // because aParentContext has one, then aRuleNode
796 nsRuleNode
* aVisitedRuleNode
,
798 nsCSSPseudoElements::Type aPseudoType
,
799 Element
* aElementForAnimation
,
802 NS_PRECONDITION((!aPseudoTag
&&
804 nsCSSPseudoElements::ePseudo_NotPseudoElement
) ||
806 nsCSSPseudoElements::GetPseudoType(aPseudoTag
) ==
810 if (aVisitedRuleNode
== aRuleNode
) {
811 // No need to force creation of a visited style in this case.
812 aVisitedRuleNode
= nullptr;
815 // Ensure |aVisitedRuleNode != nullptr| corresponds to the need to
816 // create an if-visited style context, and that in that case, we have
817 // parentIfVisited set correctly.
818 nsStyleContext
*parentIfVisited
=
819 aParentContext
? aParentContext
->GetStyleIfVisited() : nullptr;
820 if (parentIfVisited
) {
821 if (!aVisitedRuleNode
) {
822 aVisitedRuleNode
= aRuleNode
;
825 if (aVisitedRuleNode
) {
826 parentIfVisited
= aParentContext
;
830 if (aFlags
& eIsLink
) {
831 // If this node is a link, we want its visited's style context's
832 // parent to be the regular style context of its parent, because
833 // only the visitedness of the relevant link should influence style.
834 parentIfVisited
= aParentContext
;
837 bool relevantLinkVisited
= (aFlags
& eIsLink
) ?
838 (aFlags
& eIsVisitedLink
) :
839 (aParentContext
&& aParentContext
->RelevantLinkVisited());
841 nsRefPtr
<nsStyleContext
> result
;
843 result
= aParentContext
->FindChildWithRules(aPseudoTag
, aRuleNode
,
845 relevantLinkVisited
);
849 fprintf(stdout
, "--- SharedSC %d ---\n", ++gSharedCount
);
851 fprintf(stdout
, "+++ NewSC %d +++\n", ++gNewCount
);
855 result
= NS_NewStyleContext(aParentContext
, aPseudoTag
, aPseudoType
,
857 aFlags
& eSkipParentDisplayBasedStyleFixup
);
858 if (aVisitedRuleNode
) {
859 nsRefPtr
<nsStyleContext
> resultIfVisited
=
860 NS_NewStyleContext(parentIfVisited
, aPseudoTag
, aPseudoType
,
862 aFlags
& eSkipParentDisplayBasedStyleFixup
);
863 if (!parentIfVisited
) {
864 mRoots
.AppendElement(resultIfVisited
);
866 resultIfVisited
->SetIsStyleIfVisited();
867 result
->SetStyleIfVisited(resultIfVisited
.forget());
869 if (relevantLinkVisited
) {
870 result
->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED
);
873 if (!aParentContext
) {
874 mRoots
.AppendElement(result
);
878 NS_ASSERTION(result
->GetPseudoType() == aPseudoType
, "Unexpected type");
879 NS_ASSERTION(result
->GetPseudo() == aPseudoTag
, "Unexpected pseudo");
882 if (aFlags
& eDoAnimation
) {
883 // Normally the animation manager has already added the correct
884 // style rule. However, if the animation-name just changed, it
885 // might have been wrong. So ask it to double-check based on the
886 // resulting style context.
887 nsIStyleRule
*oldAnimRule
= GetAnimationRule(aRuleNode
);
888 nsIStyleRule
*animRule
= PresContext()->AnimationManager()->
889 CheckAnimationRule(result
, aElementForAnimation
);
890 NS_ABORT_IF_FALSE(result
->RuleNode() == aRuleNode
,
891 "unexpected rule node");
892 NS_ABORT_IF_FALSE(!result
->GetStyleIfVisited() == !aVisitedRuleNode
,
893 "unexpected visited rule node");
894 NS_ABORT_IF_FALSE(!aVisitedRuleNode
||
895 result
->GetStyleIfVisited()->RuleNode() ==
897 "unexpected visited rule node");
898 NS_ABORT_IF_FALSE(!aVisitedRuleNode
||
899 oldAnimRule
== GetAnimationRule(aVisitedRuleNode
),
900 "animation rule mismatch between rule nodes");
901 if (oldAnimRule
!= animRule
) {
902 nsRuleNode
*ruleNode
=
903 ReplaceAnimationRule(aRuleNode
, oldAnimRule
, animRule
);
904 nsRuleNode
*visitedRuleNode
= aVisitedRuleNode
905 ? ReplaceAnimationRule(aVisitedRuleNode
, oldAnimRule
, animRule
)
907 NS_ABORT_IF_FALSE(!visitedRuleNode
||
908 GetAnimationRule(ruleNode
) ==
909 GetAnimationRule(visitedRuleNode
),
910 "animation rule mismatch between rule nodes");
911 result
= GetContext(aParentContext
, ruleNode
, visitedRuleNode
,
912 aPseudoTag
, aPseudoType
, nullptr,
913 aFlags
& ~eDoAnimation
);
917 if (aElementForAnimation
&& aElementForAnimation
->IsHTML(nsGkAtoms::body
) &&
918 aPseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
&&
919 PresContext()->CompatibilityMode() == eCompatibility_NavQuirks
) {
920 nsIDocument
* doc
= aElementForAnimation
->GetCurrentDoc();
921 if (doc
&& doc
->GetBodyElement() == aElementForAnimation
) {
922 // Update the prescontext's body color
923 PresContext()->SetBodyTextColor(result
->StyleColor()->mColor
);
927 return result
.forget();
931 nsStyleSet::AddImportantRules(nsRuleNode
* aCurrLevelNode
,
932 nsRuleNode
* aLastPrevLevelNode
,
933 nsRuleWalker
* aRuleWalker
)
935 NS_ASSERTION(aCurrLevelNode
&&
936 aCurrLevelNode
!= aLastPrevLevelNode
, "How did we get here?");
938 nsAutoTArray
<nsIStyleRule
*, 16> importantRules
;
939 for (nsRuleNode
*node
= aCurrLevelNode
; node
!= aLastPrevLevelNode
;
940 node
= node
->GetParent()) {
941 // We guarantee that we never walk the root node here, so no need
942 // to null-check GetRule(). Furthermore, it must be a CSS rule.
943 NS_ASSERTION(nsRefPtr
<css::StyleRule
>(do_QueryObject(node
->GetRule())),
944 "Unexpected non-CSS rule");
946 nsIStyleRule
* impRule
=
947 static_cast<css::StyleRule
*>(node
->GetRule())->GetImportantRule();
949 importantRules
.AppendElement(impRule
);
952 NS_ASSERTION(importantRules
.Length() != 0,
953 "Why did we think there were important rules?");
955 for (uint32_t i
= importantRules
.Length(); i
-- != 0; ) {
956 aRuleWalker
->Forward(importantRules
[i
]);
962 nsStyleSet::AssertNoImportantRules(nsRuleNode
* aCurrLevelNode
,
963 nsRuleNode
* aLastPrevLevelNode
)
968 for (nsRuleNode
*node
= aCurrLevelNode
; node
!= aLastPrevLevelNode
;
969 node
= node
->GetParent()) {
970 nsRefPtr
<css::StyleRule
> rule(do_QueryObject(node
->GetRule()));
971 NS_ASSERTION(rule
, "Unexpected non-CSS rule");
973 NS_ASSERTION(!rule
->GetImportantRule(), "Unexpected important rule");
978 nsStyleSet::AssertNoCSSRules(nsRuleNode
* aCurrLevelNode
,
979 nsRuleNode
* aLastPrevLevelNode
)
984 for (nsRuleNode
*node
= aCurrLevelNode
; node
!= aLastPrevLevelNode
;
985 node
= node
->GetParent()) {
986 nsIStyleRule
*rule
= node
->GetRule();
987 nsRefPtr
<css::StyleRule
> cssRule(do_QueryObject(rule
));
988 NS_ASSERTION(!cssRule
|| !cssRule
->Selector(), "Unexpected CSS rule");
993 // Enumerate the rules in a way that cares about the order of the rules.
995 nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc
,
996 RuleProcessorData
* aData
, Element
* aElement
,
997 nsRuleWalker
* aRuleWalker
)
999 PROFILER_LABEL("nsStyleSet", "FileRules",
1000 js::ProfileEntry::Category::CSS
);
1002 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
1005 // [least important]
1006 // - UA normal rules = Agent normal
1007 // - User normal rules = User normal
1008 // - Presentation hints = PresHint normal
1009 // - SVG Animation (highest pres hint) = SVGAttrAnimation normal
1010 // - Author normal rules = Document normal
1011 // - Override normal rules = Override normal
1012 // - animation rules = Animation normal
1013 // - Author !important rules = Document !important
1014 // - Override !important rules = Override !important
1015 // - User !important rules = User !important
1016 // - UA !important rules = Agent !important
1017 // - transition rules = Transition normal
1020 // Save off the last rule before we start walking our agent sheets;
1021 // this will be either the root or one of the restriction rules.
1022 nsRuleNode
* lastRestrictionRN
= aRuleWalker
->CurrentNode();
1024 aRuleWalker
->SetLevel(eAgentSheet
, false, true);
1025 if (mRuleProcessors
[eAgentSheet
])
1026 (*aCollectorFunc
)(mRuleProcessors
[eAgentSheet
], aData
);
1027 nsRuleNode
* lastAgentRN
= aRuleWalker
->CurrentNode();
1028 bool haveImportantUARules
= !aRuleWalker
->GetCheckForImportantRules();
1030 aRuleWalker
->SetLevel(eUserSheet
, false, true);
1031 bool skipUserStyles
=
1032 aElement
&& aElement
->IsInNativeAnonymousSubtree();
1033 if (!skipUserStyles
&& mRuleProcessors
[eUserSheet
]) // NOTE: different
1034 (*aCollectorFunc
)(mRuleProcessors
[eUserSheet
], aData
);
1035 nsRuleNode
* lastUserRN
= aRuleWalker
->CurrentNode();
1036 bool haveImportantUserRules
= !aRuleWalker
->GetCheckForImportantRules();
1038 aRuleWalker
->SetLevel(ePresHintSheet
, false, false);
1039 if (mRuleProcessors
[ePresHintSheet
])
1040 (*aCollectorFunc
)(mRuleProcessors
[ePresHintSheet
], aData
);
1042 aRuleWalker
->SetLevel(eSVGAttrAnimationSheet
, false, false);
1043 if (mRuleProcessors
[eSVGAttrAnimationSheet
])
1044 (*aCollectorFunc
)(mRuleProcessors
[eSVGAttrAnimationSheet
], aData
);
1045 nsRuleNode
* lastSVGAttrAnimationRN
= aRuleWalker
->CurrentNode();
1047 aRuleWalker
->SetLevel(eDocSheet
, false, true);
1048 bool cutOffInheritance
= false;
1049 if (mBindingManager
&& aElement
) {
1050 // We can supply additional document-level sheets that should be walked.
1051 mBindingManager
->WalkRules(aCollectorFunc
,
1052 static_cast<ElementDependentRuleProcessorData
*>(aData
),
1053 &cutOffInheritance
);
1055 if (!skipUserStyles
&& !cutOffInheritance
&& // NOTE: different
1056 mRuleProcessors
[eDocSheet
])
1057 (*aCollectorFunc
)(mRuleProcessors
[eDocSheet
], aData
);
1058 nsRuleNode
* lastDocRN
= aRuleWalker
->CurrentNode();
1059 bool haveImportantDocRules
= !aRuleWalker
->GetCheckForImportantRules();
1060 nsTArray
<nsRuleNode
*> lastScopedRNs
;
1061 nsTArray
<bool> haveImportantScopedRules
;
1062 bool haveAnyImportantScopedRules
= false;
1063 if (!skipUserStyles
&& !cutOffInheritance
&&
1064 aElement
&& aElement
->IsElementInStyleScope()) {
1065 lastScopedRNs
.SetLength(mScopedDocSheetRuleProcessors
.Length());
1066 haveImportantScopedRules
.SetLength(mScopedDocSheetRuleProcessors
.Length());
1067 for (uint32_t i
= 0; i
< mScopedDocSheetRuleProcessors
.Length(); i
++) {
1068 aRuleWalker
->SetLevel(eScopedDocSheet
, false, true);
1069 nsCSSRuleProcessor
* processor
=
1070 static_cast<nsCSSRuleProcessor
*>(mScopedDocSheetRuleProcessors
[i
].get());
1071 aData
->mScope
= processor
->GetScopeElement();
1072 (*aCollectorFunc
)(mScopedDocSheetRuleProcessors
[i
], aData
);
1073 lastScopedRNs
[i
] = aRuleWalker
->CurrentNode();
1074 haveImportantScopedRules
[i
] = !aRuleWalker
->GetCheckForImportantRules();
1075 haveAnyImportantScopedRules
= haveAnyImportantScopedRules
|| haveImportantScopedRules
[i
];
1077 aData
->mScope
= nullptr;
1079 nsRuleNode
* lastScopedRN
= aRuleWalker
->CurrentNode();
1080 aRuleWalker
->SetLevel(eStyleAttrSheet
, false, true);
1081 if (mRuleProcessors
[eStyleAttrSheet
])
1082 (*aCollectorFunc
)(mRuleProcessors
[eStyleAttrSheet
], aData
);
1083 nsRuleNode
* lastStyleAttrRN
= aRuleWalker
->CurrentNode();
1084 bool haveImportantStyleAttrRules
= !aRuleWalker
->GetCheckForImportantRules();
1086 aRuleWalker
->SetLevel(eOverrideSheet
, false, true);
1087 if (mRuleProcessors
[eOverrideSheet
])
1088 (*aCollectorFunc
)(mRuleProcessors
[eOverrideSheet
], aData
);
1089 nsRuleNode
* lastOvrRN
= aRuleWalker
->CurrentNode();
1090 bool haveImportantOverrideRules
= !aRuleWalker
->GetCheckForImportantRules();
1092 // This needs to match IsMoreSpecificThanAnimation() above.
1093 aRuleWalker
->SetLevel(eAnimationSheet
, false, false);
1094 (*aCollectorFunc
)(mRuleProcessors
[eAnimationSheet
], aData
);
1096 if (haveAnyImportantScopedRules
) {
1097 for (uint32_t i
= lastScopedRNs
.Length(); i
-- != 0; ) {
1098 aRuleWalker
->SetLevel(eScopedDocSheet
, true, false);
1099 nsRuleNode
* startRN
= lastScopedRNs
[i
];
1100 nsRuleNode
* endRN
= i
== 0 ? lastDocRN
: lastScopedRNs
[i
- 1];
1101 if (haveImportantScopedRules
[i
]) {
1102 AddImportantRules(startRN
, endRN
, aRuleWalker
); // scoped
1106 AssertNoImportantRules(startRN
, endRN
);
1113 AssertNoImportantRules(lastScopedRN
, lastDocRN
);
1117 if (haveImportantDocRules
) {
1118 aRuleWalker
->SetLevel(eDocSheet
, true, false);
1119 AddImportantRules(lastDocRN
, lastSVGAttrAnimationRN
, aRuleWalker
); // doc
1123 AssertNoImportantRules(lastDocRN
, lastSVGAttrAnimationRN
);
1127 if (haveImportantStyleAttrRules
) {
1128 aRuleWalker
->SetLevel(eStyleAttrSheet
, true, false);
1129 AddImportantRules(lastStyleAttrRN
, lastScopedRN
, aRuleWalker
); // style attr
1133 AssertNoImportantRules(lastStyleAttrRN
, lastScopedRN
);
1137 if (haveImportantOverrideRules
) {
1138 aRuleWalker
->SetLevel(eOverrideSheet
, true, false);
1139 AddImportantRules(lastOvrRN
, lastStyleAttrRN
, aRuleWalker
); // override
1143 AssertNoImportantRules(lastOvrRN
, lastStyleAttrRN
);
1148 AssertNoCSSRules(lastSVGAttrAnimationRN
, lastUserRN
);
1151 if (haveImportantUserRules
) {
1152 aRuleWalker
->SetLevel(eUserSheet
, true, false);
1153 AddImportantRules(lastUserRN
, lastAgentRN
, aRuleWalker
); //user
1157 AssertNoImportantRules(lastUserRN
, lastAgentRN
);
1161 if (haveImportantUARules
) {
1162 aRuleWalker
->SetLevel(eAgentSheet
, true, false);
1163 AddImportantRules(lastAgentRN
, lastRestrictionRN
, aRuleWalker
); //agent
1167 AssertNoImportantRules(lastAgentRN
, lastRestrictionRN
);
1172 AssertNoCSSRules(lastRestrictionRN
, mRuleTree
);
1176 nsRuleNode
*lastImportantRN
= aRuleWalker
->CurrentNode();
1178 aRuleWalker
->SetLevel(eTransitionSheet
, false, false);
1179 (*aCollectorFunc
)(mRuleProcessors
[eTransitionSheet
], aData
);
1181 AssertNoCSSRules(aRuleWalker
->CurrentNode(), lastImportantRN
);
1186 // Enumerate all the rules in a way that doesn't care about the order
1187 // of the rules and doesn't walk !important-rules.
1189 nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc
,
1190 ElementDependentRuleProcessorData
* aData
,
1191 bool aWalkAllXBLStylesheets
)
1193 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
1195 if (mRuleProcessors
[eAgentSheet
])
1196 (*aFunc
)(mRuleProcessors
[eAgentSheet
], aData
);
1198 bool skipUserStyles
= aData
->mElement
->IsInNativeAnonymousSubtree();
1199 if (!skipUserStyles
&& mRuleProcessors
[eUserSheet
]) // NOTE: different
1200 (*aFunc
)(mRuleProcessors
[eUserSheet
], aData
);
1202 if (mRuleProcessors
[ePresHintSheet
])
1203 (*aFunc
)(mRuleProcessors
[ePresHintSheet
], aData
);
1205 if (mRuleProcessors
[eSVGAttrAnimationSheet
])
1206 (*aFunc
)(mRuleProcessors
[eSVGAttrAnimationSheet
], aData
);
1208 bool cutOffInheritance
= false;
1209 if (mBindingManager
) {
1210 // We can supply additional document-level sheets that should be walked.
1211 if (aWalkAllXBLStylesheets
) {
1212 mBindingManager
->WalkAllRules(aFunc
, aData
);
1214 mBindingManager
->WalkRules(aFunc
, aData
, &cutOffInheritance
);
1217 if (!skipUserStyles
&& !cutOffInheritance
) {
1218 if (mRuleProcessors
[eDocSheet
]) // NOTE: different
1219 (*aFunc
)(mRuleProcessors
[eDocSheet
], aData
);
1220 if (aData
->mElement
->IsElementInStyleScope()) {
1221 for (uint32_t i
= 0; i
< mScopedDocSheetRuleProcessors
.Length(); i
++)
1222 (*aFunc
)(mScopedDocSheetRuleProcessors
[i
], aData
);
1225 if (mRuleProcessors
[eStyleAttrSheet
])
1226 (*aFunc
)(mRuleProcessors
[eStyleAttrSheet
], aData
);
1227 if (mRuleProcessors
[eOverrideSheet
])
1228 (*aFunc
)(mRuleProcessors
[eOverrideSheet
], aData
);
1229 (*aFunc
)(mRuleProcessors
[eAnimationSheet
], aData
);
1230 (*aFunc
)(mRuleProcessors
[eTransitionSheet
], aData
);
1234 InitStyleScopes(TreeMatchContext
& aTreeContext
, Element
* aElement
)
1236 if (aElement
->IsElementInStyleScope()) {
1237 aTreeContext
.InitStyleScopes(aElement
->GetParentElementCrossingShadowRoot());
1241 already_AddRefed
<nsStyleContext
>
1242 nsStyleSet::ResolveStyleFor(Element
* aElement
,
1243 nsStyleContext
* aParentContext
)
1245 TreeMatchContext
treeContext(true, nsRuleWalker::eRelevantLinkUnvisited
,
1246 aElement
->OwnerDoc());
1247 InitStyleScopes(treeContext
, aElement
);
1248 return ResolveStyleFor(aElement
, aParentContext
, treeContext
);
1251 already_AddRefed
<nsStyleContext
>
1252 nsStyleSet::ResolveStyleFor(Element
* aElement
,
1253 nsStyleContext
* aParentContext
,
1254 TreeMatchContext
& aTreeMatchContext
)
1256 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1257 NS_ASSERTION(aElement
, "aElement must not be null");
1259 nsRuleWalker
ruleWalker(mRuleTree
, mAuthorStyleDisabled
);
1260 aTreeMatchContext
.ResetForUnvisitedMatching();
1261 ElementRuleProcessorData
data(PresContext(), aElement
, &ruleWalker
,
1263 WalkDisableTextZoomRule(aElement
, &ruleWalker
);
1264 FileRules(EnumRulesMatching
<ElementRuleProcessorData
>, &data
, aElement
,
1267 nsRuleNode
*ruleNode
= ruleWalker
.CurrentNode();
1268 nsRuleNode
*visitedRuleNode
= nullptr;
1270 if (aTreeMatchContext
.HaveRelevantLink()) {
1271 aTreeMatchContext
.ResetForVisitedMatching();
1273 FileRules(EnumRulesMatching
<ElementRuleProcessorData
>, &data
, aElement
,
1275 visitedRuleNode
= ruleWalker
.CurrentNode();
1278 uint32_t flags
= eDoAnimation
;
1279 if (nsCSSRuleProcessor::IsLink(aElement
)) {
1282 if (nsCSSRuleProcessor::GetContentState(aElement
, aTreeMatchContext
).
1283 HasState(NS_EVENT_STATE_VISITED
)) {
1284 flags
|= eIsVisitedLink
;
1286 if (aTreeMatchContext
.mSkippingParentDisplayBasedStyleFixup
) {
1287 flags
|= eSkipParentDisplayBasedStyleFixup
;
1290 return GetContext(aParentContext
, ruleNode
, visitedRuleNode
,
1291 nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement
,
1295 already_AddRefed
<nsStyleContext
>
1296 nsStyleSet::ResolveStyleForRules(nsStyleContext
* aParentContext
,
1297 const nsTArray
< nsCOMPtr
<nsIStyleRule
> > &aRules
)
1299 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1301 nsRuleWalker
ruleWalker(mRuleTree
, mAuthorStyleDisabled
);
1302 // FIXME: Perhaps this should be passed in, but it probably doesn't
1304 ruleWalker
.SetLevel(eDocSheet
, false, false);
1305 for (uint32_t i
= 0; i
< aRules
.Length(); i
++) {
1306 ruleWalker
.ForwardOnPossiblyCSSRule(aRules
.ElementAt(i
));
1309 return GetContext(aParentContext
, ruleWalker
.CurrentNode(), nullptr,
1310 nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement
,
1314 already_AddRefed
<nsStyleContext
>
1315 nsStyleSet::ResolveStyleByAddingRules(nsStyleContext
* aBaseContext
,
1316 const nsCOMArray
<nsIStyleRule
> &aRules
)
1318 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1320 nsRuleWalker
ruleWalker(mRuleTree
, mAuthorStyleDisabled
);
1321 ruleWalker
.SetCurrentNode(aBaseContext
->RuleNode());
1322 // This needs to be the transition sheet because that is the highest
1323 // level of the cascade, and thus the only thing that makes sense if
1324 // we are ever going to call ResolveStyleWithReplacement on the
1325 // resulting context. It's also the right thing for the one case (the
1326 // transition manager's cover rule) where we put the result of this
1327 // function in the style context tree.
1328 ruleWalker
.SetLevel(eTransitionSheet
, false, false);
1329 for (int32_t i
= 0; i
< aRules
.Count(); i
++) {
1330 ruleWalker
.ForwardOnPossiblyCSSRule(aRules
.ObjectAt(i
));
1333 nsRuleNode
*ruleNode
= ruleWalker
.CurrentNode();
1334 nsRuleNode
*visitedRuleNode
= nullptr;
1336 if (aBaseContext
->GetStyleIfVisited()) {
1337 ruleWalker
.SetCurrentNode(aBaseContext
->GetStyleIfVisited()->RuleNode());
1338 for (int32_t i
= 0; i
< aRules
.Count(); i
++) {
1339 ruleWalker
.ForwardOnPossiblyCSSRule(aRules
.ObjectAt(i
));
1341 visitedRuleNode
= ruleWalker
.CurrentNode();
1344 uint32_t flags
= eNoFlags
;
1345 if (aBaseContext
->IsLinkContext()) {
1348 // GetContext handles propagating RelevantLinkVisited state from the
1349 // parent in non-link cases; all we need to pass in is if this link
1351 if (aBaseContext
->RelevantLinkVisited()) {
1352 flags
|= eIsVisitedLink
;
1355 return GetContext(aBaseContext
->GetParent(), ruleNode
, visitedRuleNode
,
1356 aBaseContext
->GetPseudo(),
1357 aBaseContext
->GetPseudoType(),
1361 struct RuleNodeInfo
{
1362 nsIStyleRule
* mRule
;
1367 struct CascadeLevel
{
1370 bool mCheckForImportantRules
;
1371 nsRestyleHint mLevelReplacementHint
;
1374 static const CascadeLevel gCascadeLevels
[] = {
1375 { nsStyleSet::eAgentSheet
, false, false, nsRestyleHint(0) },
1376 { nsStyleSet::eUserSheet
, false, false, nsRestyleHint(0) },
1377 { nsStyleSet::ePresHintSheet
, false, false, nsRestyleHint(0) },
1378 { nsStyleSet::eSVGAttrAnimationSheet
, false, false, eRestyle_SVGAttrAnimations
},
1379 { nsStyleSet::eDocSheet
, false, false, nsRestyleHint(0) },
1380 { nsStyleSet::eScopedDocSheet
, false, false, nsRestyleHint(0) },
1381 { nsStyleSet::eStyleAttrSheet
, false, true, eRestyle_StyleAttribute
},
1382 { nsStyleSet::eOverrideSheet
, false, false, nsRestyleHint(0) },
1383 { nsStyleSet::eAnimationSheet
, false, false, eRestyle_CSSAnimations
},
1384 { nsStyleSet::eScopedDocSheet
, true, false, nsRestyleHint(0) },
1385 { nsStyleSet::eDocSheet
, true, false, nsRestyleHint(0) },
1386 { nsStyleSet::eStyleAttrSheet
, true, false, eRestyle_StyleAttribute
},
1387 { nsStyleSet::eOverrideSheet
, true, false, nsRestyleHint(0) },
1388 { nsStyleSet::eUserSheet
, true, false, nsRestyleHint(0) },
1389 { nsStyleSet::eAgentSheet
, true, false, nsRestyleHint(0) },
1390 { nsStyleSet::eTransitionSheet
, false, false, eRestyle_CSSTransitions
},
1394 nsStyleSet::RuleNodeWithReplacement(Element
* aElement
,
1395 nsRuleNode
* aOldRuleNode
,
1396 nsCSSPseudoElements::Type aPseudoType
,
1397 nsRestyleHint aReplacements
)
1399 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
1401 NS_ABORT_IF_FALSE(!(aReplacements
& ~(eRestyle_CSSTransitions
|
1402 eRestyle_CSSAnimations
|
1403 eRestyle_SVGAttrAnimations
|
1404 eRestyle_StyleAttribute
|
1405 eRestyle_ChangeAnimationPhase
|
1406 eRestyle_ChangeAnimationPhaseDescendants
|
1408 eRestyle_ForceDescendants
)),
1409 // FIXME: Once bug 979133 lands we'll have a better
1410 // way to print these.
1411 nsPrintfCString("unexpected replacement bits 0x%lX",
1412 uint32_t(aReplacements
)).get());
1414 // If we're changing animation phase, we have to reconsider what rules
1415 // are in these four levels.
1416 if (aReplacements
& (eRestyle_ChangeAnimationPhase
|
1417 eRestyle_ChangeAnimationPhaseDescendants
)) {
1418 // Animations are only on elements and on :before and :after
1419 // pseudo-elements, so those are the only things we need to consider
1420 // when changing animation phase. Furthermore, the :before and
1421 // :after pseudo-elements cannot have style attributes (although
1422 // some other pseudo-elements can). This lets us avoid the problem
1423 // that the eRestyle_StyleAttribute case below can't handle
1424 // pseudo-elements, but not adding that bit to aReplacements for
1425 // pseudo-elements, since we don't need it.
1426 if (aPseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
) {
1427 aReplacements
|= eRestyle_CSSTransitions
|
1428 eRestyle_CSSAnimations
|
1429 eRestyle_SVGAttrAnimations
|
1430 eRestyle_StyleAttribute
;
1431 } else if (aPseudoType
== nsCSSPseudoElements::ePseudo_before
||
1432 aPseudoType
== nsCSSPseudoElements::ePseudo_after
) {
1433 aReplacements
|= eRestyle_CSSTransitions
|
1434 eRestyle_CSSAnimations
|
1435 eRestyle_SVGAttrAnimations
;
1439 // FIXME (perf): This should probably not rebuild the whole path, but
1440 // only the path from the last change in the rule tree, like
1441 // ReplaceAnimationRule in nsStyleSet.cpp does. (That could then
1442 // perhaps share this code, too?)
1443 // But if we do that, we'll need to pass whether we are rebuilding the
1444 // rule tree from ElementRestyler::RestyleSelf to avoid taking that
1445 // path when we're rebuilding the rule tree.
1447 nsTArray
<RuleNodeInfo
> rules
;
1448 for (nsRuleNode
* ruleNode
= aOldRuleNode
; !ruleNode
->IsRoot();
1449 ruleNode
= ruleNode
->GetParent()) {
1450 RuleNodeInfo
* curRule
= rules
.AppendElement();
1451 curRule
->mRule
= ruleNode
->GetRule();
1452 curRule
->mLevel
= ruleNode
->GetLevel();
1453 curRule
->mIsImportant
= ruleNode
->IsImportantRule();
1456 nsRuleWalker
ruleWalker(mRuleTree
, mAuthorStyleDisabled
);
1457 auto rulesIndex
= rules
.Length();
1459 // We need to transfer this information between the non-!important and
1460 // !important phases for the style attribute level.
1461 nsRuleNode
* lastScopedRN
= nullptr;
1462 nsRuleNode
* lastStyleAttrRN
= nullptr;
1463 bool haveImportantStyleAttrRules
= false;
1465 for (const CascadeLevel
*level
= gCascadeLevels
,
1466 *levelEnd
= ArrayEnd(gCascadeLevels
);
1467 level
!= levelEnd
; ++level
) {
1469 bool doReplace
= level
->mLevelReplacementHint
& aReplacements
;
1471 ruleWalker
.SetLevel(level
->mLevel
, level
->mIsImportant
,
1472 level
->mCheckForImportantRules
&& doReplace
);
1475 switch (level
->mLevelReplacementHint
) {
1476 case eRestyle_CSSAnimations
: {
1477 if (aPseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
||
1478 aPseudoType
== nsCSSPseudoElements::ePseudo_before
||
1479 aPseudoType
== nsCSSPseudoElements::ePseudo_after
) {
1480 nsIStyleRule
* rule
= PresContext()->AnimationManager()->
1481 GetAnimationRule(aElement
, aPseudoType
);
1483 ruleWalker
.ForwardOnPossiblyCSSRule(rule
);
1488 case eRestyle_CSSTransitions
: {
1489 if (aPseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
||
1490 aPseudoType
== nsCSSPseudoElements::ePseudo_before
||
1491 aPseudoType
== nsCSSPseudoElements::ePseudo_after
) {
1492 nsIStyleRule
* rule
= PresContext()->TransitionManager()->
1493 GetAnimationRule(aElement
, aPseudoType
);
1495 ruleWalker
.ForwardOnPossiblyCSSRule(rule
);
1500 case eRestyle_SVGAttrAnimations
: {
1501 MOZ_ASSERT(aReplacements
& (eRestyle_ChangeAnimationPhase
|
1502 eRestyle_ChangeAnimationPhaseDescendants
),
1503 "don't know how to do this level without phase change");
1505 SVGAttrAnimationRuleProcessor
* ruleProcessor
=
1506 static_cast<SVGAttrAnimationRuleProcessor
*>(
1507 mRuleProcessors
[eSVGAttrAnimationSheet
].get());
1508 if (ruleProcessor
&&
1509 aPseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
) {
1510 ruleProcessor
->ElementRulesMatching(aElement
, &ruleWalker
);
1514 case eRestyle_StyleAttribute
: {
1515 MOZ_ASSERT(aReplacements
& (eRestyle_ChangeAnimationPhase
|
1516 eRestyle_ChangeAnimationPhaseDescendants
),
1517 "don't know how to do this level without phase change");
1519 if (!level
->mIsImportant
) {
1520 // First time through, we handle the non-!important rule.
1521 MOZ_ASSERT(aPseudoType
==
1522 nsCSSPseudoElements::ePseudo_NotPseudoElement
,
1523 "this code doesn't know how to replace "
1524 "pseudo-element rules");
1525 nsHTMLCSSStyleSheet
* ruleProcessor
=
1526 static_cast<nsHTMLCSSStyleSheet
*>(
1527 mRuleProcessors
[eStyleAttrSheet
].get());
1528 if (ruleProcessor
&&
1529 // check condition we asserted above (belt & braces security)
1530 aPseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
) {
1531 lastScopedRN
= ruleWalker
.CurrentNode();
1532 ruleProcessor
->ElementRulesMatching(PresContext(),
1535 lastStyleAttrRN
= ruleWalker
.CurrentNode();
1536 haveImportantStyleAttrRules
=
1537 !ruleWalker
.GetCheckForImportantRules();
1540 // Second time through, we handle the !important rule(s).
1541 if (haveImportantStyleAttrRules
) {
1542 AddImportantRules(lastStyleAttrRN
, lastScopedRN
, &ruleWalker
);
1548 MOZ_ASSERT(false, "unexpected result from gCascadeLevels lookup");
1553 while (rulesIndex
!= 0) {
1555 const RuleNodeInfo
& ruleInfo
= rules
[rulesIndex
];
1557 if (ruleInfo
.mLevel
!= level
->mLevel
||
1558 ruleInfo
.mIsImportant
!= level
->mIsImportant
) {
1564 ruleWalker
.ForwardOnPossiblyCSSRule(ruleInfo
.mRule
);
1569 NS_ASSERTION(rulesIndex
== 0,
1570 "rules are in incorrect cascading order, "
1571 "which means we replaced them incorrectly");
1573 return ruleWalker
.CurrentNode();
1576 already_AddRefed
<nsStyleContext
>
1577 nsStyleSet::ResolveStyleWithReplacement(Element
* aElement
,
1578 nsStyleContext
* aNewParentContext
,
1579 nsStyleContext
* aOldStyleContext
,
1580 nsRestyleHint aReplacements
)
1582 nsRuleNode
* ruleNode
=
1583 RuleNodeWithReplacement(aElement
, aOldStyleContext
->RuleNode(),
1584 aOldStyleContext
->GetPseudoType(), aReplacements
);
1586 nsRuleNode
* visitedRuleNode
= nullptr;
1587 nsStyleContext
* oldStyleIfVisited
= aOldStyleContext
->GetStyleIfVisited();
1588 if (oldStyleIfVisited
) {
1589 if (oldStyleIfVisited
->RuleNode() == aOldStyleContext
->RuleNode()) {
1590 visitedRuleNode
= ruleNode
;
1593 RuleNodeWithReplacement(aElement
, oldStyleIfVisited
->RuleNode(),
1594 oldStyleIfVisited
->GetPseudoType(),
1599 uint32_t flags
= eNoFlags
;
1600 if (aOldStyleContext
->IsLinkContext()) {
1603 // GetContext handles propagating RelevantLinkVisited state from the
1604 // parent in non-link cases; all we need to pass in is if this link
1606 if (aOldStyleContext
->RelevantLinkVisited()) {
1607 flags
|= eIsVisitedLink
;
1611 nsCSSPseudoElements::Type pseudoType
= aOldStyleContext
->GetPseudoType();
1612 Element
* elementForAnimation
= nullptr;
1613 if (pseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
||
1614 pseudoType
== nsCSSPseudoElements::ePseudo_before
||
1615 pseudoType
== nsCSSPseudoElements::ePseudo_after
) {
1616 // We want to compute a correct elementForAnimation to pass in
1617 // because at this point the parameter is more than just the element
1618 // for animation; it's also used for the SetBodyTextColor call when
1619 // it's the body element.
1620 // However, we only want to set the flag to call CheckAnimationRule
1621 // if we're dealing with a replacement (such as style attribute
1622 // replacement) that could lead to the animation property changing,
1623 // and we explicitly do NOT want to call CheckAnimationRule when
1624 // we're trying to do an animation-only update.
1625 if (aReplacements
& ~(eRestyle_CSSTransitions
| eRestyle_CSSAnimations
)) {
1626 flags
|= eDoAnimation
;
1628 elementForAnimation
= aElement
;
1629 NS_ASSERTION(pseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
||
1630 !elementForAnimation
->GetPrimaryFrame() ||
1631 elementForAnimation
->GetPrimaryFrame()->StyleContext()->
1633 nsCSSPseudoElements::ePseudo_NotPseudoElement
,
1634 "aElement should be the element and not the pseudo-element");
1637 if (aElement
&& aElement
->IsRootOfAnonymousSubtree()) {
1638 // For anonymous subtree roots, don't tweak "display" value based on whether
1639 // or not the parent is styled as a flex/grid container. (If the parent
1640 // has anonymous-subtree kids, then we know it's not actually going to get
1641 // a flex/grid container frame, anyway.)
1642 flags
|= eSkipParentDisplayBasedStyleFixup
;
1645 return GetContext(aNewParentContext
, ruleNode
, visitedRuleNode
,
1646 aOldStyleContext
->GetPseudo(), pseudoType
,
1647 elementForAnimation
, flags
);
1651 already_AddRefed
<nsStyleContext
>
1652 nsStyleSet::ResolveStyleForNonElement(nsStyleContext
* aParentContext
)
1654 return GetContext(aParentContext
, mRuleTree
, nullptr,
1655 nsCSSAnonBoxes::mozNonElement
,
1656 nsCSSPseudoElements::ePseudo_AnonBox
, nullptr,
1661 nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType
,
1662 nsRuleWalker
* aRuleWalker
)
1664 // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
1665 aRuleWalker
->SetLevel(eAgentSheet
, false, false);
1666 if (aPseudoType
== nsCSSPseudoElements::ePseudo_firstLetter
)
1667 aRuleWalker
->Forward(mFirstLetterRule
);
1668 else if (aPseudoType
== nsCSSPseudoElements::ePseudo_firstLine
)
1669 aRuleWalker
->Forward(mFirstLineRule
);
1670 else if (aPseudoType
== nsCSSPseudoElements::ePseudo_mozPlaceholder
)
1671 aRuleWalker
->Forward(mPlaceholderRule
);
1675 nsStyleSet::WalkDisableTextZoomRule(Element
* aElement
, nsRuleWalker
* aRuleWalker
)
1677 aRuleWalker
->SetLevel(eAgentSheet
, false, false);
1678 if (aElement
->IsSVG(nsGkAtoms::text
))
1679 aRuleWalker
->Forward(mDisableTextZoomStyleRule
);
1682 already_AddRefed
<nsStyleContext
>
1683 nsStyleSet::ResolvePseudoElementStyle(Element
* aParentElement
,
1684 nsCSSPseudoElements::Type aType
,
1685 nsStyleContext
* aParentContext
,
1686 Element
* aPseudoElement
)
1688 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1690 NS_ASSERTION(aType
< nsCSSPseudoElements::ePseudo_PseudoElementCount
,
1691 "must have pseudo element type");
1692 NS_ASSERTION(aParentElement
, "Must have parent element");
1694 nsRuleWalker
ruleWalker(mRuleTree
, mAuthorStyleDisabled
);
1695 TreeMatchContext
treeContext(true, nsRuleWalker::eRelevantLinkUnvisited
,
1696 aParentElement
->OwnerDoc());
1697 InitStyleScopes(treeContext
, aParentElement
);
1698 PseudoElementRuleProcessorData
data(PresContext(), aParentElement
,
1699 &ruleWalker
, aType
, treeContext
,
1701 WalkRestrictionRule(aType
, &ruleWalker
);
1702 FileRules(EnumRulesMatching
<PseudoElementRuleProcessorData
>, &data
,
1703 aParentElement
, &ruleWalker
);
1705 nsRuleNode
*ruleNode
= ruleWalker
.CurrentNode();
1706 nsRuleNode
*visitedRuleNode
= nullptr;
1708 if (treeContext
.HaveRelevantLink()) {
1709 treeContext
.ResetForVisitedMatching();
1711 WalkRestrictionRule(aType
, &ruleWalker
);
1712 FileRules(EnumRulesMatching
<PseudoElementRuleProcessorData
>, &data
,
1713 aParentElement
, &ruleWalker
);
1714 visitedRuleNode
= ruleWalker
.CurrentNode();
1717 // For pseudos, |data.IsLink()| being true means that
1718 // our parent node is a link.
1719 uint32_t flags
= eNoFlags
;
1720 if (aType
== nsCSSPseudoElements::ePseudo_before
||
1721 aType
== nsCSSPseudoElements::ePseudo_after
) {
1722 flags
|= eDoAnimation
;
1724 // Flex and grid containers don't expect to have any pseudo-element children
1725 // aside from ::before and ::after. So if we have such a child, we're not
1726 // actually in a flex/grid container, and we should skip flex/grid item
1728 flags
|= eSkipParentDisplayBasedStyleFixup
;
1731 return GetContext(aParentContext
, ruleNode
, visitedRuleNode
,
1732 nsCSSPseudoElements::GetPseudoAtom(aType
), aType
,
1733 aParentElement
, flags
);
1736 already_AddRefed
<nsStyleContext
>
1737 nsStyleSet::ProbePseudoElementStyle(Element
* aParentElement
,
1738 nsCSSPseudoElements::Type aType
,
1739 nsStyleContext
* aParentContext
)
1741 TreeMatchContext
treeContext(true, nsRuleWalker::eRelevantLinkUnvisited
,
1742 aParentElement
->OwnerDoc());
1743 InitStyleScopes(treeContext
, aParentElement
);
1744 return ProbePseudoElementStyle(aParentElement
, aType
, aParentContext
,
1748 already_AddRefed
<nsStyleContext
>
1749 nsStyleSet::ProbePseudoElementStyle(Element
* aParentElement
,
1750 nsCSSPseudoElements::Type aType
,
1751 nsStyleContext
* aParentContext
,
1752 TreeMatchContext
& aTreeMatchContext
,
1753 Element
* aPseudoElement
)
1755 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1757 NS_ASSERTION(aType
< nsCSSPseudoElements::ePseudo_PseudoElementCount
,
1758 "must have pseudo element type");
1759 NS_ASSERTION(aParentElement
, "aParentElement must not be null");
1761 nsIAtom
* pseudoTag
= nsCSSPseudoElements::GetPseudoAtom(aType
);
1762 nsRuleWalker
ruleWalker(mRuleTree
, mAuthorStyleDisabled
);
1763 aTreeMatchContext
.ResetForUnvisitedMatching();
1764 PseudoElementRuleProcessorData
data(PresContext(), aParentElement
,
1765 &ruleWalker
, aType
, aTreeMatchContext
,
1767 WalkRestrictionRule(aType
, &ruleWalker
);
1768 // not the root if there was a restriction rule
1769 nsRuleNode
*adjustedRoot
= ruleWalker
.CurrentNode();
1770 FileRules(EnumRulesMatching
<PseudoElementRuleProcessorData
>, &data
,
1771 aParentElement
, &ruleWalker
);
1773 nsRuleNode
*ruleNode
= ruleWalker
.CurrentNode();
1774 if (ruleNode
== adjustedRoot
) {
1778 nsRuleNode
*visitedRuleNode
= nullptr;
1780 if (aTreeMatchContext
.HaveRelevantLink()) {
1781 aTreeMatchContext
.ResetForVisitedMatching();
1783 WalkRestrictionRule(aType
, &ruleWalker
);
1784 FileRules(EnumRulesMatching
<PseudoElementRuleProcessorData
>, &data
,
1785 aParentElement
, &ruleWalker
);
1786 visitedRuleNode
= ruleWalker
.CurrentNode();
1789 // For pseudos, |data.IsLink()| being true means that
1790 // our parent node is a link.
1791 uint32_t flags
= eNoFlags
;
1792 if (aType
== nsCSSPseudoElements::ePseudo_before
||
1793 aType
== nsCSSPseudoElements::ePseudo_after
) {
1794 flags
|= eDoAnimation
;
1796 // Flex and grid containers don't expect to have any pseudo-element children
1797 // aside from ::before and ::after. So if we have such a child, we're not
1798 // actually in a flex/grid container, and we should skip flex/grid item
1800 flags
|= eSkipParentDisplayBasedStyleFixup
;
1803 nsRefPtr
<nsStyleContext
> result
=
1804 GetContext(aParentContext
, ruleNode
, visitedRuleNode
,
1806 aParentElement
, flags
);
1808 // For :before and :after pseudo-elements, having display: none or no
1809 // 'content' property is equivalent to not having the pseudo-element
1812 (pseudoTag
== nsCSSPseudoElements::before
||
1813 pseudoTag
== nsCSSPseudoElements::after
)) {
1814 const nsStyleDisplay
*display
= result
->StyleDisplay();
1815 const nsStyleContent
*content
= result
->StyleContent();
1816 // XXXldb What is contentCount for |content: ""|?
1817 if (display
->mDisplay
== NS_STYLE_DISPLAY_NONE
||
1818 content
->ContentCount() == 0) {
1823 return result
.forget();
1826 already_AddRefed
<nsStyleContext
>
1827 nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom
* aPseudoTag
,
1828 nsStyleContext
* aParentContext
)
1830 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1833 bool isAnonBox
= nsCSSAnonBoxes::IsAnonBox(aPseudoTag
)
1835 && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag
)
1838 NS_PRECONDITION(isAnonBox
, "Unexpected pseudo");
1841 nsRuleWalker
ruleWalker(mRuleTree
, mAuthorStyleDisabled
);
1842 AnonBoxRuleProcessorData
data(PresContext(), aPseudoTag
, &ruleWalker
);
1843 FileRules(EnumRulesMatching
<AnonBoxRuleProcessorData
>, &data
, nullptr,
1846 if (aPseudoTag
== nsCSSAnonBoxes::pageContent
) {
1847 // Add any @page rules that are specified.
1848 nsTArray
<nsCSSPageRule
*> rules
;
1849 nsTArray
<css::ImportantRule
*> importantRules
;
1850 nsPresContext
* presContext
= PresContext();
1851 presContext
->StyleSet()->AppendPageRules(presContext
, rules
);
1852 for (uint32_t i
= 0, i_end
= rules
.Length(); i
!= i_end
; ++i
) {
1853 ruleWalker
.Forward(rules
[i
]);
1854 css::ImportantRule
* importantRule
= rules
[i
]->GetImportantRule();
1855 if (importantRule
) {
1856 importantRules
.AppendElement(importantRule
);
1859 for (uint32_t i
= 0, i_end
= importantRules
.Length(); i
!= i_end
; ++i
) {
1860 ruleWalker
.Forward(importantRules
[i
]);
1864 return GetContext(aParentContext
, ruleWalker
.CurrentNode(), nullptr,
1865 aPseudoTag
, nsCSSPseudoElements::ePseudo_AnonBox
,
1870 already_AddRefed
<nsStyleContext
>
1871 nsStyleSet::ResolveXULTreePseudoStyle(Element
* aParentElement
,
1872 nsIAtom
* aPseudoTag
,
1873 nsStyleContext
* aParentContext
,
1874 nsICSSPseudoComparator
* aComparator
)
1876 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1878 NS_ASSERTION(aPseudoTag
, "must have pseudo tag");
1879 NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag
),
1880 "Unexpected pseudo");
1882 nsRuleWalker
ruleWalker(mRuleTree
, mAuthorStyleDisabled
);
1883 TreeMatchContext
treeContext(true, nsRuleWalker::eRelevantLinkUnvisited
,
1884 aParentElement
->OwnerDoc());
1885 InitStyleScopes(treeContext
, aParentElement
);
1886 XULTreeRuleProcessorData
data(PresContext(), aParentElement
, &ruleWalker
,
1887 aPseudoTag
, aComparator
, treeContext
);
1888 FileRules(EnumRulesMatching
<XULTreeRuleProcessorData
>, &data
, aParentElement
,
1891 nsRuleNode
*ruleNode
= ruleWalker
.CurrentNode();
1892 nsRuleNode
*visitedRuleNode
= nullptr;
1894 if (treeContext
.HaveRelevantLink()) {
1895 treeContext
.ResetForVisitedMatching();
1897 FileRules(EnumRulesMatching
<XULTreeRuleProcessorData
>, &data
,
1898 aParentElement
, &ruleWalker
);
1899 visitedRuleNode
= ruleWalker
.CurrentNode();
1902 return GetContext(aParentContext
, ruleNode
, visitedRuleNode
,
1903 // For pseudos, |data.IsLink()| being true means that
1904 // our parent node is a link.
1905 aPseudoTag
, nsCSSPseudoElements::ePseudo_XULTree
,
1911 nsStyleSet::AppendFontFaceRules(nsPresContext
* aPresContext
,
1912 nsTArray
<nsFontFaceRuleContainer
>& aArray
)
1914 NS_ENSURE_FALSE(mInShutdown
, false);
1915 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
1917 for (uint32_t i
= 0; i
< ArrayLength(gCSSSheetTypes
); ++i
) {
1918 if (gCSSSheetTypes
[i
] == eScopedDocSheet
)
1920 nsCSSRuleProcessor
*ruleProc
= static_cast<nsCSSRuleProcessor
*>
1921 (mRuleProcessors
[gCSSSheetTypes
[i
]].get());
1922 if (ruleProc
&& !ruleProc
->AppendFontFaceRules(aPresContext
, aArray
))
1929 nsStyleSet::KeyframesRuleForName(nsPresContext
* aPresContext
,
1930 const nsString
& aName
)
1932 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1933 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
1935 for (uint32_t i
= ArrayLength(gCSSSheetTypes
); i
-- != 0; ) {
1936 if (gCSSSheetTypes
[i
] == eScopedDocSheet
)
1938 nsCSSRuleProcessor
*ruleProc
= static_cast<nsCSSRuleProcessor
*>
1939 (mRuleProcessors
[gCSSSheetTypes
[i
]].get());
1942 nsCSSKeyframesRule
* result
=
1943 ruleProc
->KeyframesRuleForName(aPresContext
, aName
);
1950 nsCSSCounterStyleRule
*
1951 nsStyleSet::CounterStyleRuleForName(nsPresContext
* aPresContext
,
1952 const nsAString
& aName
)
1954 NS_ENSURE_FALSE(mInShutdown
, nullptr);
1955 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
1957 for (uint32_t i
= ArrayLength(gCSSSheetTypes
); i
-- != 0; ) {
1958 if (gCSSSheetTypes
[i
] == eScopedDocSheet
)
1960 nsCSSRuleProcessor
*ruleProc
= static_cast<nsCSSRuleProcessor
*>
1961 (mRuleProcessors
[gCSSSheetTypes
[i
]].get());
1964 nsCSSCounterStyleRule
*result
=
1965 ruleProc
->CounterStyleRuleForName(aPresContext
, aName
);
1973 nsStyleSet::AppendFontFeatureValuesRules(nsPresContext
* aPresContext
,
1974 nsTArray
<nsCSSFontFeatureValuesRule
*>& aArray
)
1976 NS_ENSURE_FALSE(mInShutdown
, false);
1977 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
1979 for (uint32_t i
= 0; i
< ArrayLength(gCSSSheetTypes
); ++i
) {
1980 nsCSSRuleProcessor
*ruleProc
= static_cast<nsCSSRuleProcessor
*>
1981 (mRuleProcessors
[gCSSSheetTypes
[i
]].get());
1983 !ruleProc
->AppendFontFeatureValuesRules(aPresContext
, aArray
))
1991 already_AddRefed
<gfxFontFeatureValueSet
>
1992 nsStyleSet::GetFontFeatureValuesLookup()
1994 if (mInitFontFeatureValuesLookup
) {
1995 mInitFontFeatureValuesLookup
= false;
1997 nsTArray
<nsCSSFontFeatureValuesRule
*> rules
;
1998 AppendFontFeatureValuesRules(PresContext(), rules
);
2000 mFontFeatureValuesLookup
= new gfxFontFeatureValueSet();
2002 uint32_t i
, numRules
= rules
.Length();
2003 for (i
= 0; i
< numRules
; i
++) {
2004 nsCSSFontFeatureValuesRule
*rule
= rules
[i
];
2006 const nsTArray
<FontFamilyName
>& familyList
= rule
->GetFamilyList().GetFontlist();
2007 const nsTArray
<gfxFontFeatureValueSet::FeatureValues
>&
2008 featureValues
= rule
->GetFeatureValues();
2013 numFam
= familyList
.Length();
2014 for (f
= 0; f
< numFam
; f
++) {
2015 mFontFeatureValuesLookup
->AddFontFeatureValues(familyList
[f
].mName
,
2021 nsRefPtr
<gfxFontFeatureValueSet
> lookup
= mFontFeatureValuesLookup
;
2022 return lookup
.forget();
2026 nsStyleSet::AppendPageRules(nsPresContext
* aPresContext
,
2027 nsTArray
<nsCSSPageRule
*>& aArray
)
2029 NS_ENSURE_FALSE(mInShutdown
, false);
2030 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
2032 for (uint32_t i
= 0; i
< ArrayLength(gCSSSheetTypes
); ++i
) {
2033 if (gCSSSheetTypes
[i
] == eScopedDocSheet
)
2035 nsCSSRuleProcessor
* ruleProc
= static_cast<nsCSSRuleProcessor
*>
2036 (mRuleProcessors
[gCSSSheetTypes
[i
]].get());
2037 if (ruleProc
&& !ruleProc
->AppendPageRules(aPresContext
, aArray
))
2044 nsStyleSet::BeginShutdown(nsPresContext
* aPresContext
)
2047 mRoots
.Clear(); // no longer valid, since we won't keep it up to date
2051 nsStyleSet::Shutdown(nsPresContext
* aPresContext
)
2053 mRuleTree
->Destroy();
2054 mRuleTree
= nullptr;
2056 // We can have old rule trees either because:
2057 // (1) we failed the assertions in EndReconstruct, or
2058 // (2) we're shutting down within a reconstruct (see bug 462392)
2059 for (uint32_t i
= mOldRuleTrees
.Length(); i
> 0; ) {
2061 mOldRuleTrees
[i
]->Destroy();
2063 mOldRuleTrees
.Clear();
2066 static const uint32_t kGCInterval
= 300;
2069 nsStyleSet::NotifyStyleContextDestroyed(nsPresContext
* aPresContext
,
2070 nsStyleContext
* aStyleContext
)
2075 // Remove style contexts from mRoots even if mOldRuleTree is non-null. This
2076 // could be a style context from the new ruletree!
2077 if (!aStyleContext
->GetParent()) {
2078 mRoots
.RemoveElement(aStyleContext
);
2084 if (mUnusedRuleNodeCount
>= kGCInterval
) {
2090 nsStyleSet::GCRuleTrees()
2092 mUnusedRuleNodeCount
= 0;
2094 // Mark the style context tree by marking all style contexts which
2095 // have no parent, which will mark all descendants. This will reach
2096 // style contexts in the undisplayed map and "additional style
2097 // contexts" since they are descendants of the roots.
2098 for (int32_t i
= mRoots
.Length() - 1; i
>= 0; --i
) {
2102 // Sweep the rule tree.
2107 NS_ASSERTION(!deleted
, "Root node must not be gc'd");
2109 // Sweep the old rule trees.
2110 for (uint32_t i
= mOldRuleTrees
.Length(); i
> 0; ) {
2112 if (mOldRuleTrees
[i
]->Sweep()) {
2113 // It was deleted, as it should be.
2114 mOldRuleTrees
.RemoveElementAt(i
);
2116 NS_NOTREACHED("old rule tree still referenced");
2122 * Return an equivalent to aRuleNode with both animation and transition
2123 * rules removed, and post a restyle if needed.
2125 static inline nsRuleNode
*
2126 SkipAnimationRules(nsRuleNode
* aRuleNode
, Element
* aElementOrPseudoElement
,
2127 bool aPostAnimationRestyles
)
2129 nsRuleNode
* ruleNode
= aRuleNode
;
2130 // The transition rule must be at the top of the cascade.
2131 if (!ruleNode
->IsRoot() &&
2132 ruleNode
->GetLevel() == nsStyleSet::eTransitionSheet
) {
2133 ruleNode
= ruleNode
->GetParent();
2135 NS_ABORT_IF_FALSE(ruleNode
->IsRoot() ||
2136 ruleNode
->GetLevel() != nsStyleSet::eTransitionSheet
,
2137 "can't have more than one transition rule");
2139 // Use our existing ReplaceAnimationRule function to replace the
2140 // animation rule, if present.
2141 nsIStyleRule
* animationRule
= GetAnimationRule(ruleNode
);
2142 if (animationRule
) {
2143 ruleNode
= ReplaceAnimationRule(ruleNode
, animationRule
, nullptr);
2146 if (ruleNode
!= aRuleNode
&& aPostAnimationRestyles
) {
2147 NS_ASSERTION(aElementOrPseudoElement
,
2148 "How can we have transition rules but no element?");
2149 // Need to do an animation restyle, just like
2150 // nsTransitionManager::WalkTransitionRule and
2151 // nsAnimationManager::GetAnimationRule would.
2152 aRuleNode
->PresContext()->PresShell()->
2153 RestyleForAnimation(aElementOrPseudoElement
, eRestyle_Self
);
2158 already_AddRefed
<nsStyleContext
>
2159 nsStyleSet::ReparentStyleContext(nsStyleContext
* aStyleContext
,
2160 nsStyleContext
* aNewParentContext
,
2162 // aElementOrPseudoElement is temporary
2163 // until bug 960465 lands, and for
2164 // SkipAnimationRules only
2165 Element
* aElementOrPseudoElement
)
2167 MOZ_ASSERT(aStyleContext
, "aStyleContext must not be null");
2169 // This short-circuit is OK because we don't call TryStartingTransition
2170 // during style reresolution if the style context pointer hasn't changed.
2171 if (aStyleContext
->GetParent() == aNewParentContext
) {
2172 nsRefPtr
<nsStyleContext
> ret
= aStyleContext
;
2173 return ret
.forget();
2176 nsIAtom
* pseudoTag
= aStyleContext
->GetPseudo();
2177 nsCSSPseudoElements::Type pseudoType
= aStyleContext
->GetPseudoType();
2178 nsRuleNode
* ruleNode
= aStyleContext
->RuleNode();
2180 // Skip transition rules as needed just like
2181 // nsTransitionManager::WalkTransitionRule would.
2182 RestyleManager
* restyleManager
= PresContext()->RestyleManager();
2183 bool skipAnimationRules
= restyleManager
->SkipAnimationRules();
2184 bool postAnimationRestyles
= restyleManager
->PostAnimationRestyles();
2185 if (skipAnimationRules
) {
2186 // Make sure that we're not using transition rules or animation rules for
2187 // our new style context. If we need them, an animation restyle will
2189 ruleNode
= SkipAnimationRules(ruleNode
, aElementOrPseudoElement
,
2190 postAnimationRestyles
);
2193 nsRuleNode
* visitedRuleNode
= nullptr;
2194 nsStyleContext
* visitedContext
= aStyleContext
->GetStyleIfVisited();
2195 // Reparenting a style context just changes where we inherit from,
2196 // not what rules we match or what our DOM looks like. In
2197 // particular, it doesn't change whether this is a style context for
2199 if (visitedContext
) {
2200 visitedRuleNode
= visitedContext
->RuleNode();
2201 // Again, skip transition rules as needed
2202 if (skipAnimationRules
) {
2203 // FIXME do something here for animations?
2205 SkipAnimationRules(visitedRuleNode
, aElementOrPseudoElement
,
2206 postAnimationRestyles
);
2210 uint32_t flags
= eNoFlags
;
2211 if (aStyleContext
->IsLinkContext()) {
2214 // GetContext handles propagating RelevantLinkVisited state from the
2215 // parent in non-link cases; all we need to pass in is if this link
2217 if (aStyleContext
->RelevantLinkVisited()) {
2218 flags
|= eIsVisitedLink
;
2222 if (pseudoType
== nsCSSPseudoElements::ePseudo_NotPseudoElement
||
2223 pseudoType
== nsCSSPseudoElements::ePseudo_before
||
2224 pseudoType
== nsCSSPseudoElements::ePseudo_after
) {
2225 flags
|= eDoAnimation
;
2228 if (aElement
&& aElement
->IsRootOfAnonymousSubtree()) {
2229 // For anonymous subtree roots, don't tweak "display" value based on whether
2230 // or not the parent is styled as a flex/grid container. (If the parent
2231 // has anonymous-subtree kids, then we know it's not actually going to get
2232 // a flex/grid container frame, anyway.)
2233 flags
|= eSkipParentDisplayBasedStyleFixup
;
2236 return GetContext(aNewParentContext
, ruleNode
, visitedRuleNode
,
2237 pseudoTag
, pseudoType
,
2241 struct MOZ_STACK_CLASS StatefulData
: public StateRuleProcessorData
{
2242 StatefulData(nsPresContext
* aPresContext
, Element
* aElement
,
2243 EventStates aStateMask
, TreeMatchContext
& aTreeMatchContext
)
2244 : StateRuleProcessorData(aPresContext
, aElement
, aStateMask
,
2246 mHint(nsRestyleHint(0))
2248 nsRestyleHint mHint
;
2251 struct MOZ_STACK_CLASS StatefulPseudoElementData
: public PseudoElementStateRuleProcessorData
{
2252 StatefulPseudoElementData(nsPresContext
* aPresContext
, Element
* aElement
,
2253 EventStates aStateMask
, nsCSSPseudoElements::Type aPseudoType
,
2254 TreeMatchContext
& aTreeMatchContext
, Element
* aPseudoElement
)
2255 : PseudoElementStateRuleProcessorData(aPresContext
, aElement
, aStateMask
,
2256 aPseudoType
, aTreeMatchContext
,
2258 mHint(nsRestyleHint(0))
2260 nsRestyleHint mHint
;
2263 static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor
* aProcessor
,
2266 StatefulData
* data
= (StatefulData
*)aData
;
2267 if (aProcessor
->HasDocumentStateDependentStyle(data
)) {
2268 data
->mHint
= eRestyle_Self
;
2269 return false; // don't continue
2271 return true; // continue
2274 // Test if style is dependent on a document state.
2276 nsStyleSet::HasDocumentStateDependentStyle(nsPresContext
* aPresContext
,
2277 nsIContent
* aContent
,
2278 EventStates aStateMask
)
2280 if (!aContent
|| !aContent
->IsElement())
2283 TreeMatchContext
treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited
,
2284 aContent
->OwnerDoc());
2285 InitStyleScopes(treeContext
, aContent
->AsElement());
2286 StatefulData
data(aPresContext
, aContent
->AsElement(), aStateMask
,
2288 WalkRuleProcessors(SheetHasDocumentStateStyle
, &data
, true);
2289 return data
.mHint
!= 0;
2292 static bool SheetHasStatefulStyle(nsIStyleRuleProcessor
* aProcessor
,
2295 StatefulData
* data
= (StatefulData
*)aData
;
2296 nsRestyleHint hint
= aProcessor
->HasStateDependentStyle(data
);
2297 data
->mHint
= nsRestyleHint(data
->mHint
| hint
);
2298 return true; // continue
2301 static bool SheetHasStatefulPseudoElementStyle(nsIStyleRuleProcessor
* aProcessor
,
2304 StatefulPseudoElementData
* data
= (StatefulPseudoElementData
*)aData
;
2305 nsRestyleHint hint
= aProcessor
->HasStateDependentStyle(data
);
2306 data
->mHint
= nsRestyleHint(data
->mHint
| hint
);
2307 return true; // continue
2310 // Test if style is dependent on content state
2312 nsStyleSet::HasStateDependentStyle(nsPresContext
* aPresContext
,
2314 EventStates aStateMask
)
2316 TreeMatchContext
treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited
,
2317 aElement
->OwnerDoc());
2318 InitStyleScopes(treeContext
, aElement
);
2319 StatefulData
data(aPresContext
, aElement
, aStateMask
, treeContext
);
2320 WalkRuleProcessors(SheetHasStatefulStyle
, &data
, false);
2325 nsStyleSet::HasStateDependentStyle(nsPresContext
* aPresContext
,
2327 nsCSSPseudoElements::Type aPseudoType
,
2328 Element
* aPseudoElement
,
2329 EventStates aStateMask
)
2331 TreeMatchContext
treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited
,
2332 aElement
->OwnerDoc());
2333 InitStyleScopes(treeContext
, aElement
);
2334 StatefulPseudoElementData
data(aPresContext
, aElement
, aStateMask
,
2335 aPseudoType
, treeContext
, aPseudoElement
);
2336 WalkRuleProcessors(SheetHasStatefulPseudoElementStyle
, &data
, false);
2340 struct MOZ_STACK_CLASS AttributeData
: public AttributeRuleProcessorData
{
2341 AttributeData(nsPresContext
* aPresContext
,
2342 Element
* aElement
, nsIAtom
* aAttribute
, int32_t aModType
,
2343 bool aAttrHasChanged
, TreeMatchContext
& aTreeMatchContext
)
2344 : AttributeRuleProcessorData(aPresContext
, aElement
, aAttribute
, aModType
,
2345 aAttrHasChanged
, aTreeMatchContext
),
2346 mHint(nsRestyleHint(0))
2348 nsRestyleHint mHint
;
2352 SheetHasAttributeStyle(nsIStyleRuleProcessor
* aProcessor
, void *aData
)
2354 AttributeData
* data
= (AttributeData
*)aData
;
2355 nsRestyleHint hint
= aProcessor
->HasAttributeDependentStyle(data
);
2356 data
->mHint
= nsRestyleHint(data
->mHint
| hint
);
2357 return true; // continue
2360 // Test if style is dependent on content state
2362 nsStyleSet::HasAttributeDependentStyle(nsPresContext
* aPresContext
,
2364 nsIAtom
* aAttribute
,
2366 bool aAttrHasChanged
)
2368 TreeMatchContext
treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited
,
2369 aElement
->OwnerDoc());
2370 InitStyleScopes(treeContext
, aElement
);
2371 AttributeData
data(aPresContext
, aElement
, aAttribute
,
2372 aModType
, aAttrHasChanged
, treeContext
);
2373 WalkRuleProcessors(SheetHasAttributeStyle
, &data
, false);
2378 nsStyleSet::MediumFeaturesChanged(nsPresContext
* aPresContext
)
2380 NS_ASSERTION(mBatching
== 0, "rule processors out of date");
2382 // We can't use WalkRuleProcessors without a content node.
2383 bool stylesChanged
= false;
2384 for (uint32_t i
= 0; i
< ArrayLength(mRuleProcessors
); ++i
) {
2385 nsIStyleRuleProcessor
*processor
= mRuleProcessors
[i
];
2389 bool thisChanged
= processor
->MediumFeaturesChanged(aPresContext
);
2390 stylesChanged
= stylesChanged
|| thisChanged
;
2392 for (uint32_t i
= 0; i
< mScopedDocSheetRuleProcessors
.Length(); ++i
) {
2393 nsIStyleRuleProcessor
*processor
= mScopedDocSheetRuleProcessors
[i
];
2394 bool thisChanged
= processor
->MediumFeaturesChanged(aPresContext
);
2395 stylesChanged
= stylesChanged
|| thisChanged
;
2398 if (mBindingManager
) {
2399 bool thisChanged
= false;
2400 mBindingManager
->MediumFeaturesChanged(aPresContext
, &thisChanged
);
2401 stylesChanged
= stylesChanged
|| thisChanged
;
2404 return stylesChanged
;
2407 CSSStyleSheet::EnsureUniqueInnerResult
2408 nsStyleSet::EnsureUniqueInnerOnCSSSheets()
2410 nsAutoTArray
<CSSStyleSheet
*, 32> queue
;
2411 for (uint32_t i
= 0; i
< ArrayLength(gCSSSheetTypes
); ++i
) {
2412 nsCOMArray
<nsIStyleSheet
> &sheets
= mSheets
[gCSSSheetTypes
[i
]];
2413 for (uint32_t j
= 0, j_end
= sheets
.Count(); j
< j_end
; ++j
) {
2414 CSSStyleSheet
* sheet
= static_cast<CSSStyleSheet
*>(sheets
[j
]);
2415 queue
.AppendElement(sheet
);
2419 if (mBindingManager
) {
2420 mBindingManager
->AppendAllSheets(queue
);
2423 CSSStyleSheet::EnsureUniqueInnerResult res
=
2424 CSSStyleSheet::eUniqueInner_AlreadyUnique
;
2425 while (!queue
.IsEmpty()) {
2426 uint32_t idx
= queue
.Length() - 1;
2427 CSSStyleSheet
* sheet
= queue
[idx
];
2428 queue
.RemoveElementAt(idx
);
2430 CSSStyleSheet::EnsureUniqueInnerResult sheetRes
=
2431 sheet
->EnsureUniqueInner();
2432 if (sheetRes
== CSSStyleSheet::eUniqueInner_ClonedInner
) {
2436 // Enqueue all the sheet's children.
2437 sheet
->AppendAllChildSheets(queue
);
2443 nsStyleSet::InitialStyleRule()
2445 if (!mInitialStyleRule
) {
2446 mInitialStyleRule
= new nsInitialStyleRule
;
2448 return mInitialStyleRule
;