Bug 867089 - Validate the playbackRate before using it. r=ehsan
[gecko.git] / layout / style / nsStyleSet.cpp
blobbe71e89d8a219e1bae19ef481420e781ef27b8fd
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 "mozilla/Util.h"
14 #include "nsStyleSet.h"
15 #include "nsCSSStyleSheet.h"
16 #include "nsIDocumentInlines.h"
17 #include "nsRuleWalker.h"
18 #include "nsStyleContext.h"
19 #include "mozilla/css/StyleRule.h"
20 #include "nsCSSAnonBoxes.h"
21 #include "nsCSSPseudoElements.h"
22 #include "nsCSSRuleProcessor.h"
23 #include "nsDataHashtable.h"
24 #include "nsIContent.h"
25 #include "nsRuleData.h"
26 #include "nsRuleProcessorData.h"
27 #include "nsTransitionManager.h"
28 #include "nsAnimationManager.h"
29 #include "nsEventStates.h"
30 #include "nsStyleSheetService.h"
31 #include "mozilla/dom/Element.h"
32 #include "GeckoProfiler.h"
34 using namespace mozilla;
35 using namespace mozilla::dom;
37 NS_IMPL_ISUPPORTS1(nsEmptyStyleRule, nsIStyleRule)
39 /* virtual */ void
40 nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
44 #ifdef DEBUG
45 /* virtual */ void
46 nsEmptyStyleRule::List(FILE* out, int32_t aIndent) const
48 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
49 fputs("[empty style rule] {}\n", out);
51 #endif
53 NS_IMPL_ISUPPORTS1(nsInitialStyleRule, nsIStyleRule)
55 /* virtual */ void
56 nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
58 // Iterate over the property groups
59 for (nsStyleStructID sid = nsStyleStructID(0);
60 sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
61 if (aRuleData->mSIDs & (1 << sid)) {
62 // Iterate over nsCSSValues within the property group
63 nsCSSValue * const value_start =
64 aRuleData->mValueStorage + aRuleData->mValueOffsets[sid];
65 for (nsCSSValue *value = value_start,
66 *value_end = value + nsCSSProps::PropertyCountInStruct(sid);
67 value != value_end; ++value) {
68 // If MathML is disabled take care not to set MathML properties (or we
69 // will trigger assertions in nsRuleNode)
70 if (sid == eStyleStruct_Font &&
71 !aRuleData->mPresContext->Document()->GetMathMLEnabled()) {
72 size_t index = value - value_start;
73 if (index == nsCSSProps::PropertyIndexInStruct(
74 eCSSProperty_script_level) ||
75 index == nsCSSProps::PropertyIndexInStruct(
76 eCSSProperty_script_size_multiplier) ||
77 index == nsCSSProps::PropertyIndexInStruct(
78 eCSSProperty_script_min_size)) {
79 continue;
82 if (value->GetUnit() == eCSSUnit_Null) {
83 value->SetInitialValue();
90 #ifdef DEBUG
91 /* virtual */ void
92 nsInitialStyleRule::List(FILE* out, int32_t aIndent) const
94 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
95 fputs("[initial style rule] {}\n", out);
97 #endif
99 static const nsStyleSet::sheetType gCSSSheetTypes[] = {
100 nsStyleSet::eAgentSheet,
101 nsStyleSet::eUserSheet,
102 nsStyleSet::eDocSheet,
103 nsStyleSet::eScopedDocSheet,
104 nsStyleSet::eOverrideSheet
107 nsStyleSet::nsStyleSet()
108 : mRuleTree(nullptr),
109 mBatching(0),
110 mInShutdown(false),
111 mAuthorStyleDisabled(false),
112 mInReconstruct(false),
113 mDirty(0),
114 mUnusedRuleNodeCount(0)
118 size_t
119 nsStyleSet::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
121 size_t n = aMallocSizeOf(this);
123 for (int i = 0; i < eSheetTypeCount; i++) {
124 if (mRuleProcessors[i]) {
125 n += mRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
127 n += mSheets[i].SizeOfExcludingThis(nullptr, aMallocSizeOf);
130 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
131 n += mScopedDocSheetRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
133 n += mScopedDocSheetRuleProcessors.SizeOfExcludingThis(aMallocSizeOf);
135 n += mRoots.SizeOfExcludingThis(aMallocSizeOf);
136 n += mOldRuleTrees.SizeOfExcludingThis(aMallocSizeOf);
138 return n;
141 void
142 nsStyleSet::Init(nsPresContext *aPresContext)
144 mFirstLineRule = new nsEmptyStyleRule;
145 mFirstLetterRule = new nsEmptyStyleRule;
146 mPlaceholderRule = new nsEmptyStyleRule;
148 mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
150 GatherRuleProcessors(eAnimationSheet);
151 GatherRuleProcessors(eTransitionSheet);
154 nsresult
155 nsStyleSet::BeginReconstruct()
157 NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
158 NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
160 // Create a new rule tree root
161 nsRuleNode* newTree =
162 nsRuleNode::CreateRootNode(mRuleTree->PresContext());
163 if (!newTree)
164 return NS_ERROR_OUT_OF_MEMORY;
166 // Save the old rule tree so we can destroy it later
167 if (!mOldRuleTrees.AppendElement(mRuleTree)) {
168 newTree->Destroy();
169 return NS_ERROR_OUT_OF_MEMORY;
172 // We need to keep mRoots so that the rule tree GC will only free the
173 // rule trees that really aren't referenced anymore (which should be
174 // all of them, if there are no bugs in reresolution code).
176 mInReconstruct = true;
177 mRuleTree = newTree;
179 return NS_OK;
182 void
183 nsStyleSet::EndReconstruct()
185 NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
186 mInReconstruct = false;
187 #ifdef DEBUG
188 for (int32_t i = mRoots.Length() - 1; i >= 0; --i) {
189 nsRuleNode *n = mRoots[i]->RuleNode();
190 while (n->GetParent()) {
191 n = n->GetParent();
193 // Since nsStyleContext's mParent and mRuleNode are immutable, and
194 // style contexts own their parents, and nsStyleContext asserts in
195 // its constructor that the style context and its parent are in the
196 // same rule tree, we don't need to check any of the children of
197 // mRoots; we only need to check the rule nodes of mRoots
198 // themselves.
200 NS_ASSERTION(n == mRuleTree, "style context has old rule node");
202 #endif
203 // This *should* destroy the only element of mOldRuleTrees, but in
204 // case of some bugs (which would trigger the above assertions), it
205 // won't.
206 GCRuleTrees();
209 void
210 nsStyleSet::SetQuirkStyleSheet(nsIStyleSheet* aQuirkStyleSheet)
212 NS_ASSERTION(aQuirkStyleSheet, "Must have quirk sheet if this is called");
213 NS_ASSERTION(!mQuirkStyleSheet, "Multiple calls to SetQuirkStyleSheet?");
214 NS_ASSERTION(mSheets[eAgentSheet].IndexOf(aQuirkStyleSheet) != -1,
215 "Quirk style sheet not one of our agent sheets?");
216 mQuirkStyleSheet = aQuirkStyleSheet;
219 typedef nsDataHashtable<nsPtrHashKey<nsINode>, uint32_t> ScopeDepthCache;
221 // Returns the depth of a style scope element, with 1 being the depth of
222 // a style scope element that has no ancestor style scope elements. The
223 // depth does not count intervening non-scope elements.
224 static uint32_t
225 GetScopeDepth(nsINode* aScopeElement, ScopeDepthCache& aCache)
227 nsINode* parent = aScopeElement->GetParent();
228 if (!parent || !parent->IsElementInStyleScope()) {
229 return 1;
232 uint32_t depth = aCache.Get(aScopeElement);
233 if (!depth) {
234 for (nsINode* n = parent; n; n = n->GetParent()) {
235 if (n->IsScopedStyleRoot()) {
236 depth = GetScopeDepth(n, aCache) + 1;
237 aCache.Put(aScopeElement, depth);
238 break;
242 return depth;
245 struct ScopedSheetOrder
247 nsCSSStyleSheet* mSheet;
248 uint32_t mDepth;
249 uint32_t mOrder;
251 bool operator==(const ScopedSheetOrder& aRHS) const
253 return mDepth == aRHS.mDepth &&
254 mOrder == aRHS.mOrder;
257 bool operator<(const ScopedSheetOrder& aRHS) const
259 if (mDepth != aRHS.mDepth) {
260 return mDepth < aRHS.mDepth;
262 return mOrder < aRHS.mOrder;
266 // Sorts aSheets such that style sheets for ancestor scopes come
267 // before those for descendant scopes, and with sheets for a single
268 // scope in document order.
269 static void
270 SortStyleSheetsByScope(nsTArray<nsCSSStyleSheet*>& aSheets)
272 uint32_t n = aSheets.Length();
273 if (n == 1) {
274 return;
277 ScopeDepthCache cache;
278 cache.Init();
280 nsTArray<ScopedSheetOrder> sheets;
281 sheets.SetLength(n);
283 // For each sheet, record the depth of its scope element and its original
284 // document order.
285 for (uint32_t i = 0; i < n; i++) {
286 sheets[i].mSheet = aSheets[i];
287 sheets[i].mDepth = GetScopeDepth(aSheets[i]->GetScopeElement(), cache);
288 sheets[i].mOrder = i;
291 // Sort by depth first, then document order.
292 sheets.Sort();
294 for (uint32_t i = 0; i < n; i++) {
295 aSheets[i] = sheets[i].mSheet;
299 nsresult
300 nsStyleSet::GatherRuleProcessors(sheetType aType)
302 mRuleProcessors[aType] = nullptr;
303 if (aType == eScopedDocSheet) {
304 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
305 nsIStyleRuleProcessor* processor = mScopedDocSheetRuleProcessors[i].get();
306 Element* scope =
307 static_cast<nsCSSRuleProcessor*>(processor)->GetScopeElement();
308 scope->ClearIsScopedStyleRoot();
310 mScopedDocSheetRuleProcessors.Clear();
312 if (mAuthorStyleDisabled && (aType == eDocSheet ||
313 aType == eScopedDocSheet ||
314 aType == eStyleAttrSheet)) {
315 // Don't regather if this level is disabled. Note that we gather
316 // preshint sheets no matter what, but then skip them for some
317 // elements later if mAuthorStyleDisabled.
318 return NS_OK;
320 if (aType == eAnimationSheet) {
321 // We have no sheet for the animations level; just a rule
322 // processor. (XXX: We should probably do this for the other
323 // non-CSS levels too!)
324 mRuleProcessors[aType] = PresContext()->AnimationManager();
325 return NS_OK;
327 if (aType == eTransitionSheet) {
328 // We have no sheet for the transitions level; just a rule
329 // processor. (XXX: We should probably do this for the other
330 // non-CSS levels too!)
331 mRuleProcessors[aType] = PresContext()->TransitionManager();
332 return NS_OK;
334 if (aType == eScopedDocSheet) {
335 // Create a rule processor for each scope.
336 uint32_t count = mSheets[eScopedDocSheet].Count();
337 if (count) {
338 // Gather the scoped style sheets into an array as
339 // nsCSSStyleSheets, and mark all of their scope elements
340 // as scoped style roots.
341 nsTArray<nsCSSStyleSheet*> sheets(count);
342 for (uint32_t i = 0; i < count; i++) {
343 nsRefPtr<nsCSSStyleSheet> sheet =
344 do_QueryObject(mSheets[eScopedDocSheet].ObjectAt(i));
345 sheets.AppendElement(sheet);
347 Element* scope = sheet->GetScopeElement();
348 scope->SetIsScopedStyleRoot();
351 // Sort the scoped style sheets so that those for the same scope are
352 // adjacent and that ancestor scopes come before descendent scopes.
353 SortStyleSheetsByScope(sheets);
355 uint32_t start = 0, end;
356 do {
357 // Find the range of style sheets with the same scope.
358 Element* scope = sheets[start]->GetScopeElement();
359 end = start + 1;
360 while (end < count && sheets[end]->GetScopeElement() == scope) {
361 end++;
364 scope->SetIsScopedStyleRoot();
366 // Create a rule processor for the scope.
367 nsTArray< nsRefPtr<nsCSSStyleSheet> > sheetsForScope;
368 sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
369 mScopedDocSheetRuleProcessors.AppendElement
370 (new nsCSSRuleProcessor(sheetsForScope, uint8_t(aType), scope));
372 start = end;
373 } while (start < count);
375 return NS_OK;
377 if (mSheets[aType].Count()) {
378 switch (aType) {
379 case eAgentSheet:
380 case eUserSheet:
381 case eDocSheet:
382 case eOverrideSheet: {
383 // levels containing CSS stylesheets (apart from eScopedDocSheet)
384 nsCOMArray<nsIStyleSheet>& sheets = mSheets[aType];
385 nsTArray<nsRefPtr<nsCSSStyleSheet> > cssSheets(sheets.Count());
386 for (int32_t i = 0, i_end = sheets.Count(); i < i_end; ++i) {
387 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheets[i]);
388 NS_ASSERTION(cssSheet, "not a CSS sheet");
389 cssSheets.AppendElement(cssSheet);
391 mRuleProcessors[aType] =
392 new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr);
393 } break;
395 default:
396 // levels containing non-CSS stylesheets
397 NS_ASSERTION(mSheets[aType].Count() == 1, "only one sheet per level");
398 mRuleProcessors[aType] = do_QueryInterface(mSheets[aType][0]);
399 break;
403 return NS_OK;
406 static bool
407 IsScopedStyleSheet(nsIStyleSheet* aSheet)
409 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(aSheet);
410 NS_ASSERTION(cssSheet, "expected aSheet to be an nsCSSStyleSheet");
412 return cssSheet->GetScopeElement();
415 nsresult
416 nsStyleSet::AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
418 NS_PRECONDITION(aSheet, "null arg");
419 NS_ASSERTION(aSheet->IsApplicable(),
420 "Inapplicable sheet being placed in style set");
421 mSheets[aType].RemoveObject(aSheet);
422 if (!mSheets[aType].AppendObject(aSheet))
423 return NS_ERROR_OUT_OF_MEMORY;
425 if (!mBatching)
426 return GatherRuleProcessors(aType);
428 mDirty |= 1 << aType;
429 return NS_OK;
432 nsresult
433 nsStyleSet::PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
435 NS_PRECONDITION(aSheet, "null arg");
436 NS_ASSERTION(aSheet->IsApplicable(),
437 "Inapplicable sheet being placed in style set");
438 mSheets[aType].RemoveObject(aSheet);
439 if (!mSheets[aType].InsertObjectAt(aSheet, 0))
440 return NS_ERROR_OUT_OF_MEMORY;
442 if (!mBatching)
443 return GatherRuleProcessors(aType);
445 mDirty |= 1 << aType;
446 return NS_OK;
449 nsresult
450 nsStyleSet::RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet)
452 NS_PRECONDITION(aSheet, "null arg");
453 NS_ASSERTION(aSheet->IsComplete(),
454 "Incomplete sheet being removed from style set");
455 mSheets[aType].RemoveObject(aSheet);
456 if (!mBatching)
457 return GatherRuleProcessors(aType);
459 mDirty |= 1 << aType;
460 return NS_OK;
463 nsresult
464 nsStyleSet::ReplaceSheets(sheetType aType,
465 const nsCOMArray<nsIStyleSheet> &aNewSheets)
467 mSheets[aType].Clear();
468 if (!mSheets[aType].AppendObjects(aNewSheets))
469 return NS_ERROR_OUT_OF_MEMORY;
471 if (!mBatching)
472 return GatherRuleProcessors(aType);
474 mDirty |= 1 << aType;
475 return NS_OK;
478 nsresult
479 nsStyleSet::InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
480 nsIStyleSheet *aReferenceSheet)
482 NS_PRECONDITION(aNewSheet && aReferenceSheet, "null arg");
483 NS_ASSERTION(aNewSheet->IsApplicable(),
484 "Inapplicable sheet being placed in style set");
486 mSheets[aType].RemoveObject(aNewSheet);
487 int32_t idx = mSheets[aType].IndexOf(aReferenceSheet);
488 if (idx < 0)
489 return NS_ERROR_INVALID_ARG;
491 if (!mSheets[aType].InsertObjectAt(aNewSheet, idx))
492 return NS_ERROR_OUT_OF_MEMORY;
494 if (!mBatching)
495 return GatherRuleProcessors(aType);
497 mDirty |= 1 << aType;
498 return NS_OK;
501 bool
502 nsStyleSet::GetAuthorStyleDisabled()
504 return mAuthorStyleDisabled;
507 nsresult
508 nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
510 if (aStyleDisabled == !mAuthorStyleDisabled) {
511 mAuthorStyleDisabled = aStyleDisabled;
512 BeginUpdate();
513 mDirty |= 1 << eDocSheet |
514 1 << eScopedDocSheet |
515 1 << eStyleAttrSheet;
516 return EndUpdate();
518 return NS_OK;
521 // -------- Doc Sheets
523 nsresult
524 nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument)
526 NS_PRECONDITION(aSheet && aDocument, "null arg");
527 NS_ASSERTION(aSheet->IsApplicable(),
528 "Inapplicable sheet being placed in style set");
530 sheetType type = IsScopedStyleSheet(aSheet) ?
531 eScopedDocSheet :
532 eDocSheet;
533 nsCOMArray<nsIStyleSheet>& sheets = mSheets[type];
535 sheets.RemoveObject(aSheet);
536 nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
538 // lowest index first
539 int32_t newDocIndex = aDocument->GetIndexOfStyleSheet(aSheet);
541 int32_t count = sheets.Count();
542 int32_t index;
543 for (index = 0; index < count; index++) {
544 nsIStyleSheet* sheet = sheets.ObjectAt(index);
545 int32_t sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
546 if (sheetDocIndex > newDocIndex)
547 break;
549 // If the sheet is not owned by the document it can be an author
550 // sheet registered at nsStyleSheetService or an additional author
551 // sheet on the document, which means the new
552 // doc sheet should end up before it.
553 if (sheetDocIndex < 0 &&
554 ((sheetService &&
555 sheetService->AuthorStyleSheets()->IndexOf(sheet) >= 0) ||
556 sheet == aDocument->FirstAdditionalAuthorSheet()))
557 break;
559 if (!sheets.InsertObjectAt(aSheet, index))
560 return NS_ERROR_OUT_OF_MEMORY;
561 if (!mBatching)
562 return GatherRuleProcessors(type);
564 mDirty |= 1 << type;
565 return NS_OK;
568 nsresult
569 nsStyleSet::RemoveDocStyleSheet(nsIStyleSheet *aSheet)
571 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(aSheet);
572 bool isScoped = cssSheet && cssSheet->GetScopeElement();
573 return RemoveStyleSheet(isScoped ? eScopedDocSheet : eDocSheet, aSheet);
576 // Batching
577 void
578 nsStyleSet::BeginUpdate()
580 ++mBatching;
583 nsresult
584 nsStyleSet::EndUpdate()
586 NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
587 if (--mBatching) {
588 // We're not completely done yet.
589 return NS_OK;
592 for (int i = 0; i < eSheetTypeCount; ++i) {
593 if (mDirty & (1 << i)) {
594 nsresult rv = GatherRuleProcessors(sheetType(i));
595 NS_ENSURE_SUCCESS(rv, rv);
599 mDirty = 0;
600 return NS_OK;
603 void
604 nsStyleSet::EnableQuirkStyleSheet(bool aEnable)
606 #ifdef DEBUG
607 bool oldEnabled;
609 nsCOMPtr<nsIDOMCSSStyleSheet> domSheet =
610 do_QueryInterface(mQuirkStyleSheet);
611 domSheet->GetDisabled(&oldEnabled);
612 oldEnabled = !oldEnabled;
614 #endif
615 mQuirkStyleSheet->SetEnabled(aEnable);
616 #ifdef DEBUG
617 // This should always be OK, since SetEnabled should call
618 // ClearRuleCascades.
619 // Note that we can hit this codepath multiple times when document.open()
620 // (potentially implied) happens multiple times.
621 if (mRuleProcessors[eAgentSheet] && aEnable != oldEnabled) {
622 static_cast<nsCSSRuleProcessor*>(static_cast<nsIStyleRuleProcessor*>(
623 mRuleProcessors[eAgentSheet]))->AssertQuirksChangeOK();
625 #endif
628 template<class T>
629 static bool
630 EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
632 T* data = static_cast<T*>(aData);
633 aProcessor->RulesMatching(data);
634 return true;
637 static inline bool
638 IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
640 return !aRuleNode->IsRoot() &&
641 (aRuleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
642 aRuleNode->IsImportantRule());
645 static nsIStyleRule*
646 GetAnimationRule(nsRuleNode *aRuleNode)
648 nsRuleNode *n = aRuleNode;
649 while (IsMoreSpecificThanAnimation(n)) {
650 n = n->GetParent();
653 if (n->IsRoot() || n->GetLevel() != nsStyleSet::eAnimationSheet) {
654 return nullptr;
657 return n->GetRule();
660 static nsRuleNode*
661 ReplaceAnimationRule(nsRuleNode *aOldRuleNode,
662 nsIStyleRule *aOldAnimRule,
663 nsIStyleRule *aNewAnimRule)
665 nsTArray<nsRuleNode*> moreSpecificNodes;
667 nsRuleNode *n = aOldRuleNode;
668 while (IsMoreSpecificThanAnimation(n)) {
669 moreSpecificNodes.AppendElement(n);
670 n = n->GetParent();
673 if (aOldAnimRule) {
674 NS_ABORT_IF_FALSE(n->GetRule() == aOldAnimRule, "wrong rule");
675 NS_ABORT_IF_FALSE(n->GetLevel() == nsStyleSet::eAnimationSheet,
676 "wrong level");
677 n = n->GetParent();
680 NS_ABORT_IF_FALSE(!IsMoreSpecificThanAnimation(n) &&
681 (n->IsRoot() ||
682 n->GetLevel() != nsStyleSet::eAnimationSheet),
683 "wrong level");
685 if (aNewAnimRule) {
686 n = n->Transition(aNewAnimRule, nsStyleSet::eAnimationSheet, false);
689 for (uint32_t i = moreSpecificNodes.Length(); i-- != 0; ) {
690 nsRuleNode *oldNode = moreSpecificNodes[i];
691 n = n->Transition(oldNode->GetRule(), oldNode->GetLevel(),
692 oldNode->IsImportantRule());
695 return n;
699 * |GetContext| implements sharing of style contexts (not just the data
700 * on the rule nodes) between siblings and cousins of the same
701 * generation. (It works for cousins of the same generation since
702 * |aParentContext| could itself be a shared context.)
704 already_AddRefed<nsStyleContext>
705 nsStyleSet::GetContext(nsStyleContext* aParentContext,
706 nsRuleNode* aRuleNode,
707 // aVisitedRuleNode may be null; if it is null
708 // it means that we don't need to force creation
709 // of a StyleIfVisited. (But if we make one
710 // because aParentContext has one, then aRuleNode
711 // should be used.)
712 nsRuleNode* aVisitedRuleNode,
713 nsIAtom* aPseudoTag,
714 nsCSSPseudoElements::Type aPseudoType,
715 Element* aElementForAnimation,
716 uint32_t aFlags)
718 NS_PRECONDITION((!aPseudoTag &&
719 aPseudoType ==
720 nsCSSPseudoElements::ePseudo_NotPseudoElement) ||
721 (aPseudoTag &&
722 nsCSSPseudoElements::GetPseudoType(aPseudoTag) ==
723 aPseudoType),
724 "Pseudo mismatch");
726 if (aVisitedRuleNode == aRuleNode) {
727 // No need to force creation of a visited style in this case.
728 aVisitedRuleNode = nullptr;
731 // Ensure |aVisitedRuleNode != nullptr| corresponds to the need to
732 // create an if-visited style context, and that in that case, we have
733 // parentIfVisited set correctly.
734 nsStyleContext *parentIfVisited =
735 aParentContext ? aParentContext->GetStyleIfVisited() : nullptr;
736 if (parentIfVisited) {
737 if (!aVisitedRuleNode) {
738 aVisitedRuleNode = aRuleNode;
740 } else {
741 if (aVisitedRuleNode) {
742 parentIfVisited = aParentContext;
746 if (aFlags & eIsLink) {
747 // If this node is a link, we want its visited's style context's
748 // parent to be the regular style context of its parent, because
749 // only the visitedness of the relevant link should influence style.
750 parentIfVisited = aParentContext;
753 nsRefPtr<nsStyleContext> result;
754 if (aParentContext)
755 result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
756 aVisitedRuleNode,
757 aFlags & eIsVisitedLink);
759 #ifdef NOISY_DEBUG
760 if (result)
761 fprintf(stdout, "--- SharedSC %d ---\n", ++gSharedCount);
762 else
763 fprintf(stdout, "+++ NewSC %d +++\n", ++gNewCount);
764 #endif
766 if (!result) {
767 result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
768 aRuleNode, aFlags & eSkipFlexItemStyleFixup);
769 if (!result)
770 return nullptr;
771 if (aVisitedRuleNode) {
772 nsRefPtr<nsStyleContext> resultIfVisited =
773 NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
774 aVisitedRuleNode,
775 aFlags & eSkipFlexItemStyleFixup);
776 if (!resultIfVisited) {
777 return nullptr;
779 if (!parentIfVisited) {
780 mRoots.AppendElement(resultIfVisited);
782 resultIfVisited->SetIsStyleIfVisited();
783 result->SetStyleIfVisited(resultIfVisited.forget());
785 bool relevantLinkVisited = (aFlags & eIsLink) ?
786 (aFlags & eIsVisitedLink) :
787 (aParentContext && aParentContext->RelevantLinkVisited());
789 if (relevantLinkVisited) {
790 result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
793 if (!aParentContext) {
794 mRoots.AppendElement(result);
797 else {
798 NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
799 NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
802 if (aFlags & eDoAnimation) {
803 // Normally the animation manager has already added the correct
804 // style rule. However, if the animation-name just changed, it
805 // might have been wrong. So ask it to double-check based on the
806 // resulting style context.
807 nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
808 nsIStyleRule *animRule = PresContext()->AnimationManager()->
809 CheckAnimationRule(result, aElementForAnimation);
810 NS_ABORT_IF_FALSE(result->RuleNode() == aRuleNode,
811 "unexpected rule node");
812 NS_ABORT_IF_FALSE(!result->GetStyleIfVisited() == !aVisitedRuleNode,
813 "unexpected visited rule node");
814 NS_ABORT_IF_FALSE(!aVisitedRuleNode ||
815 result->GetStyleIfVisited()->RuleNode() ==
816 aVisitedRuleNode,
817 "unexpected visited rule node");
818 if (oldAnimRule != animRule) {
819 nsRuleNode *ruleNode =
820 ReplaceAnimationRule(aRuleNode, oldAnimRule, animRule);
821 nsRuleNode *visitedRuleNode = aVisitedRuleNode
822 ? ReplaceAnimationRule(aVisitedRuleNode, oldAnimRule, animRule)
823 : nullptr;
824 result = GetContext(aParentContext, ruleNode, visitedRuleNode,
825 aPseudoTag, aPseudoType, nullptr,
826 aFlags & ~eDoAnimation);
830 if (aElementForAnimation && aElementForAnimation->IsHTML(nsGkAtoms::body) &&
831 aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement &&
832 PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
833 nsIDocument* doc = aElementForAnimation->GetCurrentDoc();
834 if (doc && doc->GetBodyElement() == aElementForAnimation) {
835 // Update the prescontext's body color
836 PresContext()->SetBodyTextColor(result->StyleColor()->mColor);
840 return result.forget();
843 void
844 nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
845 nsRuleNode* aLastPrevLevelNode,
846 nsRuleWalker* aRuleWalker)
848 NS_ASSERTION(aCurrLevelNode &&
849 aCurrLevelNode != aLastPrevLevelNode, "How did we get here?");
851 nsAutoTArray<nsIStyleRule*, 16> importantRules;
852 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
853 node = node->GetParent()) {
854 // We guarantee that we never walk the root node here, so no need
855 // to null-check GetRule(). Furthermore, it must be a CSS rule.
856 NS_ASSERTION(nsRefPtr<css::StyleRule>(do_QueryObject(node->GetRule())),
857 "Unexpected non-CSS rule");
859 nsIStyleRule* impRule =
860 static_cast<css::StyleRule*>(node->GetRule())->GetImportantRule();
861 if (impRule)
862 importantRules.AppendElement(impRule);
865 NS_ASSERTION(importantRules.Length() != 0,
866 "Why did we think there were important rules?");
868 for (uint32_t i = importantRules.Length(); i-- != 0; ) {
869 aRuleWalker->Forward(importantRules[i]);
873 #ifdef DEBUG
874 void
875 nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
876 nsRuleNode* aLastPrevLevelNode)
878 if (!aCurrLevelNode)
879 return;
881 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
882 node = node->GetParent()) {
883 nsRefPtr<css::StyleRule> rule(do_QueryObject(node->GetRule()));
884 NS_ASSERTION(rule, "Unexpected non-CSS rule");
886 NS_ASSERTION(!rule->GetImportantRule(), "Unexpected important rule");
890 void
891 nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
892 nsRuleNode* aLastPrevLevelNode)
894 if (!aCurrLevelNode)
895 return;
897 for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
898 node = node->GetParent()) {
899 nsIStyleRule *rule = node->GetRule();
900 nsRefPtr<css::StyleRule> cssRule(do_QueryObject(rule));
901 NS_ASSERTION(!cssRule || !cssRule->Selector(), "Unexpected CSS rule");
904 #endif
906 // Enumerate the rules in a way that cares about the order of the rules.
907 void
908 nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
909 RuleProcessorData* aData, Element* aElement,
910 nsRuleWalker* aRuleWalker)
912 PROFILER_LABEL("nsStyleSet", "FileRules");
914 // Cascading order:
915 // [least important]
916 // - UA normal rules = Agent normal
917 // - User normal rules = User normal
918 // - Presentation hints = PresHint normal
919 // - Author normal rules = Document normal
920 // - Override normal rules = Override normal
921 // - animation rules = Animation normal
922 // - Author !important rules = Document !important
923 // - Override !important rules = Override !important
924 // - User !important rules = User !important
925 // - UA !important rules = Agent !important
926 // - transition rules = Transition normal
927 // [most important]
929 // Save off the last rule before we start walking our agent sheets;
930 // this will be either the root or one of the restriction rules.
931 nsRuleNode* lastRestrictionRN = aRuleWalker->CurrentNode();
933 aRuleWalker->SetLevel(eAgentSheet, false, true);
934 if (mRuleProcessors[eAgentSheet])
935 (*aCollectorFunc)(mRuleProcessors[eAgentSheet], aData);
936 nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
937 bool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
939 aRuleWalker->SetLevel(eUserSheet, false, true);
940 bool skipUserStyles =
941 aElement && aElement->IsInNativeAnonymousSubtree();
942 if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
943 (*aCollectorFunc)(mRuleProcessors[eUserSheet], aData);
944 nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
945 bool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
947 aRuleWalker->SetLevel(ePresHintSheet, false, false);
948 if (mRuleProcessors[ePresHintSheet])
949 (*aCollectorFunc)(mRuleProcessors[ePresHintSheet], aData);
950 nsRuleNode* lastPresHintRN = aRuleWalker->CurrentNode();
952 aRuleWalker->SetLevel(eDocSheet, false, true);
953 bool cutOffInheritance = false;
954 if (mBindingManager && aElement) {
955 // We can supply additional document-level sheets that should be walked.
956 mBindingManager->WalkRules(aCollectorFunc,
957 static_cast<ElementDependentRuleProcessorData*>(aData),
958 &cutOffInheritance);
960 if (!skipUserStyles && !cutOffInheritance && // NOTE: different
961 mRuleProcessors[eDocSheet])
962 (*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
963 nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
964 bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
965 nsTArray<nsRuleNode*> lastScopedRNs;
966 nsTArray<bool> haveImportantScopedRules;
967 bool haveAnyImportantScopedRules = false;
968 if (!skipUserStyles && !cutOffInheritance &&
969 aElement && aElement->IsElementInStyleScope()) {
970 lastScopedRNs.SetLength(mScopedDocSheetRuleProcessors.Length());
971 haveImportantScopedRules.SetLength(mScopedDocSheetRuleProcessors.Length());
972 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
973 aRuleWalker->SetLevel(eScopedDocSheet, false, true);
974 nsCSSRuleProcessor* processor =
975 static_cast<nsCSSRuleProcessor*>(mScopedDocSheetRuleProcessors[i].get());
976 aData->mScope = processor->GetScopeElement();
977 (*aCollectorFunc)(mScopedDocSheetRuleProcessors[i], aData);
978 lastScopedRNs[i] = aRuleWalker->CurrentNode();
979 haveImportantScopedRules[i] = !aRuleWalker->GetCheckForImportantRules();
980 haveAnyImportantScopedRules = haveAnyImportantScopedRules || haveImportantScopedRules[i];
982 aData->mScope = nullptr;
984 nsRuleNode* lastScopedRN = aRuleWalker->CurrentNode();
985 aRuleWalker->SetLevel(eStyleAttrSheet, false, true);
986 if (mRuleProcessors[eStyleAttrSheet])
987 (*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
988 nsRuleNode* lastStyleAttrRN = aRuleWalker->CurrentNode();
989 bool haveImportantStyleAttrRules = !aRuleWalker->GetCheckForImportantRules();
991 aRuleWalker->SetLevel(eOverrideSheet, false, true);
992 if (mRuleProcessors[eOverrideSheet])
993 (*aCollectorFunc)(mRuleProcessors[eOverrideSheet], aData);
994 nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
995 bool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
997 // This needs to match IsMoreSpecificThanAnimation() above.
998 aRuleWalker->SetLevel(eAnimationSheet, false, false);
999 (*aCollectorFunc)(mRuleProcessors[eAnimationSheet], aData);
1001 if (haveAnyImportantScopedRules) {
1002 for (uint32_t i = lastScopedRNs.Length(); i-- != 0; ) {
1003 aRuleWalker->SetLevel(eScopedDocSheet, true, false);
1004 nsRuleNode* startRN = lastScopedRNs[i];
1005 nsRuleNode* endRN = i == 0 ? lastDocRN : lastScopedRNs[i - 1];
1006 if (haveImportantScopedRules[i]) {
1007 AddImportantRules(startRN, endRN, aRuleWalker); // scoped
1009 #ifdef DEBUG
1010 else {
1011 AssertNoImportantRules(startRN, endRN);
1013 #endif
1016 #ifdef DEBUG
1017 else {
1018 AssertNoImportantRules(lastScopedRN, lastDocRN);
1020 #endif
1022 if (haveImportantDocRules) {
1023 aRuleWalker->SetLevel(eDocSheet, true, false);
1024 AddImportantRules(lastDocRN, lastPresHintRN, aRuleWalker); // doc
1026 #ifdef DEBUG
1027 else {
1028 AssertNoImportantRules(lastDocRN, lastPresHintRN);
1030 #endif
1032 if (haveImportantStyleAttrRules) {
1033 aRuleWalker->SetLevel(eStyleAttrSheet, true, false);
1034 AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker); // style attr
1036 #ifdef DEBUG
1037 else {
1038 AssertNoImportantRules(lastStyleAttrRN, lastScopedRN);
1040 #endif
1042 if (haveImportantOverrideRules) {
1043 aRuleWalker->SetLevel(eOverrideSheet, true, false);
1044 AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker); // override
1046 #ifdef DEBUG
1047 else {
1048 AssertNoImportantRules(lastOvrRN, lastStyleAttrRN);
1050 #endif
1052 #ifdef DEBUG
1053 AssertNoCSSRules(lastPresHintRN, lastUserRN);
1054 #endif
1056 if (haveImportantUserRules) {
1057 aRuleWalker->SetLevel(eUserSheet, true, false);
1058 AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
1060 #ifdef DEBUG
1061 else {
1062 AssertNoImportantRules(lastUserRN, lastAgentRN);
1064 #endif
1066 if (haveImportantUARules) {
1067 aRuleWalker->SetLevel(eAgentSheet, true, false);
1068 AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
1070 #ifdef DEBUG
1071 else {
1072 AssertNoImportantRules(lastAgentRN, lastRestrictionRN);
1074 #endif
1076 #ifdef DEBUG
1077 AssertNoCSSRules(lastRestrictionRN, mRuleTree);
1078 #endif
1080 #ifdef DEBUG
1081 nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
1082 #endif
1083 aRuleWalker->SetLevel(eTransitionSheet, false, false);
1084 (*aCollectorFunc)(mRuleProcessors[eTransitionSheet], aData);
1085 #ifdef DEBUG
1086 AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
1087 #endif
1091 // Enumerate all the rules in a way that doesn't care about the order
1092 // of the rules and doesn't walk !important-rules.
1093 void
1094 nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
1095 ElementDependentRuleProcessorData* aData,
1096 bool aWalkAllXBLStylesheets)
1098 if (mRuleProcessors[eAgentSheet])
1099 (*aFunc)(mRuleProcessors[eAgentSheet], aData);
1101 bool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
1102 if (!skipUserStyles && mRuleProcessors[eUserSheet]) // NOTE: different
1103 (*aFunc)(mRuleProcessors[eUserSheet], aData);
1105 if (mRuleProcessors[ePresHintSheet])
1106 (*aFunc)(mRuleProcessors[ePresHintSheet], aData);
1108 bool cutOffInheritance = false;
1109 if (mBindingManager) {
1110 // We can supply additional document-level sheets that should be walked.
1111 if (aWalkAllXBLStylesheets) {
1112 mBindingManager->WalkAllRules(aFunc, aData);
1113 } else {
1114 mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
1117 if (!skipUserStyles && !cutOffInheritance) {
1118 if (mRuleProcessors[eDocSheet]) // NOTE: different
1119 (*aFunc)(mRuleProcessors[eDocSheet], aData);
1120 if (aData->mElement->IsElementInStyleScope()) {
1121 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++)
1122 (*aFunc)(mScopedDocSheetRuleProcessors[i], aData);
1125 if (mRuleProcessors[eStyleAttrSheet])
1126 (*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
1127 if (mRuleProcessors[eOverrideSheet])
1128 (*aFunc)(mRuleProcessors[eOverrideSheet], aData);
1129 (*aFunc)(mRuleProcessors[eAnimationSheet], aData);
1130 (*aFunc)(mRuleProcessors[eTransitionSheet], aData);
1133 already_AddRefed<nsStyleContext>
1134 nsStyleSet::ResolveStyleFor(Element* aElement,
1135 nsStyleContext* aParentContext)
1137 TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1138 aElement->OwnerDoc());
1139 return ResolveStyleFor(aElement, aParentContext, treeContext);
1142 already_AddRefed<nsStyleContext>
1143 nsStyleSet::ResolveStyleFor(Element* aElement,
1144 nsStyleContext* aParentContext,
1145 TreeMatchContext& aTreeMatchContext)
1147 NS_ENSURE_FALSE(mInShutdown, nullptr);
1148 NS_ASSERTION(aElement, "aElement must not be null");
1150 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1151 aTreeMatchContext.ResetForUnvisitedMatching();
1152 ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker,
1153 aTreeMatchContext);
1154 FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
1155 &ruleWalker);
1157 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1158 nsRuleNode *visitedRuleNode = nullptr;
1160 if (aTreeMatchContext.HaveRelevantLink()) {
1161 aTreeMatchContext.ResetForVisitedMatching();
1162 ruleWalker.Reset();
1163 FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
1164 &ruleWalker);
1165 visitedRuleNode = ruleWalker.CurrentNode();
1168 uint32_t flags = eDoAnimation;
1169 if (nsCSSRuleProcessor::IsLink(aElement)) {
1170 flags |= eIsLink;
1172 if (nsCSSRuleProcessor::GetContentState(aElement, aTreeMatchContext).
1173 HasState(NS_EVENT_STATE_VISITED)) {
1174 flags |= eIsVisitedLink;
1176 if (aTreeMatchContext.mSkippingFlexItemStyleFixup) {
1177 flags |= eSkipFlexItemStyleFixup;
1180 return GetContext(aParentContext, ruleNode, visitedRuleNode,
1181 nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
1182 aElement, flags);
1185 already_AddRefed<nsStyleContext>
1186 nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
1187 const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules)
1189 NS_ENSURE_FALSE(mInShutdown, nullptr);
1191 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1192 // FIXME: Perhaps this should be passed in, but it probably doesn't
1193 // matter.
1194 ruleWalker.SetLevel(eDocSheet, false, false);
1195 for (uint32_t i = 0; i < aRules.Length(); i++) {
1196 ruleWalker.ForwardOnPossiblyCSSRule(aRules.ElementAt(i));
1199 return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
1200 nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
1201 nullptr, eNoFlags);
1204 already_AddRefed<nsStyleContext>
1205 nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
1206 nsStyleContext* aOldStyle,
1207 const nsTArray<RuleAndLevel>& aRules)
1209 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1210 for (int32_t i = aRules.Length() - 1; i >= 0; --i) {
1211 ruleWalker.SetLevel(aRules[i].mLevel, false, false);
1212 ruleWalker.ForwardOnPossiblyCSSRule(aRules[i].mRule);
1215 uint32_t flags = eNoFlags;
1216 if (aOldStyle->IsLinkContext()) {
1217 flags |= eIsLink;
1219 if (aOldStyle->RelevantLinkVisited()) {
1220 flags |= eIsVisitedLink;
1223 return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
1224 nullptr, nsCSSPseudoElements::ePseudo_NotPseudoElement,
1225 nullptr, flags);
1228 already_AddRefed<nsStyleContext>
1229 nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
1230 const nsCOMArray<nsIStyleRule> &aRules)
1232 NS_ENSURE_FALSE(mInShutdown, nullptr);
1234 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1235 ruleWalker.SetCurrentNode(aBaseContext->RuleNode());
1236 // FIXME: Perhaps this should be passed in, but it probably doesn't
1237 // matter.
1238 ruleWalker.SetLevel(eDocSheet, false, false);
1239 for (int32_t i = 0; i < aRules.Count(); i++) {
1240 ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
1243 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1244 nsRuleNode *visitedRuleNode = nullptr;
1246 if (aBaseContext->GetStyleIfVisited()) {
1247 ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->RuleNode());
1248 for (int32_t i = 0; i < aRules.Count(); i++) {
1249 ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
1251 visitedRuleNode = ruleWalker.CurrentNode();
1254 uint32_t flags = eNoFlags;
1255 if (aBaseContext->IsLinkContext()) {
1256 flags |= eIsLink;
1258 if (aBaseContext->RelevantLinkVisited()) {
1259 flags |= eIsVisitedLink;
1261 return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
1262 aBaseContext->GetPseudo(),
1263 aBaseContext->GetPseudoType(),
1264 nullptr, flags);
1267 already_AddRefed<nsStyleContext>
1268 nsStyleSet::ResolveStyleForNonElement(nsStyleContext* aParentContext)
1270 return GetContext(aParentContext, mRuleTree, nullptr,
1271 nsCSSAnonBoxes::mozNonElement,
1272 nsCSSPseudoElements::ePseudo_AnonBox, nullptr,
1273 eNoFlags);
1276 void
1277 nsStyleSet::WalkRestrictionRule(nsCSSPseudoElements::Type aPseudoType,
1278 nsRuleWalker* aRuleWalker)
1280 // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
1281 aRuleWalker->SetLevel(eAgentSheet, false, false);
1282 if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLetter)
1283 aRuleWalker->Forward(mFirstLetterRule);
1284 else if (aPseudoType == nsCSSPseudoElements::ePseudo_firstLine)
1285 aRuleWalker->Forward(mFirstLineRule);
1286 else if (aPseudoType == nsCSSPseudoElements::ePseudo_mozPlaceholder)
1287 aRuleWalker->Forward(mPlaceholderRule);
1290 already_AddRefed<nsStyleContext>
1291 nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
1292 nsCSSPseudoElements::Type aType,
1293 nsStyleContext* aParentContext)
1295 NS_ENSURE_FALSE(mInShutdown, nullptr);
1297 NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
1298 "must have pseudo element type");
1299 NS_ASSERTION(aParentElement, "Must have parent element");
1301 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1302 TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1303 aParentElement->OwnerDoc());
1304 PseudoElementRuleProcessorData data(PresContext(), aParentElement,
1305 &ruleWalker, aType, treeContext);
1306 WalkRestrictionRule(aType, &ruleWalker);
1307 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1308 aParentElement, &ruleWalker);
1310 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1311 nsRuleNode *visitedRuleNode = nullptr;
1313 if (treeContext.HaveRelevantLink()) {
1314 treeContext.ResetForVisitedMatching();
1315 ruleWalker.Reset();
1316 WalkRestrictionRule(aType, &ruleWalker);
1317 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1318 aParentElement, &ruleWalker);
1319 visitedRuleNode = ruleWalker.CurrentNode();
1322 // For pseudos, |data.IsLink()| being true means that
1323 // our parent node is a link.
1324 // Also: Flex containers shouldn't have pseudo-elements, so given that we're
1325 // looking up pseudo-element style, make sure we're not treating our node as
1326 // a flex item.
1327 uint32_t flags = eSkipFlexItemStyleFixup;
1328 if (aType == nsCSSPseudoElements::ePseudo_before ||
1329 aType == nsCSSPseudoElements::ePseudo_after) {
1330 flags |= eDoAnimation;
1333 return GetContext(aParentContext, ruleNode, visitedRuleNode,
1334 nsCSSPseudoElements::GetPseudoAtom(aType), aType,
1335 aParentElement, flags);
1338 already_AddRefed<nsStyleContext>
1339 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
1340 nsCSSPseudoElements::Type aType,
1341 nsStyleContext* aParentContext)
1343 TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1344 aParentElement->OwnerDoc());
1345 return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
1346 treeContext);
1349 already_AddRefed<nsStyleContext>
1350 nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
1351 nsCSSPseudoElements::Type aType,
1352 nsStyleContext* aParentContext,
1353 TreeMatchContext& aTreeMatchContext)
1355 NS_ENSURE_FALSE(mInShutdown, nullptr);
1357 NS_ASSERTION(aType < nsCSSPseudoElements::ePseudo_PseudoElementCount,
1358 "must have pseudo element type");
1359 NS_ASSERTION(aParentElement, "aParentElement must not be null");
1361 nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
1362 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1363 aTreeMatchContext.ResetForUnvisitedMatching();
1364 PseudoElementRuleProcessorData data(PresContext(), aParentElement,
1365 &ruleWalker, aType, aTreeMatchContext);
1366 WalkRestrictionRule(aType, &ruleWalker);
1367 // not the root if there was a restriction rule
1368 nsRuleNode *adjustedRoot = ruleWalker.CurrentNode();
1369 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1370 aParentElement, &ruleWalker);
1372 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1373 if (ruleNode == adjustedRoot) {
1374 return nullptr;
1377 nsRuleNode *visitedRuleNode = nullptr;
1379 if (aTreeMatchContext.HaveRelevantLink()) {
1380 aTreeMatchContext.ResetForVisitedMatching();
1381 ruleWalker.Reset();
1382 WalkRestrictionRule(aType, &ruleWalker);
1383 FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
1384 aParentElement, &ruleWalker);
1385 visitedRuleNode = ruleWalker.CurrentNode();
1388 // For pseudos, |data.IsLink()| being true means that
1389 // our parent node is a link.
1390 // Also: Flex containers shouldn't have pseudo-elements, so given that we're
1391 // looking up pseudo-element style, make sure we're not treating our node as
1392 // a flex item.
1393 uint32_t flags = eSkipFlexItemStyleFixup;
1394 if (aType == nsCSSPseudoElements::ePseudo_before ||
1395 aType == nsCSSPseudoElements::ePseudo_after) {
1396 flags |= eDoAnimation;
1399 nsRefPtr<nsStyleContext> result =
1400 GetContext(aParentContext, ruleNode, visitedRuleNode,
1401 pseudoTag, aType,
1402 aParentElement, flags);
1404 // For :before and :after pseudo-elements, having display: none or no
1405 // 'content' property is equivalent to not having the pseudo-element
1406 // at all.
1407 if (result &&
1408 (pseudoTag == nsCSSPseudoElements::before ||
1409 pseudoTag == nsCSSPseudoElements::after)) {
1410 const nsStyleDisplay *display = result->StyleDisplay();
1411 const nsStyleContent *content = result->StyleContent();
1412 // XXXldb What is contentCount for |content: ""|?
1413 if (display->mDisplay == NS_STYLE_DISPLAY_NONE ||
1414 content->ContentCount() == 0) {
1415 result = nullptr;
1419 return result.forget();
1422 already_AddRefed<nsStyleContext>
1423 nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
1424 nsStyleContext* aParentContext)
1426 NS_ENSURE_FALSE(mInShutdown, nullptr);
1428 #ifdef DEBUG
1429 bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag)
1430 #ifdef MOZ_XUL
1431 && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
1432 #endif
1434 NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
1435 #endif
1437 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1438 AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
1439 FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
1440 &ruleWalker);
1442 if (aPseudoTag == nsCSSAnonBoxes::pageContent) {
1443 // Add any @page rules that are specified.
1444 nsTArray<nsCSSPageRule*> rules;
1445 nsTArray<css::ImportantRule*> importantRules;
1446 nsPresContext* presContext = PresContext();
1447 presContext->StyleSet()->AppendPageRules(presContext, rules);
1448 for (uint32_t i = 0, i_end = rules.Length(); i != i_end; ++i) {
1449 ruleWalker.Forward(rules[i]);
1450 css::ImportantRule* importantRule = rules[i]->GetImportantRule();
1451 if (importantRule) {
1452 importantRules.AppendElement(importantRule);
1455 for (uint32_t i = 0, i_end = importantRules.Length(); i != i_end; ++i) {
1456 ruleWalker.Forward(importantRules[i]);
1460 return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
1461 aPseudoTag, nsCSSPseudoElements::ePseudo_AnonBox,
1462 nullptr, eNoFlags);
1465 #ifdef MOZ_XUL
1466 already_AddRefed<nsStyleContext>
1467 nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
1468 nsIAtom* aPseudoTag,
1469 nsStyleContext* aParentContext,
1470 nsICSSPseudoComparator* aComparator)
1472 NS_ENSURE_FALSE(mInShutdown, nullptr);
1474 NS_ASSERTION(aPseudoTag, "must have pseudo tag");
1475 NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
1476 "Unexpected pseudo");
1478 nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
1479 TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
1480 aParentElement->OwnerDoc());
1481 XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
1482 aPseudoTag, aComparator, treeContext);
1483 FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
1484 &ruleWalker);
1486 nsRuleNode *ruleNode = ruleWalker.CurrentNode();
1487 nsRuleNode *visitedRuleNode = nullptr;
1489 if (treeContext.HaveRelevantLink()) {
1490 treeContext.ResetForVisitedMatching();
1491 ruleWalker.Reset();
1492 FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data,
1493 aParentElement, &ruleWalker);
1494 visitedRuleNode = ruleWalker.CurrentNode();
1497 return GetContext(aParentContext, ruleNode, visitedRuleNode,
1498 // For pseudos, |data.IsLink()| being true means that
1499 // our parent node is a link.
1500 aPseudoTag, nsCSSPseudoElements::ePseudo_XULTree,
1501 nullptr, eNoFlags);
1503 #endif
1505 bool
1506 nsStyleSet::AppendFontFaceRules(nsPresContext* aPresContext,
1507 nsTArray<nsFontFaceRuleContainer>& aArray)
1509 NS_ENSURE_FALSE(mInShutdown, false);
1511 for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
1512 if (gCSSSheetTypes[i] == eScopedDocSheet)
1513 continue;
1514 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
1515 (mRuleProcessors[gCSSSheetTypes[i]].get());
1516 if (ruleProc && !ruleProc->AppendFontFaceRules(aPresContext, aArray))
1517 return false;
1519 return true;
1522 bool
1523 nsStyleSet::AppendKeyframesRules(nsPresContext* aPresContext,
1524 nsTArray<nsCSSKeyframesRule*>& aArray)
1526 NS_ENSURE_FALSE(mInShutdown, false);
1528 for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
1529 if (gCSSSheetTypes[i] == eScopedDocSheet)
1530 continue;
1531 nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
1532 (mRuleProcessors[gCSSSheetTypes[i]].get());
1533 if (ruleProc && !ruleProc->AppendKeyframesRules(aPresContext, aArray))
1534 return false;
1536 return true;
1539 bool
1540 nsStyleSet::AppendPageRules(nsPresContext* aPresContext,
1541 nsTArray<nsCSSPageRule*>& aArray)
1543 NS_ENSURE_FALSE(mInShutdown, false);
1545 for (uint32_t i = 0; i < NS_ARRAY_LENGTH(gCSSSheetTypes); ++i) {
1546 if (gCSSSheetTypes[i] == eScopedDocSheet)
1547 continue;
1548 nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
1549 (mRuleProcessors[gCSSSheetTypes[i]].get());
1550 if (ruleProc && !ruleProc->AppendPageRules(aPresContext, aArray))
1551 return false;
1553 return true;
1556 void
1557 nsStyleSet::BeginShutdown(nsPresContext* aPresContext)
1559 mInShutdown = 1;
1560 mRoots.Clear(); // no longer valid, since we won't keep it up to date
1563 void
1564 nsStyleSet::Shutdown(nsPresContext* aPresContext)
1566 mRuleTree->Destroy();
1567 mRuleTree = nullptr;
1569 // We can have old rule trees either because:
1570 // (1) we failed the assertions in EndReconstruct, or
1571 // (2) we're shutting down within a reconstruct (see bug 462392)
1572 for (uint32_t i = mOldRuleTrees.Length(); i > 0; ) {
1573 --i;
1574 mOldRuleTrees[i]->Destroy();
1576 mOldRuleTrees.Clear();
1579 static const uint32_t kGCInterval = 300;
1581 void
1582 nsStyleSet::NotifyStyleContextDestroyed(nsPresContext* aPresContext,
1583 nsStyleContext* aStyleContext)
1585 if (mInShutdown)
1586 return;
1588 // Remove style contexts from mRoots even if mOldRuleTree is non-null. This
1589 // could be a style context from the new ruletree!
1590 if (!aStyleContext->GetParent()) {
1591 mRoots.RemoveElement(aStyleContext);
1594 if (mInReconstruct)
1595 return;
1597 if (mUnusedRuleNodeCount >= kGCInterval) {
1598 GCRuleTrees();
1602 void
1603 nsStyleSet::GCRuleTrees()
1605 mUnusedRuleNodeCount = 0;
1607 // Mark the style context tree by marking all style contexts which
1608 // have no parent, which will mark all descendants. This will reach
1609 // style contexts in the undisplayed map and "additional style
1610 // contexts" since they are descendants of the roots.
1611 for (int32_t i = mRoots.Length() - 1; i >= 0; --i) {
1612 mRoots[i]->Mark();
1615 // Sweep the rule tree.
1616 #ifdef DEBUG
1617 bool deleted =
1618 #endif
1619 mRuleTree->Sweep();
1620 NS_ASSERTION(!deleted, "Root node must not be gc'd");
1622 // Sweep the old rule trees.
1623 for (uint32_t i = mOldRuleTrees.Length(); i > 0; ) {
1624 --i;
1625 if (mOldRuleTrees[i]->Sweep()) {
1626 // It was deleted, as it should be.
1627 mOldRuleTrees.RemoveElementAt(i);
1628 } else {
1629 NS_NOTREACHED("old rule tree still referenced");
1634 static inline nsRuleNode*
1635 SkipAnimationRules(nsRuleNode* aRuleNode, Element* aElement, bool isPseudo)
1637 nsRuleNode* ruleNode = aRuleNode;
1638 while (!ruleNode->IsRoot() &&
1639 (ruleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
1640 ruleNode->GetLevel() == nsStyleSet::eAnimationSheet)) {
1641 ruleNode = ruleNode->GetParent();
1643 if (ruleNode != aRuleNode) {
1644 NS_ASSERTION(aElement, "How can we have transition rules but no element?");
1645 // Need to do an animation restyle, just like
1646 // nsTransitionManager::WalkTransitionRule and
1647 // nsAnimationManager::GetAnimationRule would.
1648 nsRestyleHint hint = isPseudo ? eRestyle_Subtree : eRestyle_Self;
1649 aRuleNode->PresContext()->PresShell()->RestyleForAnimation(aElement, hint);
1651 return ruleNode;
1654 already_AddRefed<nsStyleContext>
1655 nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
1656 nsStyleContext* aNewParentContext,
1657 Element* aElement)
1659 if (!aStyleContext) {
1660 NS_NOTREACHED("must have style context");
1661 return nullptr;
1664 // This short-circuit is OK because we don't call TryStartingTransition
1665 // during style reresolution if the style context pointer hasn't changed.
1666 if (aStyleContext->GetParent() == aNewParentContext) {
1667 nsRefPtr<nsStyleContext> ret = aStyleContext;
1668 return ret.forget();
1671 nsIAtom* pseudoTag = aStyleContext->GetPseudo();
1672 nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
1673 nsRuleNode* ruleNode = aStyleContext->RuleNode();
1675 // Skip transition rules as needed just like
1676 // nsTransitionManager::WalkTransitionRule would.
1677 bool skipAnimationRules = PresContext()->IsProcessingRestyles() &&
1678 !PresContext()->IsProcessingAnimationStyleChange();
1679 if (skipAnimationRules) {
1680 // Make sure that we're not using transition rules or animation rules for
1681 // our new style context. If we need them, an animation restyle will
1682 // provide.
1683 ruleNode =
1684 SkipAnimationRules(ruleNode, aElement,
1685 pseudoType !=
1686 nsCSSPseudoElements::ePseudo_NotPseudoElement);
1689 nsRuleNode* visitedRuleNode = nullptr;
1690 nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
1691 // Reparenting a style context just changes where we inherit from,
1692 // not what rules we match or what our DOM looks like. In
1693 // particular, it doesn't change whether this is a style context for
1694 // a link.
1695 if (visitedContext) {
1696 visitedRuleNode = visitedContext->RuleNode();
1697 // Again, skip transition rules as needed
1698 if (skipAnimationRules) {
1699 // FIXME do something here for animations?
1700 visitedRuleNode =
1701 SkipAnimationRules(visitedRuleNode, aElement,
1702 pseudoType !=
1703 nsCSSPseudoElements::ePseudo_NotPseudoElement);
1707 uint32_t flags = eNoFlags;
1708 if (aStyleContext->IsLinkContext()) {
1709 flags |= eIsLink;
1712 // If we're a style context for a link, then we already know whether
1713 // our relevant link is visited, since that does not depend on our
1714 // parent. Otherwise, we need to match aNewParentContext.
1715 bool relevantLinkVisited = aStyleContext->IsLinkContext() ?
1716 aStyleContext->RelevantLinkVisited() :
1717 aNewParentContext->RelevantLinkVisited();
1719 if (relevantLinkVisited) {
1720 flags |= eIsVisitedLink;
1723 if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement ||
1724 pseudoType == nsCSSPseudoElements::ePseudo_before ||
1725 pseudoType == nsCSSPseudoElements::ePseudo_after) {
1726 flags |= eDoAnimation;
1729 if (aElement && aElement->IsRootOfAnonymousSubtree()) {
1730 // For anonymous subtree roots, don't tweak "display" value based on
1731 // whether or not the parent is styled as a flex container. (If the parent
1732 // has anonymous-subtree kids, then we know it's not actually going to get
1733 // a flex container frame, anyway.)
1734 flags |= eSkipFlexItemStyleFixup;
1737 return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
1738 pseudoTag, pseudoType,
1739 aElement, flags);
1742 struct MOZ_STACK_CLASS StatefulData : public StateRuleProcessorData {
1743 StatefulData(nsPresContext* aPresContext, Element* aElement,
1744 nsEventStates aStateMask, TreeMatchContext& aTreeMatchContext)
1745 : StateRuleProcessorData(aPresContext, aElement, aStateMask,
1746 aTreeMatchContext),
1747 mHint(nsRestyleHint(0))
1749 nsRestyleHint mHint;
1752 static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
1753 void *aData)
1755 StatefulData* data = (StatefulData*)aData;
1756 if (aProcessor->HasDocumentStateDependentStyle(data)) {
1757 data->mHint = eRestyle_Self;
1758 return false; // don't continue
1760 return true; // continue
1763 // Test if style is dependent on a document state.
1764 bool
1765 nsStyleSet::HasDocumentStateDependentStyle(nsPresContext* aPresContext,
1766 nsIContent* aContent,
1767 nsEventStates aStateMask)
1769 if (!aContent || !aContent->IsElement())
1770 return false;
1772 TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
1773 aContent->OwnerDoc());
1774 StatefulData data(aPresContext, aContent->AsElement(), aStateMask,
1775 treeContext);
1776 WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
1777 return data.mHint != 0;
1780 static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
1781 void *aData)
1783 StatefulData* data = (StatefulData*)aData;
1784 nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
1785 data->mHint = nsRestyleHint(data->mHint | hint);
1786 return true; // continue
1789 // Test if style is dependent on content state
1790 nsRestyleHint
1791 nsStyleSet::HasStateDependentStyle(nsPresContext* aPresContext,
1792 Element* aElement,
1793 nsEventStates aStateMask)
1795 TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
1796 aElement->OwnerDoc());
1797 StatefulData data(aPresContext, aElement, aStateMask, treeContext);
1798 WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
1799 return data.mHint;
1802 struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
1803 AttributeData(nsPresContext* aPresContext,
1804 Element* aElement, nsIAtom* aAttribute, int32_t aModType,
1805 bool aAttrHasChanged, TreeMatchContext& aTreeMatchContext)
1806 : AttributeRuleProcessorData(aPresContext, aElement, aAttribute, aModType,
1807 aAttrHasChanged, aTreeMatchContext),
1808 mHint(nsRestyleHint(0))
1810 nsRestyleHint mHint;
1813 static bool
1814 SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
1816 AttributeData* data = (AttributeData*)aData;
1817 nsRestyleHint hint = aProcessor->HasAttributeDependentStyle(data);
1818 data->mHint = nsRestyleHint(data->mHint | hint);
1819 return true; // continue
1822 // Test if style is dependent on content state
1823 nsRestyleHint
1824 nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
1825 Element* aElement,
1826 nsIAtom* aAttribute,
1827 int32_t aModType,
1828 bool aAttrHasChanged)
1830 TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
1831 aElement->OwnerDoc());
1832 AttributeData data(aPresContext, aElement, aAttribute,
1833 aModType, aAttrHasChanged, treeContext);
1834 WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
1835 return data.mHint;
1838 bool
1839 nsStyleSet::MediumFeaturesChanged(nsPresContext* aPresContext)
1841 // We can't use WalkRuleProcessors without a content node.
1842 bool stylesChanged = false;
1843 for (uint32_t i = 0; i < ArrayLength(mRuleProcessors); ++i) {
1844 nsIStyleRuleProcessor *processor = mRuleProcessors[i];
1845 if (!processor) {
1846 continue;
1848 bool thisChanged = processor->MediumFeaturesChanged(aPresContext);
1849 stylesChanged = stylesChanged || thisChanged;
1851 for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); ++i) {
1852 nsIStyleRuleProcessor *processor = mScopedDocSheetRuleProcessors[i];
1853 bool thisChanged = processor->MediumFeaturesChanged(aPresContext);
1854 stylesChanged = stylesChanged || thisChanged;
1857 if (mBindingManager) {
1858 bool thisChanged = false;
1859 mBindingManager->MediumFeaturesChanged(aPresContext, &thisChanged);
1860 stylesChanged = stylesChanged || thisChanged;
1863 return stylesChanged;
1866 nsCSSStyleSheet::EnsureUniqueInnerResult
1867 nsStyleSet::EnsureUniqueInnerOnCSSSheets()
1869 nsAutoTArray<nsCSSStyleSheet*, 32> queue;
1870 for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
1871 nsCOMArray<nsIStyleSheet> &sheets = mSheets[gCSSSheetTypes[i]];
1872 for (uint32_t j = 0, j_end = sheets.Count(); j < j_end; ++j) {
1873 nsCSSStyleSheet *sheet = static_cast<nsCSSStyleSheet*>(sheets[j]);
1874 if (!queue.AppendElement(sheet)) {
1875 return nsCSSStyleSheet::eUniqueInner_CloneFailed;
1880 if (mBindingManager) {
1881 mBindingManager->AppendAllSheets(queue);
1884 nsCSSStyleSheet::EnsureUniqueInnerResult res =
1885 nsCSSStyleSheet::eUniqueInner_AlreadyUnique;
1886 while (!queue.IsEmpty()) {
1887 uint32_t idx = queue.Length() - 1;
1888 nsCSSStyleSheet *sheet = queue[idx];
1889 queue.RemoveElementAt(idx);
1891 nsCSSStyleSheet::EnsureUniqueInnerResult sheetRes =
1892 sheet->EnsureUniqueInner();
1893 if (sheetRes == nsCSSStyleSheet::eUniqueInner_CloneFailed) {
1894 return sheetRes;
1896 if (sheetRes == nsCSSStyleSheet::eUniqueInner_ClonedInner) {
1897 res = sheetRes;
1900 // Enqueue all the sheet's children.
1901 if (!sheet->AppendAllChildSheets(queue)) {
1902 return nsCSSStyleSheet::eUniqueInner_CloneFailed;
1905 return res;
1908 nsIStyleRule*
1909 nsStyleSet::InitialStyleRule()
1911 if (!mInitialStyleRule) {
1912 mInitialStyleRule = new nsInitialStyleRule;
1914 return mInitialStyleRule;