Bumping manifests a=b2g-bump
[gecko.git] / layout / style / nsStyleSet.cpp
blobbb9f219f57761a4b28320ddf01e3f8d19ee55632
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
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"
39 #include "nsIFrame.h"
40 #include "RestyleManager.h"
42 using namespace mozilla;
43 using namespace mozilla::dom;
45 NS_IMPL_ISUPPORTS(nsEmptyStyleRule, nsIStyleRule)
47 /* virtual */ void
48 nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
52 #ifdef DEBUG
53 /* virtual */ void
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());
62 #endif
64 NS_IMPL_ISUPPORTS(nsInitialStyleRule, nsIStyleRule)
66 /* virtual */ void
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)) {
94 continue;
97 if (value->GetUnit() == eCSSUnit_Null) {
98 value->SetInitialValue();
105 #ifdef DEBUG
106 /* virtual */ void
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());
115 #endif
117 NS_IMPL_ISUPPORTS(nsDisableTextZoomStyleRule, nsIStyleRule)
119 /* virtual */ void
120 nsDisableTextZoomStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
122 if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Font)))
123 return;
125 nsCSSValue* value = aRuleData->ValueForTextZoom();
126 if (value->GetUnit() == eCSSUnit_Null)
127 value->SetNoneValue();
130 #ifdef DEBUG
131 /* virtual */ void
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());
140 #endif
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),
153 mBatching(0),
154 mInShutdown(false),
155 mAuthorStyleDisabled(false),
156 mInReconstruct(false),
157 mInitFontFeatureValuesLookup(true),
158 mDirty(0),
159 mUnusedRuleNodeCount(0)
163 size_t
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);
188 return n;
191 void
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);
211 nsresult
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());
220 if (!newTree)
221 return NS_ERROR_OUT_OF_MEMORY;
223 // Save the old rule tree so we can destroy it later
224 if (!mOldRuleTrees.AppendElement(mRuleTree)) {
225 newTree->Destroy();
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;
234 mRuleTree = newTree;
236 return NS_OK;
239 void
240 nsStyleSet::EndReconstruct()
242 NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
243 mInReconstruct = false;
244 #ifdef DEBUG
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
251 // themselves.
253 NS_ASSERTION(mRoots[i]->RuleNode()->RuleTree() == mRuleTree,
254 "style context has old rule node");
256 #endif
257 // This *should* destroy the only element of mOldRuleTrees, but in
258 // case of some bugs (which would trigger the above assertions), it
259 // won't.
260 GCRuleTrees();
263 void
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.
278 static uint32_t
279 GetScopeDepth(nsINode* aScopeElement, ScopeDepthCache& aCache)
281 nsINode* parent = aScopeElement->GetParent();
282 if (!parent || !parent->IsElementInStyleScope()) {
283 return 1;
286 uint32_t depth = aCache.Get(aScopeElement);
287 if (!depth) {
288 for (nsINode* n = parent; n; n = n->GetParent()) {
289 if (n->IsScopedStyleRoot()) {
290 depth = GetScopeDepth(n, aCache) + 1;
291 aCache.Put(aScopeElement, depth);
292 break;
296 return depth;
299 struct ScopedSheetOrder
301 CSSStyleSheet* mSheet;
302 uint32_t mDepth;
303 uint32_t mOrder;
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.
323 static void
324 SortStyleSheetsByScope(nsTArray<CSSStyleSheet*>& aSheets)
326 uint32_t n = aSheets.Length();
327 if (n == 1) {
328 return;
331 ScopeDepthCache cache;
333 nsTArray<ScopedSheetOrder> sheets;
334 sheets.SetLength(n);
336 // For each sheet, record the depth of its scope element and its original
337 // document order.
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.
345 sheets.Sort();
347 for (uint32_t i = 0; i < n; i++) {
348 aSheets[i] = sheets[i].mSheet;
352 nsresult
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();
362 Element* scope =
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.
376 return NS_OK;
378 switch (aType) {
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();
384 return NS_OK;
385 case eTransitionSheet:
386 MOZ_ASSERT(mSheets[aType].IsEmpty());
387 mRuleProcessors[aType] = PresContext()->TransitionManager();
388 return NS_OK;
389 case eStyleAttrSheet:
390 MOZ_ASSERT(mSheets[aType].IsEmpty());
391 mRuleProcessors[aType] = PresContext()->Document()->GetInlineStyleSheet();
392 return NS_OK;
393 case ePresHintSheet:
394 MOZ_ASSERT(mSheets[aType].IsEmpty());
395 mRuleProcessors[aType] =
396 PresContext()->Document()->GetAttributeStyleSheet();
397 return NS_OK;
398 case eSVGAttrAnimationSheet:
399 MOZ_ASSERT(mSheets[aType].IsEmpty());
400 mRuleProcessors[aType] =
401 PresContext()->Document()->GetSVGAttrAnimationRuleProcessor();
402 return NS_OK;
403 default:
404 // keep going
405 break;
407 if (aType == eScopedDocSheet) {
408 // Create a rule processor for each scope.
409 uint32_t count = mSheets[eScopedDocSheet].Count();
410 if (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;
444 do {
445 // Find the range of style sheets with the same scope.
446 Element* scope = sheets[start]->GetScopeElement();
447 end = start + 1;
448 while (end < count && sheets[end]->GetScopeElement() == scope) {
449 end++;
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,
460 oldRP));
462 start = end;
463 } while (start < count);
465 return NS_OK;
467 if (mSheets[aType].Count()) {
468 switch (aType) {
469 case eAgentSheet:
470 case eUserSheet:
471 case eDocSheet:
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()));
485 } break;
487 default:
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]);
491 break;
495 return NS_OK;
498 static bool
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();
507 nsresult
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);
520 nsresult
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);
533 nsresult
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);
544 nsresult
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);
555 nsresult
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);
565 if (idx < 0)
566 return NS_ERROR_INVALID_ARG;
568 if (!mSheets[aType].InsertObjectAt(aNewSheet, idx))
569 return NS_ERROR_OUT_OF_MEMORY;
571 return DirtyRuleProcessors(aType);
574 nsresult
575 nsStyleSet::DirtyRuleProcessors(sheetType aType)
577 if (!mBatching)
578 return GatherRuleProcessors(aType);
580 mDirty |= 1 << aType;
581 return NS_OK;
584 bool
585 nsStyleSet::GetAuthorStyleDisabled()
587 return mAuthorStyleDisabled;
590 nsresult
591 nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
593 if (aStyleDisabled == !mAuthorStyleDisabled) {
594 mAuthorStyleDisabled = aStyleDisabled;
595 BeginUpdate();
596 mDirty |= 1 << eDocSheet |
597 1 << eScopedDocSheet |
598 1 << eStyleAttrSheet;
599 return EndUpdate();
601 return NS_OK;
604 // -------- Doc Sheets
606 nsresult
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) ?
614 eScopedDocSheet :
615 eDocSheet;
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();
625 int32_t index;
626 for (index = 0; index < count; index++) {
627 nsIStyleSheet* sheet = sheets.ObjectAt(index);
628 int32_t sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
629 if (sheetDocIndex > newDocIndex)
630 break;
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 &&
637 ((sheetService &&
638 sheetService->AuthorStyleSheets()->IndexOf(sheet) >= 0) ||
639 sheet == aDocument->FirstAdditionalAuthorSheet()))
640 break;
642 if (!sheets.InsertObjectAt(aSheet, index))
643 return NS_ERROR_OUT_OF_MEMORY;
645 return DirtyRuleProcessors(type);
648 nsresult
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);
656 // Batching
657 void
658 nsStyleSet::BeginUpdate()
660 ++mBatching;
663 nsresult
664 nsStyleSet::EndUpdate()
666 NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
667 if (--mBatching) {
668 // We're not completely done yet.
669 return NS_OK;
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);
679 mDirty = 0;
680 return NS_OK;
683 void
684 nsStyleSet::EnableQuirkStyleSheet(bool aEnable)
686 if (!mQuirkStyleSheet) {
687 // SVG-as-an-image doesn't load this sheet
688 return;
690 #ifdef DEBUG
691 bool oldEnabled;
693 nsCOMPtr<nsIDOMCSSStyleSheet> domSheet =
694 do_QueryInterface(mQuirkStyleSheet);
695 domSheet->GetDisabled(&oldEnabled);
696 oldEnabled = !oldEnabled;
698 #endif
699 mQuirkStyleSheet->SetEnabled(aEnable);
700 #ifdef DEBUG
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();
709 #endif
712 template<class T>
713 static bool
714 EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
716 T* data = static_cast<T*>(aData);
717 aProcessor->RulesMatching(data);
718 return true;
721 static inline bool
722 IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
724 return !aRuleNode->IsRoot() &&
725 (aRuleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
726 aRuleNode->IsImportantRule());
729 static nsIStyleRule*
730 GetAnimationRule(nsRuleNode *aRuleNode)
732 nsRuleNode *n = aRuleNode;
733 while (IsMoreSpecificThanAnimation(n)) {
734 n = n->GetParent();
737 if (n->IsRoot() || n->GetLevel() != nsStyleSet::eAnimationSheet) {
738 return nullptr;
741 return n->GetRule();
744 static nsRuleNode*
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);
754 n = n->GetParent();
757 if (aOldAnimRule) {
758 NS_ABORT_IF_FALSE(n->GetRule() == aOldAnimRule, "wrong rule");
759 NS_ABORT_IF_FALSE(n->GetLevel() == nsStyleSet::eAnimationSheet,
760 "wrong level");
761 n = n->GetParent();
764 NS_ABORT_IF_FALSE(!IsMoreSpecificThanAnimation(n) &&
765 (n->IsRoot() ||
766 n->GetLevel() != nsStyleSet::eAnimationSheet),
767 "wrong level");
769 if (aNewAnimRule) {
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());
779 return n;
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
795 // should be used.)
796 nsRuleNode* aVisitedRuleNode,
797 nsIAtom* aPseudoTag,
798 nsCSSPseudoElements::Type aPseudoType,
799 Element* aElementForAnimation,
800 uint32_t aFlags)
802 NS_PRECONDITION((!aPseudoTag &&
803 aPseudoType ==
804 nsCSSPseudoElements::ePseudo_NotPseudoElement) ||
805 (aPseudoTag &&
806 nsCSSPseudoElements::GetPseudoType(aPseudoTag) ==
807 aPseudoType),
808 "Pseudo mismatch");
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;
824 } else {
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;
842 if (aParentContext)
843 result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
844 aVisitedRuleNode,
845 relevantLinkVisited);
847 #ifdef NOISY_DEBUG
848 if (result)
849 fprintf(stdout, "--- SharedSC %d ---\n", ++gSharedCount);
850 else
851 fprintf(stdout, "+++ NewSC %d +++\n", ++gNewCount);
852 #endif
854 if (!result) {
855 result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
856 aRuleNode,
857 aFlags & eSkipParentDisplayBasedStyleFixup);
858 if (aVisitedRuleNode) {
859 nsRefPtr<nsStyleContext> resultIfVisited =
860 NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
861 aVisitedRuleNode,
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);
877 else {
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() ==
896 aVisitedRuleNode,
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)
906 : nullptr;
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();
930 void
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();
948 if (impRule)
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]);
960 #ifdef DEBUG
961 void
962 nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
963 nsRuleNode* aLastPrevLevelNode)
965 if (!aCurrLevelNode)
966 return;
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");
977 void
978 nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
979 nsRuleNode* aLastPrevLevelNode)
981 if (!aCurrLevelNode)
982 return;
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");
991 #endif
993 // Enumerate the rules in a way that cares about the order of the rules.
994 void
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");
1004 // Cascading order:
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
1018 // [most important]
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
1104 #ifdef DEBUG
1105 else {
1106 AssertNoImportantRules(startRN, endRN);
1108 #endif
1111 #ifdef DEBUG
1112 else {
1113 AssertNoImportantRules(lastScopedRN, lastDocRN);
1115 #endif
1117 if (haveImportantDocRules) {
1118 aRuleWalker->SetLevel(eDocSheet, true, false);
1119 AddImportantRules(lastDocRN, lastSVGAttrAnimationRN, aRuleWalker); // doc
1121 #ifdef DEBUG
1122 else {
1123 AssertNoImportantRules(lastDocRN, lastSVGAttrAnimationRN);
1125 #endif
1127 if (haveImportantStyleAttrRules) {
1128 aRuleWalker->SetLevel(eStyleAttrSheet, true, false);
1129 AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker); // style attr
1131 #ifdef DEBUG
1132 else {
1133 AssertNoImportantRules(lastStyleAttrRN, lastScopedRN);
1135 #endif
1137 if (haveImportantOverrideRules) {
1138 aRuleWalker->SetLevel(eOverrideSheet, true, false);
1139 AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker); // override
1141 #ifdef DEBUG
1142 else {
1143 AssertNoImportantRules(lastOvrRN, lastStyleAttrRN);
1145 #endif
1147 #ifdef DEBUG
1148 AssertNoCSSRules(lastSVGAttrAnimationRN, lastUserRN);
1149 #endif
1151 if (haveImportantUserRules) {
1152 aRuleWalker->SetLevel(eUserSheet, true, false);
1153 AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
1155 #ifdef DEBUG
1156 else {
1157 AssertNoImportantRules(lastUserRN, lastAgentRN);
1159 #endif
1161 if (haveImportantUARules) {
1162 aRuleWalker->SetLevel(eAgentSheet, true, false);
1163 AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
1165 #ifdef DEBUG
1166 else {
1167 AssertNoImportantRules(lastAgentRN, lastRestrictionRN);
1169 #endif
1171 #ifdef DEBUG
1172 AssertNoCSSRules(lastRestrictionRN, mRuleTree);
1173 #endif
1175 #ifdef DEBUG
1176 nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
1177 #endif
1178 aRuleWalker->SetLevel(eTransitionSheet, false, false);
1179 (*aCollectorFunc)(mRuleProcessors[eTransitionSheet], aData);
1180 #ifdef DEBUG
1181 AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
1182 #endif
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.
1188 void
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);
1213 } else {
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);
1233 static void
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,
1262 aTreeMatchContext);
1263 WalkDisableTextZoomRule(aElement, &ruleWalker);
1264 FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
1265 &ruleWalker);
1267 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1268 nsRuleNode *visitedRuleNode = nullptr;
1270 if (aTreeMatchContext.HaveRelevantLink()) {
1271 aTreeMatchContext.ResetForVisitedMatching();
1272 ruleWalker.Reset();
1273 FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
1274 &ruleWalker);
1275 visitedRuleNode = ruleWalker.CurrentNode();
1278 uint32_t flags = eDoAnimation;
1279 if (nsCSSRuleProcessor::IsLink(aElement)) {
1280 flags |= eIsLink;
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,
1292 aElement, flags);
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
1303 // matter.
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,
1311 nullptr, eNoFlags);
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()) {
1346 flags |= eIsLink;
1348 // GetContext handles propagating RelevantLinkVisited state from the
1349 // parent in non-link cases; all we need to pass in is if this link
1350 // is visited.
1351 if (aBaseContext->RelevantLinkVisited()) {
1352 flags |= eIsVisitedLink;
1355 return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
1356 aBaseContext->GetPseudo(),
1357 aBaseContext->GetPseudoType(),
1358 nullptr, flags);
1361 struct RuleNodeInfo {
1362 nsIStyleRule* mRule;
1363 uint8_t mLevel;
1364 bool mIsImportant;
1367 struct CascadeLevel {
1368 uint8_t mLevel;
1369 bool mIsImportant;
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 },
1393 nsRuleNode*
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 |
1407 eRestyle_Force |
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);
1474 if (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);
1482 if (rule) {
1483 ruleWalker.ForwardOnPossiblyCSSRule(rule);
1486 break;
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);
1494 if (rule) {
1495 ruleWalker.ForwardOnPossiblyCSSRule(rule);
1498 break;
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);
1512 break;
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(),
1533 aElement,
1534 &ruleWalker);
1535 lastStyleAttrRN = ruleWalker.CurrentNode();
1536 haveImportantStyleAttrRules =
1537 !ruleWalker.GetCheckForImportantRules();
1539 } else {
1540 // Second time through, we handle the !important rule(s).
1541 if (haveImportantStyleAttrRules) {
1542 AddImportantRules(lastStyleAttrRN, lastScopedRN, &ruleWalker);
1545 break;
1547 default:
1548 MOZ_ASSERT(false, "unexpected result from gCascadeLevels lookup");
1549 break;
1553 while (rulesIndex != 0) {
1554 --rulesIndex;
1555 const RuleNodeInfo& ruleInfo = rules[rulesIndex];
1557 if (ruleInfo.mLevel != level->mLevel ||
1558 ruleInfo.mIsImportant != level->mIsImportant) {
1559 ++rulesIndex;
1560 break;
1563 if (!doReplace) {
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;
1591 } else {
1592 visitedRuleNode =
1593 RuleNodeWithReplacement(aElement, oldStyleIfVisited->RuleNode(),
1594 oldStyleIfVisited->GetPseudoType(),
1595 aReplacements);
1599 uint32_t flags = eNoFlags;
1600 if (aOldStyleContext->IsLinkContext()) {
1601 flags |= eIsLink;
1603 // GetContext handles propagating RelevantLinkVisited state from the
1604 // parent in non-link cases; all we need to pass in is if this link
1605 // is visited.
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()->
1632 GetPseudoType() ==
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,
1657 eNoFlags);
1660 void
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);
1674 void
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,
1700 aPseudoElement);
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();
1710 ruleWalker.Reset();
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;
1723 } else {
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
1727 // style fixup.
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,
1745 treeContext);
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,
1766 aPseudoElement);
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) {
1775 return nullptr;
1778 nsRuleNode *visitedRuleNode = nullptr;
1780 if (aTreeMatchContext.HaveRelevantLink()) {
1781 aTreeMatchContext.ResetForVisitedMatching();
1782 ruleWalker.Reset();
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;
1795 } else {
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
1799 // style fixup.
1800 flags |= eSkipParentDisplayBasedStyleFixup;
1803 nsRefPtr<nsStyleContext> result =
1804 GetContext(aParentContext, ruleNode, visitedRuleNode,
1805 pseudoTag, aType,
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
1810 // at all.
1811 if (result &&
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) {
1819 result = nullptr;
1823 return result.forget();
1826 already_AddRefed<nsStyleContext>
1827 nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
1828 nsStyleContext* aParentContext)
1830 NS_ENSURE_FALSE(mInShutdown, nullptr);
1832 #ifdef DEBUG
1833 bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag)
1834 #ifdef MOZ_XUL
1835 && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
1836 #endif
1838 NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
1839 #endif
1841 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1842 AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
1843 FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
1844 &ruleWalker);
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,
1866 nullptr, eNoFlags);
1869 #ifdef MOZ_XUL
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,
1889 &ruleWalker);
1891 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1892 nsRuleNode *visitedRuleNode = nullptr;
1894 if (treeContext.HaveRelevantLink()) {
1895 treeContext.ResetForVisitedMatching();
1896 ruleWalker.Reset();
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,
1906 nullptr, eNoFlags);
1908 #endif
1910 bool
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)
1919 continue;
1920 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
1921 (mRuleProcessors[gCSSSheetTypes[i]].get());
1922 if (ruleProc && !ruleProc->AppendFontFaceRules(aPresContext, aArray))
1923 return false;
1925 return true;
1928 nsCSSKeyframesRule*
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)
1937 continue;
1938 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
1939 (mRuleProcessors[gCSSSheetTypes[i]].get());
1940 if (!ruleProc)
1941 continue;
1942 nsCSSKeyframesRule* result =
1943 ruleProc->KeyframesRuleForName(aPresContext, aName);
1944 if (result)
1945 return result;
1947 return nullptr;
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)
1959 continue;
1960 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
1961 (mRuleProcessors[gCSSSheetTypes[i]].get());
1962 if (!ruleProc)
1963 continue;
1964 nsCSSCounterStyleRule *result =
1965 ruleProc->CounterStyleRuleForName(aPresContext, aName);
1966 if (result)
1967 return result;
1969 return nullptr;
1972 bool
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());
1982 if (ruleProc &&
1983 !ruleProc->AppendFontFeatureValuesRules(aPresContext, aArray))
1985 return false;
1988 return true;
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();
2010 // for each family
2011 size_t f, numFam;
2013 numFam = familyList.Length();
2014 for (f = 0; f < numFam; f++) {
2015 mFontFeatureValuesLookup->AddFontFeatureValues(familyList[f].mName,
2016 featureValues);
2021 nsRefPtr<gfxFontFeatureValueSet> lookup = mFontFeatureValuesLookup;
2022 return lookup.forget();
2025 bool
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)
2034 continue;
2035 nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
2036 (mRuleProcessors[gCSSSheetTypes[i]].get());
2037 if (ruleProc && !ruleProc->AppendPageRules(aPresContext, aArray))
2038 return false;
2040 return true;
2043 void
2044 nsStyleSet::BeginShutdown(nsPresContext* aPresContext)
2046 mInShutdown = 1;
2047 mRoots.Clear(); // no longer valid, since we won't keep it up to date
2050 void
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; ) {
2060 --i;
2061 mOldRuleTrees[i]->Destroy();
2063 mOldRuleTrees.Clear();
2066 static const uint32_t kGCInterval = 300;
2068 void
2069 nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
2070 nsStyleContext* aStyleContext)
2072 if (mInShutdown)
2073 return;
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);
2081 if (mInReconstruct)
2082 return;
2084 if (mUnusedRuleNodeCount >= kGCInterval) {
2085 GCRuleTrees();
2089 void
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) {
2099 mRoots[i]->Mark();
2102 // Sweep the rule tree.
2103 #ifdef DEBUG
2104 bool deleted =
2105 #endif
2106 mRuleTree->Sweep();
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; ) {
2111 --i;
2112 if (mOldRuleTrees[i]->Sweep()) {
2113 // It was deleted, as it should be.
2114 mOldRuleTrees.RemoveElementAt(i);
2115 } else {
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);
2155 return ruleNode;
2158 already_AddRefed<nsStyleContext>
2159 nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
2160 nsStyleContext* aNewParentContext,
2161 Element* aElement,
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
2188 // provide.
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
2198 // a link.
2199 if (visitedContext) {
2200 visitedRuleNode = visitedContext->RuleNode();
2201 // Again, skip transition rules as needed
2202 if (skipAnimationRules) {
2203 // FIXME do something here for animations?
2204 visitedRuleNode =
2205 SkipAnimationRules(visitedRuleNode, aElementOrPseudoElement,
2206 postAnimationRestyles);
2210 uint32_t flags = eNoFlags;
2211 if (aStyleContext->IsLinkContext()) {
2212 flags |= eIsLink;
2214 // GetContext handles propagating RelevantLinkVisited state from the
2215 // parent in non-link cases; all we need to pass in is if this link
2216 // is visited.
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,
2238 aElement, flags);
2241 struct MOZ_STACK_CLASS StatefulData : public StateRuleProcessorData {
2242 StatefulData(nsPresContext* aPresContext, Element* aElement,
2243 EventStates aStateMask, TreeMatchContext& aTreeMatchContext)
2244 : StateRuleProcessorData(aPresContext, aElement, aStateMask,
2245 aTreeMatchContext),
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,
2257 aPseudoElement),
2258 mHint(nsRestyleHint(0))
2260 nsRestyleHint mHint;
2263 static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
2264 void *aData)
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.
2275 bool
2276 nsStyleSet::HasDocumentStateDependentStyle(nsPresContext* aPresContext,
2277 nsIContent* aContent,
2278 EventStates aStateMask)
2280 if (!aContent || !aContent->IsElement())
2281 return false;
2283 TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
2284 aContent->OwnerDoc());
2285 InitStyleScopes(treeContext, aContent->AsElement());
2286 StatefulData data(aPresContext, aContent->AsElement(), aStateMask,
2287 treeContext);
2288 WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
2289 return data.mHint != 0;
2292 static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
2293 void *aData)
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,
2302 void *aData)
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
2311 nsRestyleHint
2312 nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
2313 Element* aElement,
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);
2321 return data.mHint;
2324 nsRestyleHint
2325 nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
2326 Element* aElement,
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);
2337 return data.mHint;
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;
2351 static bool
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
2361 nsRestyleHint
2362 nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
2363 Element* aElement,
2364 nsIAtom* aAttribute,
2365 int32_t aModType,
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);
2374 return data.mHint;
2377 bool
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];
2386 if (!processor) {
2387 continue;
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) {
2433 res = sheetRes;
2436 // Enqueue all the sheet's children.
2437 sheet->AppendAllChildSheets(queue);
2439 return res;
2442 nsIStyleRule*
2443 nsStyleSet::InitialStyleRule()
2445 if (!mInitialStyleRule) {
2446 mInitialStyleRule = new nsInitialStyleRule;
2448 return mInitialStyleRule;