Rule.cpp (5197B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* base class for all rule types in a CSS style sheet */ 8 9 #include "Rule.h" 10 11 #include "mozilla/HoldDropJSObjects.h" 12 #include "mozilla/ServoBindings.h" 13 #include "mozilla/css/GroupRule.h" 14 #include "mozilla/dom/CSSImportRule.h" 15 #include "mozilla/dom/Document.h" 16 #include "mozilla/dom/DocumentOrShadowRoot.h" 17 #include "nsCCUncollectableMarker.h" 18 #include "nsWrapperCacheInlines.h" 19 20 using namespace mozilla; 21 using namespace mozilla::dom; 22 23 namespace mozilla::css { 24 25 NS_IMPL_CYCLE_COLLECTING_ADDREF(Rule) 26 NS_IMPL_CYCLE_COLLECTING_RELEASE(Rule) 27 28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Rule) 29 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 30 NS_INTERFACE_MAP_ENTRY(nsISupports) 31 NS_INTERFACE_MAP_END 32 33 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(Rule) 34 35 bool Rule::IsCCLeaf() const { return !PreservingWrapper(); } 36 37 bool Rule::IsKnownLive() const { 38 if (HasKnownLiveWrapper()) { 39 return true; 40 } 41 42 StyleSheet* sheet = GetStyleSheet(); 43 if (!sheet) { 44 return false; 45 } 46 47 Document* doc = sheet->GetKeptAliveByDocument(); 48 return doc && 49 nsCCUncollectableMarker::InGeneration(doc->GetMarkedCCGeneration()); 50 } 51 52 void Rule::UnlinkDeclarationWrapper(nsWrapperCache& aDecl) { 53 // We have to be a bit careful here. We have two separate nsWrapperCache 54 // instances, aDecl and this, that both correspond to the same CC participant: 55 // this. If we just used ReleaseWrapper() on one of them, that would 56 // unpreserve that one wrapper, then trace us with a tracer that clears JS 57 // things, and we would clear the wrapper on the cache that has not 58 // unpreserved the wrapper yet. That would violate the invariant that the 59 // cache keeps caching the wrapper until the wrapper dies. 60 // 61 // So instead we use a special case version of ReleaseWrapper to unpreserve 62 // both wrappers before doing any clearing. 63 bool needDrop = PreservingWrapper() || aDecl.PreservingWrapper(); 64 ReleaseWrapperWithoutDrop(); 65 aDecl.ReleaseWrapperWithoutDrop(); 66 if (needDrop) { 67 DropJSObjects(this); 68 } 69 } 70 71 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Rule) 72 return tmp->IsCCLeaf() || tmp->IsKnownLive(); 73 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END 74 75 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(Rule) 76 // Please see documentation for nsCycleCollectionParticipant::CanSkip* for why 77 // we need to check HasNothingToTrace here but not in the other two CanSkip 78 // methods. 79 return tmp->IsCCLeaf() || (tmp->IsKnownLive() && tmp->HasNothingToTrace(tmp)); 80 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END 81 82 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Rule) 83 return tmp->IsCCLeaf() || tmp->IsKnownLive(); 84 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END 85 86 /* virtual */ 87 void Rule::DropSheetReference() { mSheet = nullptr; } 88 89 void Rule::SetCssText(const nsACString& aCssText) { 90 // We used to throw for some rule types, but not all. Specifically, we did 91 // not throw for StyleRule. Let's just always not throw. 92 } 93 94 Rule* Rule::GetParentRule() const { return mParentRule; } 95 96 #ifdef DEBUG 97 void Rule::AssertParentRuleType() { 98 // Would be nice to check that this->Type() is StyleCssRuleType::Keyframe 99 // when mParentRule->Tye() is StyleCssRuleType::Keyframes, but we can't call 100 // this->Type() here since it's virtual. 101 // Same for StyleCssRuleType::Margin and StyleCssRuleType::Page. 102 if (mParentRule) { 103 auto type = mParentRule->Type(); 104 MOZ_ASSERT(type == StyleCssRuleType::Media || 105 type == StyleCssRuleType::Style || 106 type == StyleCssRuleType::Document || 107 type == StyleCssRuleType::Supports || 108 type == StyleCssRuleType::Keyframes || 109 type == StyleCssRuleType::LayerBlock || 110 type == StyleCssRuleType::Container || 111 type == StyleCssRuleType::Scope || 112 type == StyleCssRuleType::StartingStyle || 113 type == StyleCssRuleType::Page); 114 } 115 } 116 #endif 117 118 bool Rule::IsReadOnly() const { 119 MOZ_ASSERT(!mSheet || !mParentRule || 120 mSheet->IsReadOnly() == mParentRule->IsReadOnly(), 121 "a parent rule should be read only iff the owning sheet is " 122 "read only"); 123 return mSheet && mSheet->IsReadOnly(); 124 } 125 126 bool Rule::IsIncompleteImportRule() const { 127 if (Type() != StyleCssRuleType::Import) { 128 return false; 129 } 130 auto* sheet = static_cast<const dom::CSSImportRule*>(this)->GetStyleSheet(); 131 return !sheet || !sheet->IsComplete(); 132 } 133 134 auto Rule::GetContainingRuleStateForParsing() const -> ContainingRuleState { 135 ContainingRuleState result; 136 for (const auto* rule = this; rule; rule = rule->GetParentRule()) { 137 auto type = rule->Type(); 138 result.mContainingTypes |= (1 << UnderlyingValue(type)); 139 if (result.mParseRelativeType.isNothing() && 140 (type == StyleCssRuleType::Style || type == StyleCssRuleType::Scope)) { 141 result.mParseRelativeType.emplace(type); 142 } 143 } 144 return result; 145 } 146 147 } // namespace mozilla::css